git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4891 818b1a75-f10b-46b9-bf7c-635c3b92a50f
This commit is contained in:
@@ -1 +0,0 @@
|
|||||||
/usr/share/automake-1.11/COPYING
|
|
||||||
@@ -1,370 +0,0 @@
|
|||||||
Installation Instructions
|
|
||||||
*************************
|
|
||||||
|
|
||||||
Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
|
|
||||||
Inc.
|
|
||||||
|
|
||||||
Copying and distribution of this file, with or without modification,
|
|
||||||
are permitted in any medium without royalty provided the copyright
|
|
||||||
notice and this notice are preserved. This file is offered as-is,
|
|
||||||
without warranty of any kind.
|
|
||||||
|
|
||||||
Basic Installation
|
|
||||||
==================
|
|
||||||
|
|
||||||
Briefly, the shell commands `./configure; make; make install' should
|
|
||||||
configure, build, and install this package. The following
|
|
||||||
more-detailed instructions are generic; see the `README' file for
|
|
||||||
instructions specific to this package. Some packages provide this
|
|
||||||
`INSTALL' file but do not implement all of the features documented
|
|
||||||
below. The lack of an optional feature in a given package is not
|
|
||||||
necessarily a bug. More recommendations for GNU packages can be found
|
|
||||||
in *note Makefile Conventions: (standards)Makefile Conventions.
|
|
||||||
|
|
||||||
The `configure' shell script attempts to guess correct values for
|
|
||||||
various system-dependent variables used during compilation. It uses
|
|
||||||
those values to create a `Makefile' in each directory of the package.
|
|
||||||
It may also create one or more `.h' files containing system-dependent
|
|
||||||
definitions. Finally, it creates a shell script `config.status' that
|
|
||||||
you can run in the future to recreate the current configuration, and a
|
|
||||||
file `config.log' containing compiler output (useful mainly for
|
|
||||||
debugging `configure').
|
|
||||||
|
|
||||||
It can also use an optional file (typically called `config.cache'
|
|
||||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
|
||||||
the results of its tests to speed up reconfiguring. Caching is
|
|
||||||
disabled by default to prevent problems with accidental use of stale
|
|
||||||
cache files.
|
|
||||||
|
|
||||||
If you need to do unusual things to compile the package, please try
|
|
||||||
to figure out how `configure' could check whether to do them, and mail
|
|
||||||
diffs or instructions to the address given in the `README' so they can
|
|
||||||
be considered for the next release. If you are using the cache, and at
|
|
||||||
some point `config.cache' contains results you don't want to keep, you
|
|
||||||
may remove or edit it.
|
|
||||||
|
|
||||||
The file `configure.ac' (or `configure.in') is used to create
|
|
||||||
`configure' by a program called `autoconf'. You need `configure.ac' if
|
|
||||||
you want to change it or regenerate `configure' using a newer version
|
|
||||||
of `autoconf'.
|
|
||||||
|
|
||||||
The simplest way to compile this package is:
|
|
||||||
|
|
||||||
1. `cd' to the directory containing the package's source code and type
|
|
||||||
`./configure' to configure the package for your system.
|
|
||||||
|
|
||||||
Running `configure' might take a while. While running, it prints
|
|
||||||
some messages telling which features it is checking for.
|
|
||||||
|
|
||||||
2. Type `make' to compile the package.
|
|
||||||
|
|
||||||
3. Optionally, type `make check' to run any self-tests that come with
|
|
||||||
the package, generally using the just-built uninstalled binaries.
|
|
||||||
|
|
||||||
4. Type `make install' to install the programs and any data files and
|
|
||||||
documentation. When installing into a prefix owned by root, it is
|
|
||||||
recommended that the package be configured and built as a regular
|
|
||||||
user, and only the `make install' phase executed with root
|
|
||||||
privileges.
|
|
||||||
|
|
||||||
5. Optionally, type `make installcheck' to repeat any self-tests, but
|
|
||||||
this time using the binaries in their final installed location.
|
|
||||||
This target does not install anything. Running this target as a
|
|
||||||
regular user, particularly if the prior `make install' required
|
|
||||||
root privileges, verifies that the installation completed
|
|
||||||
correctly.
|
|
||||||
|
|
||||||
6. You can remove the program binaries and object files from the
|
|
||||||
source code directory by typing `make clean'. To also remove the
|
|
||||||
files that `configure' created (so you can compile the package for
|
|
||||||
a different kind of computer), type `make distclean'. There is
|
|
||||||
also a `make maintainer-clean' target, but that is intended mainly
|
|
||||||
for the package's developers. If you use it, you may have to get
|
|
||||||
all sorts of other programs in order to regenerate files that came
|
|
||||||
with the distribution.
|
|
||||||
|
|
||||||
7. Often, you can also type `make uninstall' to remove the installed
|
|
||||||
files again. In practice, not all packages have tested that
|
|
||||||
uninstallation works correctly, even though it is required by the
|
|
||||||
GNU Coding Standards.
|
|
||||||
|
|
||||||
8. Some packages, particularly those that use Automake, provide `make
|
|
||||||
distcheck', which can by used by developers to test that all other
|
|
||||||
targets like `make install' and `make uninstall' work correctly.
|
|
||||||
This target is generally not run by end users.
|
|
||||||
|
|
||||||
Compilers and Options
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Some systems require unusual options for compilation or linking that
|
|
||||||
the `configure' script does not know about. Run `./configure --help'
|
|
||||||
for details on some of the pertinent environment variables.
|
|
||||||
|
|
||||||
You can give `configure' initial values for configuration parameters
|
|
||||||
by setting variables in the command line or in the environment. Here
|
|
||||||
is an example:
|
|
||||||
|
|
||||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
|
||||||
|
|
||||||
*Note Defining Variables::, for more details.
|
|
||||||
|
|
||||||
Compiling For Multiple Architectures
|
|
||||||
====================================
|
|
||||||
|
|
||||||
You can compile the package for more than one kind of computer at the
|
|
||||||
same time, by placing the object files for each architecture in their
|
|
||||||
own directory. To do this, you can use GNU `make'. `cd' to the
|
|
||||||
directory where you want the object files and executables to go and run
|
|
||||||
the `configure' script. `configure' automatically checks for the
|
|
||||||
source code in the directory that `configure' is in and in `..'. This
|
|
||||||
is known as a "VPATH" build.
|
|
||||||
|
|
||||||
With a non-GNU `make', it is safer to compile the package for one
|
|
||||||
architecture at a time in the source code directory. After you have
|
|
||||||
installed the package for one architecture, use `make distclean' before
|
|
||||||
reconfiguring for another architecture.
|
|
||||||
|
|
||||||
On MacOS X 10.5 and later systems, you can create libraries and
|
|
||||||
executables that work on multiple system types--known as "fat" or
|
|
||||||
"universal" binaries--by specifying multiple `-arch' options to the
|
|
||||||
compiler but only a single `-arch' option to the preprocessor. Like
|
|
||||||
this:
|
|
||||||
|
|
||||||
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
|
||||||
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
|
||||||
CPP="gcc -E" CXXCPP="g++ -E"
|
|
||||||
|
|
||||||
This is not guaranteed to produce working output in all cases, you
|
|
||||||
may have to build one architecture at a time and combine the results
|
|
||||||
using the `lipo' tool if you have problems.
|
|
||||||
|
|
||||||
Installation Names
|
|
||||||
==================
|
|
||||||
|
|
||||||
By default, `make install' installs the package's commands under
|
|
||||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
|
||||||
can specify an installation prefix other than `/usr/local' by giving
|
|
||||||
`configure' the option `--prefix=PREFIX', where PREFIX must be an
|
|
||||||
absolute file name.
|
|
||||||
|
|
||||||
You can specify separate installation prefixes for
|
|
||||||
architecture-specific files and architecture-independent files. If you
|
|
||||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
|
||||||
PREFIX as the prefix for installing programs and libraries.
|
|
||||||
Documentation and other data files still use the regular prefix.
|
|
||||||
|
|
||||||
In addition, if you use an unusual directory layout you can give
|
|
||||||
options like `--bindir=DIR' to specify different values for particular
|
|
||||||
kinds of files. Run `configure --help' for a list of the directories
|
|
||||||
you can set and what kinds of files go in them. In general, the
|
|
||||||
default for these options is expressed in terms of `${prefix}', so that
|
|
||||||
specifying just `--prefix' will affect all of the other directory
|
|
||||||
specifications that were not explicitly provided.
|
|
||||||
|
|
||||||
The most portable way to affect installation locations is to pass the
|
|
||||||
correct locations to `configure'; however, many packages provide one or
|
|
||||||
both of the following shortcuts of passing variable assignments to the
|
|
||||||
`make install' command line to change installation locations without
|
|
||||||
having to reconfigure or recompile.
|
|
||||||
|
|
||||||
The first method involves providing an override variable for each
|
|
||||||
affected directory. For example, `make install
|
|
||||||
prefix=/alternate/directory' will choose an alternate location for all
|
|
||||||
directory configuration variables that were expressed in terms of
|
|
||||||
`${prefix}'. Any directories that were specified during `configure',
|
|
||||||
but not in terms of `${prefix}', must each be overridden at install
|
|
||||||
time for the entire installation to be relocated. The approach of
|
|
||||||
makefile variable overrides for each directory variable is required by
|
|
||||||
the GNU Coding Standards, and ideally causes no recompilation.
|
|
||||||
However, some platforms have known limitations with the semantics of
|
|
||||||
shared libraries that end up requiring recompilation when using this
|
|
||||||
method, particularly noticeable in packages that use GNU Libtool.
|
|
||||||
|
|
||||||
The second method involves providing the `DESTDIR' variable. For
|
|
||||||
example, `make install DESTDIR=/alternate/directory' will prepend
|
|
||||||
`/alternate/directory' before all installation names. The approach of
|
|
||||||
`DESTDIR' overrides is not required by the GNU Coding Standards, and
|
|
||||||
does not work on platforms that have drive letters. On the other hand,
|
|
||||||
it does better at avoiding recompilation issues, and works well even
|
|
||||||
when some directory options were not specified in terms of `${prefix}'
|
|
||||||
at `configure' time.
|
|
||||||
|
|
||||||
Optional Features
|
|
||||||
=================
|
|
||||||
|
|
||||||
If the package supports it, you can cause programs to be installed
|
|
||||||
with an extra prefix or suffix on their names by giving `configure' the
|
|
||||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
|
||||||
|
|
||||||
Some packages pay attention to `--enable-FEATURE' options to
|
|
||||||
`configure', where FEATURE indicates an optional part of the package.
|
|
||||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
|
||||||
is something like `gnu-as' or `x' (for the X Window System). The
|
|
||||||
`README' should mention any `--enable-' and `--with-' options that the
|
|
||||||
package recognizes.
|
|
||||||
|
|
||||||
For packages that use the X Window System, `configure' can usually
|
|
||||||
find the X include and library files automatically, but if it doesn't,
|
|
||||||
you can use the `configure' options `--x-includes=DIR' and
|
|
||||||
`--x-libraries=DIR' to specify their locations.
|
|
||||||
|
|
||||||
Some packages offer the ability to configure how verbose the
|
|
||||||
execution of `make' will be. For these packages, running `./configure
|
|
||||||
--enable-silent-rules' sets the default to minimal output, which can be
|
|
||||||
overridden with `make V=1'; while running `./configure
|
|
||||||
--disable-silent-rules' sets the default to verbose, which can be
|
|
||||||
overridden with `make V=0'.
|
|
||||||
|
|
||||||
Particular systems
|
|
||||||
==================
|
|
||||||
|
|
||||||
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
|
|
||||||
CC is not installed, it is recommended to use the following options in
|
|
||||||
order to use an ANSI C compiler:
|
|
||||||
|
|
||||||
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
|
|
||||||
|
|
||||||
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
|
|
||||||
|
|
||||||
HP-UX `make' updates targets which have the same time stamps as
|
|
||||||
their prerequisites, which makes it generally unusable when shipped
|
|
||||||
generated files such as `configure' are involved. Use GNU `make'
|
|
||||||
instead.
|
|
||||||
|
|
||||||
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
|
|
||||||
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
|
|
||||||
a workaround. If GNU CC is not installed, it is therefore recommended
|
|
||||||
to try
|
|
||||||
|
|
||||||
./configure CC="cc"
|
|
||||||
|
|
||||||
and if that doesn't work, try
|
|
||||||
|
|
||||||
./configure CC="cc -nodtk"
|
|
||||||
|
|
||||||
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
|
|
||||||
directory contains several dysfunctional programs; working variants of
|
|
||||||
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
|
|
||||||
in your `PATH', put it _after_ `/usr/bin'.
|
|
||||||
|
|
||||||
On Haiku, software installed for all users goes in `/boot/common',
|
|
||||||
not `/usr/local'. It is recommended to use the following options:
|
|
||||||
|
|
||||||
./configure --prefix=/boot/common
|
|
||||||
|
|
||||||
Specifying the System Type
|
|
||||||
==========================
|
|
||||||
|
|
||||||
There may be some features `configure' cannot figure out
|
|
||||||
automatically, but needs to determine by the type of machine the package
|
|
||||||
will run on. Usually, assuming the package is built to be run on the
|
|
||||||
_same_ architectures, `configure' can figure that out, but if it prints
|
|
||||||
a message saying it cannot guess the machine type, give it the
|
|
||||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
|
||||||
type, such as `sun4', or a canonical name which has the form:
|
|
||||||
|
|
||||||
CPU-COMPANY-SYSTEM
|
|
||||||
|
|
||||||
where SYSTEM can have one of these forms:
|
|
||||||
|
|
||||||
OS
|
|
||||||
KERNEL-OS
|
|
||||||
|
|
||||||
See the file `config.sub' for the possible values of each field. If
|
|
||||||
`config.sub' isn't included in this package, then this package doesn't
|
|
||||||
need to know the machine type.
|
|
||||||
|
|
||||||
If you are _building_ compiler tools for cross-compiling, you should
|
|
||||||
use the option `--target=TYPE' to select the type of system they will
|
|
||||||
produce code for.
|
|
||||||
|
|
||||||
If you want to _use_ a cross compiler, that generates code for a
|
|
||||||
platform different from the build platform, you should specify the
|
|
||||||
"host" platform (i.e., that on which the generated programs will
|
|
||||||
eventually be run) with `--host=TYPE'.
|
|
||||||
|
|
||||||
Sharing Defaults
|
|
||||||
================
|
|
||||||
|
|
||||||
If you want to set default values for `configure' scripts to share,
|
|
||||||
you can create a site shell script called `config.site' that gives
|
|
||||||
default values for variables like `CC', `cache_file', and `prefix'.
|
|
||||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
|
||||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
|
||||||
`CONFIG_SITE' environment variable to the location of the site script.
|
|
||||||
A warning: not all `configure' scripts look for a site script.
|
|
||||||
|
|
||||||
Defining Variables
|
|
||||||
==================
|
|
||||||
|
|
||||||
Variables not defined in a site shell script can be set in the
|
|
||||||
environment passed to `configure'. However, some packages may run
|
|
||||||
configure again during the build, and the customized values of these
|
|
||||||
variables may be lost. In order to avoid this problem, you should set
|
|
||||||
them in the `configure' command line, using `VAR=value'. For example:
|
|
||||||
|
|
||||||
./configure CC=/usr/local2/bin/gcc
|
|
||||||
|
|
||||||
causes the specified `gcc' to be used as the C compiler (unless it is
|
|
||||||
overridden in the site shell script).
|
|
||||||
|
|
||||||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
|
|
||||||
an Autoconf bug. Until the bug is fixed you can use this workaround:
|
|
||||||
|
|
||||||
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
|
|
||||||
|
|
||||||
`configure' Invocation
|
|
||||||
======================
|
|
||||||
|
|
||||||
`configure' recognizes the following options to control how it
|
|
||||||
operates.
|
|
||||||
|
|
||||||
`--help'
|
|
||||||
`-h'
|
|
||||||
Print a summary of all of the options to `configure', and exit.
|
|
||||||
|
|
||||||
`--help=short'
|
|
||||||
`--help=recursive'
|
|
||||||
Print a summary of the options unique to this package's
|
|
||||||
`configure', and exit. The `short' variant lists options used
|
|
||||||
only in the top level, while the `recursive' variant lists options
|
|
||||||
also present in any nested packages.
|
|
||||||
|
|
||||||
`--version'
|
|
||||||
`-V'
|
|
||||||
Print the version of Autoconf used to generate the `configure'
|
|
||||||
script, and exit.
|
|
||||||
|
|
||||||
`--cache-file=FILE'
|
|
||||||
Enable the cache: use and save the results of the tests in FILE,
|
|
||||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
|
||||||
disable caching.
|
|
||||||
|
|
||||||
`--config-cache'
|
|
||||||
`-C'
|
|
||||||
Alias for `--cache-file=config.cache'.
|
|
||||||
|
|
||||||
`--quiet'
|
|
||||||
`--silent'
|
|
||||||
`-q'
|
|
||||||
Do not print messages saying which checks are being made. To
|
|
||||||
suppress all normal output, redirect it to `/dev/null' (any error
|
|
||||||
messages will still be shown).
|
|
||||||
|
|
||||||
`--srcdir=DIR'
|
|
||||||
Look for the package's source code in directory DIR. Usually
|
|
||||||
`configure' can determine that directory automatically.
|
|
||||||
|
|
||||||
`--prefix=DIR'
|
|
||||||
Use DIR as the installation prefix. *note Installation Names::
|
|
||||||
for more details, including other options available for fine-tuning
|
|
||||||
the installation locations.
|
|
||||||
|
|
||||||
`--no-create'
|
|
||||||
`-n'
|
|
||||||
Run the configure checks, but stop before creating any output
|
|
||||||
files.
|
|
||||||
|
|
||||||
`configure' also accepts some other, not widely useful, options. Run
|
|
||||||
`configure --help' for more details.
|
|
||||||
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
ACLOCAL_AMFLAGS = -I m4
|
|
||||||
|
|
||||||
SUBDIRS = access_restriction auc db s6a utils tests .
|
|
||||||
|
|
||||||
AM_CFLAGS = @ADD_CFLAGS@ \
|
|
||||||
-I$(top_srcdir)/access_restriction \
|
|
||||||
-I$(top_srcdir)/auc \
|
|
||||||
-I$(top_srcdir)/db \
|
|
||||||
-I$(top_srcdir)/s6a \
|
|
||||||
-I$(top_srcdir)/utils
|
|
||||||
|
|
||||||
bin_PROGRAMS = openair-hss
|
|
||||||
|
|
||||||
openair_hssdir=$(sysconfdir)/openair-hss
|
|
||||||
openair_hss_DATA = $(top_builddir)/conf/hss.conf $(top_srcdir)/conf/hss_fd.conf
|
|
||||||
|
|
||||||
openair_hss_LDADD = \
|
|
||||||
$(top_builddir)/s6a/libs6a.la \
|
|
||||||
$(top_builddir)/db/libdb.la \
|
|
||||||
$(top_builddir)/auc/libauc.la \
|
|
||||||
$(top_builddir)/access_restriction/libaccess_restriction.la \
|
|
||||||
$(top_builddir)/utils/libutils.la
|
|
||||||
|
|
||||||
openair_hss_SOURCES = \
|
|
||||||
hss_config.h \
|
|
||||||
hss_main.c
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
AM_CFLAGS = @ADD_CFLAGS@ \
|
|
||||||
-I$(top_srcdir) \
|
|
||||||
-I$(top_srcdir)/utils
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libaccess_restriction.la
|
|
||||||
|
|
||||||
libaccess_restriction_la_LDFLAGS = -all-static
|
|
||||||
libaccess_restriction_la_SOURCES = \
|
|
||||||
access_restriction.c access_restriction.h
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "conversion.h"
|
|
||||||
#include "access_restriction.h"
|
|
||||||
|
|
||||||
/* TODO: identification of MCC and MNC within an IMSI should be done according
|
|
||||||
* to a table that maps MCC to 2 or 3 digits expected...
|
|
||||||
* By default we will assume there is only 2 digits for our use.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Split a PLMN formed of <MCC><MNC> to mcc and mnc.
|
|
||||||
* In case MNC is formed of only two digits a 0 is inserted at the most significant
|
|
||||||
* digit.
|
|
||||||
* When PLMN is represented using european convention it contains only two digits,
|
|
||||||
* while three digits are used in North American Standard.
|
|
||||||
* Encoding of PLMN is defined in ITU E.212.
|
|
||||||
* @param plmn string either 5 or 6 digits resulting of the concatenation of
|
|
||||||
* MCC and MNC.
|
|
||||||
*/
|
|
||||||
int split_plmn(uint8_t plmn[3], uint8_t mcc[3], uint8_t mnc[3])
|
|
||||||
{
|
|
||||||
if (plmn == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
mcc[0] = plmn[0] & 0x0F;
|
|
||||||
mcc[1] = (plmn[0] & 0xF0) >> 4;
|
|
||||||
mcc[2] = plmn[1] & 0x0F;
|
|
||||||
|
|
||||||
if ((plmn[1] & 0xF0) == 0xF0) {
|
|
||||||
/* Only 2 digits case */
|
|
||||||
mnc[1] = plmn[2] & 0x0F;
|
|
||||||
mnc[2] = (plmn[2] & 0xF0) >> 4;
|
|
||||||
mnc[0] = 0;
|
|
||||||
} else {
|
|
||||||
mnc[0] = plmn[2] & 0x0F;
|
|
||||||
mnc[1] = (plmn[2] & 0xF0) >> 4;
|
|
||||||
mnc[2] = ((plmn[1] & 0xF0) >> 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply restriction (if any) to current 'visited' PLMN for this user.
|
|
||||||
* Criterias are based on ODB (operator determined barring), visited PLMN
|
|
||||||
* and user PLMN (obtain from IMSI).
|
|
||||||
* @param imsi is the user identity formed of MCC.MNC.MSIN (14 or 15 digits long)
|
|
||||||
* @param vplmn is the plmn of the cell the UE is currently attached to
|
|
||||||
*/
|
|
||||||
#define FORMAT_MCC(mCC) (mCC[0] * 100 + mCC[1] * 10 + mCC[2])
|
|
||||||
#define FORMAT_MNC(mNC) (mNC[0] * 100 + mNC[1] * 10 + mNC[2])
|
|
||||||
|
|
||||||
int apply_access_restriction(char *imsi, uint8_t *vplmn)
|
|
||||||
{
|
|
||||||
uint8_t vmcc[3], vmnc[3];
|
|
||||||
uint8_t hmcc[3], hmnc[3];
|
|
||||||
|
|
||||||
uint8_t imsi_hex[15];
|
|
||||||
|
|
||||||
if (bcd_to_hex(imsi_hex, imsi, strlen(imsi)) != 0) {
|
|
||||||
fprintf(stderr, "Failed to convert imsi %s to hex representation\n",
|
|
||||||
imsi);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* There is a problem while converting the PLMN... */
|
|
||||||
if (split_plmn(vplmn, vmcc, vmnc) != 0) {
|
|
||||||
fprintf(stderr, "Fail to convert vplmn %02x%02x%02x to mcc/mnc for imsi %s\n",
|
|
||||||
vplmn[0], vplmn[1], vplmn[2], imsi);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "Converted %02x%02x%02x to plmn %u.%u\n", vplmn[0], vplmn[1], vplmn[2],
|
|
||||||
FORMAT_MCC(vmcc), FORMAT_MNC(vmnc));
|
|
||||||
|
|
||||||
/* MCC is always 3 digits */
|
|
||||||
memcpy(hmcc, &imsi_hex[0], 3);
|
|
||||||
if (memcmp(vmcc, hmcc, 3) != 0) {
|
|
||||||
fprintf(stderr, "Only France MCC is handled for now, got imsi plmn %u.%u for a visited plmn %u.%u\n",
|
|
||||||
FORMAT_MCC(hmcc), FORMAT_MNC(hmnc), FORMAT_MCC(vmcc), FORMAT_MNC(vmnc));
|
|
||||||
/* Reject the association */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* In France MNC is composed of 2 digits and thus imsi by 14 digit */
|
|
||||||
hmnc[0] = 0;
|
|
||||||
memcpy(&hmnc[1], &imsi_hex[3], 2);
|
|
||||||
|
|
||||||
if ((memcmp(vmcc, hmcc, 3) != 0) && (memcmp(vmnc, hmnc, 3) != 0)) {
|
|
||||||
fprintf(stderr, "UE is roaming from %u.%u to %u.%u which is not allowed"
|
|
||||||
" by the ODB\n", FORMAT_MCC(hmcc), FORMAT_MNC(hmnc), FORMAT_MCC(vmcc), FORMAT_MNC(vmnc));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* User has successfully passed all the checking -> accept the association */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef ACCESS_RESTRICTION_H_
|
|
||||||
#define ACCESS_RESTRICTION_H_
|
|
||||||
|
|
||||||
int split_plmn(uint8_t *plmn, uint8_t mcc[3], uint8_t mnc[3]);
|
|
||||||
|
|
||||||
int apply_access_restriction(char *imsi, uint8_t *vplmn);
|
|
||||||
|
|
||||||
#endif /* ACCESS_RESTRICTION_H_ */
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
AM_CFLAGS = @ADD_CFLAGS@ \
|
|
||||||
-I$(top_srcdir) \
|
|
||||||
-I$(top_srcdir)/utils
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libauc.la
|
|
||||||
|
|
||||||
libauc_la_LDFLAGS = -all-static
|
|
||||||
libauc_la_SOURCES = \
|
|
||||||
auc.h \
|
|
||||||
fx.c \
|
|
||||||
kdf.c \
|
|
||||||
random.c \
|
|
||||||
rijndael.c \
|
|
||||||
sequence_number.c
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <gmp.h>
|
|
||||||
|
|
||||||
#ifndef AUC_H_
|
|
||||||
#define AUC_H_
|
|
||||||
|
|
||||||
#define SQN_LENGTH_BITS (48)
|
|
||||||
#define SQN_LENGTH_OCTEST (SQN_LENGTH_BITS/8)
|
|
||||||
#define IK_LENGTH_BITS (128)
|
|
||||||
#define IK_LENGTH_OCTETS (IK_LENGTH_BITS/8)
|
|
||||||
#define RAND_LENGTH_OCTETS (16)
|
|
||||||
#define RAND_LENGTH_BITS (RAND_LENGTH_OCTETS*8)
|
|
||||||
#define XRES_LENGTH_OCTETS (8)
|
|
||||||
#define AUTN_LENGTH_OCTETS (16)
|
|
||||||
#define KASME_LENGTH_OCTETS (32)
|
|
||||||
#define MAC_S_LENGTH (8)
|
|
||||||
|
|
||||||
extern uint8_t opc[16];
|
|
||||||
|
|
||||||
typedef mpz_t random_t;
|
|
||||||
typedef mpz_t sqn_t;
|
|
||||||
|
|
||||||
typedef uint8_t u8;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t rand[16];
|
|
||||||
uint8_t rand_new;
|
|
||||||
uint8_t xres[8];
|
|
||||||
uint8_t autn[16];
|
|
||||||
uint8_t kasme[32];
|
|
||||||
} auc_vector_t;
|
|
||||||
|
|
||||||
void RijndaelKeySchedule(u8 key[16]);
|
|
||||||
void RijndaelEncrypt(u8 in[16], u8 out[16]);
|
|
||||||
|
|
||||||
/* Sequence number functions */
|
|
||||||
struct sqn_ue_s;
|
|
||||||
struct sqn_ue_s *sqn_exists(uint64_t imsi);
|
|
||||||
void sqn_insert(struct sqn_ue_s *item);
|
|
||||||
void sqn_init(struct sqn_ue_s *item);
|
|
||||||
struct sqn_ue_s *sqn_new(uint64_t imsi);
|
|
||||||
void sqn_list_init(void);
|
|
||||||
void sqn_get(uint64_t imsi, uint8_t sqn[6]);
|
|
||||||
|
|
||||||
/* Random number functions */
|
|
||||||
struct random_state_s;
|
|
||||||
void random_init(void);
|
|
||||||
void generate_random(uint8_t *random, ssize_t length);
|
|
||||||
|
|
||||||
void SetOPc(u8 op_c[16]);
|
|
||||||
|
|
||||||
void f1 ( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2],
|
|
||||||
u8 mac_a[8] );
|
|
||||||
void f1star( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2],
|
|
||||||
u8 mac_s[8] );
|
|
||||||
void f2345 ( u8 k[16], u8 rand[16],
|
|
||||||
u8 res[8], u8 ck[16], u8 ik[16], u8 ak[6] );
|
|
||||||
void f5star( u8 k[16], u8 rand[16],
|
|
||||||
u8 ak[6] );
|
|
||||||
|
|
||||||
void generate_autn(u8 sqn[6], u8 ak[6], u8 amf[2], u8 mac_a[8], u8 autn[16]);
|
|
||||||
int generate_vector(uint64_t imsi, uint8_t key[16], uint8_t plmn[3],
|
|
||||||
uint8_t sqn[6], auc_vector_t *vector);
|
|
||||||
|
|
||||||
inline
|
|
||||||
void kdf(uint8_t *key, uint16_t key_len, uint8_t *s, uint16_t s_len, uint8_t *out,
|
|
||||||
uint16_t out_len);
|
|
||||||
|
|
||||||
inline
|
|
||||||
void derive_kasme(uint8_t ck[16], uint8_t ik[16], uint8_t plmn[3], uint8_t sqn[6],
|
|
||||||
uint8_t ak[6], uint8_t kasme[32]);
|
|
||||||
|
|
||||||
uint8_t *sqn_ms_derive(uint8_t *key, uint8_t *auts, uint8_t *rand);
|
|
||||||
|
|
||||||
static inline void print_buffer(const char *prefix, uint8_t *buffer, int length)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
fprintf(stdout, "%s", prefix);
|
|
||||||
for (i = 0; i < length; i++) {
|
|
||||||
fprintf(stdout, "%02x.", buffer[i]);
|
|
||||||
}
|
|
||||||
fprintf(stdout, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* AUC_H_ */
|
|
||||||
@@ -1,249 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------
|
|
||||||
* Example algorithms f1, f1*, f2, f3, f4, f5, f5*
|
|
||||||
*-------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* A sample implementation of the example 3GPP authentication and
|
|
||||||
* key agreement functions f1, f1*, f2, f3, f4, f5 and f5*. This is
|
|
||||||
* a byte-oriented implementation of the functions, and of the block
|
|
||||||
* cipher kernel function Rijndael.
|
|
||||||
*
|
|
||||||
* This has been coded for clarity, not necessarily for efficiency.
|
|
||||||
*
|
|
||||||
* The functions f2, f3, f4 and f5 share the same inputs and have
|
|
||||||
* been coded together as a single function. f1, f1* and f5* are
|
|
||||||
* all coded separately.
|
|
||||||
*
|
|
||||||
*-----------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "auc.h"
|
|
||||||
|
|
||||||
/*--------- Operator Variant Algorithm Configuration Field --------*/
|
|
||||||
/*------- Insert your value of OP here -------*/
|
|
||||||
u8 OP[16];
|
|
||||||
|
|
||||||
/*--------------------------- prototypes --------------------------*/
|
|
||||||
void ComputeOPc( u8 op_c[16] );
|
|
||||||
|
|
||||||
void SetOPc(u8 op_c[16])
|
|
||||||
{
|
|
||||||
memcpy(OP, op_c, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
void generate_autn(u8 sqn[6], u8 ak[6], u8 amf[2], u8 mac_a[8], u8 autn[16])
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 6; i++) {
|
|
||||||
autn[i] = sqn[i] ^ ak[i];
|
|
||||||
}
|
|
||||||
memcpy(&autn[6], amf, 2);
|
|
||||||
memcpy(&autn[8], mac_a, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
|
||||||
* Algorithm f1
|
|
||||||
*-------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Computes network authentication code MAC-A from key K, random
|
|
||||||
* challenge RAND, sequence number SQN and authentication management
|
|
||||||
* field AMF.
|
|
||||||
*
|
|
||||||
*-----------------------------------------------------------------*/
|
|
||||||
void f1 ( u8 k[16], u8 _rand[16], u8 sqn[6], u8 amf[2],
|
|
||||||
u8 mac_a[8] )
|
|
||||||
{
|
|
||||||
u8 op_c[16];
|
|
||||||
u8 temp[16];
|
|
||||||
u8 in1[16];
|
|
||||||
u8 out1[16];
|
|
||||||
u8 rijndaelInput[16];
|
|
||||||
u8 i;
|
|
||||||
RijndaelKeySchedule( k );
|
|
||||||
ComputeOPc( op_c );
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
rijndaelInput[i] = _rand[i] ^ op_c[i];
|
|
||||||
RijndaelEncrypt( rijndaelInput, temp );
|
|
||||||
for (i=0; i<6; i++)
|
|
||||||
{
|
|
||||||
in1[i] = sqn[i];
|
|
||||||
in1[i+8] = sqn[i];
|
|
||||||
}
|
|
||||||
for (i=0; i<2; i++)
|
|
||||||
{
|
|
||||||
in1[i+6] = amf[i];
|
|
||||||
in1[i+14] = amf[i];
|
|
||||||
}
|
|
||||||
/* XOR op_c and in1, rotate by r1=64, and XOR *
|
|
||||||
* on the constant c1 (which is all zeroes) */
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i];
|
|
||||||
/* XOR on the value temp computed before */
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
rijndaelInput[i] ^= temp[i];
|
|
||||||
RijndaelEncrypt( rijndaelInput, out1 );
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
out1[i] ^= op_c[i];
|
|
||||||
for (i=0; i<8; i++)
|
|
||||||
mac_a[i] = out1[i];
|
|
||||||
return;
|
|
||||||
} /* end of function f1 */
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
|
||||||
* Algorithms f2-f5
|
|
||||||
*-------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Takes key K and random challenge RAND, and returns response RES,
|
|
||||||
* confidentiality key CK, integrity key IK and anonymity key AK.
|
|
||||||
*
|
|
||||||
*-----------------------------------------------------------------*/
|
|
||||||
void f2345 ( u8 k[16], u8 _rand[16],
|
|
||||||
u8 res[8], u8 ck[16], u8 ik[16], u8 ak[6] )
|
|
||||||
{
|
|
||||||
u8 op_c[16];
|
|
||||||
u8 temp[16];
|
|
||||||
u8 out[16];
|
|
||||||
u8 rijndaelInput[16];
|
|
||||||
u8 i;
|
|
||||||
RijndaelKeySchedule( k );
|
|
||||||
ComputeOPc( op_c );
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
rijndaelInput[i] = _rand[i] ^ op_c[i];
|
|
||||||
RijndaelEncrypt( rijndaelInput, temp );
|
|
||||||
/* To obtain output block OUT2: XOR OPc and TEMP, *
|
|
||||||
* rotate by r2=0, and XOR on the constant c2 (which *
|
|
||||||
* is all zeroes except that the last bit is 1). */
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
rijndaelInput[i] = temp[i] ^ op_c[i];
|
|
||||||
rijndaelInput[15] ^= 1;
|
|
||||||
RijndaelEncrypt( rijndaelInput, out );
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
out[i] ^= op_c[i];
|
|
||||||
for (i=0; i<8; i++)
|
|
||||||
res[i] = out[i+8];
|
|
||||||
for (i=0; i<6; i++)
|
|
||||||
ak[i] = out[i];
|
|
||||||
/* To obtain output block OUT3: XOR OPc and TEMP, *
|
|
||||||
* rotate by r3=32, and XOR on the constant c3 (which *
|
|
||||||
* is all zeroes except that the next to last bit is 1). */
|
|
||||||
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
rijndaelInput[(i+12) % 16] = temp[i] ^ op_c[i];
|
|
||||||
rijndaelInput[15] ^= 2;
|
|
||||||
RijndaelEncrypt( rijndaelInput, out );
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
out[i] ^= op_c[i];
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
ck[i] = out[i];
|
|
||||||
/* To obtain output block OUT4: XOR OPc and TEMP, *
|
|
||||||
* rotate by r4=64, and XOR on the constant c4 (which *
|
|
||||||
* is all zeroes except that the 2nd from last bit is 1). */
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
rijndaelInput[(i+8) % 16] = temp[i] ^ op_c[i];
|
|
||||||
rijndaelInput[15] ^= 4;
|
|
||||||
RijndaelEncrypt( rijndaelInput, out );
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
out[i] ^= op_c[i];
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
ik[i] = out[i];
|
|
||||||
return;
|
|
||||||
} /* end of function f2345 */
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
|
||||||
* Algorithm f1*
|
|
||||||
*-------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Computes resynch authentication code MAC-S from key K, random
|
|
||||||
* challenge RAND, sequence number SQN and authentication management
|
|
||||||
* field AMF.
|
|
||||||
*
|
|
||||||
*-----------------------------------------------------------------*/
|
|
||||||
void f1star( u8 k[16], u8 _rand[16], u8 sqn[6], u8 amf[2],
|
|
||||||
u8 mac_s[8] )
|
|
||||||
{
|
|
||||||
u8 op_c[16];
|
|
||||||
u8 temp[16];
|
|
||||||
u8 in1[16];
|
|
||||||
u8 out1[16];
|
|
||||||
u8 rijndaelInput[16];
|
|
||||||
u8 i;
|
|
||||||
RijndaelKeySchedule( k );
|
|
||||||
ComputeOPc( op_c );
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
rijndaelInput[i] = _rand[i] ^ op_c[i];
|
|
||||||
RijndaelEncrypt( rijndaelInput, temp );
|
|
||||||
for (i=0; i<6; i++)
|
|
||||||
{
|
|
||||||
in1[i] = sqn[i];
|
|
||||||
in1[i+8] = sqn[i];
|
|
||||||
}
|
|
||||||
for (i=0; i<2; i++)
|
|
||||||
{
|
|
||||||
in1[i+6] = amf[i];
|
|
||||||
in1[i+14] = amf[i];
|
|
||||||
}
|
|
||||||
/* XOR op_c and in1, rotate by r1=64, and XOR *
|
|
||||||
* on the constant c1 (which is all zeroes) */
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i];
|
|
||||||
/* XOR on the value temp computed before */
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
rijndaelInput[i] ^= temp[i];
|
|
||||||
RijndaelEncrypt( rijndaelInput, out1 );
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
out1[i] ^= op_c[i];
|
|
||||||
for (i=0; i<8; i++)
|
|
||||||
mac_s[i] = out1[i+8];
|
|
||||||
return;
|
|
||||||
} /* end of function f1star */
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
|
||||||
* Algorithm f5*
|
|
||||||
*-------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Takes key K and random challenge RAND, and returns resynch
|
|
||||||
* anonymity key AK.
|
|
||||||
*
|
|
||||||
*-----------------------------------------------------------------*/
|
|
||||||
void f5star( u8 k[16], u8 _rand[16],
|
|
||||||
u8 ak[6] )
|
|
||||||
{
|
|
||||||
u8 op_c[16];
|
|
||||||
u8 temp[16];
|
|
||||||
u8 out[16];
|
|
||||||
u8 rijndaelInput[16];
|
|
||||||
u8 i;
|
|
||||||
RijndaelKeySchedule( k );
|
|
||||||
ComputeOPc( op_c );
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
rijndaelInput[i] = _rand[i] ^ op_c[i];
|
|
||||||
RijndaelEncrypt( rijndaelInput, temp );
|
|
||||||
/* To obtain output block OUT5: XOR OPc and TEMP, *
|
|
||||||
* rotate by r5=96, and XOR on the constant c5 (which *
|
|
||||||
* is all zeroes except that the 3rd from last bit is 1). */
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
rijndaelInput[(i+4) % 16] = temp[i] ^ op_c[i];
|
|
||||||
rijndaelInput[15] ^= 8;
|
|
||||||
RijndaelEncrypt( rijndaelInput, out );
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
out[i] ^= op_c[i];
|
|
||||||
for (i=0; i<6; i++)
|
|
||||||
ak[i] = out[i];
|
|
||||||
return;
|
|
||||||
} /* end of function f5star */
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
|
||||||
* Function to compute OPc from OP and K. Assumes key schedule has
|
|
||||||
a lready been performed. *
|
|
||||||
*-----------------------------------------------------------------*/
|
|
||||||
void ComputeOPc( u8 op_c[16] )
|
|
||||||
{
|
|
||||||
u8 i;
|
|
||||||
RijndaelEncrypt( OP, op_c );
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
op_c[i] ^= OP[i];
|
|
||||||
return;
|
|
||||||
} /* end of function ComputeOPc */
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
#include <pthread.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <gmp.h>
|
|
||||||
#include <nettle/hmac.h>
|
|
||||||
|
|
||||||
#include "auc.h"
|
|
||||||
|
|
||||||
uint8_t opc[16] = {
|
|
||||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
|
||||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @param key the input key
|
|
||||||
* @param key_len length of the key
|
|
||||||
* @param s string for key derivation as defined in 3GPP TS.33401 Annex A
|
|
||||||
* @param s_len length of s
|
|
||||||
* @param out buffer to place the output of kdf
|
|
||||||
* @param ou_len expected length for the output key
|
|
||||||
*/
|
|
||||||
inline
|
|
||||||
void kdf(uint8_t *key, uint16_t key_len, uint8_t *s, uint16_t s_len, uint8_t *out,
|
|
||||||
uint16_t out_len)
|
|
||||||
{
|
|
||||||
struct hmac_sha256_ctx ctx;
|
|
||||||
|
|
||||||
memset(&ctx, 0, sizeof(ctx));
|
|
||||||
|
|
||||||
hmac_sha256_set_key(&ctx, key_len, key);
|
|
||||||
hmac_sha256_update(&ctx, s_len, s);
|
|
||||||
hmac_sha256_digest(&ctx, out_len, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Derive the Kasme using the KDF (key derive function).
|
|
||||||
* See 3GPP TS.33401 Annex A.2
|
|
||||||
* The input String S to the KDF is composed of 14 bytes:
|
|
||||||
* FC = 0x10
|
|
||||||
* P0 = SN id = PLMN
|
|
||||||
* L0 = length(SN id) = 0x00 0x03
|
|
||||||
* P1 = SQN xor AK
|
|
||||||
* L1 = length(P1) = 0x00 0x06
|
|
||||||
*/
|
|
||||||
inline
|
|
||||||
void derive_kasme(uint8_t ck[16], uint8_t ik[16], uint8_t plmn[3], uint8_t sqn[6],
|
|
||||||
uint8_t ak[6], uint8_t *kasme)
|
|
||||||
{
|
|
||||||
uint8_t s[14];
|
|
||||||
int i;
|
|
||||||
uint8_t key[32];
|
|
||||||
|
|
||||||
/* The input key is equal to the concatenation of CK and IK */
|
|
||||||
memcpy(&key[0], ck, 16);
|
|
||||||
memcpy(&key[16], ik, 16);
|
|
||||||
|
|
||||||
SetOPc(opc);
|
|
||||||
|
|
||||||
/* FC */
|
|
||||||
s[0] = 0x10;
|
|
||||||
|
|
||||||
/* SN id is composed of MCC and MNC
|
|
||||||
* Octets:
|
|
||||||
* 1 MCC digit 2 | MCC digit 1
|
|
||||||
* 2 MNC digit 3 | MCC digit 3
|
|
||||||
* 3 MNC digit 2 | MNC digit 1
|
|
||||||
*/
|
|
||||||
memcpy(&s[1], plmn, 3);
|
|
||||||
|
|
||||||
/* L0 */
|
|
||||||
s[4] = 0x00;
|
|
||||||
s[5] = 0x03;
|
|
||||||
|
|
||||||
/* P1 */
|
|
||||||
for (i = 0; i < 6; i++) {
|
|
||||||
s[6 + i] = sqn[i] ^ ak[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* L1 */
|
|
||||||
s[12] = 0x00;
|
|
||||||
s[13] = 0x06;
|
|
||||||
|
|
||||||
#if defined(DEBUG_AUC_KDF)
|
|
||||||
for (i = 0; i < 32; i++)
|
|
||||||
printf("0x%02x ", key[i]);
|
|
||||||
printf("\n");
|
|
||||||
for (i = 0; i < 14; i++)
|
|
||||||
printf("0x%02x ", s[i]);
|
|
||||||
printf("\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
kdf(key, 32, s, 14, kasme, 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
int generate_vector(uint64_t imsi, uint8_t key[16], uint8_t plmn[3],
|
|
||||||
uint8_t sqn[6], auc_vector_t *vector)
|
|
||||||
{
|
|
||||||
/* in E-UTRAN an authentication vector is composed of:
|
|
||||||
* - RAND
|
|
||||||
* - XRES
|
|
||||||
* - AUTN
|
|
||||||
* - KASME
|
|
||||||
*/
|
|
||||||
|
|
||||||
uint8_t amf[] = { 0x80, 0x00 };
|
|
||||||
uint8_t mac_a[8];
|
|
||||||
uint8_t ck[16];
|
|
||||||
uint8_t ik[16];
|
|
||||||
uint8_t ak[6];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (vector == NULL) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compute MAC */
|
|
||||||
f1(key, vector->rand, sqn, amf, mac_a);
|
|
||||||
|
|
||||||
print_buffer("MAC_A : ", mac_a, 8);
|
|
||||||
print_buffer("SQN : ", sqn, 6);
|
|
||||||
print_buffer("AK : ", ak, 6);
|
|
||||||
print_buffer("RAND : ", vector->rand, 16);
|
|
||||||
|
|
||||||
/* Compute XRES, CK, IK, AK */
|
|
||||||
f2345(key, vector->rand, vector->xres, ck, ik, ak);
|
|
||||||
|
|
||||||
/* AUTN = SQN ^ AK || AMF || MAC */
|
|
||||||
generate_autn(sqn, ak, amf, mac_a, vector->autn);
|
|
||||||
|
|
||||||
print_buffer("XRES : ", vector->xres, 8);
|
|
||||||
|
|
||||||
derive_kasme(ck, ik, plmn, sqn, ak, vector->kasme);
|
|
||||||
print_buffer("KASME : ", vector->kasme, 32);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#include <pthread.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <gmp.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
#include "auc.h"
|
|
||||||
|
|
||||||
typedef struct random_state_s {
|
|
||||||
pthread_mutex_t lock;
|
|
||||||
gmp_randstate_t state;
|
|
||||||
} random_state_t;
|
|
||||||
|
|
||||||
random_state_t random_state;
|
|
||||||
|
|
||||||
void random_init(void)
|
|
||||||
{
|
|
||||||
// mpz_t number;
|
|
||||||
// pthread_mutex_init(&random_state.lock, NULL);
|
|
||||||
// mpz_init(number);
|
|
||||||
// gmp_randinit_default(random_state.state);
|
|
||||||
// srand(time(NULL));
|
|
||||||
struct timeval t1;
|
|
||||||
gettimeofday(&t1, NULL);
|
|
||||||
srand(t1.tv_usec * t1.tv_sec);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generate a random number between 0 and 2^length - 1 where length is expressed
|
|
||||||
* in bits.
|
|
||||||
*/
|
|
||||||
void generate_random(uint8_t *random_p, ssize_t length)
|
|
||||||
{
|
|
||||||
// random_t random_nb;
|
|
||||||
|
|
||||||
// mpz_init_set_ui(random_nb, 0);
|
|
||||||
|
|
||||||
// pthread_mutex_lock(&random_state.lock);
|
|
||||||
// mpz_urandomb(random_nb, random_state.state, 8 * length);
|
|
||||||
// pthread_mutex_unlock(&random_state.lock);
|
|
||||||
|
|
||||||
// mpz_export(random_p, NULL, 1, length, 0, 0, random_nb);
|
|
||||||
int r = 0, i, mask = 0, shift;
|
|
||||||
|
|
||||||
for (i = 0; i < length; i ++) {
|
|
||||||
// if ((i % sizeof(i)) == 0)
|
|
||||||
// r = rand();
|
|
||||||
// shift = 8 * (i % sizeof(i));
|
|
||||||
// mask = 0xFF << shift;
|
|
||||||
// random_p[i] = (r & mask) >> shift;
|
|
||||||
random_p[i] = rand();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <gmp.h>
|
|
||||||
|
|
||||||
#include "auc.h"
|
|
||||||
|
|
||||||
typedef uint8_t u8;
|
|
||||||
typedef uint32_t u32;
|
|
||||||
|
|
||||||
/*-------------------- Rijndael round subkeys ---------------------*/
|
|
||||||
u8 roundKeys[11][4][4];
|
|
||||||
/*--------------------- Rijndael S box table ----------------------*/
|
|
||||||
u8 S[256] = {
|
|
||||||
99,124,119,123,242,107,111,197, 48, 1,103, 43,254,215,171,118,
|
|
||||||
202,130,201,125,250, 89, 71,240,173,212,162,175,156,164,114,192,
|
|
||||||
183,253,147, 38, 54, 63,247,204, 52,165,229,241,113,216, 49, 21,
|
|
||||||
4,199, 35,195, 24,150, 5,154, 7, 18,128,226,235, 39,178,117,
|
|
||||||
9,131, 44, 26, 27,110, 90,160, 82, 59,214,179, 41,227, 47,132,
|
|
||||||
83,209, 0,237, 32,252,177, 91,106,203,190, 57, 74, 76, 88,207,
|
|
||||||
208,239,170,251, 67, 77, 51,133, 69,249, 2,127, 80, 60,159,168,
|
|
||||||
81,163, 64,143,146,157, 56,245,188,182,218, 33, 16,255,243,210,
|
|
||||||
205, 12, 19,236, 95,151, 68, 23,196,167,126, 61,100, 93, 25,115,
|
|
||||||
96,129, 79,220, 34, 42,144,136, 70,238,184, 20,222, 94, 11,219,
|
|
||||||
224, 50, 58, 10, 73, 6, 36, 92,194,211,172, 98,145,149,228,121,
|
|
||||||
231,200, 55,109,141,213, 78,169,108, 86,244,234,101,122,174, 8,
|
|
||||||
186,120, 37, 46, 28,166,180,198,232,221,116, 31, 75,189,139,138,
|
|
||||||
112, 62,181,102, 72, 3,246, 14, 97, 53, 87,185,134,193, 29,158,
|
|
||||||
225,248,152, 17,105,217,142,148,155, 30,135,233,206, 85, 40,223,
|
|
||||||
140,161,137, 13,191,230, 66,104, 65,153, 45, 15,176, 84,187, 22,
|
|
||||||
};
|
|
||||||
/*------- This array does the multiplication by x in GF(2^8) ------*/
|
|
||||||
u8 Xtime[256] = {
|
|
||||||
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
|
|
||||||
32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
|
|
||||||
64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94,
|
|
||||||
96, 98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,
|
|
||||||
128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,
|
|
||||||
160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,
|
|
||||||
192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,
|
|
||||||
224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,254,
|
|
||||||
27, 25, 31, 29, 19, 17, 23, 21, 11, 9, 15, 13, 3, 1, 7, 5,
|
|
||||||
59, 57, 63, 61, 51, 49, 55, 53, 43, 41, 47, 45, 35, 33, 39, 37,
|
|
||||||
91, 89, 95, 93, 83, 81, 87, 85, 75, 73, 79, 77, 67, 65, 71, 69,
|
|
||||||
123,121,127,125,115,113,119,117,107,105,111,109, 99, 97,103,101,
|
|
||||||
155,153,159,157,147,145,151,149,139,137,143,141,131,129,135,133,
|
|
||||||
187,185,191,189,179,177,183,181,171,169,175,173,163,161,167,165,
|
|
||||||
219,217,223,221,211,209,215,213,203,201,207,205,195,193,199,197,
|
|
||||||
251,249,255,253,243,241,247,245,235,233,239,237,227,225,231,229
|
|
||||||
};
|
|
||||||
/*-------------------------------------------------------------------
|
|
||||||
* Rijndael key schedule function. Takes 16-byte key and creates
|
|
||||||
* all Rijndael's internal subkeys ready for encryption.
|
|
||||||
*-----------------------------------------------------------------*/
|
|
||||||
void RijndaelKeySchedule( u8 key[16] )
|
|
||||||
{
|
|
||||||
u8 roundConst;
|
|
||||||
int i, j;
|
|
||||||
/* first round key equals key */
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
roundKeys[0][i & 0x03][i>>2] = key[i];
|
|
||||||
roundConst = 1;
|
|
||||||
/* now calculate round keys */
|
|
||||||
for (i=1; i<11; i++)
|
|
||||||
{
|
|
||||||
roundKeys[i][0][0] = S[roundKeys[i-1][1][3]]
|
|
||||||
^ roundKeys[i-1][0][0] ^ roundConst;
|
|
||||||
roundKeys[i][1][0] = S[roundKeys[i-1][2][3]]
|
|
||||||
^ roundKeys[i-1][1][0];
|
|
||||||
roundKeys[i][2][0] = S[roundKeys[i-1][3][3]]
|
|
||||||
^ roundKeys[i-1][2][0];
|
|
||||||
roundKeys[i][3][0] = S[roundKeys[i-1][0][3]]
|
|
||||||
^ roundKeys[i-1][3][0];
|
|
||||||
for (j=0; j<4; j++)
|
|
||||||
{
|
|
||||||
roundKeys[i][j][1] = roundKeys[i-1][j][1] ^ roundKeys[i][j][0];
|
|
||||||
roundKeys[i][j][2] = roundKeys[i-1][j][2] ^ roundKeys[i][j][1];
|
|
||||||
roundKeys[i][j][3] = roundKeys[i-1][j][3] ^ roundKeys[i][j][2];
|
|
||||||
}
|
|
||||||
/* update round constant */
|
|
||||||
roundConst = Xtime[roundConst];
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} /* end of function RijndaelKeySchedule */
|
|
||||||
/* Round key addition function */
|
|
||||||
void KeyAdd(u8 state[4][4], u8 roundKeys[11][4][4], int round)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
for (i=0; i<4; i++)
|
|
||||||
for (j=0; j<4; j++)
|
|
||||||
state[i][j] ^= roundKeys[round][i][j];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* Byte substitution transformation */
|
|
||||||
int ByteSub(u8 state[4][4])
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
for (i=0; i<4; i++)
|
|
||||||
for (j=0; j<4; j++)
|
|
||||||
state[i][j] = S[state[i][j]];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* Row shift transformation */
|
|
||||||
void ShiftRow(u8 state[4][4])
|
|
||||||
{
|
|
||||||
u8 temp;
|
|
||||||
/* left rotate row 1 by 1 */
|
|
||||||
temp = state[1][0];
|
|
||||||
state[1][0] = state[1][1];
|
|
||||||
state[1][1] = state[1][2];
|
|
||||||
state[1][2] = state[1][3];
|
|
||||||
state[1][3] = temp;
|
|
||||||
/* left rotate row 2 by 2 */
|
|
||||||
temp = state[2][0];
|
|
||||||
state[2][0] = state[2][2];
|
|
||||||
state[2][2] = temp;
|
|
||||||
temp = state[2][1];
|
|
||||||
state[2][1] = state[2][3];
|
|
||||||
state[2][3] = temp;
|
|
||||||
/* left rotate row 3 by 3 */
|
|
||||||
temp = state[3][0];
|
|
||||||
state[3][0] = state[3][3];
|
|
||||||
state[3][3] = state[3][2];
|
|
||||||
state[3][2] = state[3][1];
|
|
||||||
state[3][1] = temp;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* MixColumn transformation*/
|
|
||||||
void MixColumn(u8 state[4][4])
|
|
||||||
{
|
|
||||||
u8 temp, tmp, tmp0;
|
|
||||||
int i;
|
|
||||||
/* do one column at a time */
|
|
||||||
for (i=0; i<4;i++)
|
|
||||||
{
|
|
||||||
temp = state[0][i] ^ state[1][i] ^ state[2][i] ^ state[3][i];
|
|
||||||
tmp0 = state[0][i];
|
|
||||||
/* Xtime array does multiply by x in GF2^8 */
|
|
||||||
tmp = Xtime[state[0][i] ^ state[1][i]];
|
|
||||||
state[0][i] ^= temp ^ tmp;
|
|
||||||
tmp = Xtime[state[1][i] ^ state[2][i]];
|
|
||||||
state[1][i] ^= temp ^ tmp;
|
|
||||||
tmp = Xtime[state[2][i] ^ state[3][i]];
|
|
||||||
state[2][i] ^= temp ^ tmp;
|
|
||||||
tmp = Xtime[state[3][i] ^ tmp0];
|
|
||||||
state[3][i] ^= temp ^ tmp;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/*-------------------------------------------------------------------
|
|
||||||
* Rijndael encryption function. Takes 16-byte input and creates
|
|
||||||
* 16-byte output (using round keys already derived from 16-byte
|
|
||||||
* key).
|
|
||||||
*-----------------------------------------------------------------*/
|
|
||||||
void RijndaelEncrypt( u8 input[16], u8 output[16] )
|
|
||||||
{
|
|
||||||
u8 state[4][4];
|
|
||||||
int i, r;
|
|
||||||
/* initialise state array from input byte string */
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
state[i & 0x3][i>>2] = input[i];
|
|
||||||
/* add first round_key */
|
|
||||||
KeyAdd(state, roundKeys, 0);
|
|
||||||
/* do lots of full rounds */
|
|
||||||
for (r=1; r<=9; r++)
|
|
||||||
{
|
|
||||||
ByteSub(state);
|
|
||||||
ShiftRow(state);
|
|
||||||
MixColumn(state);
|
|
||||||
KeyAdd(state, roundKeys, r);
|
|
||||||
}
|
|
||||||
/* final round */
|
|
||||||
ByteSub(state);
|
|
||||||
ShiftRow(state);
|
|
||||||
KeyAdd(state, roundKeys, r);
|
|
||||||
/* produce output byte string from state array */
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
{
|
|
||||||
output[i] = state[i & 0x3][i>>2];
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} /* end of function RijndaelEncrypt */
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "auc.h"
|
|
||||||
|
|
||||||
uint8_t *sqn_ms_derive(uint8_t *key, uint8_t *auts, uint8_t *rand_p)
|
|
||||||
{
|
|
||||||
/* AUTS = Conc(SQN MS ) || MAC-S
|
|
||||||
* Conc(SQN MS ) = SQN MS ^ f5* (RAND)
|
|
||||||
* MAC-S = f1* (SQN MS || RAND || AMF)
|
|
||||||
*/
|
|
||||||
uint8_t ak[6];
|
|
||||||
uint8_t *conc_sqn_ms;
|
|
||||||
uint8_t *mac_s;
|
|
||||||
uint8_t mac_s_computed[MAC_S_LENGTH];
|
|
||||||
uint8_t *sqn_ms;
|
|
||||||
uint8_t amf[2] = { 0, 0 };
|
|
||||||
int i;
|
|
||||||
|
|
||||||
conc_sqn_ms = auts;
|
|
||||||
mac_s = &auts[6];
|
|
||||||
|
|
||||||
sqn_ms = malloc(SQN_LENGTH_OCTEST);
|
|
||||||
|
|
||||||
SetOPc(opc);
|
|
||||||
|
|
||||||
/* Derive AK from key and rand */
|
|
||||||
f5star(key, rand_p, ak);
|
|
||||||
|
|
||||||
for (i = 0; i < 6; i++) {
|
|
||||||
sqn_ms[i] = ak[i] ^ conc_sqn_ms[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
print_buffer("KEY : ", key, 16);
|
|
||||||
print_buffer("RAND : ", rand_p, 16);
|
|
||||||
print_buffer("AUTS : ", auts, 14);
|
|
||||||
print_buffer("AK : ", ak, 6);
|
|
||||||
print_buffer("SQN_MS : ", sqn_ms, 6);
|
|
||||||
print_buffer("MAC_S : ", mac_s, 8);
|
|
||||||
|
|
||||||
f1star(key, rand_p, sqn_ms, amf, mac_s_computed);
|
|
||||||
|
|
||||||
print_buffer("MAC_S +: ", mac_s_computed, 8);
|
|
||||||
|
|
||||||
if (memcmp(mac_s_computed, mac_s, 8) != 0) {
|
|
||||||
fprintf(stderr, "Failed to verify computed SQN_MS\n");
|
|
||||||
free(sqn_ms);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sqn_ms;
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
autoreconf --force --install -I m4
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
## MySQL mandatory options
|
|
||||||
MYSQL_server = "127.0.0.1";
|
|
||||||
MYSQL_user = "hssadmin";
|
|
||||||
MYSQL_pass = "admin";
|
|
||||||
MYSQL_db = "oai_db";
|
|
||||||
|
|
||||||
## Freediameter options
|
|
||||||
FD_conf = "/etc/openair-hss/hss_fd.conf";
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
## MySQL mandatory options
|
|
||||||
MYSQL_server = "127.0.0.1";
|
|
||||||
MYSQL_user = "hssadmin";
|
|
||||||
MYSQL_pass = "admin";
|
|
||||||
MYSQL_db = "oai_db";
|
|
||||||
|
|
||||||
## Freediameter options
|
|
||||||
FD_conf = "@AM_CONF_DIR@/hss_fd.conf";
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
# -------- Local ---------
|
|
||||||
|
|
||||||
# Uncomment if the framework cannot resolv it.
|
|
||||||
Identity = "hss.eur";
|
|
||||||
|
|
||||||
# TLS configuration (see previous section)
|
|
||||||
TLS_Cred = "/homes/roux/lte-epc/openair3/OPENAIRHSS/conf/hss.cert.pem",
|
|
||||||
"/homes/roux/lte-epc/openair3/OPENAIRHSS/conf/hss.key.pem";
|
|
||||||
TLS_CA = "/homes/roux/lte-epc/openair3/OPENAIRHSS/conf/cacert.pem";
|
|
||||||
|
|
||||||
# Disable use of TCP protocol (only listen and connect in SCTP)
|
|
||||||
# Default : TCP enabled
|
|
||||||
No_TCP;
|
|
||||||
#No_SCTP;
|
|
||||||
|
|
||||||
# Disable use of IPv6 addresses (only IP)
|
|
||||||
# Default : IPv6 enabled
|
|
||||||
# No_IPv6;
|
|
||||||
|
|
||||||
# Limit the number of SCTP streams
|
|
||||||
SCTP_streams = 15;
|
|
||||||
|
|
||||||
NoRelay;
|
|
||||||
TLS_old_method;
|
|
||||||
|
|
||||||
# Core 2 DUO
|
|
||||||
AppServThreads = 4;
|
|
||||||
|
|
||||||
# -------- Extensions ---------
|
|
||||||
|
|
||||||
# Uncomment (and create rtd.conf) to specify routing table for this peer.
|
|
||||||
#LoadExtension = "rt_default.fdx" : "rtd.conf";
|
|
||||||
|
|
||||||
# Uncomment (and create acl.conf) to allow incoming connections from other peers.
|
|
||||||
#LoadExtension = "acl_wl.fdx" : "/homes/roux/lte-epc/openair3/OPENAIRHSS/conf/acl.conf";
|
|
||||||
|
|
||||||
# Uncomment to display periodic state information
|
|
||||||
#LoadExtension = "dbg_monitor.fdx";
|
|
||||||
|
|
||||||
# Uncomment to enable an interactive Python interpreter session.
|
|
||||||
# (see doc/dbg_interactive.py.sample for more information)
|
|
||||||
#LoadExtension = "dbg_interactive.fdx";
|
|
||||||
|
|
||||||
# Load the RFC4005 dictionary objects
|
|
||||||
#LoadExtension = "dict_nasreq.fdx";
|
|
||||||
|
|
||||||
LoadExtension = "dict_nas_mipv6.fdx";
|
|
||||||
LoadExtension = "dict_s6a.fdx";
|
|
||||||
|
|
||||||
# Load RFC4072 dictionary objects
|
|
||||||
#LoadExtension = "dict_eap.fdx";
|
|
||||||
|
|
||||||
# Load the Diameter EAP server extension (requires diameap.conf)
|
|
||||||
#LoadExtension = "app_diameap.fdx" : "diameap.conf";
|
|
||||||
|
|
||||||
# Load the Accounting Server extension (requires app_acct.conf)
|
|
||||||
#LoadExtension = "app_acct.fdx" : "app_acct.conf";
|
|
||||||
|
|
||||||
# -------- Peers ---------
|
|
||||||
|
|
||||||
# The framework will actively attempt to establish and maintain a connection
|
|
||||||
# with the peers listed here.
|
|
||||||
# For only accepting incoming connections, see the acl_wl.fx extension.
|
|
||||||
|
|
||||||
#ConnectPeer = "ubuntu.localdomain" { ConnectTo = "127.0.0.1"; No_TLS; };
|
|
||||||
#ConnectPeer = "roux.test.fr" { No_TLS; };
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
rm -rf demoCA
|
|
||||||
mkdir demoCA
|
|
||||||
echo 01 > demoCA/serial
|
|
||||||
touch demoCA/index.txt
|
|
||||||
|
|
||||||
echo "Creating certificate for HSS"
|
|
||||||
#
|
|
||||||
# # CA self certificate
|
|
||||||
# openssl req -new -batch -x509 -days 3650 -nodes -newkey rsa:1024 -out cacert.pem -keyout cakey.pem -subj /CN=test.fr/C=FR/ST=Biot/L=Aix/O=test.fr/OU=mobiles
|
|
||||||
#
|
|
||||||
# openssl genrsa -out hss.key.pem 1024
|
|
||||||
# openssl req -new -batch -out hss.csr.pem -key hss.key.pem -subj /CN=hss.test.fr/C=FR/ST=Biot/L=Aix/O=test.fr/OU=mobiles
|
|
||||||
# openssl ca -cert cacert.pem -keyfile cakey.pem -in hss.csr.pem -out hss.cert.pem -outdir . -batch
|
|
||||||
|
|
||||||
# CA self certificate
|
|
||||||
openssl req -new -batch -x509 -days 3650 -nodes -newkey rsa:1024 -out cacert.pem -keyout cakey.pem -subj /CN=eur/C=FR/ST=PACA/L=Aix/O=Eurecom/OU=CM
|
|
||||||
|
|
||||||
openssl genrsa -out hss.key.pem 1024
|
|
||||||
openssl req -new -batch -out hss.csr.pem -key hss.key.pem -subj /CN=hss.eur/C=FR/ST=PACA/L=Aix/O=Eurecom/OU=CM
|
|
||||||
openssl ca -cert cacert.pem -keyfile cakey.pem -in hss.csr.pem -out hss.cert.pem -outdir . -batch
|
|
||||||
|
|
||||||
# openssl genrsa -out $hss.key.pem 1024
|
|
||||||
# openssl req -new -batch -out $hss.csr.pem -key $hss.key.pem -subj /CN=$hss.test.fr/C=FR/ST=Biot/L=Aix/O=test.fr/OU=mobiles
|
|
||||||
# openssl ca -cert cacert.pem -keyfile cakey.pem -in $hss.csr.pem -out $hss.cert.pem -outdir . -batch
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
AC_PREREQ([2.65])
|
|
||||||
|
|
||||||
define([svnversion], esyscmd([sh -c "svnversion ..|tr -d '\n'"]))
|
|
||||||
|
|
||||||
AC_DEFINE(SVN_REVISION, "svnversion", [SVN Revision])
|
|
||||||
|
|
||||||
AC_INIT([openair-hss], [1.0.0.svnversion], [openair_admin@eurecom.fr])
|
|
||||||
AC_CANONICAL_BUILD
|
|
||||||
AC_CANONICAL_TARGET
|
|
||||||
AM_INIT_AUTOMAKE([1.11 silent-rules])
|
|
||||||
|
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
|
||||||
|
|
||||||
AC_CONFIG_HEADERS([config.h])
|
|
||||||
|
|
||||||
AM_MAINTAINER_MODE
|
|
||||||
|
|
||||||
AM_SILENT_RULES([yes])
|
|
||||||
|
|
||||||
PKG_CHECK_MODULES(CHECK, [check >= 0.9.4], [HAVE_CHECK=true], [HAVE_CHECK=false])
|
|
||||||
AM_CONDITIONAL(HAVE_CHECK, test x$HAVE_CHECK = xtrue)
|
|
||||||
|
|
||||||
AM_PROG_LEX
|
|
||||||
AM_PROG_LIBTOOL
|
|
||||||
|
|
||||||
AC_PROG_YACC
|
|
||||||
AC_PROG_CXX
|
|
||||||
AC_PROG_RANLIB
|
|
||||||
|
|
||||||
AC_TYPE_INT8_T
|
|
||||||
AC_TYPE_INT16_T
|
|
||||||
AC_TYPE_INT32_T
|
|
||||||
AC_TYPE_UINT8_T
|
|
||||||
AC_TYPE_UINT16_T
|
|
||||||
AC_TYPE_UINT32_T
|
|
||||||
AC_TYPE_UINT64_T
|
|
||||||
AC_TYPE_SIZE_T
|
|
||||||
AC_TYPE_SSIZE_T
|
|
||||||
|
|
||||||
AC_CHECK_HEADERS([libintl.h malloc.h netinet/in.h stddef.h])
|
|
||||||
|
|
||||||
AC_CHECK_FUNCS([memset strdup strerror])
|
|
||||||
AC_C_INLINE
|
|
||||||
|
|
||||||
AC_FUNC_ALLOCA
|
|
||||||
AC_FUNC_MALLOC
|
|
||||||
AC_FUNC_REALLOC
|
|
||||||
|
|
||||||
dnl *** Autoconf support ***
|
|
||||||
AC_ARG_ENABLE(autoconf,
|
|
||||||
[ --disable-autoconf disable automatic generation of configure script ],
|
|
||||||
enable_autoconf=$enableval, enable_autoconf=yes
|
|
||||||
)
|
|
||||||
AC_PATH_PROG(AUTOCONF, autoconf, @echo autoconf not available)
|
|
||||||
AC_PATH_PROG(AUTOHEADER, autoheader, @echo autoheader not available)
|
|
||||||
if test -z "$AUTOCONF"; then enable_autoconf=no ; fi
|
|
||||||
if test -z "$AUTOHEADER"; then enable_autoconf=no ; fi
|
|
||||||
if test x$enable_autoconf = xyes; then
|
|
||||||
CONFIGURE_DEPENDS="configure.in"
|
|
||||||
fi
|
|
||||||
AC_SUBST(CONFIGURE_DEPENDS)
|
|
||||||
|
|
||||||
AC_CHECK_LIB([mysqlclient],
|
|
||||||
[mysql_init],
|
|
||||||
[],
|
|
||||||
[])
|
|
||||||
|
|
||||||
dnl ***freediameter support***
|
|
||||||
AC_CHECK_LIB([fdcore], [fd_core_initialize], [],
|
|
||||||
[AC_MSG_ERROR(Free diameter lib not installed)])
|
|
||||||
AC_CHECK_LIB([fdproto], [fd_core_initialize], [],
|
|
||||||
[AC_MSG_ERROR(Free diameter lib not installed)])
|
|
||||||
|
|
||||||
dnl *** Freediameter requirements ***
|
|
||||||
AC_CHECK_HEADERS([signalent.h])
|
|
||||||
AC_CHECK_FUNCS([ntohll strndup])
|
|
||||||
AC_DEFINE([HAVE_AI_ADDRCONFIG], [],
|
|
||||||
[Define to 1 if you have AI_ADDRCONFIG defined in netdb.h])
|
|
||||||
AC_DEFINE([HAVE_CLOCK_GETTIME], [],
|
|
||||||
[Define to 1 if you have clock_gettime in librt])
|
|
||||||
AC_DEFINE([HAVE_PTHREAD_BAR], [],
|
|
||||||
[Define to 1 if you have pthread_barrier_wait in libpthread])
|
|
||||||
AC_DEFINE([SCTP_CONNECTX_4_ARGS], [],
|
|
||||||
[Define to 1 if sctp_connectx function accepts 4 arguments])
|
|
||||||
AC_CHECK_LIB([rt], [clock_gettime], [AC_DEFINE(HAVE_CLOCK_GETTIME, 1)], [])
|
|
||||||
AC_CHECK_LIB([pthread], [pthread_barrier_wait],
|
|
||||||
[AC_DEFINE(HAVE_PTHREAD_BAR, 1)], [])
|
|
||||||
AC_CHECK_DECL([AI_ADDRCONFIG],
|
|
||||||
[AC_DEFINE(HAVE_AI_ADDRCONFIG, 1)],
|
|
||||||
[], [[#include <netdb.h>]])
|
|
||||||
AC_MSG_CHECKING(if sctp_connectx accepts 4 arguments)
|
|
||||||
AC_LINK_IFELSE([
|
|
||||||
AC_LANG_SOURCE(
|
|
||||||
[[int main() { return sctp_connectx(0, NULL, 0, NULL); }]])
|
|
||||||
], [AC_DEFINE(SCTP_CONNECTX_4_ARGS, 1)])
|
|
||||||
AC_CHECK_LIB([gnutls],
|
|
||||||
[gnutls_hash],
|
|
||||||
[AC_DEFINE(GNUTLS_VERSION_210, 1,
|
|
||||||
[Define to 1 if you have gnutls 2.10 installed])],
|
|
||||||
[])
|
|
||||||
AC_CHECK_LIB([gnutls],
|
|
||||||
[gnutls_x509_trust_list_verify_crt],
|
|
||||||
[AC_DEFINE(GNUTLS_VERSION_300, 1,
|
|
||||||
[Define to 1 if you have gnutls 3.0 installed])],
|
|
||||||
[])
|
|
||||||
AC_CHECK_LIB([gnutls],
|
|
||||||
[gnutls_handshake_set_timeout],
|
|
||||||
[AC_DEFINE(GNUTLS_VERSION_310, 1,
|
|
||||||
[Define to 1 if you have gnutls 3.1 installed])],
|
|
||||||
[])
|
|
||||||
|
|
||||||
AC_DEFINE(FREE_DIAMETER_MINIMUM_VERSION, "1.1.5", [freeDiameter minimum version])
|
|
||||||
|
|
||||||
AC_CHECK_LIB(gmp, __gmpz_init, ,
|
|
||||||
[AC_MSG_ERROR([GNU MP not found, see http://gmplib.org/])])
|
|
||||||
AC_CHECK_LIB([nettle],
|
|
||||||
[nettle_hmac_sha256_set_key],
|
|
||||||
[],
|
|
||||||
[AC_MSG_ERROR(nettle is not installed)])
|
|
||||||
AC_CHECK_LIB([pthread],
|
|
||||||
[pthread_getspecific],
|
|
||||||
[],
|
|
||||||
[AC_MSG_ERROR(lib pthread is not installed)])
|
|
||||||
|
|
||||||
AC_SUBST(ADD_CFLAGS)
|
|
||||||
|
|
||||||
dnl Add these flags
|
|
||||||
CFLAGS="$CFLAGS -Wall"
|
|
||||||
CFLAGS="$CFLAGS -Wshadow"
|
|
||||||
CFLAGS="$CFLAGS -Wcast-align"
|
|
||||||
CFLAGS="$CFLAGS -Wchar-subscripts"
|
|
||||||
CFLAGS="$CFLAGS -Wmissing-prototypes"
|
|
||||||
CFLAGS="$CFLAGS -Wmissing-declarations"
|
|
||||||
CFLAGS="$CFLAGS -Werror=implicit-function-declaration"
|
|
||||||
|
|
||||||
AC_C_BIGENDIAN
|
|
||||||
if test "x$ac_cv_c_bigendian" = "xyes"; then
|
|
||||||
CFLAGS="$CFLAGS -DBYTE_ORDER=BIG_ENDIAN"
|
|
||||||
else
|
|
||||||
CFLAGS="$CFLAGS -DBYTE_ORDER=LITTLE_ENDIAN"
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_SUBST([AM_CFLAGS])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(dh_install, AS_HELP_STRING([--enable-dh-install], [Replace some variables for installation]),
|
|
||||||
[],
|
|
||||||
[])
|
|
||||||
|
|
||||||
if test x$enable_dh_install == xyes; then
|
|
||||||
AC_SUBST(AM_CONF_DIR, $sysconfdir/openair-hss)
|
|
||||||
else
|
|
||||||
AC_SUBST(AM_CONF_DIR, $srcdir/conf)
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_OUTPUT( \
|
|
||||||
conf/hss.conf \
|
|
||||||
access_restriction/Makefile \
|
|
||||||
auc/Makefile \
|
|
||||||
db/Makefile \
|
|
||||||
s6a/Makefile \
|
|
||||||
utils/Makefile \
|
|
||||||
tests/Makefile \
|
|
||||||
Makefile \
|
|
||||||
)
|
|
||||||
|
|
||||||
echo "
|
|
||||||
($PACKAGE_NAME) version $PACKAGE_VERSION
|
|
||||||
Prefix.........: $prefix
|
|
||||||
C Compiler.....: $CC $CFLAGS
|
|
||||||
Linker.........: $LD $LDFLAGS $LIBS
|
|
||||||
Tests..........: ${HAVE_CHECK}
|
|
||||||
"
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
AM_CFLAGS = @ADD_CFLAGS@ \
|
|
||||||
-I$(top_srcdir) \
|
|
||||||
-I$(top_srcdir)/s6a \
|
|
||||||
-I$(top_srcdir)/utils
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libdb.la
|
|
||||||
|
|
||||||
libdb_la_LDFLAGS = -all-static
|
|
||||||
libdb_la_SOURCES = \
|
|
||||||
db_proto.h db_connector.c \
|
|
||||||
db_subscription_data.c \
|
|
||||||
db_epc_equipment.c
|
|
||||||
@@ -1,585 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <error.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#include <mysql/mysql.h>
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "db_proto.h"
|
|
||||||
|
|
||||||
database_t *db_desc;
|
|
||||||
|
|
||||||
static void print_buffer(const char *prefix, uint8_t *buffer, int length)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
fprintf(stdout, "%s", prefix);
|
|
||||||
for (i = 0; i < length; i++) {
|
|
||||||
fprintf(stdout, "%02x.", buffer[i]);
|
|
||||||
}
|
|
||||||
fprintf(stdout, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int hss_mysql_connect(const hss_config_t *hss_config_p)
|
|
||||||
{
|
|
||||||
const int mysql_reconnect_val = 1;
|
|
||||||
|
|
||||||
if ((hss_config_p->mysql_server == NULL) ||
|
|
||||||
(hss_config_p->mysql_user == NULL) ||
|
|
||||||
(hss_config_p->mysql_password == NULL) ||
|
|
||||||
(hss_config_p->mysql_database == NULL))
|
|
||||||
{
|
|
||||||
DB_ERROR("An empty name is not allowed\n");
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DB_DEBUG("Initializing db layer\n");
|
|
||||||
|
|
||||||
db_desc = malloc(sizeof(database_t));
|
|
||||||
if (db_desc == NULL) {
|
|
||||||
DB_DEBUG("An error occured on MALLOC\n");
|
|
||||||
return errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_init(&db_desc->db_cs_mutex, NULL);
|
|
||||||
|
|
||||||
/* Copy database configuration from static hss config */
|
|
||||||
db_desc->server = strdup(hss_config_p->mysql_server);
|
|
||||||
db_desc->user = strdup(hss_config_p->mysql_user);
|
|
||||||
db_desc->password = strdup(hss_config_p->mysql_password);
|
|
||||||
db_desc->database = strdup(hss_config_p->mysql_database);
|
|
||||||
|
|
||||||
/* Init mySQL client */
|
|
||||||
db_desc->db_conn = mysql_init(NULL);
|
|
||||||
|
|
||||||
mysql_options(db_desc->db_conn, MYSQL_OPT_RECONNECT, &mysql_reconnect_val);
|
|
||||||
|
|
||||||
/* Try to connect to database */
|
|
||||||
if (!mysql_real_connect(db_desc->db_conn, db_desc->server, db_desc->user,
|
|
||||||
db_desc->password, db_desc->database, 0, NULL, 0)) {
|
|
||||||
DB_ERROR("An error occured while connecting to db: %s\n",
|
|
||||||
mysql_error(db_desc->db_conn));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the multi statement ON */
|
|
||||||
mysql_set_server_option(db_desc->db_conn, MYSQL_OPTION_MULTI_STATEMENTS_ON);
|
|
||||||
|
|
||||||
DB_DEBUG("Initializing db layer: DONE\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void hss_mysql_disconnect(void)
|
|
||||||
{
|
|
||||||
mysql_close(db_desc->db_conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
int hss_mysql_update_loc(const char *imsi, mysql_ul_ans_t *mysql_ul_ans)
|
|
||||||
{
|
|
||||||
MYSQL_RES *res;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
char query[255];
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if ((db_desc->db_conn == NULL) || (mysql_ul_ans == NULL)) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(imsi) > 15) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(query, "SELECT `access_restriction`,`mmeidentity_idmmeidentity`,"
|
|
||||||
"`msisdn`,`ue_ambr_ul`,`ue_ambr_dl`,`rau_tau_timer` "
|
|
||||||
"FROM `users` WHERE `users`.`imsi`='%s' ", imsi);
|
|
||||||
|
|
||||||
memcpy(mysql_ul_ans->imsi, imsi, strlen(imsi) + 1);
|
|
||||||
|
|
||||||
DB_DEBUG("Query: %s\n", query);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
if (mysql_query(db_desc->db_conn, query))
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
DB_ERROR("Query execution failed: %s\n",
|
|
||||||
mysql_error(db_desc->db_conn));
|
|
||||||
mysql_thread_end();
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = mysql_store_result(db_desc->db_conn);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
if ((row = mysql_fetch_row(res)) != NULL) {
|
|
||||||
int mme_id;
|
|
||||||
/* MSISDN may be NULL */
|
|
||||||
mysql_ul_ans->access_restriction = atoi(row[0]);
|
|
||||||
if ((mme_id = atoi(row[1])) > 0) {
|
|
||||||
ret = hss_mysql_query_mmeidentity(mme_id, &mysql_ul_ans->mme_identity);
|
|
||||||
} else {
|
|
||||||
mysql_ul_ans->mme_identity.mme_host[0] = '\0';
|
|
||||||
mysql_ul_ans->mme_identity.mme_realm[0] = '\0';
|
|
||||||
}
|
|
||||||
if (row[2] != 0) {
|
|
||||||
memcpy(mysql_ul_ans->msisdn, row[2], strlen(row[2]));
|
|
||||||
}
|
|
||||||
mysql_ul_ans->aggr_ul = atoi(row[3]);
|
|
||||||
mysql_ul_ans->aggr_dl = atoi(row[4]);
|
|
||||||
mysql_ul_ans->rau_tau = atoi(row[5]);
|
|
||||||
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hss_mysql_purge_ue(mysql_pu_req_t *mysql_pu_req,
|
|
||||||
mysql_pu_ans_t *mysql_pu_ans)
|
|
||||||
{
|
|
||||||
MYSQL_RES *res;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
char query[255];
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if ((db_desc->db_conn == NULL) ||
|
|
||||||
(mysql_pu_req == NULL) ||
|
|
||||||
(mysql_pu_ans == NULL))
|
|
||||||
{
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(mysql_pu_req->imsi) > 15) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(query, "UPDATE `users` SET `users`.`ms_ps_status`=\"PURGED\" "
|
|
||||||
"WHERE `users`.`imsi`='%s'; "
|
|
||||||
"SELECT `users`.`mmeidentity_idmmeidentity` FROM `users` "
|
|
||||||
"WHERE `users`.`imsi`=%s ",
|
|
||||||
mysql_pu_req->imsi, mysql_pu_req->imsi);
|
|
||||||
|
|
||||||
DB_DEBUG("Query: %s\n", query);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
if (mysql_query(db_desc->db_conn, query))
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
DB_ERROR("Query execution failed: %s\n",
|
|
||||||
mysql_error(db_desc->db_conn));
|
|
||||||
mysql_thread_end();
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = mysql_store_result(db_desc->db_conn);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
if ((row = mysql_fetch_row(res)) != NULL) {
|
|
||||||
int mme_id;
|
|
||||||
if ((mme_id = atoi(row[0])) > 0) {
|
|
||||||
ret = hss_mysql_query_mmeidentity(mme_id, mysql_pu_ans);
|
|
||||||
} else {
|
|
||||||
mysql_pu_ans->mme_host[0] = '\0';
|
|
||||||
mysql_pu_ans->mme_realm[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hss_mysql_get_user(const char *imsi)
|
|
||||||
{
|
|
||||||
MYSQL_RES *res;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
char query[255];
|
|
||||||
|
|
||||||
if (db_desc->db_conn == NULL) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(query, "SELECT `imsi` FROM `users` WHERE `users`.`imsi`=%s ", imsi);
|
|
||||||
|
|
||||||
DB_DEBUG("Query: %s\n", query);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
if (mysql_query(db_desc->db_conn, query))
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
DB_ERROR("Query execution failed: %s\n",
|
|
||||||
mysql_error(db_desc->db_conn));
|
|
||||||
mysql_thread_end();
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = mysql_store_result(db_desc->db_conn);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
if ((row = mysql_fetch_row(res)) != NULL) {
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mysql_push_up_loc(mysql_ul_push_t *ul_push_p)
|
|
||||||
{
|
|
||||||
MYSQL_RES *res;
|
|
||||||
char query[500];
|
|
||||||
int query_length = 0;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
if ((db_desc->db_conn == NULL) || (ul_push_p == NULL)) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: multi-statement check results
|
|
||||||
|
|
||||||
if (ul_push_p->mme_identity_present == MME_IDENTITY_PRESENT) {
|
|
||||||
query_length += sprintf(&query[query_length], "INSERT INTO `mmeidentity`"
|
|
||||||
" (`mmehost`,`mmerealm`) SELECT '%s','%s' FROM `mmeidentity` WHERE NOT"
|
|
||||||
" EXISTS (SELECT * FROM `mmeidentity` WHERE `mmehost`='%s'"
|
|
||||||
" AND `mmerealm`='%s') LIMIT 1;", ul_push_p->mme_identity.mme_host,
|
|
||||||
ul_push_p->mme_identity.mme_realm, ul_push_p->mme_identity.mme_host,
|
|
||||||
ul_push_p->mme_identity.mme_realm);
|
|
||||||
}
|
|
||||||
query_length += sprintf(&query[query_length], "UPDATE `users`%s SET ",
|
|
||||||
ul_push_p->mme_identity_present == MME_IDENTITY_PRESENT ?
|
|
||||||
",`mmeidentity`" : "");
|
|
||||||
|
|
||||||
if (ul_push_p->imei_present == IMEI_PRESENT) {
|
|
||||||
query_length += sprintf(&query[query_length], "`imei`='%s',",
|
|
||||||
ul_push_p->imei);
|
|
||||||
}
|
|
||||||
if (ul_push_p->sv_present == SV_PRESENT) {
|
|
||||||
query_length += sprintf(&query[query_length], "`imeisv`='%*s',", 2,
|
|
||||||
ul_push_p->software_version);
|
|
||||||
}
|
|
||||||
if (ul_push_p->mme_identity_present == MME_IDENTITY_PRESENT) {
|
|
||||||
query_length += sprintf(&query[query_length],
|
|
||||||
"`users`.`mmeidentity_idmmeidentity`=`mmeidentity`.`idmmeidentity`, "
|
|
||||||
"`users`.`ms_ps_status`=\"NOT_PURGED\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
query_length += sprintf(&query[query_length], " WHERE `users`.`imsi`='%s'",
|
|
||||||
ul_push_p->imsi);
|
|
||||||
if (ul_push_p->mme_identity_present == MME_IDENTITY_PRESENT) {
|
|
||||||
query_length += sprintf(&query[query_length],
|
|
||||||
" AND `mmeidentity`.`mmehost`='%s'"
|
|
||||||
" AND `mmeidentity`.`mmerealm`='%s'",
|
|
||||||
ul_push_p->mme_identity.mme_host, ul_push_p->mme_identity.mme_realm);
|
|
||||||
}
|
|
||||||
|
|
||||||
DB_DEBUG("Query: %s\n", query);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
if (mysql_query(db_desc->db_conn, query))
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
fprintf(stderr, "Query execution failed: %s\n",
|
|
||||||
mysql_error(db_desc->db_conn));
|
|
||||||
mysql_thread_end();
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* process each statement result */
|
|
||||||
do {
|
|
||||||
/* did current statement return data? */
|
|
||||||
res = mysql_store_result(db_desc->db_conn);
|
|
||||||
if (res)
|
|
||||||
{
|
|
||||||
/* yes; process rows and free the result set */
|
|
||||||
mysql_free_result(res);
|
|
||||||
}
|
|
||||||
else /* no result set or error */
|
|
||||||
{
|
|
||||||
if (mysql_field_count(db_desc->db_conn) == 0)
|
|
||||||
{
|
|
||||||
DB_ERROR("%lld rows affected\n",
|
|
||||||
mysql_affected_rows(db_desc->db_conn));
|
|
||||||
}
|
|
||||||
else /* some error occurred */
|
|
||||||
{
|
|
||||||
DB_ERROR("Could not retrieve result set\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* more results? -1 = no, >0 = error, 0 = yes (keep looping) */
|
|
||||||
if ((status = mysql_next_result(db_desc->db_conn)) > 0)
|
|
||||||
DB_ERROR("Could not execute statement\n");
|
|
||||||
} while (status == 0);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hss_mysql_push_rand_sqn(const char *imsi, uint8_t *rand_p, uint8_t *sqn)
|
|
||||||
{
|
|
||||||
int status = 0, i;
|
|
||||||
MYSQL_RES *res;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
char query[255];
|
|
||||||
int query_length = 0;
|
|
||||||
uint64_t sqn_decimal = 0;
|
|
||||||
|
|
||||||
if (db_desc->db_conn == NULL) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rand_p == NULL || sqn == NULL) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sqn_decimal = ((uint64_t)sqn[0] << 40) | ((uint64_t)sqn[1] << 32) |
|
|
||||||
(sqn[2] << 24) | (sqn[3] << 16) | (sqn[4] << 8) | sqn[5];
|
|
||||||
|
|
||||||
query_length = sprintf(query, "UPDATE `users` SET `rand`=UNHEX('");
|
|
||||||
for (i = 0; i < RAND_LENGTH; i ++) {
|
|
||||||
query_length += sprintf(&query[query_length], "%02x", rand_p[i]);
|
|
||||||
}
|
|
||||||
query_length += sprintf(&query[query_length], "'),`sqn`=%"PRIu64, sqn_decimal);
|
|
||||||
query_length += sprintf(&query[query_length], " WHERE `users`.`imsi`='%s'", imsi);
|
|
||||||
|
|
||||||
DB_DEBUG("Query: %s\n", query);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
if (mysql_query(db_desc->db_conn, query))
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
DB_ERROR("Query execution failed: %s\n",
|
|
||||||
mysql_error(db_desc->db_conn));
|
|
||||||
mysql_thread_end();
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* process each statement result */
|
|
||||||
do {
|
|
||||||
/* did current statement return data? */
|
|
||||||
res = mysql_store_result(db_desc->db_conn);
|
|
||||||
if (res)
|
|
||||||
{
|
|
||||||
/* yes; process rows and free the result set */
|
|
||||||
mysql_free_result(res);
|
|
||||||
}
|
|
||||||
else /* no result set or error */
|
|
||||||
{
|
|
||||||
if (mysql_field_count(db_desc->db_conn) == 0)
|
|
||||||
{
|
|
||||||
DB_ERROR("%lld rows affected\n",
|
|
||||||
mysql_affected_rows(db_desc->db_conn));
|
|
||||||
}
|
|
||||||
else /* some error occurred */
|
|
||||||
{
|
|
||||||
DB_ERROR("Could not retrieve result set\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* more results? -1 = no, >0 = error, 0 = yes (keep looping) */
|
|
||||||
if ((status = mysql_next_result(db_desc->db_conn)) > 0)
|
|
||||||
DB_ERROR("Could not execute statement\n");
|
|
||||||
} while (status == 0);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hss_mysql_increment_sqn(const char *imsi)
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
MYSQL_RES *res;
|
|
||||||
char query[255];
|
|
||||||
|
|
||||||
if (db_desc->db_conn == NULL) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
if (imsi == NULL) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* + 32 = 2 ^ sizeof(IND) (see 3GPP TS. 33.102) */
|
|
||||||
sprintf(query, "UPDATE `users` SET `sqn` = `sqn` + 32 WHERE `users`.`imsi`=%s", imsi);
|
|
||||||
|
|
||||||
DB_DEBUG("Query: %s\n", query);
|
|
||||||
|
|
||||||
if (mysql_query(db_desc->db_conn, query))
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
DB_ERROR("Query execution failed: %s\n",
|
|
||||||
mysql_error(db_desc->db_conn));
|
|
||||||
mysql_thread_end();
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* process each statement result */
|
|
||||||
do {
|
|
||||||
/* did current statement return data? */
|
|
||||||
res = mysql_store_result(db_desc->db_conn);
|
|
||||||
if (res)
|
|
||||||
{
|
|
||||||
/* yes; process rows and free the result set */
|
|
||||||
mysql_free_result(res);
|
|
||||||
}
|
|
||||||
else /* no result set or error */
|
|
||||||
{
|
|
||||||
if (mysql_field_count(db_desc->db_conn) == 0)
|
|
||||||
{
|
|
||||||
DB_ERROR("%lld rows affected\n",
|
|
||||||
mysql_affected_rows(db_desc->db_conn));
|
|
||||||
}
|
|
||||||
else /* some error occurred */
|
|
||||||
{
|
|
||||||
DB_ERROR("Could not retrieve result set\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* more results? -1 = no, >0 = error, 0 = yes (keep looping) */
|
|
||||||
if ((status = mysql_next_result(db_desc->db_conn)) > 0)
|
|
||||||
DB_ERROR("Could not execute statement\n");
|
|
||||||
} while (status == 0);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hss_mysql_auth_info(mysql_auth_info_req_t *auth_info_req,
|
|
||||||
mysql_auth_info_resp_t *auth_info_resp)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
MYSQL_RES *res;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
char query[255];
|
|
||||||
|
|
||||||
if (db_desc->db_conn == NULL) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
if ((auth_info_req == NULL) || (auth_info_resp == NULL)) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(query, "SELECT `key`,`sqn`,`rand` FROM `users` WHERE `users`.`imsi`=%s ",
|
|
||||||
auth_info_req->imsi);
|
|
||||||
|
|
||||||
DB_DEBUG("Query: %s\n", query);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
if (mysql_query(db_desc->db_conn, query))
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
DB_ERROR("Query execution failed: %s\n",
|
|
||||||
mysql_error(db_desc->db_conn));
|
|
||||||
mysql_thread_end();
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = mysql_store_result(db_desc->db_conn);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
if ((row = mysql_fetch_row(res)) != NULL) {
|
|
||||||
if (row[0] == NULL || row[1] == NULL || row[2] == NULL) {
|
|
||||||
ret = EINVAL;
|
|
||||||
}
|
|
||||||
if (row[0] != NULL) {
|
|
||||||
print_buffer("Key: ", (uint8_t*)row[0], KEY_LENGTH);
|
|
||||||
memcpy(auth_info_resp->key, row[0], KEY_LENGTH);
|
|
||||||
}
|
|
||||||
if (row[1] != NULL) {
|
|
||||||
uint64_t sqn = 0;
|
|
||||||
|
|
||||||
sqn = atoll(row[1]);
|
|
||||||
printf("Received SQN %s converted to %"PRIu64"\n", row[1], sqn);
|
|
||||||
|
|
||||||
auth_info_resp->sqn[0] = (sqn & (255UL << 40)) >> 40;
|
|
||||||
auth_info_resp->sqn[1] = (sqn & (255UL << 32)) >> 32;
|
|
||||||
auth_info_resp->sqn[2] = (sqn & (255UL << 24)) >> 24;
|
|
||||||
auth_info_resp->sqn[3] = (sqn & (255UL << 16)) >> 16;
|
|
||||||
auth_info_resp->sqn[4] = (sqn & (255UL << 8)) >> 8;
|
|
||||||
auth_info_resp->sqn[5] = (sqn & 0xFF);
|
|
||||||
|
|
||||||
print_buffer("SQN: ", auth_info_resp->sqn, SQN_LENGTH);
|
|
||||||
}
|
|
||||||
if (row[2] != NULL) {
|
|
||||||
print_buffer("RAND: ", (uint8_t*)row[2], RAND_LENGTH);
|
|
||||||
memcpy(auth_info_resp->rand, row[2], RAND_LENGTH);
|
|
||||||
}
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <error.h>
|
|
||||||
|
|
||||||
#include <mysql/mysql.h>
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "db_proto.h"
|
|
||||||
|
|
||||||
int hss_mysql_query_mmeidentity(const int id_mme_identity,
|
|
||||||
mysql_mme_identity_t *mme_identity_p)
|
|
||||||
{
|
|
||||||
MYSQL_RES *res;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
char query[255];
|
|
||||||
|
|
||||||
if ((db_desc->db_conn == NULL) || (mme_identity_p == NULL)) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(mme_identity_p, 0, sizeof(mysql_mme_identity_t));
|
|
||||||
|
|
||||||
sprintf(query, "SELECT mmehost,mmerealm FROM mmeidentity WHERE "
|
|
||||||
"mmeidentity.idmmeidentity='%d' ", id_mme_identity);
|
|
||||||
|
|
||||||
DB_DEBUG("Query: %s\n", query);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
if (mysql_query(db_desc->db_conn, query))
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
DB_ERROR("Query execution failed: %s\n",
|
|
||||||
mysql_error(db_desc->db_conn));
|
|
||||||
mysql_thread_end();
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = mysql_store_result(db_desc->db_conn);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
if ((row = mysql_fetch_row(res)) != NULL) {
|
|
||||||
if (row[0] != NULL) {
|
|
||||||
memcpy(mme_identity_p->mme_host, row[0], strlen(row[0]));
|
|
||||||
} else {
|
|
||||||
mme_identity_p->mme_host[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (row[1] != NULL) {
|
|
||||||
memcpy(mme_identity_p->mme_realm, row[1], strlen(row[1]));
|
|
||||||
} else {
|
|
||||||
mme_identity_p->mme_realm[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hss_mysql_check_epc_equipment(mysql_mme_identity_t *mme_identity_p)
|
|
||||||
{
|
|
||||||
MYSQL_RES *res;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
char query[255];
|
|
||||||
|
|
||||||
if ((db_desc->db_conn == NULL) || (mme_identity_p == NULL)) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(query, "SELECT idmmeidentity FROM mmeidentity WHERE mmeidentity.mmehost='%s' ",
|
|
||||||
mme_identity_p->mme_host);
|
|
||||||
|
|
||||||
DB_DEBUG("Query: %s\n", query);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
if (mysql_query(db_desc->db_conn, query))
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
DB_ERROR("Query execution failed: %s\n",
|
|
||||||
mysql_error(db_desc->db_conn));
|
|
||||||
mysql_thread_end();
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = mysql_store_result(db_desc->db_conn);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
if ((row = mysql_fetch_row(res)) != NULL) {
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <mysql/mysql.h>
|
|
||||||
|
|
||||||
#include <netinet/in.h> /* To provide internet addresses strings helpers */
|
|
||||||
|
|
||||||
#ifndef DB_PROTO_H_
|
|
||||||
#define DB_PROTO_H_
|
|
||||||
|
|
||||||
#define DB_DEBUG(fmt, args...) fprintf(stdout, "%s:%d: "fmt, __FILE__, __LINE__, ##args)
|
|
||||||
#define DB_ERROR(fmt, args...) fprintf(stderr, "%s:%d: "fmt, __FILE__, __LINE__, ##args)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* The mysql reference connector object */
|
|
||||||
MYSQL *db_conn;
|
|
||||||
char *server;
|
|
||||||
char *user;
|
|
||||||
char *password;
|
|
||||||
char *database;
|
|
||||||
|
|
||||||
pthread_mutex_t db_cs_mutex;
|
|
||||||
} database_t;
|
|
||||||
|
|
||||||
extern database_t *db_desc;
|
|
||||||
|
|
||||||
typedef uint32_t pre_emp_vul_t;
|
|
||||||
typedef uint32_t pre_emp_cap_t;
|
|
||||||
typedef uint8_t access_restriction_t;
|
|
||||||
typedef uint32_t ambr_t;
|
|
||||||
typedef uint8_t qci_t;
|
|
||||||
typedef uint8_t prio_level_t;
|
|
||||||
typedef uint32_t rau_tau_t;
|
|
||||||
|
|
||||||
#define IMSI_LENGTH_MAX (15)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char imsi[IMSI_LENGTH_MAX + 1];
|
|
||||||
} mysql_auth_info_req_t;
|
|
||||||
|
|
||||||
/* Expressed in bytes */
|
|
||||||
#define KEY_LENGTH (16)
|
|
||||||
#define SQN_LENGTH (6)
|
|
||||||
#define RAND_LENGTH (16)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t key[KEY_LENGTH];
|
|
||||||
uint8_t sqn[SQN_LENGTH];
|
|
||||||
/* RAND should not be here... */
|
|
||||||
uint8_t rand[RAND_LENGTH];
|
|
||||||
} mysql_auth_info_resp_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char imsi[IMSI_LENGTH_MAX + 1];
|
|
||||||
/* New computed SQN that will be used on next auth info req */
|
|
||||||
uint8_t sqn[SQN_LENGTH];
|
|
||||||
} mysql_sqn_push_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* An MME may have already been registered as serving the UE. */
|
|
||||||
char mme_host[255];
|
|
||||||
char mme_realm[200];
|
|
||||||
} mysql_mme_identity_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char imsi[16];
|
|
||||||
/* MSISDN this parameter may be NULL */
|
|
||||||
char msisdn[16];
|
|
||||||
|
|
||||||
/* Maximum aggregated bitrates for the user */
|
|
||||||
ambr_t aggr_ul;
|
|
||||||
ambr_t aggr_dl;
|
|
||||||
|
|
||||||
/* Subscribed RAU-TAU timer */
|
|
||||||
rau_tau_t rau_tau;
|
|
||||||
|
|
||||||
access_restriction_t access_restriction;
|
|
||||||
mysql_mme_identity_t mme_identity;
|
|
||||||
} mysql_ul_ans_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* Bit masks indicating presence of optional fields */
|
|
||||||
#define MME_IDENTITY_PRESENT (0x1)
|
|
||||||
#define MME_SUPPORTED_FEATURES_PRESENT (0x1)
|
|
||||||
#define IMEI_PRESENT (0x1)
|
|
||||||
#define SV_PRESENT (0x1)
|
|
||||||
#define UE_SRVCC_PRESENT (0x1)
|
|
||||||
|
|
||||||
unsigned mme_identity_present:1;
|
|
||||||
unsigned mme_supported_features_present:1;
|
|
||||||
unsigned imei_present:1;
|
|
||||||
unsigned sv_present:1;
|
|
||||||
unsigned ue_srvcc_present:1;
|
|
||||||
|
|
||||||
/* IMSI */
|
|
||||||
char imsi[16];
|
|
||||||
/* Origin host and realm */
|
|
||||||
mysql_mme_identity_t mme_identity;
|
|
||||||
/* IMEISV */
|
|
||||||
char imei[16];
|
|
||||||
char software_version[2];
|
|
||||||
|
|
||||||
uint32_t ue_srvcc;
|
|
||||||
uint32_t mme_supported_features;
|
|
||||||
} mysql_ul_push_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
IPV4 = 0,
|
|
||||||
IPV6 = 1,
|
|
||||||
IPV4V6 = 2,
|
|
||||||
IPV4_OR_IPV6 = 3,
|
|
||||||
} pdn_type_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char ipv4_address[INET_ADDRSTRLEN];
|
|
||||||
char ipv6_address[INET6_ADDRSTRLEN];
|
|
||||||
} pdn_address_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char apn[61];
|
|
||||||
pdn_type_t pdn_type;
|
|
||||||
pdn_address_t pdn_address;
|
|
||||||
ambr_t aggr_ul;
|
|
||||||
ambr_t aggr_dl;
|
|
||||||
qci_t qci;
|
|
||||||
prio_level_t priority_level;
|
|
||||||
pre_emp_cap_t pre_emp_cap;
|
|
||||||
pre_emp_vul_t pre_emp_vul;
|
|
||||||
} mysql_pdn_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* IMSI */
|
|
||||||
char imsi[16];
|
|
||||||
} mysql_pu_req_t;
|
|
||||||
|
|
||||||
typedef mysql_mme_identity_t mysql_pu_ans_t;
|
|
||||||
|
|
||||||
int hss_mysql_connect(const hss_config_t *hss_config_p);
|
|
||||||
|
|
||||||
void hss_mysql_disconnect(void);
|
|
||||||
|
|
||||||
int hss_mysql_get_user(const char *imsi);
|
|
||||||
|
|
||||||
int hss_mysql_update_loc(const char *imsi, mysql_ul_ans_t *mysql_ul_ans);
|
|
||||||
|
|
||||||
int hss_mysql_query_mmeidentity(const int id_mme_identity,
|
|
||||||
mysql_mme_identity_t *mme_identity_p);
|
|
||||||
|
|
||||||
int hss_mysql_check_epc_equipment(mysql_mme_identity_t *mme_identity_p);
|
|
||||||
|
|
||||||
int mysql_push_up_loc(mysql_ul_push_t *ul_push_p);
|
|
||||||
|
|
||||||
int hss_mysql_purge_ue(mysql_pu_req_t *mysql_pu_req,
|
|
||||||
mysql_pu_ans_t *mysql_pu_ans);
|
|
||||||
|
|
||||||
int hss_mysql_query_pdns(const char *imsi,
|
|
||||||
mysql_pdn_t **pdns_p,
|
|
||||||
uint8_t *nb_pdns);
|
|
||||||
|
|
||||||
int hss_mysql_auth_info(mysql_auth_info_req_t *auth_info_req,
|
|
||||||
mysql_auth_info_resp_t *auth_info_resp);
|
|
||||||
|
|
||||||
int hss_mysql_push_rand_sqn(const char *imsi, uint8_t *rand_p, uint8_t *sqn);
|
|
||||||
|
|
||||||
int hss_mysql_increment_sqn(const char *imsi);
|
|
||||||
|
|
||||||
#endif /* DB_PROTO_H_ */
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
#include <pthread.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <error.h>
|
|
||||||
|
|
||||||
#include <mysql/mysql.h>
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "db_proto.h"
|
|
||||||
|
|
||||||
int hss_mysql_query_pdns(const char *imsi,
|
|
||||||
mysql_pdn_t **pdns_p,
|
|
||||||
uint8_t *nb_pdns)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
MYSQL_RES *res;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
char query[255];
|
|
||||||
mysql_pdn_t *pdn_array = NULL;
|
|
||||||
|
|
||||||
if (db_desc->db_conn == NULL) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
if (nb_pdns == NULL || pdns_p == NULL) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(query, "SELECT * FROM `pdn` WHERE "
|
|
||||||
"`pdn`.`users_imsi`=%s LIMIT 10; ", imsi);
|
|
||||||
|
|
||||||
printf("Query: %s\n", query);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
if (mysql_query(db_desc->db_conn, query))
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
fprintf(stderr, "Query execution failed: %s\n",
|
|
||||||
mysql_error(db_desc->db_conn));
|
|
||||||
mysql_thread_end();
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = mysql_store_result(db_desc->db_conn);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&db_desc->db_cs_mutex);
|
|
||||||
|
|
||||||
*nb_pdns = 0;
|
|
||||||
|
|
||||||
while ((row = mysql_fetch_row(res)) != NULL)
|
|
||||||
{
|
|
||||||
mysql_pdn_t *pdn_elm; /* Local PDN element in array */
|
|
||||||
unsigned long *lengths;
|
|
||||||
|
|
||||||
lengths = mysql_fetch_lengths(res);
|
|
||||||
|
|
||||||
*nb_pdns += 1;
|
|
||||||
if (*nb_pdns == 1) {
|
|
||||||
/* First row, must malloc */
|
|
||||||
pdn_array = malloc(sizeof(mysql_pdn_t));
|
|
||||||
} else {
|
|
||||||
pdn_array = realloc(pdn_array, *nb_pdns * sizeof(mysql_pdn_t));
|
|
||||||
}
|
|
||||||
if (pdn_array == NULL) {
|
|
||||||
/* Error on malloc */
|
|
||||||
ret = ENOMEM;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
pdn_elm = &pdn_array[*nb_pdns - 1];
|
|
||||||
/* Copying the APN */
|
|
||||||
memset(pdn_elm, 0, sizeof(mysql_pdn_t));
|
|
||||||
memcpy(pdn_elm->apn, row[1], lengths[1]);
|
|
||||||
/* PDN Type + PDN address */
|
|
||||||
if (strcmp(row[2], "IPv6") == 0) {
|
|
||||||
pdn_elm->pdn_type = IPV6;
|
|
||||||
memcpy(pdn_elm->pdn_address.ipv6_address, row[4], lengths[4]);
|
|
||||||
pdn_elm->pdn_address.ipv6_address[lengths[4]] = '\0';
|
|
||||||
} else if (strcmp(row[2], "IPv4v6") == 0) {
|
|
||||||
pdn_elm->pdn_type = IPV4V6;
|
|
||||||
memcpy(pdn_elm->pdn_address.ipv4_address, row[3], lengths[3]);
|
|
||||||
pdn_elm->pdn_address.ipv4_address[lengths[3]] = '\0';
|
|
||||||
memcpy(pdn_elm->pdn_address.ipv6_address, row[4], lengths[4]);
|
|
||||||
pdn_elm->pdn_address.ipv6_address[lengths[4]] = '\0';
|
|
||||||
} else if (strcmp(row[2], "IPv4_or_IPv6") == 0) {
|
|
||||||
pdn_elm->pdn_type = IPV4_OR_IPV6;
|
|
||||||
memcpy(pdn_elm->pdn_address.ipv4_address, row[3], lengths[3]);
|
|
||||||
pdn_elm->pdn_address.ipv4_address[lengths[3]] = '\0';
|
|
||||||
memcpy(pdn_elm->pdn_address.ipv6_address, row[4], lengths[4]);
|
|
||||||
pdn_elm->pdn_address.ipv6_address[lengths[4]] = '\0';
|
|
||||||
} else {
|
|
||||||
pdn_elm->pdn_type = IPV4;
|
|
||||||
memcpy(pdn_elm->pdn_address.ipv4_address, row[3], lengths[3]);
|
|
||||||
pdn_elm->pdn_address.ipv4_address[lengths[3]] = '\0';
|
|
||||||
}
|
|
||||||
pdn_elm->aggr_ul = atoi(row[5]);
|
|
||||||
pdn_elm->aggr_dl = atoi(row[6]);
|
|
||||||
pdn_elm->qci = atoi(row[9]);
|
|
||||||
pdn_elm->priority_level = atoi(row[10]);
|
|
||||||
if (strcmp(row[11], "ENABLED") == 0) {
|
|
||||||
pdn_elm->pre_emp_cap = 0;
|
|
||||||
} else {
|
|
||||||
pdn_elm->pre_emp_cap = 1;
|
|
||||||
}
|
|
||||||
if (strcmp(row[12], "DISABLED") == 0) {
|
|
||||||
pdn_elm->pre_emp_vul = 1;
|
|
||||||
} else {
|
|
||||||
pdn_elm->pre_emp_vul = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
|
|
||||||
/* We did not find any APN for the requested IMSI */
|
|
||||||
if (*nb_pdns == 0) {
|
|
||||||
return EINVAL;
|
|
||||||
} else {
|
|
||||||
*pdns_p = pdn_array;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (pdn_array) {
|
|
||||||
free(pdn_array);
|
|
||||||
}
|
|
||||||
pdn_array = NULL;
|
|
||||||
*pdns_p = pdn_array;
|
|
||||||
*nb_pdns = 0;
|
|
||||||
mysql_free_result(res);
|
|
||||||
mysql_thread_end();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
-- phpMyAdmin SQL Dump
|
|
||||||
-- version 3.4.10.1deb1
|
|
||||||
-- http://www.phpmyadmin.net
|
|
||||||
--
|
|
||||||
-- Client: localhost
|
|
||||||
-- Généré le : Mer 18 Décembre 2013 à 18:01
|
|
||||||
-- Version du serveur: 5.5.34
|
|
||||||
-- Version de PHP: 5.3.10-1ubuntu3.9
|
|
||||||
|
|
||||||
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
|
|
||||||
SET time_zone = "+00:00";
|
|
||||||
|
|
||||||
|
|
||||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
|
||||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
|
||||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
|
||||||
/*!40101 SET NAMES utf8 */;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Base de données: `oai_db`
|
|
||||||
--
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Structure de la table `apn`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `apn` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`apn-name` varchar(60) NOT NULL,
|
|
||||||
`pdn-type` enum('IPv4','IPv6','IPv4v6','IPv4_or_IPv6') NOT NULL,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `apn-name` (`apn-name`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Structure de la table `mmeidentity`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `mmeidentity` (
|
|
||||||
`idmmeidentity` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`mmehost` varchar(255) DEFAULT NULL,
|
|
||||||
`mmerealm` varchar(200) DEFAULT NULL,
|
|
||||||
`UE-Reachability` tinyint(1) NOT NULL COMMENT 'Indicates whether the MME supports UE Reachability Notifcation',
|
|
||||||
PRIMARY KEY (`idmmeidentity`)
|
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=39 ;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Contenu de la table `mmeidentity`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `mmeidentity` (`idmmeidentity`, `mmehost`, `mmerealm`, `UE-Reachability`) VALUES
|
|
||||||
(29, 'yang.eur', 'eur', 0),
|
|
||||||
(28, 'nord.eur', 'eur', 0),
|
|
||||||
(30, 'hades.eur', 'eur', 0),
|
|
||||||
(35, 'olympie-Latitude-E6520.eur', 'eur', 0),
|
|
||||||
(33, 'orcus.eur', 'eur', 0),
|
|
||||||
(36, 'caviar.eur', 'eur', 0),
|
|
||||||
(37, 'sud.eur', 'eur', 0),
|
|
||||||
(38, 'tapenade.eur', 'eur', 1);
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Structure de la table `pdn`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `pdn` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`apn` varchar(60) NOT NULL,
|
|
||||||
`pdn_type` enum('IPv4','IPv6','IPv4v6','IPv4_or_IPv6') NOT NULL DEFAULT 'IPv4',
|
|
||||||
`pdn_ipv4` varchar(15) DEFAULT '0.0.0.0',
|
|
||||||
`pdn_ipv6` varchar(45) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT '0:0:0:0:0:0:0:0',
|
|
||||||
`aggregate_ambr_ul` int(10) unsigned DEFAULT '50000000',
|
|
||||||
`aggregate_ambr_dl` int(10) unsigned DEFAULT '100000000',
|
|
||||||
`pgw_id` int(11) NOT NULL,
|
|
||||||
`users_imsi` varchar(15) NOT NULL,
|
|
||||||
`qci` tinyint(3) unsigned NOT NULL DEFAULT '9',
|
|
||||||
`priority_level` tinyint(3) unsigned NOT NULL DEFAULT '15',
|
|
||||||
`pre_emp_cap` enum('ENABLED','DISABLED') DEFAULT 'DISABLED',
|
|
||||||
`pre_emp_vul` enum('ENABLED','DISABLED') DEFAULT 'DISABLED',
|
|
||||||
`LIPA-Permissions` enum('LIPA-prohibited','LIPA-only','LIPA-conditional') NOT NULL DEFAULT 'LIPA-only',
|
|
||||||
PRIMARY KEY (`id`,`pgw_id`,`users_imsi`),
|
|
||||||
KEY `fk_pdn_pgw1_idx` (`pgw_id`),
|
|
||||||
KEY `fk_pdn_users1_idx` (`users_imsi`)
|
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=8 ;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Contenu de la table `pdn`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `pdn` (`id`, `apn`, `pdn_type`, `pdn_ipv4`, `pdn_ipv6`, `aggregate_ambr_ul`, `aggregate_ambr_dl`, `pgw_id`, `users_imsi`, `qci`, `priority_level`, `pre_emp_cap`, `pre_emp_vul`, `LIPA-Permissions`) VALUES
|
|
||||||
(2, 'wap.test.fr', 'IPv4v6', '10.0.0.5', '0:0:0:0:0:0:0:1', 1048576, 14400000, 2, '20834123456789', 8, 2, 'ENABLED', 'DISABLED', 'LIPA-only'),
|
|
||||||
(3, 'toto.eurecom.fr', 'IPv4v6', '0.0.0.0', '2001:0db8:85a3:0042:1000:8a2e:0370:7334', 50000, 100000, 2, '20834123456710', 1, 3, 'DISABLED', 'DISABLED', 'LIPA-only'),
|
|
||||||
(4, 'edge.eurecom.fr', 'IPv4_or_IPv6', '0.0.0.0', '2001:0db8:85a3:0042:1000:8a2e:0370:7356', 50000000, 100000000, 1, '20834123456789', 3, 4, 'ENABLED', 'DISABLED', 'LIPA-only'),
|
|
||||||
(7, 'internet.v6.eur', 'IPv6', '0.0.0.0', '0:0:0:0:0:0:0:0', 50000000, 100000000, 4, '20834123456789', 9, 15, 'DISABLED', 'ENABLED', 'LIPA-only'),
|
|
||||||
(1, 'internet.v4.eur', 'IPv4', '0.0.0.0', '0:0:0:0:0:0:0:0', 50000000, 100000000, 3, '20834123456789', 9, 15, 'DISABLED', 'ENABLED', 'LIPA-only');
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Structure de la table `pgw`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `pgw` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`ipv4` varchar(15) NOT NULL,
|
|
||||||
`ipv6` varchar(39) NOT NULL,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `ipv4` (`ipv4`),
|
|
||||||
UNIQUE KEY `ipv6` (`ipv6`)
|
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Contenu de la table `pgw`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `pgw` (`id`, `ipv4`, `ipv6`) VALUES
|
|
||||||
(1, '127.0.0.1', '0:0:0:0:0:0:0:1'),
|
|
||||||
(2, '192.168.56.101', ''),
|
|
||||||
(3, '10.0.0.2', '0');
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Structure de la table `terminal-info`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `terminal-info` (
|
|
||||||
`imei` varchar(15) NOT NULL,
|
|
||||||
`sv` varchar(2) NOT NULL,
|
|
||||||
UNIQUE KEY `imei` (`imei`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Structure de la table `users`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `users` (
|
|
||||||
`imsi` varchar(15) NOT NULL,
|
|
||||||
`msisdn` varchar(46) DEFAULT NULL,
|
|
||||||
`imei` varchar(15) DEFAULT NULL,
|
|
||||||
`imei_sv` varchar(2) DEFAULT NULL,
|
|
||||||
`ms_ps_status` enum('PURGED','NOT_PURGED') DEFAULT 'PURGED' COMMENT 'Indicates that ESM and EMM status are purged from MME',
|
|
||||||
`rau_tau_timer` int(10) unsigned DEFAULT '120',
|
|
||||||
`ue_ambr_ul` bigint(20) unsigned DEFAULT '50000000' COMMENT 'Subscribed UE AMBR in uplink',
|
|
||||||
`ue_ambr_dl` bigint(20) unsigned DEFAULT '100000000' COMMENT 'Subscribed UE AMBR in downlink',
|
|
||||||
`access_restriction` int(10) unsigned DEFAULT '60' COMMENT '3GPP TS.29272 #7.3.31',
|
|
||||||
`mme_cap` int(10) unsigned zerofill DEFAULT NULL,
|
|
||||||
`mmeidentity_idmmeidentity` int(11) NOT NULL DEFAULT '0',
|
|
||||||
`key` varbinary(16) NOT NULL DEFAULT '0' COMMENT 'UE security key',
|
|
||||||
`RFSP-Index` smallint(5) unsigned NOT NULL DEFAULT '1' COMMENT 'Index to RRM configuration. Possible values from 1 to 256',
|
|
||||||
`urrp_mme` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'UE reachability request requested by HSS',
|
|
||||||
`sqn` int(10) unsigned zerofill NOT NULL,
|
|
||||||
`rand` varbinary(16) NOT NULL,
|
|
||||||
PRIMARY KEY (`imsi`,`mmeidentity_idmmeidentity`),
|
|
||||||
KEY `fk_users_mmeidentity_idx1` (`mmeidentity_idmmeidentity`)
|
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Contenu de la table `users`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `users` (`imsi`, `msisdn`, `imei`, `imei_sv`, `ms_ps_status`, `rau_tau_timer`, `ue_ambr_ul`, `ue_ambr_dl`, `access_restriction`, `mme_cap`, `mmeidentity_idmmeidentity`, `key`, `RFSP-Index`, `urrp_mme`, `sqn`, `rand`) VALUES
|
|
||||||
('20834123456789', '380561234567', '12345678', '23', 'NOT_PURGED', 50, 50000000, 100000000, 47, 0000000000, 36, '+ÖEŸ‚ų\0•,IH�ÿH', 0, 0, 0000000096, 'Px¼X \Z1¡Éx™ß'),
|
|
||||||
('208920000000008', NULL, NULL, NULL, 'PURGED', 120, 50000000, 100000000, 60, 0000000000, 0, '‹¯G?/�Д‡ÌË× |hb', 1, 0, 0000027276, '''©$Ìy2¨dËêmù');
|
|
||||||
|
|
||||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
|
||||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
|
||||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
openair-hss (1.0.0-1) UNRELEASED; urgency=low
|
|
||||||
|
|
||||||
* Initial release. (Closes: #XXXXXX)
|
|
||||||
|
|
||||||
-- Sebastien Roux <roux@nord> Wed, 10 Apr 2013 09:54:55 +0200
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
7
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
Source: openair-hss
|
|
||||||
Maintainer: Sebastien ROUX <sebastien.roux@eurecom.fr>
|
|
||||||
Section: misc
|
|
||||||
Priority: optional
|
|
||||||
Standards-Version: 3.9.2
|
|
||||||
Build-Depends: debhelper (>= 8),
|
|
||||||
make, gcc, bison, flex, autotools,
|
|
||||||
libmysqlclient-dev, libsctp-dev,
|
|
||||||
freediameter-dev, freediameter-dictionary-s6a, freediameter-dictionary-mip6,
|
|
||||||
libgmp-dev, libnettle-dev
|
|
||||||
|
|
||||||
Package: openair-hss
|
|
||||||
Architecture: any
|
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
|
||||||
Description: Implementation of R10 HSS for 3GPP LTE core network
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
etc/openair-hss/
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
openair-hss_1.0.0-1_i386.deb misc optional
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
conf/hss.conf
|
|
||||||
conf/hss_fd.conf
|
|
||||||
db/oai_db.sql
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/usr/bin/make -f
|
|
||||||
|
|
||||||
export DH_OPTIONS
|
|
||||||
|
|
||||||
%:
|
|
||||||
dh $@
|
|
||||||
|
|
||||||
override_dh_auto_configure:
|
|
||||||
dh_auto_configure -- --enable-dh-install LDFLAGS='-L/usr/local/lib'
|
|
||||||
|
|
||||||
# Don't run tests:
|
|
||||||
override_dh_auto_test:
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "db_proto.h"
|
|
||||||
#include "s6a_proto.h"
|
|
||||||
#include "auc.h"
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
hss_config_t hss_config;
|
|
||||||
|
|
||||||
memset(&hss_config, 0, sizeof(hss_config_t));
|
|
||||||
|
|
||||||
if (config_init(argc, argv, &hss_config) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hss_mysql_connect(&hss_config) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
random_init();
|
|
||||||
|
|
||||||
s6a_init(&hss_config);
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
/* TODO: handle signals here */
|
|
||||||
sleep(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
AM_CFLAGS = @ADD_CFLAGS@ \
|
|
||||||
-I$(top_srcdir) \
|
|
||||||
-I$(top_srcdir)/access_restriction \
|
|
||||||
-I$(top_srcdir)/auc \
|
|
||||||
-I$(top_srcdir)/db \
|
|
||||||
-I$(top_srcdir)/utils
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libs6a.la
|
|
||||||
|
|
||||||
libs6a_la_LDFLAGS = -all-static
|
|
||||||
libs6a_la_SOURCES = \
|
|
||||||
s6a_common.c \
|
|
||||||
s6a_fd.c s6a_proto.h \
|
|
||||||
s6a_auth_info.c \
|
|
||||||
s6a_up_loc.c \
|
|
||||||
s6a_purge_ue.c \
|
|
||||||
s6a_error.c \
|
|
||||||
s6a_subscription_data.c \
|
|
||||||
s6a_in_addr.c \
|
|
||||||
s6a_peers.c \
|
|
||||||
s6a_supported_features.h s6a_supported_features.c
|
|
||||||
@@ -1,280 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
/*! \file s6a_auth_info.c
|
|
||||||
* \brief Handle an authentication information request procedure and generate the answer
|
|
||||||
* \author Sebastien ROUX <sebastien.roux@eurecom.fr>
|
|
||||||
* \date 2013
|
|
||||||
* \version 0.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "db_proto.h"
|
|
||||||
#include "s6a_proto.h"
|
|
||||||
#include "auc.h"
|
|
||||||
#include "access_restriction.h"
|
|
||||||
|
|
||||||
int s6a_auth_info_cb(struct msg **msg, struct avp *paramavp,
|
|
||||||
struct session *sess, void *opaque,
|
|
||||||
enum disp_action *act)
|
|
||||||
{
|
|
||||||
struct msg *ans, *qry;
|
|
||||||
struct avp *avp, *failed_avp = NULL;
|
|
||||||
|
|
||||||
struct avp_hdr *hdr;
|
|
||||||
union avp_value value;
|
|
||||||
|
|
||||||
/* Database queries */
|
|
||||||
mysql_auth_info_req_t auth_info_req;
|
|
||||||
mysql_auth_info_resp_t auth_info_resp;
|
|
||||||
|
|
||||||
/* Authentication vector */
|
|
||||||
auc_vector_t vector;
|
|
||||||
|
|
||||||
int ret = 0;
|
|
||||||
int result_code = ER_DIAMETER_SUCCESS;
|
|
||||||
int experimental = 0;
|
|
||||||
uint64_t imsi;
|
|
||||||
uint8_t *sqn = NULL, *auts = NULL;
|
|
||||||
|
|
||||||
if (msg == NULL) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create answer header */
|
|
||||||
qry = *msg;
|
|
||||||
CHECK_FCT(fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0));
|
|
||||||
ans = *msg;
|
|
||||||
|
|
||||||
/* Retrieving IMSI AVP: User-Name */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_imsi, &avp));
|
|
||||||
if (avp) {
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
|
|
||||||
if (hdr->avp_value->os.len > IMSI_LENGTH_MAX) {
|
|
||||||
result_code = ER_DIAMETER_INVALID_AVP_VALUE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
sprintf(auth_info_req.imsi, "%*s", (int)hdr->avp_value->os.len,
|
|
||||||
hdr->avp_value->os.data);
|
|
||||||
sscanf(auth_info_req.imsi, "%"SCNu64, &imsi);
|
|
||||||
} else {
|
|
||||||
result_code = ER_DIAMETER_MISSING_AVP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieving Supported Features AVP. This is an optional AVP. */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_supported_features, &avp));
|
|
||||||
if (avp) {
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieving the Requested-EUTRAN-Authentication-Info.
|
|
||||||
* If this AVP is not present, we have to check for
|
|
||||||
* Requested-GERAN-Authentication-Info AVP which will mean that the request
|
|
||||||
* comes from RAT other than E-UTRAN, case not handled by this HSS
|
|
||||||
* implementation.
|
|
||||||
*/
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_req_e_utran_auth_info, &avp));
|
|
||||||
if (avp) {
|
|
||||||
struct avp *child_avp;
|
|
||||||
|
|
||||||
/* Walk through childs avp */
|
|
||||||
CHECK_FCT(fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &child_avp, NULL));
|
|
||||||
while (child_avp) {
|
|
||||||
/* Retrieve the header of the child avp */
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(child_avp, &hdr));
|
|
||||||
switch(hdr->avp_code) {
|
|
||||||
case AVP_CODE_NUMBER_OF_REQ_VECTORS: {
|
|
||||||
/* We allow only one vector request */
|
|
||||||
if (hdr->avp_value->u32 != 1) {
|
|
||||||
result_code = ER_DIAMETER_INVALID_AVP_VALUE;
|
|
||||||
failed_avp = child_avp;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case AVP_CODE_IMMEDIATE_RESP_PREF:
|
|
||||||
/* We always respond immediately to the request */
|
|
||||||
break;
|
|
||||||
case AVP_CODE_RE_SYNCHRONIZATION_INFO:
|
|
||||||
/* The resynchronization-info AVP is present.
|
|
||||||
* AUTS = Conc(SQN MS ) || MAC-S
|
|
||||||
*/
|
|
||||||
if (avp) {
|
|
||||||
auts = hdr->avp_value->os.data;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default: {
|
|
||||||
/* This AVP is not expected on s6a interface */
|
|
||||||
result_code = ER_DIAMETER_AVP_UNSUPPORTED;
|
|
||||||
failed_avp = child_avp;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Go to next AVP in the grouped AVP */
|
|
||||||
CHECK_FCT(fd_msg_browse(child_avp, MSG_BRW_NEXT, &child_avp, NULL));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_req_geran_auth_info, &avp));
|
|
||||||
if (avp) {
|
|
||||||
result_code = DIAMETER_ERROR_RAT_NOT_ALLOWED;
|
|
||||||
experimental = 1;
|
|
||||||
goto out;
|
|
||||||
} else {
|
|
||||||
result_code = ER_DIAMETER_INVALID_AVP_VALUE;
|
|
||||||
failed_avp = avp;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieving the Visited-PLMN-Id AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_visited_plmn_id, &avp));
|
|
||||||
if (avp) {
|
|
||||||
/* TODO: check PLMN and allow/reject connectivity depending on roaming */
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
|
|
||||||
if (hdr->avp_value->os.len == 3) {
|
|
||||||
if (apply_access_restriction(auth_info_req.imsi, hdr->avp_value->os.data) != 0) {
|
|
||||||
/* We found that user is roaming and has no right to do it ->
|
|
||||||
* reject the connection
|
|
||||||
*/
|
|
||||||
result_code = DIAMETER_ERROR_ROAMING_NOT_ALLOWED;
|
|
||||||
experimental = 1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result_code = ER_DIAMETER_INVALID_AVP_VALUE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Mandatory AVP, raise an error if not present */
|
|
||||||
result_code = ER_DIAMETER_MISSING_AVP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fetch User data */
|
|
||||||
if (hss_mysql_auth_info(&auth_info_req, &auth_info_resp) != 0) {
|
|
||||||
/* Database query failed... */
|
|
||||||
result_code = DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE;
|
|
||||||
experimental = 1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auts != NULL) {
|
|
||||||
/* Try to derive SQN_MS from previous RAND */
|
|
||||||
sqn = sqn_ms_derive(auth_info_resp.key, auts, auth_info_resp.rand);
|
|
||||||
if (sqn != NULL) {
|
|
||||||
/* We succeeded to verify SQN_MS... */
|
|
||||||
|
|
||||||
/* Pick a new RAND and store SQN_MS + RAND in the HSS */
|
|
||||||
generate_random(vector.rand, RAND_LENGTH);
|
|
||||||
hss_mysql_push_rand_sqn(auth_info_req.imsi, auth_info_resp.rand, sqn);
|
|
||||||
|
|
||||||
// hss_mysql_increment_sqn(auth_info_req.imsi);
|
|
||||||
|
|
||||||
free(sqn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fetch new user data */
|
|
||||||
if (hss_mysql_auth_info(&auth_info_req, &auth_info_resp) != 0) {
|
|
||||||
/* Database query failed... */
|
|
||||||
result_code = DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE;
|
|
||||||
experimental = 1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
sqn = auth_info_resp.sqn;
|
|
||||||
|
|
||||||
memcpy(vector.rand, auth_info_resp.rand, RAND_LENGTH);
|
|
||||||
} else {
|
|
||||||
/* Pick a new RAND and store SQN_MS + RAND in the HSS */
|
|
||||||
generate_random(vector.rand, RAND_LENGTH);
|
|
||||||
sqn = auth_info_resp.sqn;
|
|
||||||
hss_mysql_push_rand_sqn(auth_info_req.imsi, vector.rand, sqn);
|
|
||||||
}
|
|
||||||
|
|
||||||
hss_mysql_increment_sqn(auth_info_req.imsi);
|
|
||||||
|
|
||||||
/* Generate authentication vector */
|
|
||||||
generate_vector(imsi, auth_info_resp.key,
|
|
||||||
hdr->avp_value->os.data, sqn, &vector);
|
|
||||||
|
|
||||||
/* We add the vector */
|
|
||||||
{
|
|
||||||
struct avp *e_utran_vector, *child_avp;
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_authentication_info, 0, &avp));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_e_utran_vector, 0, &e_utran_vector));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_rand, 0, &child_avp));
|
|
||||||
value.os.data = vector.rand;
|
|
||||||
value.os.len = RAND_LENGTH_OCTETS;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(e_utran_vector, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_xres, 0, &child_avp));
|
|
||||||
value.os.data = vector.xres;
|
|
||||||
value.os.len = XRES_LENGTH_OCTETS;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(e_utran_vector, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_autn, 0, &child_avp));
|
|
||||||
value.os.data = vector.autn;
|
|
||||||
value.os.len = AUTN_LENGTH_OCTETS;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(e_utran_vector, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_kasme, 0, &child_avp));
|
|
||||||
value.os.data = vector.kasme;
|
|
||||||
value.os.len = KASME_LENGTH_OCTETS;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(e_utran_vector, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, e_utran_vector));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp));
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
/* Add the Auth-Session-State AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_auth_session_state, &avp));
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_auth_session_state, 0, &avp));
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(avp, hdr->avp_value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp));
|
|
||||||
|
|
||||||
/* Append the result code to the answer */
|
|
||||||
CHECK_FCT(s6a_add_result_code(ans, failed_avp, result_code, experimental));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_send(msg, NULL, NULL ));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "db_proto.h"
|
|
||||||
#include "s6a_proto.h"
|
|
||||||
|
|
||||||
int s6a_add_result_code(struct msg *ans, struct avp *failed_avp, int result_code, int experimental)
|
|
||||||
{
|
|
||||||
struct avp *avp;
|
|
||||||
union avp_value value;
|
|
||||||
|
|
||||||
if (DIAMETER_ERROR_IS_VENDOR(result_code) && experimental != 0) {
|
|
||||||
struct avp *experimental_result;
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_experimental_result,
|
|
||||||
0, &experimental_result));
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_vendor_id,
|
|
||||||
0, &avp));
|
|
||||||
value.u32 = VENDOR_3GPP;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(experimental_result, MSG_BRW_LAST_CHILD, avp));
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_experimental_result_code,
|
|
||||||
0, &avp));
|
|
||||||
value.u32 = result_code;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(experimental_result, MSG_BRW_LAST_CHILD, avp));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, experimental_result));
|
|
||||||
|
|
||||||
/* Add Origin_Host & Origin_Realm AVPs */
|
|
||||||
CHECK_FCT(fd_msg_add_origin(ans, 0));
|
|
||||||
} else {
|
|
||||||
/* This is a code defined in the base protocol: result-code AVP should
|
|
||||||
* be used.
|
|
||||||
*/
|
|
||||||
CHECK_FCT(fd_msg_rescode_set(ans, retcode_2_string(result_code), NULL,
|
|
||||||
failed_avp, 1));
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "db_proto.h"
|
|
||||||
#include "s6a_proto.h"
|
|
||||||
|
|
||||||
inline char *experimental_retcode_2_string(int ret_code)
|
|
||||||
{
|
|
||||||
switch(ret_code) {
|
|
||||||
/* Experimental-Result-Codes */
|
|
||||||
case DIAMETER_ERROR_USER_UNKNOWN:
|
|
||||||
return "DIAMETER_ERROR_USER_UNKNOWN";
|
|
||||||
case DIAMETER_ERROR_ROAMING_NOT_ALLOWED:
|
|
||||||
return "DIAMETER_ERROR_ROAMING_NOT_ALLOWED";
|
|
||||||
case DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION:
|
|
||||||
return "DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION";
|
|
||||||
case DIAMETER_ERROR_RAT_NOT_ALLOWED:
|
|
||||||
return "DIAMETER_ERROR_RAT_NOT_ALLOWED";
|
|
||||||
case DIAMETER_ERROR_EQUIPMENT_UNKNOWN:
|
|
||||||
return "DIAMETER_ERROR_EQUIPMENT_UNKNOWN";
|
|
||||||
case DIAMETER_ERROR_UNKOWN_SERVING_NODE:
|
|
||||||
return "DIAMETER_ERROR_UNKOWN_SERVING_NODE";
|
|
||||||
case DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE:
|
|
||||||
return "DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE";
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return "DIAMETER_AVP_UNSUPPORTED";
|
|
||||||
}
|
|
||||||
|
|
||||||
inline char *retcode_2_string(int ret_code)
|
|
||||||
{
|
|
||||||
switch(ret_code) {
|
|
||||||
case ER_DIAMETER_SUCCESS:
|
|
||||||
return "DIAMETER_SUCCESS";
|
|
||||||
case ER_DIAMETER_MISSING_AVP:
|
|
||||||
return "DIAMETER_MISSING_AVP";
|
|
||||||
case ER_DIAMETER_INVALID_AVP_VALUE:
|
|
||||||
return "DIAMETER_INVALID_AVP_VALUE";
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return "DIAMETER_AVP_UNSUPPORTED";
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,350 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
#if HAVE_CONFIG_H
|
|
||||||
# include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <freeDiameter/freeDiameter-host.h>
|
|
||||||
#include <freeDiameter/libfdcore.h>
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "db_proto.h"
|
|
||||||
#include "s6a_proto.h"
|
|
||||||
|
|
||||||
/* session handler for s6a sessions state machine */
|
|
||||||
static struct session_handler *s6a_reg = NULL;
|
|
||||||
|
|
||||||
/* handler for s6a server callback */
|
|
||||||
static struct disp_hdl *handle;
|
|
||||||
s6a_cnf_t s6a_cnf;
|
|
||||||
|
|
||||||
void s6a_cli_sess_cleanup(void * arg, char * sid, void * opaque);
|
|
||||||
|
|
||||||
void s6a_cli_sess_cleanup(void * arg, char * sid, void * opaque)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int s6a_init_objs(void)
|
|
||||||
{
|
|
||||||
vendor_id_t vendor_3gpp = VENDOR_3GPP;
|
|
||||||
application_id_t app_s6a = APP_S6A;
|
|
||||||
|
|
||||||
memset(&s6a_cnf, 0, sizeof(s6a_cnf));
|
|
||||||
|
|
||||||
/* Pre-loading vendor object */
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_ID,
|
|
||||||
(void*)&vendor_3gpp, &s6a_cnf.dataobj_s6a_vendor, ENOENT));
|
|
||||||
/* Pre-loading application object */
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_APPLICATION,
|
|
||||||
APPLICATION_BY_ID, (void*)&app_s6a,
|
|
||||||
&s6a_cnf.dataobj_s6a_app, ENOENT));
|
|
||||||
|
|
||||||
/* Pre-loading commands objects */
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_COMMAND,
|
|
||||||
CMD_BY_NAME, "Authentication-Information-Request",
|
|
||||||
&s6a_cnf.dataobj_s6a_auth_cmd, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_COMMAND,
|
|
||||||
CMD_BY_NAME, "Update-Location-Request",
|
|
||||||
&s6a_cnf.dataobj_s6a_loc_up, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_COMMAND,
|
|
||||||
CMD_BY_NAME, "Purge-UE-Request",
|
|
||||||
&s6a_cnf.dataobj_s6a_purge_ue, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_COMMAND,
|
|
||||||
CMD_BY_NAME, "Cancel-Location-Request",
|
|
||||||
&s6a_cnf.dataobj_s6a_cancel_loc_req, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_COMMAND,
|
|
||||||
CMD_BY_NAME, "Cancel-Location-Answer",
|
|
||||||
&s6a_cnf.dataobj_s6a_cancel_loc_ans, ENOENT));
|
|
||||||
|
|
||||||
/* Pre-loading AVPs objects */
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME, "Origin-Host",
|
|
||||||
&s6a_cnf.dataobj_s6a_origin_host, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME, "Origin-Realm",
|
|
||||||
&s6a_cnf.dataobj_s6a_origin_realm, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "User-Name",
|
|
||||||
&s6a_cnf.dataobj_s6a_imsi, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "IMEI",
|
|
||||||
&s6a_cnf.dataobj_s6a_imei, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Software-Version",
|
|
||||||
&s6a_cnf.dataobj_s6a_software_version, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Supported-Features",
|
|
||||||
&s6a_cnf.dataobj_s6a_supported_features, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Requested-EUTRAN-Authentication-Info",
|
|
||||||
&s6a_cnf.dataobj_s6a_req_e_utran_auth_info, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Number-Of-Requested-Vectors",
|
|
||||||
&s6a_cnf.dataobj_s6a_req_nb_of_req_vectors, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Re-Synchronization-Info",
|
|
||||||
&s6a_cnf.dataobj_s6a_req_resync_info, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Requested-UTRAN-GERAN-Authentication-Info",
|
|
||||||
&s6a_cnf.dataobj_s6a_req_geran_auth_info, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Immediate-Response-Preferred",
|
|
||||||
&s6a_cnf.dataobj_s6a_immediate_response_pref, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Visited-PLMN-Id",
|
|
||||||
&s6a_cnf.dataobj_s6a_visited_plmn_id, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME, "Result-Code",
|
|
||||||
&s6a_cnf.dataobj_s6a_result_code, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME, "Experimental-Result",
|
|
||||||
&s6a_cnf.dataobj_s6a_experimental_result, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME, "Vendor-Id",
|
|
||||||
&s6a_cnf.dataobj_s6a_vendor_id, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME, "Experimental-Result-Code",
|
|
||||||
&s6a_cnf.dataobj_s6a_experimental_result_code, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Auth-Session-State",
|
|
||||||
&s6a_cnf.dataobj_s6a_auth_session_state, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Authentication-Info",
|
|
||||||
&s6a_cnf.dataobj_s6a_authentication_info, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "E-UTRAN-Vector",
|
|
||||||
&s6a_cnf.dataobj_s6a_e_utran_vector, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "RAND",
|
|
||||||
&s6a_cnf.dataobj_s6a_rand, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "XRES",
|
|
||||||
&s6a_cnf.dataobj_s6a_xres, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "AUTN",
|
|
||||||
&s6a_cnf.dataobj_s6a_autn, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "KASME",
|
|
||||||
&s6a_cnf.dataobj_s6a_kasme, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "ULR-Flags",
|
|
||||||
&s6a_cnf.dataobj_s6a_ulr_flags, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "ULA-Flags",
|
|
||||||
&s6a_cnf.dataobj_s6a_ula_flags, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "PUR-Flags",
|
|
||||||
&s6a_cnf.dataobj_s6a_pur_flags, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "PUA-Flags",
|
|
||||||
&s6a_cnf.dataobj_s6a_pua_flags, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "RAT-Type",
|
|
||||||
&s6a_cnf.dataobj_s6a_rat_type, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Terminal-Information",
|
|
||||||
&s6a_cnf.dataobj_s6a_terminal_info, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "UE-SRVCC-Capability",
|
|
||||||
&s6a_cnf.dataobj_s6a_ue_srvcc_cap, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "GMLC-Address",
|
|
||||||
&s6a_cnf.dataobj_s6a_gmlc_addr, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Subscription-Data",
|
|
||||||
&s6a_cnf.dataobj_s6a_subscription_data, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Subscriber-Status",
|
|
||||||
&s6a_cnf.dataobj_s6a_subscriber_status, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "MSISDN",
|
|
||||||
&s6a_cnf.dataobj_s6a_msisdn, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "AMBR",
|
|
||||||
&s6a_cnf.dataobj_s6a_ambr, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Network-Access-Mode",
|
|
||||||
&s6a_cnf.dataobj_s6a_network_access_mode, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Access-Restriction-Data",
|
|
||||||
&s6a_cnf.dataobj_s6a_access_restriction_data, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "APN-Configuration-Profile",
|
|
||||||
&s6a_cnf.dataobj_s6a_apn_configuration_profile, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Subscribed-Periodic-RAU-TAU-Timer",
|
|
||||||
&s6a_cnf.dataobj_s6a_subscribed_rau_tau_timer, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Context-Identifier",
|
|
||||||
&s6a_cnf.dataobj_s6a_context_identifier, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "All-APN-Configurations-Included-Indicator",
|
|
||||||
&s6a_cnf.dataobj_s6a_all_apn_conf_inc_ind, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "APN-Configuration",
|
|
||||||
&s6a_cnf.dataobj_s6a_apn_configuration, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Max-Requested-Bandwidth-UL",
|
|
||||||
&s6a_cnf.dataobj_s6a_max_bandwidth_ul, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Max-Requested-Bandwidth-DL",
|
|
||||||
&s6a_cnf.dataobj_s6a_max_bandwidth_dl, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "PDN-Type",
|
|
||||||
&s6a_cnf.dataobj_s6a_pdn_type, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Service-Selection",
|
|
||||||
&s6a_cnf.dataobj_s6a_service_selection, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "EPS-Subscribed-QoS-Profile",
|
|
||||||
&s6a_cnf.dataobj_s6a_eps_subscribed_qos_profile, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "QoS-Class-Identifier",
|
|
||||||
&s6a_cnf.dataobj_s6a_qos_class_identifier, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Allocation-Retention-Priority",
|
|
||||||
&s6a_cnf.dataobj_s6a_allocation_retention_priority, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Priority-Level",
|
|
||||||
&s6a_cnf.dataobj_s6a_priority_level, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Pre-emption-Capability",
|
|
||||||
&s6a_cnf.dataobj_s6a_pre_emption_capability, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Pre-emption-Vulnerability",
|
|
||||||
&s6a_cnf.dataobj_s6a_pre_emption_vulnerability, ENOENT));
|
|
||||||
CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP,
|
|
||||||
AVP_BY_NAME_ALL_VENDORS, "Served-Party-IP-Address",
|
|
||||||
&s6a_cnf.dataobj_s6a_served_party_ip_addr, ENOENT));
|
|
||||||
|
|
||||||
/* Advertise the support for the test application in the peer */
|
|
||||||
CHECK_FCT(fd_disp_app_support(s6a_cnf.dataobj_s6a_app,
|
|
||||||
s6a_cnf.dataobj_s6a_vendor, 1, 0));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int s6a_init(hss_config_t *hss_config_p)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
struct disp_when when;
|
|
||||||
char why[100];
|
|
||||||
|
|
||||||
fprintf(stdout, "Initializing s6a layer\n");
|
|
||||||
|
|
||||||
ret = fd_core_initialize();
|
|
||||||
if (ret != 0) {
|
|
||||||
strcpy(why, "fd_core_initialize");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = fd_core_start();
|
|
||||||
if (ret != 0) {
|
|
||||||
strcpy(why, "fd_core_start");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse the external configuration file */
|
|
||||||
ret = fd_core_parseconf(hss_config_p->freediameter_config);
|
|
||||||
if (ret != 0) {
|
|
||||||
strcpy(why, "fd_core_parseconf");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We wait till freediameter has completed loading extensions */
|
|
||||||
fd_core_waitstartcomplete();
|
|
||||||
|
|
||||||
/* Register the peer acceptor/rejector */
|
|
||||||
fd_peer_validate_register(s6a_peer_validate);
|
|
||||||
|
|
||||||
/* Initialize useful objects */
|
|
||||||
ret = s6a_init_objs();
|
|
||||||
if (ret != 0) {
|
|
||||||
strcpy(why, "s6a_init_objs");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create handler for sessions */
|
|
||||||
CHECK_FCT(fd_sess_handler_create(&s6a_reg, s6a_cli_sess_cleanup, NULL));
|
|
||||||
|
|
||||||
/* Register the callback */
|
|
||||||
memset(&when, 0, sizeof(when));
|
|
||||||
when.command = s6a_cnf.dataobj_s6a_auth_cmd;
|
|
||||||
when.app = s6a_cnf.dataobj_s6a_app;
|
|
||||||
|
|
||||||
/* Register the callbacks for S6A Application */
|
|
||||||
CHECK_FCT(fd_disp_register(s6a_auth_info_cb, DISP_HOW_CC, &when, NULL,
|
|
||||||
&handle));
|
|
||||||
|
|
||||||
if (handle == NULL) {
|
|
||||||
strcpy(why, "cannot register authentication info req cb");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
when.command = s6a_cnf.dataobj_s6a_loc_up;
|
|
||||||
when.app = s6a_cnf.dataobj_s6a_app;
|
|
||||||
|
|
||||||
/* Register the callbacks for S6A Application */
|
|
||||||
CHECK_FCT(fd_disp_register(s6a_up_loc_cb, DISP_HOW_CC, &when, NULL,
|
|
||||||
&handle));
|
|
||||||
|
|
||||||
if (handle == NULL) {
|
|
||||||
strcpy(why, "cannot register update location req cb");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
when.command = s6a_cnf.dataobj_s6a_purge_ue;
|
|
||||||
when.app = s6a_cnf.dataobj_s6a_app;
|
|
||||||
|
|
||||||
/* Register the callbacks for S6A Application */
|
|
||||||
CHECK_FCT(fd_disp_register(s6a_purge_ue_cb, DISP_HOW_CC, &when, NULL,
|
|
||||||
&handle));
|
|
||||||
|
|
||||||
if (handle == NULL) {
|
|
||||||
strcpy(why, "cannot register purge ue req cb");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stdout, "Initializing s6a layer: DONE\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err:
|
|
||||||
fprintf(stdout, "Initializing s6a layer: FAILED (%s)\n", why);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "db_proto.h"
|
|
||||||
#include "s6a_proto.h"
|
|
||||||
|
|
||||||
/* http://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml*/
|
|
||||||
|
|
||||||
/* Perform a conversion between ipv4 in BCD to AVP served-party-ip-address */
|
|
||||||
int s6a_add_ipv4_address(struct avp *avp, const char *ipv4_addr)
|
|
||||||
{
|
|
||||||
struct avp *child_avp;
|
|
||||||
union avp_value value;
|
|
||||||
|
|
||||||
uint8_t ipv4[6]; /* Converted IPv4 address with family */
|
|
||||||
in_addr_t sin;
|
|
||||||
|
|
||||||
if (ipv4_addr == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is an IPv4 family -> ipv4 buffer should start with 0x0001 */
|
|
||||||
ipv4[0] = 0x00;
|
|
||||||
ipv4[1] = 0x01;
|
|
||||||
|
|
||||||
sin = inet_addr(ipv4_addr);
|
|
||||||
/* No need to add the address if it is an any address */
|
|
||||||
if (sin != INADDR_ANY) {
|
|
||||||
memcpy(&ipv4[2], &sin, 4);
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_served_party_ip_addr, 0, &child_avp));
|
|
||||||
value.os.data = ipv4;
|
|
||||||
value.os.len = 6;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* No IP address added to AVP */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Perform a conversion between ipv6 in BCD to AVP served-party-ip-address */
|
|
||||||
int s6a_add_ipv6_address(struct avp *avp, const char *ipv6_addr)
|
|
||||||
{
|
|
||||||
struct avp *child_avp;
|
|
||||||
union avp_value value;
|
|
||||||
|
|
||||||
uint8_t ipv6[18];
|
|
||||||
struct in6_addr sin6;
|
|
||||||
|
|
||||||
if (ipv6_addr == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&sin6, 0, sizeof(struct in6_addr));
|
|
||||||
|
|
||||||
/* This is an IPv6 family -> ipv6 buffer should start with 0x0002 */
|
|
||||||
ipv6[0] = 0x00;
|
|
||||||
ipv6[1] = 0x02;
|
|
||||||
|
|
||||||
if (inet_pton(AF_INET6, ipv6_addr, &sin6) == -1) {
|
|
||||||
fprintf(stderr, "INET6 address conversion has failed\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the IPV6 address is 0:0:0:0:0:0:0:0 then we don't add it to the
|
|
||||||
* served-party ip address and consider the ip address can be dynamically
|
|
||||||
* allocated.
|
|
||||||
*/
|
|
||||||
if (!IN6_IS_ADDR_UNSPECIFIED(sin6.s6_addr32)) {
|
|
||||||
memcpy(&ipv6[2], &sin6.s6_addr, 16);
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_served_party_ip_addr, 0, &child_avp));
|
|
||||||
value.os.data = ipv6;
|
|
||||||
value.os.len = 18;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
/*! \file s6a_peers.c
|
|
||||||
* \brief Authenticate a new peer connecting to the HSS by checking the database
|
|
||||||
* \author Sebastien ROUX <sebastien.roux@eurecom.fr>
|
|
||||||
* \date 2013
|
|
||||||
* \version 0.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "db_proto.h"
|
|
||||||
#include "s6a_proto.h"
|
|
||||||
|
|
||||||
int s6a_peer_validate(struct peer_info *info, int *auth, int (**cb2)(struct peer_info *))
|
|
||||||
{
|
|
||||||
mysql_mme_identity_t mme_identity;
|
|
||||||
|
|
||||||
if (info == NULL) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&mme_identity, 0, sizeof(mysql_mme_identity_t));
|
|
||||||
|
|
||||||
/* We received a new connection. Check the database for allowed equipments
|
|
||||||
* on EPC
|
|
||||||
*/
|
|
||||||
|
|
||||||
memcpy(mme_identity.mme_host, info->pi_diamid, info->pi_diamidlen);
|
|
||||||
|
|
||||||
if (hss_mysql_check_epc_equipment(&mme_identity) != 0) {
|
|
||||||
/* The MME has not been found in list of known peers -> reject it */
|
|
||||||
*auth = -1;
|
|
||||||
fprintf(stdout, "Rejecting %s: either db has no knowledge of this peer "
|
|
||||||
"or sql query failed\n", info->pi_diamid);
|
|
||||||
} else {
|
|
||||||
*auth = 1;
|
|
||||||
|
|
||||||
/* For now we don't use security */
|
|
||||||
info->config.pic_flags.sec = PI_SEC_NONE;
|
|
||||||
info->config.pic_flags.persist = PI_PRST_NONE;
|
|
||||||
fprintf(stdout, "Accepting %s peer\n", info->pi_diamid);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#include <freeDiameter/freeDiameter-host.h>
|
|
||||||
#include <freeDiameter/libfdcore.h>
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
|
|
||||||
#ifndef S6A_PROTO_H_
|
|
||||||
#define S6A_PROTO_H_
|
|
||||||
|
|
||||||
#define VENDOR_3GPP (10415)
|
|
||||||
#define APP_S6A (16777251)
|
|
||||||
|
|
||||||
/* Errors that fall within the Permanent Failures category shall be used to
|
|
||||||
* inform the peer that the request has failed, and should not be attempted
|
|
||||||
* again. The Result-Code AVP values defined in Diameter Base Protocol RFC 3588
|
|
||||||
* shall be applied. When one of the result codes defined here is included in a
|
|
||||||
* response, it shall be inside an Experimental-Result AVP and the Result-Code
|
|
||||||
* AVP shall be absent.
|
|
||||||
*/
|
|
||||||
#define DIAMETER_ERROR_USER_UNKNOWN (5001)
|
|
||||||
#define DIAMETER_ERROR_ROAMING_NOT_ALLOWED (5004)
|
|
||||||
#define DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION (5420)
|
|
||||||
#define DIAMETER_ERROR_RAT_NOT_ALLOWED (5421)
|
|
||||||
#define DIAMETER_ERROR_EQUIPMENT_UNKNOWN (5422)
|
|
||||||
#define DIAMETER_ERROR_UNKOWN_SERVING_NODE (5423)
|
|
||||||
|
|
||||||
/* Result codes that fall within the transient failures category shall be used
|
|
||||||
* to inform a peer that the request could not be satisfied at the time it was
|
|
||||||
* received, but may be able to satisfy the request in the future. The
|
|
||||||
* Result-Code AVP values defined in Diameter Base Protocol RFC 3588 shall be
|
|
||||||
* applied. When one of the result codes defined here is included in a response,
|
|
||||||
* it shall be inside an Experimental-Result AVP and the Result-Code AVP shall
|
|
||||||
* be absent.
|
|
||||||
*/
|
|
||||||
#define DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE (4181)
|
|
||||||
|
|
||||||
#define DIAMETER_ERROR_IS_VENDOR(x) \
|
|
||||||
((x == DIAMETER_ERROR_USER_UNKNOWN) || \
|
|
||||||
(x == DIAMETER_ERROR_ROAMING_NOT_ALLOWED) || \
|
|
||||||
(x == DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION) || \
|
|
||||||
(x == DIAMETER_ERROR_RAT_NOT_ALLOWED) || \
|
|
||||||
(x == DIAMETER_ERROR_EQUIPMENT_UNKNOWN) || \
|
|
||||||
(x == DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE) || \
|
|
||||||
(x == DIAMETER_ERROR_UNKOWN_SERVING_NODE))
|
|
||||||
|
|
||||||
#define AVP_CODE_IMEI (1402)
|
|
||||||
#define AVP_CODE_SOFTWARE_VERSION (1403)
|
|
||||||
#define AVP_CODE_NUMBER_OF_REQ_VECTORS (1410)
|
|
||||||
#define AVP_CODE_RE_SYNCHRONIZATION_INFO (1411)
|
|
||||||
#define AVP_CODE_IMMEDIATE_RESP_PREF (1412)
|
|
||||||
#define AVP_CODE_3GPP2_MEID (1471)
|
|
||||||
#define AVP_CODE_FEATURE_LIST (629)
|
|
||||||
#define AVP_CODE_VENDOR_ID (266)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
struct dict_object *dataobj_s6a_vendor; /* s6a vendor object */
|
|
||||||
struct dict_object *dataobj_s6a_app; /* s6a application object */
|
|
||||||
/* Commands */
|
|
||||||
struct dict_object *dataobj_s6a_auth_cmd; /* s6a authentication command */
|
|
||||||
struct dict_object *dataobj_s6a_loc_up; /* s6a update location */
|
|
||||||
struct dict_object *dataobj_s6a_purge_ue; /* s6a purge ue req */
|
|
||||||
struct dict_object *dataobj_s6a_cancel_loc_req; /* s6a Cancel Location req */
|
|
||||||
struct dict_object *dataobj_s6a_cancel_loc_ans; /* s6a Cancel Location ans */
|
|
||||||
/* AVPs */
|
|
||||||
struct dict_object *dataobj_s6a_origin_host;
|
|
||||||
struct dict_object *dataobj_s6a_origin_realm;
|
|
||||||
struct dict_object *dataobj_s6a_imsi; /* s6a imsi avp */
|
|
||||||
struct dict_object *dataobj_s6a_imei;
|
|
||||||
struct dict_object *dataobj_s6a_software_version;
|
|
||||||
struct dict_object *dataobj_s6a_supported_features;
|
|
||||||
struct dict_object *dataobj_s6a_req_e_utran_auth_info;
|
|
||||||
struct dict_object *dataobj_s6a_req_resync_info;
|
|
||||||
struct dict_object *dataobj_s6a_req_nb_of_req_vectors;
|
|
||||||
struct dict_object *dataobj_s6a_req_geran_auth_info;
|
|
||||||
struct dict_object *dataobj_s6a_immediate_response_pref;
|
|
||||||
struct dict_object *dataobj_s6a_visited_plmn_id;
|
|
||||||
struct dict_object *dataobj_s6a_result_code;
|
|
||||||
struct dict_object *dataobj_s6a_experimental_result;
|
|
||||||
struct dict_object *dataobj_s6a_vendor_id;
|
|
||||||
struct dict_object *dataobj_s6a_experimental_result_code;
|
|
||||||
struct dict_object *dataobj_s6a_auth_session_state;
|
|
||||||
struct dict_object *dataobj_s6a_authentication_info;
|
|
||||||
struct dict_object *dataobj_s6a_e_utran_vector;
|
|
||||||
struct dict_object *dataobj_s6a_rand;
|
|
||||||
struct dict_object *dataobj_s6a_xres;
|
|
||||||
struct dict_object *dataobj_s6a_autn;
|
|
||||||
struct dict_object *dataobj_s6a_kasme;
|
|
||||||
struct dict_object *dataobj_s6a_ulr_flags;
|
|
||||||
struct dict_object *dataobj_s6a_ula_flags;
|
|
||||||
struct dict_object *dataobj_s6a_pur_flags;
|
|
||||||
struct dict_object *dataobj_s6a_pua_flags;
|
|
||||||
struct dict_object *dataobj_s6a_rat_type;
|
|
||||||
struct dict_object *dataobj_s6a_terminal_info;
|
|
||||||
struct dict_object *dataobj_s6a_ue_srvcc_cap;
|
|
||||||
struct dict_object *dataobj_s6a_gmlc_addr;
|
|
||||||
struct dict_object *dataobj_s6a_subscription_data;
|
|
||||||
struct dict_object *dataobj_s6a_subscriber_status;
|
|
||||||
struct dict_object *dataobj_s6a_msisdn;
|
|
||||||
struct dict_object *dataobj_s6a_ambr;
|
|
||||||
struct dict_object *dataobj_s6a_network_access_mode;
|
|
||||||
struct dict_object *dataobj_s6a_access_restriction_data;
|
|
||||||
struct dict_object *dataobj_s6a_apn_configuration_profile;
|
|
||||||
struct dict_object *dataobj_s6a_subscribed_rau_tau_timer;
|
|
||||||
struct dict_object *dataobj_s6a_context_identifier;
|
|
||||||
/* All-APN-Configurations-Included-Indicator */
|
|
||||||
struct dict_object *dataobj_s6a_all_apn_conf_inc_ind;
|
|
||||||
struct dict_object *dataobj_s6a_apn_configuration;
|
|
||||||
/* Max-Requested-Bandwidth-UL */
|
|
||||||
struct dict_object *dataobj_s6a_max_bandwidth_ul;
|
|
||||||
/* Max-Requested-Bandwidth-DL */
|
|
||||||
struct dict_object *dataobj_s6a_max_bandwidth_dl;
|
|
||||||
struct dict_object *dataobj_s6a_pdn_type;
|
|
||||||
struct dict_object *dataobj_s6a_service_selection;
|
|
||||||
struct dict_object *dataobj_s6a_eps_subscribed_qos_profile;
|
|
||||||
struct dict_object *dataobj_s6a_qos_class_identifier;
|
|
||||||
struct dict_object *dataobj_s6a_allocation_retention_priority;
|
|
||||||
struct dict_object *dataobj_s6a_priority_level;
|
|
||||||
struct dict_object *dataobj_s6a_pre_emption_capability;
|
|
||||||
struct dict_object *dataobj_s6a_pre_emption_vulnerability;
|
|
||||||
struct dict_object *dataobj_s6a_served_party_ip_addr;
|
|
||||||
} s6a_cnf_t;
|
|
||||||
|
|
||||||
/* External definition of the S6A decriptor */
|
|
||||||
extern s6a_cnf_t s6a_cnf;
|
|
||||||
|
|
||||||
/* Length of IMSI should not exceed 15 digits */
|
|
||||||
#define IMSI_LENGTH (15)
|
|
||||||
#define IMEI_LENGTH (15)
|
|
||||||
#define SV_LENGTH (2)
|
|
||||||
|
|
||||||
/* ULR-Flags meaning: */
|
|
||||||
#define ULR_SINGLE_REGISTRATION_IND (1U)
|
|
||||||
#define ULR_S6A_S6D_INDICATOR (1U << 1)
|
|
||||||
#define ULR_SKIP_SUBSCRIBER_DATA (1U << 2)
|
|
||||||
#define ULR_GPRS_SUBSCRIPTION_DATA_IND (1U << 3)
|
|
||||||
#define ULR_NODE_TYPE_IND (1U << 4)
|
|
||||||
#define ULR_INITIAL_ATTACH_IND (1U << 5)
|
|
||||||
#define ULR_PS_LCS_SUPPORTED_BY_UE (1U << 6)
|
|
||||||
#define ULR_PAD_VALID(x) ((x & ~0x7f) == 0)
|
|
||||||
|
|
||||||
/* ULA-Flags */
|
|
||||||
#define ULA_SEPARATION_IND (1U)
|
|
||||||
|
|
||||||
/* PUR-Flags */
|
|
||||||
#define PUR_UE_PURGED_IN_MME (1U)
|
|
||||||
#define PUR_UE_PURGED_IN_SGSN (1U << 1)
|
|
||||||
#define PUR_PAD_VALID(x) ((x & ~0x3) == 0)
|
|
||||||
|
|
||||||
/* PUA-FLAGS */
|
|
||||||
#define PUA_FREEZE_M_TMSI (1U)
|
|
||||||
#define PUA_FREEZE_P_TMSI (1U << 1)
|
|
||||||
|
|
||||||
/* Access-restriction-data bits */
|
|
||||||
#define UTRAN_NOT_ALLOWED (1U)
|
|
||||||
#define GERAN_NOT_ALLOWED (1U << 1)
|
|
||||||
#define GAN_NOT_ALLOWED (1U << 2)
|
|
||||||
#define I_HSDPA_EVO_NOT_ALLOWED (1U << 3)
|
|
||||||
#define E_UTRAN_NOT_ALLOWED (1U << 4)
|
|
||||||
#define HO_TO_NON_3GPP_NOT_ALLOWED (1U << 5)
|
|
||||||
#define ARD_CHECK_PAD(x) ((x & ~0x3f) == 0)
|
|
||||||
|
|
||||||
#define FLAG_IS_SET(x, flag) ((x) & (flag))
|
|
||||||
|
|
||||||
#define FLAGS_SET(x, flags) ((x) |= (flags))
|
|
||||||
|
|
||||||
#define FLAGS_CLEAR(x, flags) ((x) = (x) & ~(flags))
|
|
||||||
|
|
||||||
/** \brief Initialize the s6a layer using freeDiameter
|
|
||||||
* \param hss_config_p pointer the global HSS configuration
|
|
||||||
* @returns 0 if the init was successfull, != 0 in case of failure
|
|
||||||
*/
|
|
||||||
int s6a_init(hss_config_t *hss_config_p);
|
|
||||||
|
|
||||||
/** \brief Callback function for new equipements connections to the HSS. See
|
|
||||||
* libfdproto from freeDiameter for more informations on the peer validate
|
|
||||||
* callback
|
|
||||||
* \param info Peer freeDiameter info
|
|
||||||
* \param auth Result of the peer authentication, possible values:
|
|
||||||
* * 1 = accept
|
|
||||||
* * 0 = unknown
|
|
||||||
* * -1 = reject
|
|
||||||
* \param cb2 possible second callback to validate the TLS authentication
|
|
||||||
* @return 0 if the init was successfull, != 0 in case of failure
|
|
||||||
*/
|
|
||||||
int s6a_peer_validate(struct peer_info *info, int *auth, int (**cb2)(struct peer_info *));
|
|
||||||
|
|
||||||
/* Callback called when corresponding request/answer is received */
|
|
||||||
int s6a_auth_info_cb(struct msg **msg, struct avp *paramavp,
|
|
||||||
struct session *sess, void *opaque,
|
|
||||||
enum disp_action *act);
|
|
||||||
|
|
||||||
int s6a_up_loc_cb(struct msg **msg, struct avp *paramavp,
|
|
||||||
struct session *sess, void *opaque,
|
|
||||||
enum disp_action *act);
|
|
||||||
|
|
||||||
int s6a_purge_ue_cb(struct msg **msg, struct avp *paramavp,
|
|
||||||
struct session *sess, void *opaque,
|
|
||||||
enum disp_action *act);
|
|
||||||
|
|
||||||
int s6a_add_subscription_data_avp(struct msg *message, mysql_ul_ans_t *msql_ans);
|
|
||||||
|
|
||||||
int s6a_add_result_code(struct msg *ans, struct avp *failed_avp,
|
|
||||||
int result_code, int experimental);
|
|
||||||
|
|
||||||
int s6a_add_ipv4_address(struct avp *avp, const char *ipv4_addr);
|
|
||||||
int s6a_add_ipv6_address(struct avp *avp, const char *ipv6_addr);
|
|
||||||
inline char *experimental_retcode_2_string(int ret_code);
|
|
||||||
inline char *retcode_2_string(int ret_code);
|
|
||||||
|
|
||||||
#endif /* S6A_PROTO_H_ */
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
/*! \file s6a_purge_ue.c
|
|
||||||
* \brief Handle a purge UE request and generate the corresponding answer
|
|
||||||
* \author Sebastien ROUX <sebastien.roux@eurecom.fr>
|
|
||||||
* \date 2013
|
|
||||||
* \version 0.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "db_proto.h"
|
|
||||||
#include "s6a_proto.h"
|
|
||||||
|
|
||||||
int s6a_purge_ue_cb(struct msg **msg, struct avp *paramavp,
|
|
||||||
struct session *sess, void *opaque,
|
|
||||||
enum disp_action *act)
|
|
||||||
{
|
|
||||||
struct msg *ans, *qry;
|
|
||||||
struct avp *avp, *failed_avp = NULL;
|
|
||||||
struct avp_hdr *hdr;
|
|
||||||
|
|
||||||
int ret = 0;
|
|
||||||
int result_code = ER_DIAMETER_SUCCESS;
|
|
||||||
int experimental = 0;
|
|
||||||
uint32_t pur_flags = 0;
|
|
||||||
|
|
||||||
/* MySQL requests and asnwer data */
|
|
||||||
mysql_pu_req_t pu_req;
|
|
||||||
mysql_pu_ans_t pu_ans;
|
|
||||||
|
|
||||||
if (msg == NULL) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&pu_req, 0, sizeof(mysql_pu_req_t));
|
|
||||||
|
|
||||||
qry = *msg;
|
|
||||||
/* Create the answer */
|
|
||||||
CHECK_FCT(fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0));
|
|
||||||
ans = *msg;
|
|
||||||
|
|
||||||
/* Retrieving IMSI AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_imsi, &avp));
|
|
||||||
if (avp) {
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
|
|
||||||
if (hdr->avp_value->os.len > IMSI_LENGTH) {
|
|
||||||
result_code = ER_DIAMETER_INVALID_AVP_VALUE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
sprintf(pu_req.imsi, "%*s", (int)hdr->avp_value->os.len, hdr->avp_value->os.data);
|
|
||||||
} else {
|
|
||||||
result_code = ER_DIAMETER_MISSING_AVP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieving the PUR-Flags if present */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_pur_flags, &avp));
|
|
||||||
if (avp) {
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
|
|
||||||
pur_flags = hdr->avp_value->u32;
|
|
||||||
if (FLAG_IS_SET(pur_flags, PUR_UE_PURGED_IN_SGSN)) {
|
|
||||||
/* This bit shall not be set by a standalone MME. */
|
|
||||||
result_code = ER_DIAMETER_INVALID_AVP_VALUE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret = hss_mysql_purge_ue(&pu_req, &pu_ans)) != 0) {
|
|
||||||
/* We failed to find the IMSI in the database. Replying to the request
|
|
||||||
* with the user unknown cause.
|
|
||||||
*/
|
|
||||||
experimental = 1;
|
|
||||||
result_code = DIAMETER_ERROR_USER_UNKNOWN;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieving Origin host AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_origin_host, &avp));
|
|
||||||
if (!avp) {
|
|
||||||
result_code = ER_DIAMETER_MISSING_AVP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
/* Retrieve the header from origin host and realm avps */
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
|
|
||||||
if (strncmp(pu_ans.mme_host, (char *)hdr->avp_value->os.data, hdr->avp_value->os.len) != 0)
|
|
||||||
{
|
|
||||||
result_code = DIAMETER_ERROR_UNKOWN_SERVING_NODE;
|
|
||||||
experimental = 1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieving Origin realm AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_origin_realm, &avp));
|
|
||||||
if (!avp) {
|
|
||||||
result_code = ER_DIAMETER_MISSING_AVP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
|
|
||||||
if (strncmp(pu_ans.mme_realm, (char *)hdr->avp_value->os.data, hdr->avp_value->os.len) != 0)
|
|
||||||
{
|
|
||||||
result_code = DIAMETER_ERROR_UNKOWN_SERVING_NODE;
|
|
||||||
experimental = 1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
/* Append the result code to the answer */
|
|
||||||
CHECK_FCT(s6a_add_result_code(ans, failed_avp, result_code, experimental));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_send(msg, NULL, NULL ));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,276 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "db_proto.h"
|
|
||||||
#include "s6a_proto.h"
|
|
||||||
|
|
||||||
/*! \file s6a_subscription_data.c
|
|
||||||
* \brief Add the subscription data to a message. Data are retrieved from database
|
|
||||||
* \author Sebastien ROUX <sebastien.roux@eurecom.fr>
|
|
||||||
* \date 2013
|
|
||||||
* \version 0.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
int s6a_add_subscription_data_avp(struct msg *message, mysql_ul_ans_t *mysql_ans)
|
|
||||||
{
|
|
||||||
int ret = -1, i;
|
|
||||||
mysql_pdn_t *pdns;
|
|
||||||
uint8_t nb_pdns;
|
|
||||||
struct avp *avp, *child_avp;
|
|
||||||
union avp_value value;
|
|
||||||
|
|
||||||
if (mysql_ans == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = hss_mysql_query_pdns(mysql_ans->imsi, &pdns, &nb_pdns);
|
|
||||||
|
|
||||||
if (ret != 0) {
|
|
||||||
/* mysql query failed:
|
|
||||||
* - maybe no more memory
|
|
||||||
* - maybe user is not known (should have failed before)
|
|
||||||
* - maybe imsi has no EPS subscribed
|
|
||||||
*/
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nb_pdns == 0)
|
|
||||||
{
|
|
||||||
/* No PDN for this user -> DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the Subscription-Data AVP */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_subscription_data, 0, &avp));
|
|
||||||
|
|
||||||
{
|
|
||||||
uint8_t msisdn_len = strlen(mysql_ans->msisdn);
|
|
||||||
/* The MSISDN is known in the HSS, add it to the subscription data */
|
|
||||||
if (msisdn_len > 0) {
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_msisdn, 0, &child_avp));
|
|
||||||
value.os.data = (uint8_t *)mysql_ans->msisdn;
|
|
||||||
value.os.len = msisdn_len;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We have to include the acess-restriction-data if the value stored in DB
|
|
||||||
* indicates that at least one restriction is applied to the USER.
|
|
||||||
*/
|
|
||||||
if (mysql_ans->access_restriction != 0) {
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_access_restriction_data, 0, &child_avp));
|
|
||||||
value.u32 = (uint32_t)mysql_ans->access_restriction;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add the Subscriber-Status to the list of AVP.
|
|
||||||
* It shall indicate if the service is barred or granted.
|
|
||||||
* TODO: normally this parameter comes from DB...
|
|
||||||
*/
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_subscriber_status, 0, &child_avp));
|
|
||||||
/* SERVICE_GRANTED */
|
|
||||||
value.u32 = 0;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
/* Add the Network-Access-Mode to the list of AVP.
|
|
||||||
* LTE Standalone HSS/MME: ONLY_PACKET.
|
|
||||||
*/
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_network_access_mode, 0, &child_avp));
|
|
||||||
/* SERVICE_GRANTED */
|
|
||||||
value.u32 = 2;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
/* Add the AMBR to list of AVPs */
|
|
||||||
{
|
|
||||||
struct avp *bandwidth;
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_ambr, 0, &child_avp));
|
|
||||||
|
|
||||||
/* Uplink bandwidth */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_max_bandwidth_ul, 0, &bandwidth));
|
|
||||||
value.u32 = mysql_ans->aggr_ul;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(bandwidth, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(child_avp, MSG_BRW_LAST_CHILD, bandwidth));
|
|
||||||
|
|
||||||
/* Downlink bandwidth */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_max_bandwidth_dl, 0, &bandwidth));
|
|
||||||
value.u32 = mysql_ans->aggr_dl;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(bandwidth, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(child_avp, MSG_BRW_LAST_CHILD, bandwidth));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add the APN-Configuration-Profile only if at least one APN is subscribed */
|
|
||||||
if (nb_pdns > 0)
|
|
||||||
{
|
|
||||||
struct avp *apn_profile;
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_apn_configuration_profile,
|
|
||||||
0, &apn_profile));
|
|
||||||
|
|
||||||
/* Context-Identifier */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_context_identifier, 0, &child_avp));
|
|
||||||
value.u32 = 0;
|
|
||||||
/* TODO: this is the reference to the default APN... */
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(apn_profile, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
/* All-APN-Configurations-Included-Indicator */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_all_apn_conf_inc_ind, 0, &child_avp));
|
|
||||||
value.u32 = 0;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(apn_profile, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
for (i = 0; i < nb_pdns; i++)
|
|
||||||
{
|
|
||||||
struct avp *apn_configuration;
|
|
||||||
mysql_pdn_t *pdn_elm;
|
|
||||||
|
|
||||||
pdn_elm = &pdns[i];
|
|
||||||
|
|
||||||
/* APN-Configuration */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_apn_configuration, 0, &apn_configuration));
|
|
||||||
|
|
||||||
/* Context-Identifier */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_context_identifier, 0, &child_avp));
|
|
||||||
value.u32 = i;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
/* PDN-Type */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_pdn_type, 0, &child_avp));
|
|
||||||
value.u32 = pdn_elm->pdn_type;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
if ((pdn_elm->pdn_type == IPV4) ||
|
|
||||||
(pdn_elm->pdn_type == IPV4_OR_IPV6) ||
|
|
||||||
(pdn_elm->pdn_type == IPV4V6))
|
|
||||||
{
|
|
||||||
s6a_add_ipv4_address(apn_configuration, pdn_elm->pdn_address.ipv4_address);
|
|
||||||
}
|
|
||||||
if ((pdn_elm->pdn_type == IPV6) ||
|
|
||||||
(pdn_elm->pdn_type == IPV4_OR_IPV6) ||
|
|
||||||
(pdn_elm->pdn_type == IPV4V6))
|
|
||||||
{
|
|
||||||
s6a_add_ipv6_address(apn_configuration, pdn_elm->pdn_address.ipv6_address);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Service-Selection */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_service_selection, 0, &child_avp));
|
|
||||||
value.os.data = (uint8_t*)pdn_elm->apn;
|
|
||||||
value.os.len = strlen(pdn_elm->apn);
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
/* Add the eps subscribed qos profile */
|
|
||||||
{
|
|
||||||
struct avp *qos_profile, *allocation_priority;
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_eps_subscribed_qos_profile, 0, &qos_profile));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_qos_class_identifier, 0, &child_avp));
|
|
||||||
/* For a QCI_1 */
|
|
||||||
value.u32 = (uint32_t)pdn_elm->qci;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(qos_profile, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
/* Allocation retention priority */
|
|
||||||
{
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_allocation_retention_priority, 0, &allocation_priority));
|
|
||||||
|
|
||||||
/* Priority level */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_priority_level, 0, &child_avp));
|
|
||||||
value.u32 = (uint32_t)pdn_elm->priority_level;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(allocation_priority, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
/* Pre-emption-capability */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_pre_emption_capability, 0, &child_avp));
|
|
||||||
value.u32 = (uint32_t)pdn_elm->pre_emp_cap;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(allocation_priority, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
/* Pre-emption-vulnerability */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_pre_emption_vulnerability, 0, &child_avp));
|
|
||||||
value.u32 = (uint32_t)pdn_elm->pre_emp_vul;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(allocation_priority, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_add(qos_profile, MSG_BRW_LAST_CHILD, allocation_priority));
|
|
||||||
}
|
|
||||||
CHECK_FCT(fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, qos_profile));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add the AMBR to list of AVPs */
|
|
||||||
{
|
|
||||||
struct avp *bandwidth;
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_ambr, 0, &bandwidth));
|
|
||||||
|
|
||||||
/* Uplink bandwidth */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_max_bandwidth_ul, 0, &child_avp));
|
|
||||||
value.u32 = (uint32_t)pdn_elm->aggr_ul;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(bandwidth, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
/* Downlink bandwidth */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_max_bandwidth_dl, 0, &child_avp));
|
|
||||||
value.u32 = (uint32_t)pdn_elm->aggr_dl;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(bandwidth, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, bandwidth));
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_add(apn_profile, MSG_BRW_LAST_CHILD, apn_configuration));
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, apn_profile));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Subscribed-Periodic-RAU-TAU-Timer */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_subscribed_rau_tau_timer, 0, &child_avp));
|
|
||||||
/* Request an RAU/TAU update every x seconds */
|
|
||||||
value.u32 = (uint32_t)mysql_ans->rau_tau;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp));
|
|
||||||
|
|
||||||
/* Add the AVP to the message */
|
|
||||||
CHECK_FCT(fd_msg_avp_add(message, MSG_BRW_LAST_CHILD, avp));
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (pdns) {
|
|
||||||
free(pdns);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
/*! \file s6a_supported_features.c
|
|
||||||
* \brief
|
|
||||||
* \author Sebastien ROUX <sebastien.roux@eurecom.fr>
|
|
||||||
* \date 2013
|
|
||||||
* \version 0.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "db_proto.h"
|
|
||||||
#include "s6a_proto.h"
|
|
||||||
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
|
|
||||||
#ifndef S6A_SUPPORTED_FEATURES_H_
|
|
||||||
#define S6A_SUPPORTED_FEATURES_H_
|
|
||||||
|
|
||||||
/* Operator Determined Barring of all Packet Oriented Services. */
|
|
||||||
#define ODB_ALL_APN(x) (x & 0x1)
|
|
||||||
|
|
||||||
/* Operator Determined Barring of Packet Oriented Services from access points
|
|
||||||
* that are within the HPLMN whilst the subscriber is roaming in a VPLMN.
|
|
||||||
*/
|
|
||||||
#define ODB_HPLMN_APN(x) ((x & 0x2) >> 1)
|
|
||||||
|
|
||||||
/* Operator Determined Barring of Packet Oriented Services from access points
|
|
||||||
* that are within the roamed to VPLMN
|
|
||||||
*/
|
|
||||||
#define ODB_VPLMN_APN(x) ((x & 0x4) >> 2)
|
|
||||||
|
|
||||||
/* Operator Determined Barring of all outgoing calls */
|
|
||||||
#define ODB_ALL_OG(x) ((x & 0x8) >> 3)
|
|
||||||
|
|
||||||
/* Operator Determined Barring of all outgoing international calls */
|
|
||||||
#define ODB_ALL_INT_OG ((x & 0x10) >> 4)
|
|
||||||
|
|
||||||
/* Operator Determined Barring of all outgoing international calls except those
|
|
||||||
* directed to the home PLMN country
|
|
||||||
*/
|
|
||||||
#define ODB_ALL_INT_NOT_TO_HPLMN(x) ((x & 0x20) >> 5)
|
|
||||||
|
|
||||||
/* Operator Determined Barring of all outgoing inter-zonal calls */
|
|
||||||
#define ODB_ALL_INT_ZONE_OG(x) ((x & 0x40) >> 6)
|
|
||||||
|
|
||||||
/* Operator Determined Barring of all outgoing inter-zonal calls except those
|
|
||||||
* directed to the home PLMN country
|
|
||||||
*/
|
|
||||||
#define ODB_ALL_INT_ZONE_OG_NOT_TO_HPLMN(x) ((x & 0x80) >> 7)
|
|
||||||
|
|
||||||
/* Operator Determined Barring of all outgoing international calls except those
|
|
||||||
* directed to the home PLMN country and Barring of all outgoing inter-zonal calls
|
|
||||||
*/
|
|
||||||
#define ODB_ALL_INT_ZONE_OG_AND_INT_OG_NOT_TO_HPLMN(x) ((x & 0x100) >> 8)
|
|
||||||
|
|
||||||
/* Regional Subscription */
|
|
||||||
#define REG_SUB(x) ((x & 0x200) >> 9)
|
|
||||||
|
|
||||||
/* Trace Function */
|
|
||||||
#define TRACE(x) ((x & 0x400) >> 10)
|
|
||||||
|
|
||||||
/* All LCS Privacy Exception Classes */
|
|
||||||
#define LCS_ALL_PRIV_EXCEP(x) ((x & 0x800) >> 11)
|
|
||||||
|
|
||||||
/* Allow location by any LCS client */
|
|
||||||
#define LCS_UNIVERSAL(x) ((x & 0x1000) >> 12)
|
|
||||||
|
|
||||||
/* Allow location by any value added LCS client to which a call/session is
|
|
||||||
* established from the target UE
|
|
||||||
*/
|
|
||||||
#define LCS_CALL_SESS_RELATED(x) ((x & 0x2000) >> 13)
|
|
||||||
|
|
||||||
/* Allow location by designated external value added LCS clients */
|
|
||||||
#define LCS_CALL_SESS_UNRELATED(x) ((x & 0x4000) >> 14)
|
|
||||||
|
|
||||||
/* Allow location by designated PLMN operator LCS clients */
|
|
||||||
#define LCS_PLMN_OPERATOR(x) ((x & 0x8000) >> 15)
|
|
||||||
|
|
||||||
/* Allow location by LCS clients of a designated LCS service type */
|
|
||||||
#define LCS_SERVICE_TYPE(x) ((x & 0x10000) >> 16)
|
|
||||||
|
|
||||||
/* All Mobile Originating Location Request Classes */
|
|
||||||
#define LCS_ALL_MOLR_SS(x) ((x & 0x20000) >> 17)
|
|
||||||
|
|
||||||
/* Allow an MS to request its own location */
|
|
||||||
#define LCS_BASIC_SELF_LOCATION(x) ((x & 0x40000) >> 18)
|
|
||||||
|
|
||||||
/* Allow an MS to perform self location without interaction with the PLMN */
|
|
||||||
#define LCS_AUTO_SELF_LOCATION(x) ((x & 0x80000) >> 19)
|
|
||||||
|
|
||||||
/* Allow an MS to request transfer of its location to another LCS client */
|
|
||||||
#define LCS_TRANSFER_TO_THIRD_PARTY(x) ((x & 0x100000) >> 20)
|
|
||||||
|
|
||||||
/* Short Message MO-PP */
|
|
||||||
#define SM_MO_PP(x) ((x & 0x200000) >> 21)
|
|
||||||
|
|
||||||
/* Barring of Outgoing Calls */
|
|
||||||
#define BARRING_OUTGOING_CALLS(x) ((x & 0x400000) >> 22)
|
|
||||||
|
|
||||||
/* Barring of all outgoing calls */
|
|
||||||
#define BAOC(x) ((x & 0x800000) >> 23)
|
|
||||||
|
|
||||||
/* Barring of outgoing international calls */
|
|
||||||
#define BOIC(x) ((x & 0x1000000) >> 24)
|
|
||||||
|
|
||||||
/* Barring of outgoing international calls except those directed to the home PLMN
|
|
||||||
* Country
|
|
||||||
*/
|
|
||||||
#define BOIC_EXCEPT_HC(x) ((x & 0x2000000) >> 25)
|
|
||||||
|
|
||||||
/* UE Reachability Notifcation */
|
|
||||||
#define UE_REACH_NOTIF(x) ((x & 0x4000000) >> 26)
|
|
||||||
|
|
||||||
/* Terminating Access Domain Selection Data Retrieval */
|
|
||||||
#define T_ADS_DATA_RETR(x) ((x & 0x8000000) >> 27)
|
|
||||||
|
|
||||||
/* State/Location Information Retrieval */
|
|
||||||
#define STATE_LOCATION_INFO_RETR(x) ((x & 0x10000000) >> 28)
|
|
||||||
|
|
||||||
/* Partial Purge from a Combined MME/SGSN */
|
|
||||||
#define PARTIAL_PURGE(x) ((x & 0x20000000) >> 29)
|
|
||||||
|
|
||||||
#define SUPP_FEAT_PAD_VALID(x) ((x & 0xfc000000) == 0)
|
|
||||||
|
|
||||||
#endif /* S6A_SUPPORTED_FEATURES_H_ */
|
|
||||||
@@ -1,373 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
/*! \file s6a_up_loc.c
|
|
||||||
* \brief Handle an update location message and create the answer.
|
|
||||||
* \author Sebastien ROUX <sebastien.roux@eurecom.fr>
|
|
||||||
* \date 2013
|
|
||||||
* \version 0.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "db_proto.h"
|
|
||||||
#include "s6a_proto.h"
|
|
||||||
#include "access_restriction.h"
|
|
||||||
|
|
||||||
int s6a_up_loc_cb(struct msg **msg, struct avp *paramavp,
|
|
||||||
struct session *sess, void *opaque,
|
|
||||||
enum disp_action *act)
|
|
||||||
{
|
|
||||||
struct msg *ans, *qry;
|
|
||||||
struct avp *avp, *origin_host, *origin_realm;
|
|
||||||
struct avp *failed_avp = NULL;
|
|
||||||
|
|
||||||
struct avp_hdr *origin_host_hdr, *origin_realm_hdr;
|
|
||||||
struct avp_hdr *hdr;
|
|
||||||
|
|
||||||
union avp_value value;
|
|
||||||
|
|
||||||
int ret = 0;
|
|
||||||
int result_code = ER_DIAMETER_SUCCESS;
|
|
||||||
int experimental = 0;
|
|
||||||
uint32_t ulr_flags = 0;
|
|
||||||
|
|
||||||
mysql_ul_ans_t mysql_ans;
|
|
||||||
mysql_ul_push_t mysql_push;
|
|
||||||
|
|
||||||
if (msg == NULL) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&mysql_push, 0, sizeof(mysql_ul_push_t));
|
|
||||||
memset(&mysql_ans, 0, sizeof(mysql_ul_ans_t));
|
|
||||||
|
|
||||||
fprintf(stdout, "Received new update location request\n");
|
|
||||||
|
|
||||||
qry = *msg;
|
|
||||||
/* Create the answer */
|
|
||||||
CHECK_FCT(fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0));
|
|
||||||
ans = *msg;
|
|
||||||
|
|
||||||
/* Retrieving IMSI AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_imsi, &avp));
|
|
||||||
if (avp) {
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
|
|
||||||
if (hdr->avp_value->os.len > IMSI_LENGTH) {
|
|
||||||
result_code = ER_DIAMETER_INVALID_AVP_VALUE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
sprintf(mysql_push.imsi, "%*s", (int)hdr->avp_value->os.len,
|
|
||||||
(char*)hdr->avp_value->os.data);
|
|
||||||
if ((ret = hss_mysql_update_loc(mysql_push.imsi, &mysql_ans)) != 0) {
|
|
||||||
/* We failed to find the IMSI in the database. Replying to the request
|
|
||||||
* with the user unknown cause.
|
|
||||||
*/
|
|
||||||
experimental = 1;
|
|
||||||
result_code = DIAMETER_ERROR_USER_UNKNOWN;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Cannot get IMSI AVP which is mandatory\n");
|
|
||||||
result_code = ER_DIAMETER_MISSING_AVP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieving Origin host AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_origin_host, &origin_host));
|
|
||||||
if (!origin_host) {
|
|
||||||
result_code = ER_DIAMETER_MISSING_AVP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieving Origin realm AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_origin_realm, &origin_realm));
|
|
||||||
if (!origin_realm) {
|
|
||||||
result_code = ER_DIAMETER_MISSING_AVP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieve the header from origin host and realm avps */
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(origin_host, &origin_host_hdr));
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(origin_realm, &origin_realm_hdr));
|
|
||||||
|
|
||||||
sprintf(mysql_push.mme_identity.mme_host, "%*s",
|
|
||||||
(int)origin_host_hdr->avp_value->os.len,
|
|
||||||
(char*)origin_host_hdr->avp_value->os.data);
|
|
||||||
|
|
||||||
sprintf(mysql_push.mme_identity.mme_realm, "%*s",
|
|
||||||
(int)origin_realm_hdr->avp_value->os.len,
|
|
||||||
(char*)origin_realm_hdr->avp_value->os.data);
|
|
||||||
|
|
||||||
/* Retrieving RAT type AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_rat_type, &avp));
|
|
||||||
if (avp) {
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
|
|
||||||
/* As we are in E-UTRAN stand-alone HSS, we have to reject incoming
|
|
||||||
* location request with a RAT-Type != than E-UTRAN.
|
|
||||||
* The user may be disallowed to use the specified RAT, check the access
|
|
||||||
* restriction bit mask received from DB.
|
|
||||||
*/
|
|
||||||
if ((hdr->avp_value->u32 != 1004) ||
|
|
||||||
(FLAG_IS_SET(mysql_ans.access_restriction, E_UTRAN_NOT_ALLOWED)))
|
|
||||||
{
|
|
||||||
experimental = 1;
|
|
||||||
result_code = DIAMETER_ERROR_RAT_NOT_ALLOWED;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result_code = ER_DIAMETER_MISSING_AVP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieving ULR Flags AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_ulr_flags, &avp));
|
|
||||||
if (avp) {
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
|
|
||||||
ulr_flags = hdr->avp_value->u32;
|
|
||||||
/* Check the flags received */
|
|
||||||
if (FLAG_IS_SET(ulr_flags, ULR_SINGLE_REGISTRATION_IND)) {
|
|
||||||
/* We don't handle cases where we have to inform SGSN */
|
|
||||||
result_code = ER_DIAMETER_INVALID_AVP_VALUE;
|
|
||||||
|
|
||||||
fprintf(stderr, "ULR single registration bit set (SGSN to MME): "
|
|
||||||
"not handled by standalone E-UTRAN HSS\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (!FLAG_IS_SET(ulr_flags, ULR_S6A_S6D_INDICATOR)) {
|
|
||||||
/* The request is coming from s6d interface (SGSN). */
|
|
||||||
result_code = ER_DIAMETER_INVALID_AVP_VALUE;
|
|
||||||
|
|
||||||
fprintf(stderr, "ULR S6D bit set: "
|
|
||||||
"not handled by standalone E-UTRAN HSS\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (FLAG_IS_SET(ulr_flags, ULR_NODE_TYPE_IND)) {
|
|
||||||
/* Request coming from combined SGSN/MME. */
|
|
||||||
result_code = ER_DIAMETER_INVALID_AVP_VALUE;
|
|
||||||
fprintf(stderr, "ULR conbined SGSN/MME bit set: "
|
|
||||||
"not handled by standalone E-UTRAN HSS\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (FLAG_IS_SET(ulr_flags, ULR_INITIAL_ATTACH_IND)) {
|
|
||||||
/* This bit, when set, indicates that the HSS shall send Cancel
|
|
||||||
* Location to the MME or SGSN if there is the MME or SGSN
|
|
||||||
* registration.
|
|
||||||
*/
|
|
||||||
// TODO: check if an MME is already registered, serving the UE.
|
|
||||||
// If so, it should be informed.
|
|
||||||
|
|
||||||
/* The identity of the MME will be added to db */
|
|
||||||
mysql_push.mme_identity_present = MME_IDENTITY_PRESENT;
|
|
||||||
} else {
|
|
||||||
/* The bit is not set, we are expecting that the mme contained in db
|
|
||||||
* matches the original MME.
|
|
||||||
*/
|
|
||||||
if ((mysql_ans.mme_identity.mme_host != NULL) &&
|
|
||||||
(mysql_ans.mme_identity.mme_realm != NULL))
|
|
||||||
{
|
|
||||||
/* Compare if values match expected */
|
|
||||||
if (memcmp(mysql_ans.mme_identity.mme_host, origin_host_hdr->avp_value->os.data,
|
|
||||||
origin_host_hdr->avp_value->os.len > strlen(mysql_ans.mme_identity.mme_host) ?
|
|
||||||
strlen(mysql_ans.mme_identity.mme_host) : origin_host_hdr->avp_value->os.len) != 0)
|
|
||||||
{
|
|
||||||
experimental = 1;
|
|
||||||
result_code = DIAMETER_ERROR_UNKOWN_SERVING_NODE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (memcmp(mysql_ans.mme_identity.mme_realm, origin_realm_hdr->avp_value->os.data,
|
|
||||||
origin_realm_hdr->avp_value->os.len > strlen(mysql_ans.mme_identity.mme_realm) ?
|
|
||||||
strlen(mysql_ans.mme_identity.mme_realm) : origin_realm_hdr->avp_value->os.len) != 0)
|
|
||||||
{
|
|
||||||
experimental = 1;
|
|
||||||
result_code = DIAMETER_ERROR_UNKOWN_SERVING_NODE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Failed to retrieve current serving MME and the ULR is not
|
|
||||||
* marked as an initial attach indication...
|
|
||||||
*/
|
|
||||||
experimental = 1;
|
|
||||||
result_code = DIAMETER_ERROR_UNKOWN_SERVING_NODE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!ULR_PAD_VALID(ulr_flags)) {
|
|
||||||
/* Padding is not zero'ed, may be the MME/SGSN supports newer
|
|
||||||
* release. Inform it.
|
|
||||||
*/
|
|
||||||
result_code = ER_DIAMETER_INVALID_AVP_VALUE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result_code = ER_DIAMETER_MISSING_AVP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieving Visited-PLMN-Id AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_visited_plmn_id, &avp));
|
|
||||||
if (avp) {
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
|
|
||||||
/* Roaming cases are not allowed for now.
|
|
||||||
* Reject the connectivity if PLMN visited and IMSI PLMN disagree.
|
|
||||||
*/
|
|
||||||
/* TODO */
|
|
||||||
if (hdr->avp_value->os.len == 3) {
|
|
||||||
// if (apply_access_restriction(mysql_push.imsi, hdr->avp_value->os.data) != 0) {
|
|
||||||
// /* We found that user is roaming and has no right to do it ->
|
|
||||||
// * reject the connection
|
|
||||||
// */
|
|
||||||
// result_code = DIAMETER_ERROR_ROAMING_NOT_ALLOWED;
|
|
||||||
// experimental = 1;
|
|
||||||
// goto out;
|
|
||||||
// }
|
|
||||||
} else {
|
|
||||||
result_code = ER_DIAMETER_INVALID_AVP_VALUE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result_code = ER_DIAMETER_MISSING_AVP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieving Terminal-Information AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_terminal_info, &avp));
|
|
||||||
if (avp) {
|
|
||||||
struct avp *child_avp;
|
|
||||||
|
|
||||||
/* Walk through childs avp */
|
|
||||||
CHECK_FCT(fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &child_avp, NULL));
|
|
||||||
while (child_avp) {
|
|
||||||
/* Retrieve the header of the child avp */
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(child_avp, &hdr));
|
|
||||||
switch(hdr->avp_code) {
|
|
||||||
case AVP_CODE_IMEI: {
|
|
||||||
/* Check that we do not exceed the maximum size for IMEI */
|
|
||||||
if (hdr->avp_value->os.len > IMEI_LENGTH) {
|
|
||||||
result_code = ER_DIAMETER_INVALID_AVP_VALUE;
|
|
||||||
failed_avp = child_avp;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
sprintf(mysql_push.imei, "%*s", (int)hdr->avp_value->os.len,
|
|
||||||
hdr->avp_value->os.data);
|
|
||||||
mysql_push.imei_present = IMEI_PRESENT;
|
|
||||||
} break;
|
|
||||||
case AVP_CODE_SOFTWARE_VERSION: {
|
|
||||||
/* Check the size for SV */
|
|
||||||
if (hdr->avp_value->os.len != SV_LENGTH) {
|
|
||||||
result_code = ER_DIAMETER_INVALID_AVP_VALUE;
|
|
||||||
failed_avp = child_avp;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
mysql_push.software_version[0] = hdr->avp_value->os.data[0];
|
|
||||||
mysql_push.software_version[1] = hdr->avp_value->os.data[1];
|
|
||||||
mysql_push.sv_present = SV_PRESENT;
|
|
||||||
} break;
|
|
||||||
default: /* Fall through */
|
|
||||||
case AVP_CODE_3GPP2_MEID: {
|
|
||||||
/* This AVP is not expected on s6a interface */
|
|
||||||
result_code = ER_DIAMETER_AVP_UNSUPPORTED;
|
|
||||||
failed_avp = child_avp;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Go to next AVP in the grouped AVP */
|
|
||||||
CHECK_FCT(fd_msg_browse(child_avp, MSG_BRW_NEXT, &child_avp, NULL));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieving UE-SRVCC AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_ue_srvcc_cap, &avp));
|
|
||||||
if (avp) {
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
|
|
||||||
mysql_push.ue_srvcc_present = UE_SRVCC_PRESENT;
|
|
||||||
mysql_push.ue_srvcc = hdr->avp_value->u32;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieving Supported features list AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_supported_features, &avp));
|
|
||||||
if (avp) {
|
|
||||||
struct avp *child_avp;
|
|
||||||
|
|
||||||
/* Walk through childs avp */
|
|
||||||
CHECK_FCT(fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &child_avp, NULL));
|
|
||||||
while (child_avp) {
|
|
||||||
/* Retrieve the header of the child avp */
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(child_avp, &hdr));
|
|
||||||
switch(hdr->avp_code) {
|
|
||||||
case AVP_CODE_VENDOR_ID: {
|
|
||||||
if (hdr->avp_value->u32 != VENDOR_3GPP) {
|
|
||||||
/* features from a vendor other than 3GPP is not supported */
|
|
||||||
fprintf(stderr, "Cannot interpret features list with vendor id "
|
|
||||||
"different than 3GPP(%d)\n", VENDOR_3GPP);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case AVP_CODE_FEATURE_LIST: {
|
|
||||||
mysql_push.mme_supported_features_present = MME_SUPPORTED_FEATURES_PRESENT;
|
|
||||||
mysql_push.mme_supported_features = hdr->avp_value->u32;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
/* Go to next AVP in the grouped AVP */
|
|
||||||
CHECK_FCT(fd_msg_browse(child_avp, MSG_BRW_NEXT, &child_avp, NULL));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql_push_up_loc(&mysql_push);
|
|
||||||
|
|
||||||
/* ULA flags */
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_ula_flags, 0, &avp));
|
|
||||||
value.u32 = 1;
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(avp, &value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp));
|
|
||||||
|
|
||||||
/* Only add the subscriber data if not marked as skipped by MME */
|
|
||||||
if (!FLAG_IS_SET(ulr_flags, ULR_SKIP_SUBSCRIBER_DATA)) {
|
|
||||||
if (s6a_add_subscription_data_avp(ans, &mysql_ans) != 0) {
|
|
||||||
result_code = DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION;
|
|
||||||
experimental = 1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
/* Add the Auth-Session-State AVP */
|
|
||||||
CHECK_FCT(fd_msg_search_avp(qry, s6a_cnf.dataobj_s6a_auth_session_state, &avp));
|
|
||||||
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_auth_session_state, 0, &avp));
|
|
||||||
CHECK_FCT(fd_msg_avp_setvalue(avp, hdr->avp_value));
|
|
||||||
CHECK_FCT(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp));
|
|
||||||
|
|
||||||
/* Append the result code to the answer */
|
|
||||||
CHECK_FCT(s6a_add_result_code(ans, failed_avp, result_code, experimental));
|
|
||||||
|
|
||||||
CHECK_FCT(fd_msg_send(msg, NULL, NULL ));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
# if HAVE_CHECK
|
|
||||||
# TESTS = up_loc_test
|
|
||||||
# else
|
|
||||||
# TESTS =
|
|
||||||
# endif
|
|
||||||
AM_CFLAGS = @CHECK_CFLAGS@ \
|
|
||||||
-I$(top_srcdir)/auc
|
|
||||||
|
|
||||||
if HAVE_CHECK
|
|
||||||
TESTS = up_loc_test test_security_f1 \
|
|
||||||
test_security_f2_f3_f5 \
|
|
||||||
test_security_f4_f5star \
|
|
||||||
test_kdf \
|
|
||||||
test_security_kasme
|
|
||||||
else
|
|
||||||
TESTS =
|
|
||||||
endif
|
|
||||||
|
|
||||||
test_common = \
|
|
||||||
$(top_builddir)/auc/libauc.la \
|
|
||||||
libtest_utils.la \
|
|
||||||
@CHECK_LIBS@
|
|
||||||
|
|
||||||
up_loc_test_LDADD = \
|
|
||||||
libtest_utils.la \
|
|
||||||
@CHECK_LIBS@
|
|
||||||
|
|
||||||
test_security_f1_LDADD = \
|
|
||||||
$(test_common)
|
|
||||||
|
|
||||||
test_security_f2_f3_f5_LDADD = \
|
|
||||||
$(test_common)
|
|
||||||
|
|
||||||
test_security_f4_f5star_LDADD = \
|
|
||||||
$(test_common)
|
|
||||||
|
|
||||||
test_security_kasme_LDADD = \
|
|
||||||
$(test_common)
|
|
||||||
|
|
||||||
test_kdf_LDADD = \
|
|
||||||
$(test_common)
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libtest_utils.la
|
|
||||||
libtest_utils_la_SOURCES = \
|
|
||||||
test_utils.h test_utils.c \
|
|
||||||
test_fd.h test_fd.c
|
|
||||||
|
|
||||||
check_PROGRAMS = \
|
|
||||||
up_loc_test test_security_f1 \
|
|
||||||
test_security_f2_f3_f5 \
|
|
||||||
test_security_f4_f5star \
|
|
||||||
test_security_kasme \
|
|
||||||
test_kdf
|
|
||||||
|
|
||||||
up_loc_test_SOURCES = up_loc_test.c
|
|
||||||
test_security_f1_SOURCE = test_security_f1.c
|
|
||||||
test_security_f2_f3_f5_SOURCE = test_security_f2_f3_f5.c
|
|
||||||
test_security_f4_f5star_SOURCE = test_security_f4_f5star.c
|
|
||||||
test_security_kasme_SOURCE = test_security_kasme.c
|
|
||||||
test_kdf_SOURCE = test_kdf.c
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <freeDiameter/freeDiameter-host.h>
|
|
||||||
#include <freeDiameter/libfdcore.h>
|
|
||||||
|
|
||||||
#include "test_utils.h"
|
|
||||||
#include "test_fd.h"
|
|
||||||
|
|
||||||
extern int fd_ext_add( char * filename, char * conffile );
|
|
||||||
|
|
||||||
void s6a_fd_init(void)
|
|
||||||
{
|
|
||||||
struct peer_info peer;
|
|
||||||
|
|
||||||
fd_g_debug_lvl = NONE;
|
|
||||||
|
|
||||||
memset(&peer, 0, sizeof(struct peer_info));
|
|
||||||
|
|
||||||
peer.pi_diamid = "hss.test.fr";
|
|
||||||
peer.pi_diamidlen = strlen(peer.pi_diamid);
|
|
||||||
|
|
||||||
/* Only SCTP */
|
|
||||||
peer.config.pic_flags.pro4 = PI_P4_SCTP;
|
|
||||||
peer.config.pic_flags.sec = PI_SEC_NONE;
|
|
||||||
peer.config.pic_flags.exp = PI_EXP_NONE;
|
|
||||||
|
|
||||||
peer.config.pic_port = 18678;
|
|
||||||
|
|
||||||
if (fd_core_initialize() != 0) {
|
|
||||||
fail("fd_core_initialize failed");
|
|
||||||
}
|
|
||||||
if (fd_core_start() != 0) {
|
|
||||||
fail("fd_core_start failed");
|
|
||||||
}
|
|
||||||
if (fd_core_parseconf("../../conf/hss_fd.conf") != 0) {
|
|
||||||
fail("fd_core_waitstartcomplete failed");
|
|
||||||
}
|
|
||||||
if (fd_core_waitstartcomplete() != 0) {
|
|
||||||
fail("fd_core_waitstartcomplete failed");
|
|
||||||
}
|
|
||||||
// if (fd_peer_add(&peer, NULL, NULL, NULL) != 0) {
|
|
||||||
// fail("fd_peer_add failed");
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
void s6a_fd_stop(void)
|
|
||||||
{
|
|
||||||
if (fd_core_shutdown() != 0) {
|
|
||||||
fail("fd_core_shutdown failed");
|
|
||||||
}
|
|
||||||
if (fd_core_wait_shutdown_complete() != 0) {
|
|
||||||
fail("fd_core_shutdown failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef TEST_FD_H_
|
|
||||||
#define TEST_FD_H_
|
|
||||||
|
|
||||||
void s6a_fd_init(void);
|
|
||||||
|
|
||||||
void s6a_fd_stop(void);
|
|
||||||
|
|
||||||
#endif /* TEST_FD_H_ */
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "test_utils.h"
|
|
||||||
#include "test_fd.h"
|
|
||||||
|
|
||||||
#include "auc.h"
|
|
||||||
|
|
||||||
static
|
|
||||||
void do_kdf(uint8_t *key, unsigned key_length, uint8_t *data, unsigned data_length,
|
|
||||||
uint8_t *exp, unsigned exp_length)
|
|
||||||
{
|
|
||||||
uint8_t result[32];
|
|
||||||
|
|
||||||
kdf(key, key_length, data, data_length, result, 32);
|
|
||||||
if (compare_buffer(result, exp_length, exp, exp_length) != 0) {
|
|
||||||
fail("Fail: kdf\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
doit (void)
|
|
||||||
{
|
|
||||||
/* RFC 4231 */
|
|
||||||
|
|
||||||
/* Test case 1 #4.2 */
|
|
||||||
do_kdf(HL("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
|
|
||||||
"0b0b0b0b"),
|
|
||||||
HL("4869205468657265"),
|
|
||||||
HL("b0344c61d8db38535ca8afceaf0bf12b"
|
|
||||||
"881dc200c9833da726e9376c2e32cff7"));
|
|
||||||
/* Test case 2 #4.3 */
|
|
||||||
do_kdf(HL("4a656665"),
|
|
||||||
HL("7768617420646f2079612077616e7420"
|
|
||||||
"666f72206e6f7468696e673f"),
|
|
||||||
HL("5bdcc146bf60754e6a042426089575c7"
|
|
||||||
"5a003f089d2739839dec58b964ec3843"));
|
|
||||||
/* Test case 3 #4.4 */
|
|
||||||
do_kdf(HL("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaa"),
|
|
||||||
HL("dddddddddddddddddddddddddddddddd"
|
|
||||||
"dddddddddddddddddddddddddddddddd"
|
|
||||||
"dddddddddddddddddddddddddddddddd"
|
|
||||||
"dddd"),
|
|
||||||
HL("773ea91e36800e46854db8ebd09181a7"
|
|
||||||
"2959098b3ef8c122d9635514ced565fe"));
|
|
||||||
/* Test case 4 #4.5 */
|
|
||||||
do_kdf(HL("0102030405060708090a0b0c0d0e0f10"
|
|
||||||
"111213141516171819"),
|
|
||||||
HL("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
|
|
||||||
"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
|
|
||||||
"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
|
|
||||||
"cdcd"),
|
|
||||||
HL("82558a389a443c0ea4cc819899f2083a"
|
|
||||||
"85f0faa3e578f8077a2e3ff46729665b"));
|
|
||||||
/* Test case 5 #4.6 */
|
|
||||||
do_kdf(HL("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"
|
|
||||||
"0c0c0c0c"),
|
|
||||||
HL("546573742057697468205472756e6361"
|
|
||||||
"74696f6e"),
|
|
||||||
HL("a3b6167473100ee06e0c796c2955552b"));
|
|
||||||
/* Test case 6 #4.7 */
|
|
||||||
do_kdf(HL("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaa"),
|
|
||||||
HL("54657374205573696e67204c61726765"
|
|
||||||
"72205468616e20426c6f636b2d53697a"
|
|
||||||
"65204b6579202d2048617368204b6579"
|
|
||||||
"204669727374"),
|
|
||||||
HL("60e431591ee0b67f0d8a26aacbf5b77f"
|
|
||||||
"8e0bc6213728c5140546040f0ee37f54"));
|
|
||||||
/* Test case 6 #4.7 */
|
|
||||||
do_kdf(HL("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
"aaaaaa"),
|
|
||||||
HL("54686973206973206120746573742075"
|
|
||||||
"73696e672061206c6172676572207468"
|
|
||||||
"616e20626c6f636b2d73697a65206b65"
|
|
||||||
"7920616e642061206c61726765722074"
|
|
||||||
"68616e20626c6f636b2d73697a652064"
|
|
||||||
"6174612e20546865206b6579206e6565"
|
|
||||||
"647320746f2062652068617368656420"
|
|
||||||
"6265666f7265206265696e6720757365"
|
|
||||||
"642062792074686520484d414320616c"
|
|
||||||
"676f726974686d2e"),
|
|
||||||
HL("9b09ffa71b942fcb27635fbcd5b0e944"
|
|
||||||
"bfdc63644f0713938a7f51535c3a35e2"));
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "test_utils.h"
|
|
||||||
#include "test_fd.h"
|
|
||||||
|
|
||||||
#include "auc.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t key[16];
|
|
||||||
uint8_t rand[16];
|
|
||||||
uint8_t sqn[6];
|
|
||||||
uint8_t amf[2];
|
|
||||||
uint8_t op[16];
|
|
||||||
uint8_t f1_exp[8];
|
|
||||||
uint8_t f1_star_exp[8];
|
|
||||||
} test_set_t;
|
|
||||||
|
|
||||||
test_set_t test_set[] = {
|
|
||||||
/* 35.207 #4.3 */
|
|
||||||
{
|
|
||||||
.key = {
|
|
||||||
0x46, 0x5b, 0x5c, 0xe8, 0xb1, 0x99, 0xb4, 0x9f, 0xaa, 0x5f, 0x0a,
|
|
||||||
0x2e, 0xe2, 0x38, 0xa6, 0xbc
|
|
||||||
},
|
|
||||||
.rand = {
|
|
||||||
0x23, 0x55, 0x3c, 0xbe, 0x96, 0x37, 0xa8, 0x9d, 0x21, 0x8a, 0xe6,
|
|
||||||
0x4d, 0xae, 0x47, 0xbf, 0x35
|
|
||||||
},
|
|
||||||
.sqn = { 0xff, 0x9b, 0xb4, 0xd0, 0xb6, 0x07 },
|
|
||||||
.amf = { 0xb9, 0xb9 },
|
|
||||||
.op = {
|
|
||||||
0xcd, 0xc2, 0x02, 0xd5, 0x12, 0x3e, 0x20, 0xf6, 0x2b, 0x6d, 0x67,
|
|
||||||
0x6a, 0xc7, 0x2c, 0xb3, 0x18
|
|
||||||
},
|
|
||||||
.f1_exp = { 0x4a, 0x9f, 0xfa, 0xc3, 0x54, 0xdf, 0xaf, 0xb3 },
|
|
||||||
.f1_star_exp = { 0x01, 0xcf, 0xaf, 0x9e, 0xc4, 0xe8, 0x71, 0xe9 },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.key = {
|
|
||||||
0x03, 0x96, 0xeb, 0x31, 0x7b, 0x6d, 0x1c, 0x36, 0xf1, 0x9c, 0x1c,
|
|
||||||
0x84, 0xcd, 0x6f, 0xfd, 0x16
|
|
||||||
},
|
|
||||||
.rand = {
|
|
||||||
0xc0, 0x0d, 0x60, 0x31, 0x03, 0xdc, 0xee, 0x52, 0xc4, 0x47, 0x81,
|
|
||||||
0x19, 0x49, 0x42, 0x02, 0xe8,
|
|
||||||
},
|
|
||||||
.sqn = { 0xfd, 0x8e, 0xef, 0x40, 0xdf, 0x7d },
|
|
||||||
.amf = { 0xaf, 0x17 },
|
|
||||||
.op = {
|
|
||||||
0xff, 0x53, 0xba, 0xde, 0x17, 0xdf, 0x5d, 0x4e, 0x79, 0x30, 0x73,
|
|
||||||
0xce, 0x9d, 0x75, 0x79, 0xfa
|
|
||||||
},
|
|
||||||
.f1_exp = { 0x5d, 0xf5, 0xb3, 0x18, 0x07, 0xe2, 0x58, 0xb0 },
|
|
||||||
.f1_star_exp = { 0xa8, 0xc0, 0x16, 0xe5, 0x1e, 0xf4, 0xa3, 0x43 }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
doit (void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(test_set) / sizeof(test_set_t); i++) {
|
|
||||||
uint8_t res[8];
|
|
||||||
|
|
||||||
SetOPc(test_set[i].op);
|
|
||||||
f1(test_set[i].key, test_set[i].rand, test_set[i].sqn, test_set[i].amf, res);
|
|
||||||
// printf("%02x%02x%02x%02x%02x%02x%02x%02x\n", res[0], res[1], res[2],
|
|
||||||
// res[3], res[4], res[5], res[6], res[7]);
|
|
||||||
if (memcmp(res, test_set[i].f1_exp, 8) != 0) {
|
|
||||||
fail("Test set %d (f1) : failed\n", i);
|
|
||||||
} else {
|
|
||||||
success("Test set %d (f1) : success\n", i);
|
|
||||||
}
|
|
||||||
|
|
||||||
f1star(test_set[i].key, test_set[i].rand, test_set[i].sqn, test_set[i].amf, res);
|
|
||||||
// printf("%02x%02x%02x%02x%02x%02x%02x%02x\n", res[0], res[1], res[2],
|
|
||||||
// res[3], res[4], res[5], res[6], res[7]);
|
|
||||||
if (memcmp(res, test_set[i].f1_star_exp, 8) != 0) {
|
|
||||||
fail("Test set %d (f1*): failed\n", i);
|
|
||||||
} else {
|
|
||||||
success("Test set %d (f1*): success\n", i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "test_utils.h"
|
|
||||||
#include "test_fd.h"
|
|
||||||
|
|
||||||
#include "auc.h"
|
|
||||||
|
|
||||||
static
|
|
||||||
void do_f1_f1star(uint8_t *key, uint8_t *rand, uint8_t *sqn,
|
|
||||||
uint8_t *amf, uint8_t *op, uint8_t *f1_exp,
|
|
||||||
uint8_t *f1star_exp)
|
|
||||||
{
|
|
||||||
uint8_t res[8];
|
|
||||||
|
|
||||||
SetOPc(op);
|
|
||||||
|
|
||||||
f1(key, rand, sqn, amf, res);
|
|
||||||
if (compare_buffer(res, 8, f1_exp, 8) != 0) {
|
|
||||||
fail("Fail: f1");
|
|
||||||
}
|
|
||||||
f1star(key, rand, sqn, amf, res);
|
|
||||||
if (compare_buffer(res, 8, f1star_exp, 8) != 0) {
|
|
||||||
fail("Fail: f1*");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
doit (void)
|
|
||||||
{
|
|
||||||
/* Test suite taken from 3GPP TS 35.207 */
|
|
||||||
|
|
||||||
/* Test set 1 #4.3 */
|
|
||||||
do_f1_f1star(
|
|
||||||
H("465b5ce8 b199b49f aa5f0a2e e238a6bc"),
|
|
||||||
H("23553cbe 9637a89d 218ae64d ae47bf35"),
|
|
||||||
H("ff9bb4d0 b607"),
|
|
||||||
H("b9b9"),
|
|
||||||
H("cdc202d5 123e20f6 2b6d676a c72cb318"),
|
|
||||||
H("4a9ffac3 54dfafb3"),
|
|
||||||
H("01cfaf9e c4e871e9"));
|
|
||||||
/* Test set 2 #4.4 */
|
|
||||||
do_f1_f1star(
|
|
||||||
H("0396eb31 7b6d1c36 f19c1c84 cd6ffd16"),
|
|
||||||
H("c00d6031 03dcee52 c4478119 494202e8"),
|
|
||||||
H("fd8eef40 df7d"),
|
|
||||||
H("af17"),
|
|
||||||
H("ff53bade 17df5d4e 793073ce 9d7579fa"),
|
|
||||||
H("5df5b318 07e258b0"),
|
|
||||||
H("a8c016e5 1ef4a343"));
|
|
||||||
/* Test set 3 #4.5 */
|
|
||||||
do_f1_f1star(
|
|
||||||
H("fec86ba6 eb707ed0 8905757b 1bb44b8f"),
|
|
||||||
H("9f7c8d02 1accf4db 213ccff0 c7f71a6a"),
|
|
||||||
H("9d027759 5ffc"),
|
|
||||||
H("725c"),
|
|
||||||
H("dbc59adc b6f9a0ef 735477b7 fadf8374"),
|
|
||||||
H("9cabc3e9 9baf7281"),
|
|
||||||
H("95814ba2 b3044324"));
|
|
||||||
/* Test set 4 #4.5 */
|
|
||||||
do_f1_f1star(
|
|
||||||
H("9e5944ae a94b8116 5c82fbf9 f32db751"),
|
|
||||||
H("ce83dbc5 4ac0274a 157c17f8 0d017bd6"),
|
|
||||||
H("0b604a81 eca8"),
|
|
||||||
H("9e09"),
|
|
||||||
H("223014c5 806694c0 07ca1eee f57f004f"),
|
|
||||||
H("74a58220 cba84c49"),
|
|
||||||
H("ac2cc74a 96871837"));
|
|
||||||
/* Test set 5 #4.6 */
|
|
||||||
do_f1_f1star(
|
|
||||||
H("4ab1deb0 5ca6ceb0 51fc98e7 7d026a84"),
|
|
||||||
H("74b0cd60 31a1c833 9b2b6ce2 b8c4a186"),
|
|
||||||
H("e880a1b5 80b6"),
|
|
||||||
H("9f07"),
|
|
||||||
H("2d16c5cd 1fdf6b22 383584e3 bef2a8d8"),
|
|
||||||
H("49e785dd 12626ef2"),
|
|
||||||
H("9e857903 36bb3fa2"));
|
|
||||||
/* Test set 6 #4.7 */
|
|
||||||
do_f1_f1star(
|
|
||||||
H("6c38a116 ac280c45 4f59332e e35c8c4f"),
|
|
||||||
H("ee6466bc 96202c5a 557abbef f8babf63"),
|
|
||||||
H("414b9822 2181"),
|
|
||||||
H("4464"),
|
|
||||||
H("1ba00a1a 7c6700ac 8c3ff3e9 6ad08725"),
|
|
||||||
H("078adfb4 88241a57"),
|
|
||||||
H("80246b8d 0186bcf1"));
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "test_utils.h"
|
|
||||||
#include "test_fd.h"
|
|
||||||
|
|
||||||
#include "auc.h"
|
|
||||||
|
|
||||||
static
|
|
||||||
void do_f2f3f5(uint8_t *key, uint8_t *rand, uint8_t *op, uint8_t *f2_exp,
|
|
||||||
uint8_t *f5_exp, uint8_t *f3_exp)
|
|
||||||
{
|
|
||||||
uint8_t res_f2[8];
|
|
||||||
uint8_t res_f5[6];
|
|
||||||
uint8_t res_f3[16];
|
|
||||||
uint8_t res_f4[16];
|
|
||||||
|
|
||||||
SetOPc(op);
|
|
||||||
|
|
||||||
f2345(key, rand, res_f2, res_f3, res_f4, res_f5);
|
|
||||||
if (compare_buffer(res_f2, 8, f2_exp, 8) != 0) {
|
|
||||||
fail("Fail: f2");
|
|
||||||
}
|
|
||||||
if (compare_buffer(res_f5, 6, f5_exp, 6) != 0) {
|
|
||||||
fail("Fail: f5");
|
|
||||||
}
|
|
||||||
if (compare_buffer(res_f3, 16, f3_exp, 16) != 0) {
|
|
||||||
fail("Fail: f3");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
doit (void)
|
|
||||||
{
|
|
||||||
/* Test set 1 #5.3 */
|
|
||||||
do_f2f3f5(H("465b5ce8 b199b49f aa5f0a2e e238a6bc"),
|
|
||||||
H("23553cbe 9637a89d 218ae64d ae47bf35"),
|
|
||||||
H("cdc202d5 123e20f6 2b6d676a c72cb318"),
|
|
||||||
H("a54211d5 e3ba50bf"), H("aa689c64 8370"),
|
|
||||||
H("b40ba9a3 c58b2a05 bbf0d987 b21bf8cb"));
|
|
||||||
|
|
||||||
/* Test set 2 #5.4 */
|
|
||||||
do_f2f3f5(H("0396eb31 7b6d1c36 f19c1c84 cd6ffd16"),
|
|
||||||
H("c00d6031 03dcee52 c4478119 494202e8"),
|
|
||||||
H("ff53bade 17df5d4e 793073ce 9d7579fa"),
|
|
||||||
H("d3a628ed 988620f0"), H("c4778399 5f72"),
|
|
||||||
H("58c433ff 7a7082ac d424220f 2b67c556"));
|
|
||||||
|
|
||||||
/* Test set 3 #5.5 */
|
|
||||||
do_f2f3f5(H("fec86ba6 eb707ed0 8905757b 1bb44b8f"),
|
|
||||||
H("9f7c8d02 1accf4db 213ccff0 c7f71a6a"),
|
|
||||||
H("dbc59adc b6f9a0ef 735477b7 fadf8374"),
|
|
||||||
H("8011c48c 0c214ed2"), H("33484dc2 136b"),
|
|
||||||
H("5dbdbb29 54e8f3cd e665b046 179a5098"));
|
|
||||||
|
|
||||||
/* Test set 4 #5.6 */
|
|
||||||
do_f2f3f5(H("9e5944ae a94b8116 5c82fbf9 f32db751"),
|
|
||||||
H("ce83dbc5 4ac0274a 157c17f8 0d017bd6"),
|
|
||||||
H("223014c5 806694c0 07ca1eee f57f004f"),
|
|
||||||
H("f365cd68 3cd92e96"), H("f0b9c08a d02e"),
|
|
||||||
H("e203edb3 971574f5 a94b0d61 b816345d"));
|
|
||||||
|
|
||||||
/* Test set 5 #5.7 */
|
|
||||||
do_f2f3f5(H("4ab1deb0 5ca6ceb0 51fc98e7 7d026a84"),
|
|
||||||
H("74b0cd60 31a1c833 9b2b6ce2 b8c4a186"),
|
|
||||||
H("2d16c5cd 1fdf6b22 383584e3 bef2a8d8"),
|
|
||||||
H("5860fc1b ce351e7e"), H("31e11a60 9118"),
|
|
||||||
H("7657766b 373d1c21 38f307e3 de9242f9"));
|
|
||||||
|
|
||||||
/* Test set 6 #5.8 */
|
|
||||||
do_f2f3f5(H("6c38a116 ac280c45 4f59332e e35c8c4f"),
|
|
||||||
H("ee6466bc 96202c5a 557abbef f8babf63"),
|
|
||||||
H("1ba00a1a 7c6700ac 8c3ff3e9 6ad08725"),
|
|
||||||
H("16c8233f 05a0ac28"), H("45b0f69a b06c"),
|
|
||||||
H("3f8c7587 fe8e4b23 3af676ae de30ba3b"));
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "test_utils.h"
|
|
||||||
#include "test_fd.h"
|
|
||||||
|
|
||||||
#include "auc.h"
|
|
||||||
|
|
||||||
static
|
|
||||||
void do_f4f5star(uint8_t *key, uint8_t *rand, uint8_t *op, uint8_t *f4_exp,
|
|
||||||
uint8_t *f5star_exp)
|
|
||||||
{
|
|
||||||
uint8_t res_f2[8];
|
|
||||||
uint8_t res_f5[6];
|
|
||||||
uint8_t res_f3[16];
|
|
||||||
uint8_t res_f4[16];
|
|
||||||
uint8_t res_f5star[6];
|
|
||||||
|
|
||||||
SetOPc(op);
|
|
||||||
|
|
||||||
f2345(key, rand, res_f2, res_f3, res_f4, res_f5);
|
|
||||||
if (compare_buffer(res_f4, 16, f4_exp, 16) != 0) {
|
|
||||||
fail("Fail: f4");
|
|
||||||
}
|
|
||||||
f5star(key, rand, res_f5star);
|
|
||||||
if (compare_buffer(res_f5star, 6, f5star_exp, 6) != 0) {
|
|
||||||
fail("Fail: f5star");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
doit (void)
|
|
||||||
{
|
|
||||||
/* Test set 1 #6.3 */
|
|
||||||
do_f4f5star(H("465b5ce8 b199b49f aa5f0a2e e238a6bc"),
|
|
||||||
H("23553cbe 9637a89d 218ae64d ae47bf35"),
|
|
||||||
H("cdc202d5 123e20f6 2b6d676a c72cb318"),
|
|
||||||
H("f769bcd7 51044604 12767271 1c6d3441"),
|
|
||||||
H("451e8bec a43b"));
|
|
||||||
/* Test set 2 #6.4 */
|
|
||||||
do_f4f5star(H("0396eb31 7b6d1c36 f19c1c84 cd6ffd16"),
|
|
||||||
H("c00d6031 03dcee52 c4478119 494202e8"),
|
|
||||||
H("ff53bade 17df5d4e 793073ce 9d7579fa"),
|
|
||||||
H("21a8c1f9 29702adb 3e738488 b9f5c5da"),
|
|
||||||
H("30f11970 61c1"));
|
|
||||||
/* Test set 3 #6.5 */
|
|
||||||
do_f4f5star(H("fec86ba6 eb707ed0 8905757b 1bb44b8f"),
|
|
||||||
H("9f7c8d02 1accf4db 213ccff0 c7f71a6a"),
|
|
||||||
H("dbc59adc b6f9a0ef 735477b7 fadf8374"),
|
|
||||||
H("59a92d3b 476a0443 487055cf 88b2307b"),
|
|
||||||
H("deacdd84 8cc6"));
|
|
||||||
/* Test set 4 #6.5 */
|
|
||||||
do_f4f5star(H("9e5944ae a94b8116 5c82fbf9 f32db751"),
|
|
||||||
H("ce83dbc5 4ac0274a 157c17f8 0d017bd6"),
|
|
||||||
H("223014c5 806694c0 07ca1eee f57f004f"),
|
|
||||||
H("0c4524ad eac041c4 dd830d20 854fc46b"),
|
|
||||||
H("6085a86c 6f63"));
|
|
||||||
/* Test set 5 #6.6 */
|
|
||||||
do_f4f5star(H("4ab1deb0 5ca6ceb0 51fc98e7 7d026a84"),
|
|
||||||
H("74b0cd60 31a1c833 9b2b6ce2 b8c4a186"),
|
|
||||||
H("2d16c5cd 1fdf6b22 383584e3 bef2a8d8"),
|
|
||||||
H("1c42e960 d89b8fa9 9f2744e0 708ccb53"),
|
|
||||||
H("fe2555e5 4aa9"));
|
|
||||||
/* Test set 6 #6.7 */
|
|
||||||
do_f4f5star(H("6c38a116 ac280c45 4f59332e e35c8c4f"),
|
|
||||||
H("ee6466bc 96202c5a 557abbef f8babf63"),
|
|
||||||
H("1ba00a1a 7c6700ac 8c3ff3e9 6ad08725"),
|
|
||||||
H("a7466cc1 e6b2a133 7d49d3b6 6e95d7b4"),
|
|
||||||
H("1f53cd2b 1113"));
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "test_utils.h"
|
|
||||||
#include "test_fd.h"
|
|
||||||
|
|
||||||
#include "auc.h"
|
|
||||||
|
|
||||||
static
|
|
||||||
void do_derive_kasme(uint8_t *sn_id, uint8_t *sqn, uint8_t *ak,
|
|
||||||
uint8_t *ck, uint8_t *ik, uint8_t *kasme_exp)
|
|
||||||
{
|
|
||||||
uint8_t kasme[32];
|
|
||||||
derive_kasme(ck, ik, sn_id, sqn, ak, kasme);
|
|
||||||
|
|
||||||
if (compare_buffer(kasme, 32, kasme_exp, 32) != 0) {
|
|
||||||
fail("Fail: derive_kasme\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
doit (void)
|
|
||||||
{
|
|
||||||
/* 20834 -> 024830 SNid */
|
|
||||||
do_derive_kasme(H("024830"), H("FD8EEF40DF7D"), H("AA689C648370"),
|
|
||||||
H("B40BA9A3C58B2A05BBF0D987B21BF8CB"),
|
|
||||||
H("F769BCD751044604127672711C6D3441"),
|
|
||||||
H("238E457E0F758BADBCA8D34BB2612C10"
|
|
||||||
"428D426757CB5553B2B184FA64BFC549"));
|
|
||||||
do_derive_kasme(H("02F843"), H("FD8EEF40DF7D"), H("AA689C648370"),
|
|
||||||
H("B40BA9A3C58B2A05BBF0D987B21BF8CB"),
|
|
||||||
H("F769BCD751044604127672711C6D3441"),
|
|
||||||
H("BD7A0903A7D0F68767EE2F5C90CB7D7D"
|
|
||||||
"835998D940AFDBF73173E63567C5B894"));
|
|
||||||
do_derive_kasme(H("21F354"), H("FD8EEF40DF7D"), H("AA689C648370"),
|
|
||||||
H("B40BA9A3C58B2A05BBF0D987B21BF8CB"),
|
|
||||||
H("F769BCD751044604127672711C6D3441"),
|
|
||||||
H("546A79BC6D1613A72A4D631EE0351D66"
|
|
||||||
"036B2A0C44A3831BE6D365E24F023013"));
|
|
||||||
do_derive_kasme(H("024830"), H("FF9BB4D0B607"), H("AA689C648370"),
|
|
||||||
H("B40BA9A3C58B2A05BBF0D987B21BF8CB"),
|
|
||||||
H("F769BCD751044604127672711C6D3441"),
|
|
||||||
H("564CB4D2007E4F293B67D9B29392A64A"
|
|
||||||
"DD4C776B133D895AF6499AA6882AAB62"));
|
|
||||||
do_derive_kasme(H("02F843"), H("FF9BB4D0B607"), H("AA689C648370"),
|
|
||||||
H("B40BA9A3C58B2A05BBF0D987B21BF8CB"),
|
|
||||||
H("F769BCD751044604127672711C6D3441"),
|
|
||||||
H("34865EB0DC9A6D788A905C0514529BF5"
|
|
||||||
"88485DA817FFBE92E9A9B4D033B8CC6F"));
|
|
||||||
do_derive_kasme(H("21F354"), H("FF9BB4D0B607"), H("AA689C648370"),
|
|
||||||
H("B40BA9A3C58B2A05BBF0D987B21BF8CB"),
|
|
||||||
H("F769BCD751044604127672711C6D3441"),
|
|
||||||
H("9EA141DA4B24CDEBC8F5FB3F61A05112"
|
|
||||||
"16681F121199B23EBCFACC75B358BE43"));
|
|
||||||
}
|
|
||||||
@@ -1,274 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2004-2012 Free Software Foundation, Inc.
|
|
||||||
*
|
|
||||||
* Author: Simon Josefsson
|
|
||||||
*
|
|
||||||
* This file is part of GnuTLS.
|
|
||||||
*
|
|
||||||
* GnuTLS is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* GnuTLS is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with GnuTLS; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#include "test_utils.h"
|
|
||||||
|
|
||||||
int debug = 0;
|
|
||||||
int error_count = 0;
|
|
||||||
int break_on_error = 0;
|
|
||||||
|
|
||||||
/* -1 means invalid */
|
|
||||||
static const signed char hex_digits[0x100] =
|
|
||||||
{
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned
|
|
||||||
decode_hex_length(const char *h)
|
|
||||||
{
|
|
||||||
const unsigned char *hex = (const unsigned char *) h;
|
|
||||||
unsigned count;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
for (count = i = 0; hex[i]; i++)
|
|
||||||
{
|
|
||||||
if (isspace(hex[i]))
|
|
||||||
continue;
|
|
||||||
if (hex_digits[hex[i]] < 0)
|
|
||||||
abort();
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count % 2)
|
|
||||||
abort();
|
|
||||||
return count / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
decode_hex(uint8_t *dst, const char *h)
|
|
||||||
{
|
|
||||||
const unsigned char *hex = (const unsigned char *) h;
|
|
||||||
unsigned i = 0;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
int high, low;
|
|
||||||
|
|
||||||
while (*hex && isspace(*hex))
|
|
||||||
hex++;
|
|
||||||
|
|
||||||
if (!*hex)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
high = hex_digits[*hex++];
|
|
||||||
if (high < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
while (*hex && isspace(*hex))
|
|
||||||
hex++;
|
|
||||||
|
|
||||||
if (!*hex)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
low = hex_digits[*hex++];
|
|
||||||
if (low < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dst[i++] = (high << 4) | low;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *
|
|
||||||
decode_hex_dup(const char *hex)
|
|
||||||
{
|
|
||||||
uint8_t *p;
|
|
||||||
unsigned length = decode_hex_length(hex);
|
|
||||||
|
|
||||||
p = malloc(length * sizeof(uint8_t));
|
|
||||||
|
|
||||||
if (decode_hex(p, hex))
|
|
||||||
return p;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
free(p);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fail (const char *format, ...)
|
|
||||||
{
|
|
||||||
char str[1024];
|
|
||||||
va_list arg_ptr;
|
|
||||||
|
|
||||||
va_start (arg_ptr, format);
|
|
||||||
vsnprintf ( str, sizeof(str), format, arg_ptr);
|
|
||||||
va_end (arg_ptr);
|
|
||||||
fputs(str, stderr);
|
|
||||||
error_count++;
|
|
||||||
if (break_on_error)
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
success (const char *format, ...)
|
|
||||||
{
|
|
||||||
char str[1024];
|
|
||||||
va_list arg_ptr;
|
|
||||||
|
|
||||||
va_start (arg_ptr, format);
|
|
||||||
vsnprintf ( str, sizeof(str), format, arg_ptr);
|
|
||||||
va_end (arg_ptr);
|
|
||||||
fputs(str, stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
escapeprint (const char *str, size_t len)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
printf (" (length %d bytes):\n\t", (int) len);
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
if (((str[i] & 0xFF) >= 'A' && (str[i] & 0xFF) <= 'Z') ||
|
|
||||||
((str[i] & 0xFF) >= 'a' && (str[i] & 0xFF) <= 'z') ||
|
|
||||||
((str[i] & 0xFF) >= '0' && (str[i] & 0xFF) <= '9')
|
|
||||||
|| (str[i] & 0xFF) == ' ' || (str[i] & 0xFF) == '.')
|
|
||||||
printf ("%c", (str[i] & 0xFF));
|
|
||||||
else
|
|
||||||
printf ("\\x%02X", (str[i] & 0xFF));
|
|
||||||
if ((i + 1) % 16 == 0 && (i + 1) < len)
|
|
||||||
printf ("'\n\t'");
|
|
||||||
}
|
|
||||||
printf ("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hexprint (const void *_str, size_t len)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
const char* str = _str;
|
|
||||||
|
|
||||||
printf ("\t;; ");
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
printf ("%02x ", (str[i] & 0xFF));
|
|
||||||
if ((i + 1) % 8 == 0)
|
|
||||||
printf (" ");
|
|
||||||
if ((i + 1) % 16 == 0 && i + 1 < len)
|
|
||||||
printf ("\n\t;; ");
|
|
||||||
}
|
|
||||||
printf ("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
binprint (const void *_str, size_t len)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
const char* str = _str;
|
|
||||||
|
|
||||||
printf ("\t;; ");
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
printf ("%d%d%d%d%d%d%d%d ",
|
|
||||||
(str[i] & 0xFF) & 0x80 ? 1 : 0,
|
|
||||||
(str[i] & 0xFF) & 0x40 ? 1 : 0,
|
|
||||||
(str[i] & 0xFF) & 0x20 ? 1 : 0,
|
|
||||||
(str[i] & 0xFF) & 0x10 ? 1 : 0,
|
|
||||||
(str[i] & 0xFF) & 0x08 ? 1 : 0,
|
|
||||||
(str[i] & 0xFF) & 0x04 ? 1 : 0,
|
|
||||||
(str[i] & 0xFF) & 0x02 ? 1 : 0, (str[i] & 0xFF) & 0x01 ? 1 : 0);
|
|
||||||
if ((i + 1) % 3 == 0)
|
|
||||||
printf (" ");
|
|
||||||
if ((i + 1) % 6 == 0 && i + 1 < len)
|
|
||||||
printf ("\n\t;; ");
|
|
||||||
}
|
|
||||||
printf ("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
compare_buffer(uint8_t *buffer, uint32_t length_buffer,
|
|
||||||
uint8_t *pattern, uint32_t length_pattern)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
if (length_buffer != length_pattern) {
|
|
||||||
printf("Length mismatch, expecting %d bytes, got %d bytes\n", length_pattern,
|
|
||||||
length_buffer);
|
|
||||||
hexprint(buffer, length_buffer);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
for (i = 0; i < length_buffer; i++) {
|
|
||||||
if (pattern[i] != buffer[i]) {
|
|
||||||
printf("Expecting:\n");
|
|
||||||
hexprint(pattern, length_pattern);
|
|
||||||
printf("Received:\n");
|
|
||||||
hexprint(buffer, length_buffer);
|
|
||||||
printf("Mismatch fount in byte %d\nExpecting 0x%02x, got 0x%02x\n",
|
|
||||||
i, pattern[i], buffer[i]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, char *argv[])
|
|
||||||
{
|
|
||||||
do
|
|
||||||
if (strcmp (argv[argc - 1], "-v") == 0 ||
|
|
||||||
strcmp (argv[argc - 1], "--verbose") == 0)
|
|
||||||
debug = 1;
|
|
||||||
else if (strcmp (argv[argc - 1], "-b") == 0 ||
|
|
||||||
strcmp (argv[argc - 1], "--break-on-error") == 0)
|
|
||||||
break_on_error = 1;
|
|
||||||
else if (strcmp (argv[argc - 1], "-h") == 0 ||
|
|
||||||
strcmp (argv[argc - 1], "-?") == 0 ||
|
|
||||||
strcmp (argv[argc - 1], "--help") == 0)
|
|
||||||
{
|
|
||||||
printf ("Usage: %s [-vbh?] [--verbose] [--break-on-error] [--help]\n",
|
|
||||||
argv[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
while (argc-- > 1);
|
|
||||||
|
|
||||||
doit ();
|
|
||||||
|
|
||||||
if (debug || error_count > 0)
|
|
||||||
printf ("Self test `%s' finished with %d errors\n", argv[0], error_count);
|
|
||||||
|
|
||||||
return error_count ? 1 : 0;
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2004-2012 Free Software Foundation, Inc.
|
|
||||||
*
|
|
||||||
* Author: Simon Josefsson
|
|
||||||
*
|
|
||||||
* This file is part of GnuTLS.
|
|
||||||
*
|
|
||||||
* GnuTLS is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* GnuTLS is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with GnuTLS; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef UTILS_H
|
|
||||||
#define UTILS_H
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#ifndef __attribute__
|
|
||||||
#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
|
|
||||||
#define __attribute__(Spec) /* empty */
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern int debug;
|
|
||||||
extern int error_count;
|
|
||||||
extern int break_on_error;
|
|
||||||
|
|
||||||
extern uint8_t * decode_hex_dup(const char *hex);
|
|
||||||
extern int decode_hex(uint8_t *dst, const char *h);
|
|
||||||
extern unsigned decode_hex_length(const char *h);
|
|
||||||
|
|
||||||
#define H(x) decode_hex_dup(x)
|
|
||||||
#define HL(x) decode_hex_dup(x), decode_hex_length(x)
|
|
||||||
|
|
||||||
extern void fail (const char *format, ...)
|
|
||||||
__attribute__ ((format (printf, 1, 2)));
|
|
||||||
extern void success (const char *format, ...)
|
|
||||||
__attribute__ ((format (printf, 1, 2)));
|
|
||||||
|
|
||||||
extern void escapeprint (const char *str, size_t len);
|
|
||||||
extern void hexprint (const void *str, size_t len);
|
|
||||||
extern void binprint (const void *str, size_t len);
|
|
||||||
|
|
||||||
extern int
|
|
||||||
compare_buffer(uint8_t *buffer, uint32_t length_buffer,
|
|
||||||
uint8_t *pattern, uint32_t length_pattern);
|
|
||||||
|
|
||||||
/* This must be implemented elsewhere. */
|
|
||||||
extern void doit (void);
|
|
||||||
|
|
||||||
#endif /* UTILS_H */
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "test_utils.h"
|
|
||||||
#include "test_fd.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
doit (void)
|
|
||||||
{
|
|
||||||
s6a_fd_init();
|
|
||||||
|
|
||||||
sleep(1);
|
|
||||||
|
|
||||||
s6a_fd_stop();
|
|
||||||
|
|
||||||
success ("freediameter start/stop ok\n");
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
AM_CFLAGS = @ADD_CFLAGS@
|
|
||||||
AM_YFLAGS = -d
|
|
||||||
AM_LFLAGS = -o$(LEX_OUTPUT_ROOT).c
|
|
||||||
|
|
||||||
BUILT_SOURCE = hss_parser.h
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libutils.la
|
|
||||||
libutils_la_LDFLAGS = -all-static
|
|
||||||
libutils_la_SOURCES = \
|
|
||||||
hss_parser.y hss_scanner.l \
|
|
||||||
hss_config.h hss_config.c \
|
|
||||||
conversion.h conversion.c
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#include "conversion.h"
|
|
||||||
|
|
||||||
static const char hex_to_ascii_table[16] = {
|
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
|
|
||||||
};
|
|
||||||
|
|
||||||
static const signed char ascii_to_hex_table[0x100] = {
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
|
||||||
};
|
|
||||||
|
|
||||||
static const signed char ascii_to_dec_table[0x100] = {
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
||||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
|
||||||
};
|
|
||||||
|
|
||||||
void hexa_to_ascii(uint8_t *from, char *to, size_t length)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for(i = 0; i < length; i++) {
|
|
||||||
uint8_t upper = (from[i] & 0xf0) >> 4;
|
|
||||||
uint8_t lower = from[i] & 0x0f;
|
|
||||||
to[2 * i] = hex_to_ascii_table[upper];
|
|
||||||
to[2 * i + 1] = hex_to_ascii_table[lower];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int ascii_to_hex(uint8_t *dst, const char *h)
|
|
||||||
{
|
|
||||||
const unsigned char *hex = (const unsigned char *) h;
|
|
||||||
unsigned i = 0;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
int high, low;
|
|
||||||
|
|
||||||
while (*hex && isspace(*hex)) {
|
|
||||||
hex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!*hex) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
high = ascii_to_hex_table[*hex++];
|
|
||||||
if (high < 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (*hex && isspace(*hex)) {
|
|
||||||
hex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!*hex) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
low = ascii_to_hex_table[*hex++];
|
|
||||||
if (low < 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dst[i++] = (high << 4) | low;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int bcd_to_hex(uint8_t *dst, const char *h, int h_length)
|
|
||||||
{
|
|
||||||
const unsigned char *hex = (const unsigned char *) h;
|
|
||||||
unsigned i = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < h_length; i++) {
|
|
||||||
int value = ascii_to_dec_table[*hex++];
|
|
||||||
if (value < 0)
|
|
||||||
return -1;
|
|
||||||
dst[i] = value;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef CONVERSION_H_
|
|
||||||
#define CONVERSION_H_
|
|
||||||
|
|
||||||
void hexa_to_ascii(uint8_t *from, char *to, size_t length);
|
|
||||||
int ascii_to_hex(uint8_t *dst, const char *h);
|
|
||||||
int bcd_to_hex(uint8_t *dst, const char *h, int h_length);
|
|
||||||
|
|
||||||
#endif /* CONVERSION_H_ */
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
/*! \file hss_config.c
|
|
||||||
* \brief Base configuration for the HSS. Parse command line and configuration file
|
|
||||||
* \author Sebastien ROUX <sebastien.roux@eurecom.fr>
|
|
||||||
* \date 2013
|
|
||||||
* \version 0.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if HAVE_CONFIG_H
|
|
||||||
# include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "hss_parser.h"
|
|
||||||
|
|
||||||
/* YACC forward declarations */
|
|
||||||
extern int yyparse (struct hss_config_s *hss_config_p);
|
|
||||||
|
|
||||||
static int config_parse_command_line(int argc, char *argv[],
|
|
||||||
hss_config_t *hss_config_p);
|
|
||||||
static int config_parse_file(hss_config_t *hss_config_p);
|
|
||||||
static void display_banner(void);
|
|
||||||
static void config_display(hss_config_t *hss_config_p);
|
|
||||||
|
|
||||||
static struct option long_options[] = {
|
|
||||||
{ "config", 1, 0, 'c' },
|
|
||||||
{ "help", 0, 0, 'h' },
|
|
||||||
{ "version", 0, 0, 'v' },
|
|
||||||
{ 0, 0, 0, 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char option_string[] = "c:vh";
|
|
||||||
|
|
||||||
int config_init(int argc, char *argv[], hss_config_t *hss_config_p)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (hss_config_p == NULL) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
if ((ret = config_parse_command_line(argc, argv, hss_config_p)) != 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
display_banner();
|
|
||||||
if ((ret = config_parse_file(hss_config_p)) != 0) {
|
|
||||||
/* Parsing of the file failed. -> abort */
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
config_display(hss_config_p);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void display_banner(void)
|
|
||||||
{
|
|
||||||
fprintf(stdout, "==== EURECOM %s v%s ====\n", PACKAGE_NAME, PACKAGE_VERSION);
|
|
||||||
fprintf(stdout, "Please report any bug to: %s\n\n", PACKAGE_BUGREPORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usage(void)
|
|
||||||
{
|
|
||||||
display_banner();
|
|
||||||
fprintf(stdout, "Usage: openair_hss [options]\n\n");
|
|
||||||
fprintf(stdout, "Available options:\n");
|
|
||||||
fprintf(stdout, "\t--help\n\t-h\n");
|
|
||||||
fprintf(stdout, "\t\tPrint this help and return\n\n");
|
|
||||||
fprintf(stdout, "\t--config=<path>\n\t-c<path>\n");
|
|
||||||
fprintf(stdout, "\t\tSet the configuration file for hss\n");
|
|
||||||
fprintf(stdout, "\t\tSee template in conf dir\n\n");
|
|
||||||
fprintf(stdout, "\t--version\n\t-v\n");
|
|
||||||
fprintf(stdout, "\t\tPrint %s version and return\n", PACKAGE_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void config_display(hss_config_t *hss_config_p)
|
|
||||||
{
|
|
||||||
fprintf(stdout, "Configuration\n");
|
|
||||||
fprintf(stdout, "* Global:\n");
|
|
||||||
fprintf(stdout, "\t- File .............: %s\n", hss_config_p->config);
|
|
||||||
fprintf(stdout, "* MYSQL:\n");
|
|
||||||
fprintf(stdout, "\t- Server ...........: %s\n", hss_config_p->mysql_server);
|
|
||||||
fprintf(stdout, "\t- Database .........: %s\n", hss_config_p->mysql_database);
|
|
||||||
fprintf(stdout, "\t- User .............: %s\n", hss_config_p->mysql_user);
|
|
||||||
fprintf(stdout, "\t- Password .........: %s\n",
|
|
||||||
(hss_config_p->mysql_password == NULL) ? "None" : "*****");
|
|
||||||
fprintf(stdout, "* FreeDiameter:\n");
|
|
||||||
fprintf(stdout, "\t- Conf file ........: %s\n",
|
|
||||||
hss_config_p->freediameter_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int config_parse_command_line(int argc, char *argv[],
|
|
||||||
hss_config_t *hss_config_p)
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
int option_index = 0;
|
|
||||||
|
|
||||||
while ((c = getopt_long (argc, argv, option_string, long_options,
|
|
||||||
&option_index)) != -1) {
|
|
||||||
switch(c) {
|
|
||||||
case 'c': {
|
|
||||||
hss_config_p->config = strdup(optarg);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'v': {
|
|
||||||
/* We display version and return immediately */
|
|
||||||
display_banner();
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
case 'h': {
|
|
||||||
usage();
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int config_parse_file(hss_config_t *hss_config_p)
|
|
||||||
{
|
|
||||||
extern FILE *yyin;
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
if (hss_config_p == NULL) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
if (hss_config_p->config == NULL) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Parsing configuration file: %s\n", hss_config_p->config);
|
|
||||||
|
|
||||||
yyin = fopen(hss_config_p->config, "r");
|
|
||||||
if (!yyin) {
|
|
||||||
/* We failed to open the file */
|
|
||||||
fprintf(stderr, "Unable to open the configuration file: %s (%d:%s)\n",
|
|
||||||
hss_config_p->config, errno, strerror(errno));
|
|
||||||
return errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Call the yacc parser */
|
|
||||||
ret = yyparse(hss_config_p);
|
|
||||||
|
|
||||||
/* Close the file descriptor */
|
|
||||||
if (fclose(yyin) != 0) {
|
|
||||||
fprintf(stderr, "Unable to close the configuration file: %s (%d:%s)\n",
|
|
||||||
hss_config_p->config, errno, strerror(errno));
|
|
||||||
return errno;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#ifndef HSS_CONFIG_H_
|
|
||||||
#define HSS_CONFIG_H_
|
|
||||||
|
|
||||||
typedef struct hss_config_s {
|
|
||||||
char *mysql_server;
|
|
||||||
char *mysql_user;
|
|
||||||
char *mysql_password;
|
|
||||||
char *mysql_database;
|
|
||||||
|
|
||||||
/* The freediameter configuration file */
|
|
||||||
char *freediameter_config;
|
|
||||||
|
|
||||||
/* THe HSS global configuration file */
|
|
||||||
char *config;
|
|
||||||
} hss_config_t;
|
|
||||||
|
|
||||||
int config_init(int argc, char *argv[], hss_config_t *hss_config_p);
|
|
||||||
|
|
||||||
#endif /* HSS_CONFIG_H_ */
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
/* For development only : */
|
|
||||||
%debug
|
|
||||||
%error-verbose
|
|
||||||
|
|
||||||
%parse-param {struct hss_config_s *hss_config_p}
|
|
||||||
|
|
||||||
/* Keep track of location */
|
|
||||||
%locations
|
|
||||||
%defines
|
|
||||||
%pure-parser
|
|
||||||
|
|
||||||
%{
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
#include "hss_parser.h"
|
|
||||||
|
|
||||||
void yyerror (YYLTYPE *llocp, struct hss_config_s *hss_config_p, const char *s);
|
|
||||||
|
|
||||||
extern int yywrap();
|
|
||||||
extern int yylex();
|
|
||||||
|
|
||||||
/* The Lex parser prototype */
|
|
||||||
int fddlex(YYSTYPE *lvalp, YYLTYPE *llocp);
|
|
||||||
%}
|
|
||||||
|
|
||||||
/* Values returned by lex for token */
|
|
||||||
%union {
|
|
||||||
char *string; /* The string is allocated by strdup in lex.*/
|
|
||||||
int integer; /* Store integer values */
|
|
||||||
}
|
|
||||||
|
|
||||||
%token <string> QSTRING
|
|
||||||
%token <integer> INTEGER
|
|
||||||
|
|
||||||
%token LEX_ERROR
|
|
||||||
%token FDCONF
|
|
||||||
%token MYSQL_USER
|
|
||||||
%token MYSQL_SERVER
|
|
||||||
%token MYSQL_PASS
|
|
||||||
%token MYSQL_DB
|
|
||||||
|
|
||||||
%%
|
|
||||||
conffile: /* Empty is OK -- for simplicity here, we reject in daemon later */
|
|
||||||
| conffile mysql_db
|
|
||||||
| conffile mysql_server
|
|
||||||
| conffile mysql_user
|
|
||||||
| conffile mysql_pass
|
|
||||||
| conffile fdconf
|
|
||||||
| conffile errors
|
|
||||||
{
|
|
||||||
yyerror(&yylloc, hss_config_p, "An error occurred while parsing the configuration file");
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
mysql_db: MYSQL_DB '=' QSTRING ';'
|
|
||||||
{
|
|
||||||
hss_config_p->mysql_database = $3;
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
mysql_pass: MYSQL_PASS '=' QSTRING ';'
|
|
||||||
{
|
|
||||||
hss_config_p->mysql_password = $3;
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
mysql_user: MYSQL_USER '=' QSTRING ';'
|
|
||||||
{
|
|
||||||
hss_config_p->mysql_user = $3;
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
mysql_server: MYSQL_SERVER '=' QSTRING ';'
|
|
||||||
{
|
|
||||||
hss_config_p->mysql_server = $3;
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
fdconf: FDCONF '=' QSTRING ';'
|
|
||||||
{
|
|
||||||
hss_config_p->freediameter_config = $3;
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
/* Lexical or syntax error */
|
|
||||||
errors: LEX_ERROR
|
|
||||||
| error
|
|
||||||
;
|
|
||||||
%%
|
|
||||||
|
|
||||||
void yyerror(YYLTYPE *llocp, struct hss_config_s *hss_config_p, const char *str)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Error in %s ( on line %i column %i -> line %i column %i) : %s\n",
|
|
||||||
hss_config_p->freediameter_config, llocp->first_line, llocp->first_column,
|
|
||||||
llocp->last_line, llocp->last_column, str);
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Eurecom OpenAirInterface
|
|
||||||
Copyright(c) 1999 - 2013 Eurecom
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms and conditions of the GNU General Public License,
|
|
||||||
version 2, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
The full GNU General Public License is included in this distribution in
|
|
||||||
the file called "COPYING".
|
|
||||||
|
|
||||||
Contact Information
|
|
||||||
Openair Admin: openair_admin@eurecom.fr
|
|
||||||
Openair Tech : openair_tech@eurecom.fr
|
|
||||||
Forums : http://forums.eurecom.fr/openairinterface
|
|
||||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
||||||
06410 Biot FRANCE
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
/* Lex configuration parser.
|
|
||||||
*
|
|
||||||
* This file defines the token for parsing the configuration file
|
|
||||||
*
|
|
||||||
* Note : This module is NOT thread-safe. All processing must be done from one thread only.
|
|
||||||
*/
|
|
||||||
%{
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "hss_config.h"
|
|
||||||
/* Include yacc tokens definitions */
|
|
||||||
#include "hss_parser.h"
|
|
||||||
|
|
||||||
/* Update the column information */
|
|
||||||
#ifdef DEBUG_LEX
|
|
||||||
#define YY_USER_ACTION { \
|
|
||||||
yylloc->first_column = yylloc->last_column + 1; \
|
|
||||||
yylloc->last_column = yylloc->first_column + yyleng - 1; \
|
|
||||||
TRACE_DEBUG(FULL, \
|
|
||||||
"(%d:%d-%d:%d) matched rule %d, length=%d, txt='%s'\n", \
|
|
||||||
yylloc->first_line, yylloc->first_column, \
|
|
||||||
yylloc->last_line, yylloc->last_column, \
|
|
||||||
yy_act, yyleng, yytext); \
|
|
||||||
}
|
|
||||||
#else /* DEBUG_LEX */
|
|
||||||
#define YY_USER_ACTION { \
|
|
||||||
yylloc->first_column = yylloc->last_column + 1; \
|
|
||||||
yylloc->last_column = yylloc->first_column + yyleng - 1; \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define YY_NO_INPUT
|
|
||||||
%}
|
|
||||||
|
|
||||||
%option bison-bridge
|
|
||||||
%option bison-locations
|
|
||||||
%option noyywrap
|
|
||||||
%option nounput
|
|
||||||
|
|
||||||
/* Quoted string. Multilines do not match. */
|
|
||||||
qstring \"[^\"\n]*\"
|
|
||||||
|
|
||||||
%%
|
|
||||||
|
|
||||||
/* List of patterns and actions */
|
|
||||||
|
|
||||||
<*>\n {
|
|
||||||
/* Update the line count */
|
|
||||||
yylloc->first_line++;
|
|
||||||
yylloc->last_line++;
|
|
||||||
yylloc->last_column=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
<*>([[:space:]]{-}[\n])+ ; /* Eat all spaces, not new lines */
|
|
||||||
<*>#.*$ ; /* Eat all comments */
|
|
||||||
|
|
||||||
{qstring} {
|
|
||||||
/* First copy the string without the quotes for use in the yacc parser */
|
|
||||||
if ((yylval->string = strdup(yytext+1)) == NULL) { /* This allocates one useless tail char but... it's easier :D */
|
|
||||||
return LEX_ERROR;/* on error, trig an error in yacc parser */
|
|
||||||
}
|
|
||||||
yylval->string[yyleng-2] = '\0';
|
|
||||||
|
|
||||||
/* the yacc parser will check the string is valid */
|
|
||||||
return QSTRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[:digit:]]+ {
|
|
||||||
/* Convert this to an integer value */
|
|
||||||
int ret = sscanf(yytext, "%i", &yylval->integer);
|
|
||||||
if (ret != 1) {
|
|
||||||
/* No matching: an error occurred */
|
|
||||||
fprintf(stderr, "Unable to convert the value '%s' to a valid number: %s\n",
|
|
||||||
yytext, strerror(errno));
|
|
||||||
return LEX_ERROR; /* trig an error in yacc parser */
|
|
||||||
/* Maybe we could REJECT instead of failing here? */
|
|
||||||
}
|
|
||||||
return INTEGER;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Full words tokens (keywords) */
|
|
||||||
(?i:"FD_conf") { return FDCONF; }
|
|
||||||
(?i:"MYSQL_server") { return MYSQL_SERVER; }
|
|
||||||
(?i:"MYSQL_user") { return MYSQL_USER; }
|
|
||||||
(?i:"MYSQL_pass") { return MYSQL_PASS; }
|
|
||||||
(?i:"MYSQL_db") { return MYSQL_DB; }
|
|
||||||
|
|
||||||
/* Valid single characters for yyparse */
|
|
||||||
<*>[=,:;{}] { return yytext[0]; }
|
|
||||||
|
|
||||||
<*>[[:alnum:]]+ | /* This rule is only useful to print a complete token in error messages */
|
|
||||||
/* Unrecognized character */
|
|
||||||
<*>. {
|
|
||||||
fprintf(stderr, "Unrecognized text on line %d col %d: '%s'.\n",
|
|
||||||
yylloc->first_line, yylloc->first_column, yytext);
|
|
||||||
return LEX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
%%
|
|
||||||
@@ -1,592 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1991, 1993
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the University nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SYS_QUEUE_H_
|
|
||||||
#define _SYS_QUEUE_H_
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file defines five types of data structures: singly-linked lists,
|
|
||||||
* lists, simple queues, tail queues, and circular queues.
|
|
||||||
*
|
|
||||||
* A singly-linked list is headed by a single forward pointer. The
|
|
||||||
* elements are singly linked for minimum space and pointer manipulation
|
|
||||||
* overhead at the expense of O(n) removal for arbitrary elements. New
|
|
||||||
* elements can be added to the list after an existing element or at the
|
|
||||||
* head of the list. Elements being removed from the head of the list
|
|
||||||
* should use the explicit macro for this purpose for optimum
|
|
||||||
* efficiency. A singly-linked list may only be traversed in the forward
|
|
||||||
* direction. Singly-linked lists are ideal for applications with large
|
|
||||||
* datasets and few or no removals or for implementing a LIFO queue.
|
|
||||||
*
|
|
||||||
* A list is headed by a single forward pointer (or an array of forward
|
|
||||||
* pointers for a hash table header). The elements are doubly linked
|
|
||||||
* so that an arbitrary element can be removed without a need to
|
|
||||||
* traverse the list. New elements can be added to the list before
|
|
||||||
* or after an existing element or at the head of the list. A list
|
|
||||||
* may only be traversed in the forward direction.
|
|
||||||
*
|
|
||||||
* A simple queue is headed by a pair of pointers, one the head of the
|
|
||||||
* list and the other to the tail of the list. The elements are singly
|
|
||||||
* linked to save space, so elements can only be removed from the
|
|
||||||
* head of the list. New elements can be added to the list after
|
|
||||||
* an existing element, at the head of the list, or at the end of the
|
|
||||||
* list. A simple queue may only be traversed in the forward direction.
|
|
||||||
*
|
|
||||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
|
||||||
* list and the other to the tail of the list. The elements are doubly
|
|
||||||
* linked so that an arbitrary element can be removed without a need to
|
|
||||||
* traverse the list. New elements can be added to the list before or
|
|
||||||
* after an existing element, at the head of the list, or at the end of
|
|
||||||
* the list. A tail queue may be traversed in either direction.
|
|
||||||
*
|
|
||||||
* A circle queue is headed by a pair of pointers, one to the head of the
|
|
||||||
* list and the other to the tail of the list. The elements are doubly
|
|
||||||
* linked so that an arbitrary element can be removed without a need to
|
|
||||||
* traverse the list. New elements can be added to the list before or after
|
|
||||||
* an existing element, at the head of the list, or at the end of the list.
|
|
||||||
* A circle queue may be traversed in either direction, but has a more
|
|
||||||
* complex end of list detection.
|
|
||||||
*
|
|
||||||
* For details on the use of these macros, see the queue(3) manual page.
|
|
||||||
* SLIST LIST STAILQ TAILQ CIRCLEQ
|
|
||||||
* _HEAD + + + + +
|
|
||||||
* _HEAD_INITIALIZER + + + + +
|
|
||||||
* _ENTRY + + + + +
|
|
||||||
* _INIT + + + + +
|
|
||||||
* _EMPTY + + + + +
|
|
||||||
* _FIRST + + + + +
|
|
||||||
* _NEXT + + + + +
|
|
||||||
* _PREV - - - + +
|
|
||||||
* _LAST - - + + +
|
|
||||||
* _FOREACH + + + + +
|
|
||||||
* _FOREACH_REVERSE - - - + +
|
|
||||||
* _INSERT_HEAD + + + + +
|
|
||||||
* _INSERT_BEFORE - + - + +
|
|
||||||
* _INSERT_AFTER + + + + +
|
|
||||||
* _INSERT_TAIL - - + + +
|
|
||||||
* _REMOVE_HEAD + - + - -
|
|
||||||
* _REMOVE + + + + +
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List definitions.
|
|
||||||
*/
|
|
||||||
#define LIST_HEAD(name, type) \
|
|
||||||
struct name { \
|
|
||||||
struct type *lh_first; /* first element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define LIST_HEAD_INITIALIZER(head) \
|
|
||||||
{ NULL }
|
|
||||||
|
|
||||||
#define LIST_ENTRY(type) \
|
|
||||||
struct { \
|
|
||||||
struct type *le_next; /* next element */ \
|
|
||||||
struct type **le_prev; /* address of previous next element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List functions.
|
|
||||||
*/
|
|
||||||
#define LIST_INIT(head) do { \
|
|
||||||
(head)->lh_first = NULL; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
|
||||||
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
|
||||||
(listelm)->field.le_next->field.le_prev = \
|
|
||||||
&(elm)->field.le_next; \
|
|
||||||
(listelm)->field.le_next = (elm); \
|
|
||||||
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
|
||||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
|
||||||
(elm)->field.le_next = (listelm); \
|
|
||||||
*(listelm)->field.le_prev = (elm); \
|
|
||||||
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
|
||||||
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
|
||||||
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
|
||||||
(head)->lh_first = (elm); \
|
|
||||||
(elm)->field.le_prev = &(head)->lh_first; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define LIST_REMOVE(elm, field) do { \
|
|
||||||
if ((elm)->field.le_next != NULL) \
|
|
||||||
(elm)->field.le_next->field.le_prev = \
|
|
||||||
(elm)->field.le_prev; \
|
|
||||||
*(elm)->field.le_prev = (elm)->field.le_next; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define LIST_FOREACH(var, head, field) \
|
|
||||||
for ((var) = ((head)->lh_first); \
|
|
||||||
(var); \
|
|
||||||
(var) = ((var)->field.le_next))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List access methods.
|
|
||||||
*/
|
|
||||||
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
|
|
||||||
#define LIST_FIRST(head) ((head)->lh_first)
|
|
||||||
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Singly-linked List definitions.
|
|
||||||
*/
|
|
||||||
#define SLIST_HEAD(name, type) \
|
|
||||||
struct name { \
|
|
||||||
struct type *slh_first; /* first element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SLIST_HEAD_INITIALIZER(head) \
|
|
||||||
{ NULL }
|
|
||||||
|
|
||||||
#define SLIST_ENTRY(type) \
|
|
||||||
struct { \
|
|
||||||
struct type *sle_next; /* next element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Singly-linked List functions.
|
|
||||||
*/
|
|
||||||
#define SLIST_INIT(head) do { \
|
|
||||||
(head)->slh_first = NULL; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
|
||||||
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
|
||||||
(slistelm)->field.sle_next = (elm); \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
|
||||||
(elm)->field.sle_next = (head)->slh_first; \
|
|
||||||
(head)->slh_first = (elm); \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define SLIST_REMOVE_HEAD(head, field) do { \
|
|
||||||
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define SLIST_REMOVE(head, elm, type, field) do { \
|
|
||||||
if ((head)->slh_first == (elm)) { \
|
|
||||||
SLIST_REMOVE_HEAD((head), field); \
|
|
||||||
} \
|
|
||||||
else { \
|
|
||||||
struct type *curelm = (head)->slh_first; \
|
|
||||||
while(curelm->field.sle_next != (elm)) \
|
|
||||||
curelm = curelm->field.sle_next; \
|
|
||||||
curelm->field.sle_next = \
|
|
||||||
curelm->field.sle_next->field.sle_next; \
|
|
||||||
} \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define SLIST_FOREACH(var, head, field) \
|
|
||||||
for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Singly-linked List access methods.
|
|
||||||
*/
|
|
||||||
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
|
|
||||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
|
||||||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Singly-linked Tail queue declarations.
|
|
||||||
*/
|
|
||||||
#define STAILQ_HEAD(name, type) \
|
|
||||||
struct name { \
|
|
||||||
struct type *stqh_first; /* first element */ \
|
|
||||||
struct type **stqh_last; /* addr of last next element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define STAILQ_HEAD_INITIALIZER(head) \
|
|
||||||
{ NULL, &(head).stqh_first }
|
|
||||||
|
|
||||||
#define STAILQ_ENTRY(type) \
|
|
||||||
struct { \
|
|
||||||
struct type *stqe_next; /* next element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Singly-linked Tail queue functions.
|
|
||||||
*/
|
|
||||||
#define STAILQ_INIT(head) do { \
|
|
||||||
(head)->stqh_first = NULL; \
|
|
||||||
(head)->stqh_last = &(head)->stqh_first; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
|
|
||||||
if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \
|
|
||||||
(head)->stqh_last = &(elm)->field.stqe_next; \
|
|
||||||
(head)->stqh_first = (elm); \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
|
|
||||||
(elm)->field.stqe_next = NULL; \
|
|
||||||
*(head)->stqh_last = (elm); \
|
|
||||||
(head)->stqh_last = &(elm)->field.stqe_next; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
|
||||||
if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\
|
|
||||||
(head)->stqh_last = &(elm)->field.stqe_next; \
|
|
||||||
(listelm)->field.stqe_next = (elm); \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define STAILQ_REMOVE_HEAD(head, field) do { \
|
|
||||||
if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
|
|
||||||
(head)->stqh_last = &(head)->stqh_first; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define STAILQ_REMOVE(head, elm, type, field) do { \
|
|
||||||
if ((head)->stqh_first == (elm)) { \
|
|
||||||
STAILQ_REMOVE_HEAD((head), field); \
|
|
||||||
} else { \
|
|
||||||
struct type *curelm = (head)->stqh_first; \
|
|
||||||
while (curelm->field.stqe_next != (elm)) \
|
|
||||||
curelm = curelm->field.stqe_next; \
|
|
||||||
if ((curelm->field.stqe_next = \
|
|
||||||
curelm->field.stqe_next->field.stqe_next) == NULL) \
|
|
||||||
(head)->stqh_last = &(curelm)->field.stqe_next; \
|
|
||||||
} \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define STAILQ_FOREACH(var, head, field) \
|
|
||||||
for ((var) = ((head)->stqh_first); \
|
|
||||||
(var); \
|
|
||||||
(var) = ((var)->field.stqe_next))
|
|
||||||
|
|
||||||
#define STAILQ_CONCAT(head1, head2) do { \
|
|
||||||
if (!STAILQ_EMPTY((head2))) { \
|
|
||||||
*(head1)->stqh_last = (head2)->stqh_first; \
|
|
||||||
(head1)->stqh_last = (head2)->stqh_last; \
|
|
||||||
STAILQ_INIT((head2)); \
|
|
||||||
} \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Singly-linked Tail queue access methods.
|
|
||||||
*/
|
|
||||||
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
|
|
||||||
#define STAILQ_FIRST(head) ((head)->stqh_first)
|
|
||||||
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Simple queue definitions.
|
|
||||||
*/
|
|
||||||
#define SIMPLEQ_HEAD(name, type) \
|
|
||||||
struct name { \
|
|
||||||
struct type *sqh_first; /* first element */ \
|
|
||||||
struct type **sqh_last; /* addr of last next element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SIMPLEQ_HEAD_INITIALIZER(head) \
|
|
||||||
{ NULL, &(head).sqh_first }
|
|
||||||
|
|
||||||
#define SIMPLEQ_ENTRY(type) \
|
|
||||||
struct { \
|
|
||||||
struct type *sqe_next; /* next element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Simple queue functions.
|
|
||||||
*/
|
|
||||||
#define SIMPLEQ_INIT(head) do { \
|
|
||||||
(head)->sqh_first = NULL; \
|
|
||||||
(head)->sqh_last = &(head)->sqh_first; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
|
||||||
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
|
||||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
|
||||||
(head)->sqh_first = (elm); \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
|
||||||
(elm)->field.sqe_next = NULL; \
|
|
||||||
*(head)->sqh_last = (elm); \
|
|
||||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
|
||||||
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
|
|
||||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
|
||||||
(listelm)->field.sqe_next = (elm); \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
|
|
||||||
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
|
|
||||||
(head)->sqh_last = &(head)->sqh_first; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define SIMPLEQ_REMOVE(head, elm, type, field) do { \
|
|
||||||
if ((head)->sqh_first == (elm)) { \
|
|
||||||
SIMPLEQ_REMOVE_HEAD((head), field); \
|
|
||||||
} else { \
|
|
||||||
struct type *curelm = (head)->sqh_first; \
|
|
||||||
while (curelm->field.sqe_next != (elm)) \
|
|
||||||
curelm = curelm->field.sqe_next; \
|
|
||||||
if ((curelm->field.sqe_next = \
|
|
||||||
curelm->field.sqe_next->field.sqe_next) == NULL) \
|
|
||||||
(head)->sqh_last = &(curelm)->field.sqe_next; \
|
|
||||||
} \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define SIMPLEQ_FOREACH(var, head, field) \
|
|
||||||
for ((var) = ((head)->sqh_first); \
|
|
||||||
(var); \
|
|
||||||
(var) = ((var)->field.sqe_next))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Simple queue access methods.
|
|
||||||
*/
|
|
||||||
#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL)
|
|
||||||
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
|
|
||||||
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Tail queue definitions.
|
|
||||||
*/
|
|
||||||
#define _TAILQ_HEAD(name, type, qual) \
|
|
||||||
struct name { \
|
|
||||||
qual type *tqh_first; /* first element */ \
|
|
||||||
qual type *qual *tqh_last; /* addr of last next element */ \
|
|
||||||
}
|
|
||||||
#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,)
|
|
||||||
|
|
||||||
#define TAILQ_HEAD_INITIALIZER(head) \
|
|
||||||
{ NULL, &(head).tqh_first }
|
|
||||||
|
|
||||||
#define _TAILQ_ENTRY(type, qual) \
|
|
||||||
struct { \
|
|
||||||
qual type *tqe_next; /* next element */ \
|
|
||||||
qual type *qual *tqe_prev; /* address of previous next element */\
|
|
||||||
}
|
|
||||||
#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Tail queue functions.
|
|
||||||
*/
|
|
||||||
#define TAILQ_INIT(head) do { \
|
|
||||||
(head)->tqh_first = NULL; \
|
|
||||||
(head)->tqh_last = &(head)->tqh_first; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
|
||||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
|
||||||
(head)->tqh_first->field.tqe_prev = \
|
|
||||||
&(elm)->field.tqe_next; \
|
|
||||||
else \
|
|
||||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
|
||||||
(head)->tqh_first = (elm); \
|
|
||||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
|
||||||
(elm)->field.tqe_next = NULL; \
|
|
||||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
|
||||||
*(head)->tqh_last = (elm); \
|
|
||||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
|
||||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
|
||||||
(elm)->field.tqe_next->field.tqe_prev = \
|
|
||||||
&(elm)->field.tqe_next; \
|
|
||||||
else \
|
|
||||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
|
||||||
(listelm)->field.tqe_next = (elm); \
|
|
||||||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
|
||||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
|
||||||
(elm)->field.tqe_next = (listelm); \
|
|
||||||
*(listelm)->field.tqe_prev = (elm); \
|
|
||||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define TAILQ_REMOVE(head, elm, field) do { \
|
|
||||||
if (((elm)->field.tqe_next) != NULL) \
|
|
||||||
(elm)->field.tqe_next->field.tqe_prev = \
|
|
||||||
(elm)->field.tqe_prev; \
|
|
||||||
else \
|
|
||||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
|
||||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define TAILQ_FOREACH(var, head, field) \
|
|
||||||
for ((var) = ((head)->tqh_first); \
|
|
||||||
(var); \
|
|
||||||
(var) = ((var)->field.tqe_next))
|
|
||||||
|
|
||||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
|
||||||
for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \
|
|
||||||
(var); \
|
|
||||||
(var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
|
|
||||||
|
|
||||||
#define TAILQ_CONCAT(head1, head2, field) do { \
|
|
||||||
if (!TAILQ_EMPTY(head2)) { \
|
|
||||||
*(head1)->tqh_last = (head2)->tqh_first; \
|
|
||||||
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
|
|
||||||
(head1)->tqh_last = (head2)->tqh_last; \
|
|
||||||
TAILQ_INIT((head2)); \
|
|
||||||
} \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Tail queue access methods.
|
|
||||||
*/
|
|
||||||
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
|
|
||||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
|
||||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
|
||||||
|
|
||||||
#define TAILQ_LAST(head, headname) \
|
|
||||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
|
||||||
#define TAILQ_PREV(elm, headname, field) \
|
|
||||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Circular queue definitions.
|
|
||||||
*/
|
|
||||||
#define CIRCLEQ_HEAD(name, type) \
|
|
||||||
struct name { \
|
|
||||||
struct type *cqh_first; /* first element */ \
|
|
||||||
struct type *cqh_last; /* last element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CIRCLEQ_HEAD_INITIALIZER(head) \
|
|
||||||
{ (void *)&head, (void *)&head }
|
|
||||||
|
|
||||||
#define CIRCLEQ_ENTRY(type) \
|
|
||||||
struct { \
|
|
||||||
struct type *cqe_next; /* next element */ \
|
|
||||||
struct type *cqe_prev; /* previous element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Circular queue functions.
|
|
||||||
*/
|
|
||||||
#define CIRCLEQ_INIT(head) do { \
|
|
||||||
(head)->cqh_first = (void *)(head); \
|
|
||||||
(head)->cqh_last = (void *)(head); \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
|
||||||
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
|
||||||
(elm)->field.cqe_prev = (listelm); \
|
|
||||||
if ((listelm)->field.cqe_next == (void *)(head)) \
|
|
||||||
(head)->cqh_last = (elm); \
|
|
||||||
else \
|
|
||||||
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
|
||||||
(listelm)->field.cqe_next = (elm); \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
|
||||||
(elm)->field.cqe_next = (listelm); \
|
|
||||||
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
|
||||||
if ((listelm)->field.cqe_prev == (void *)(head)) \
|
|
||||||
(head)->cqh_first = (elm); \
|
|
||||||
else \
|
|
||||||
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
|
||||||
(listelm)->field.cqe_prev = (elm); \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
|
||||||
(elm)->field.cqe_next = (head)->cqh_first; \
|
|
||||||
(elm)->field.cqe_prev = (void *)(head); \
|
|
||||||
if ((head)->cqh_last == (void *)(head)) \
|
|
||||||
(head)->cqh_last = (elm); \
|
|
||||||
else \
|
|
||||||
(head)->cqh_first->field.cqe_prev = (elm); \
|
|
||||||
(head)->cqh_first = (elm); \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
|
||||||
(elm)->field.cqe_next = (void *)(head); \
|
|
||||||
(elm)->field.cqe_prev = (head)->cqh_last; \
|
|
||||||
if ((head)->cqh_first == (void *)(head)) \
|
|
||||||
(head)->cqh_first = (elm); \
|
|
||||||
else \
|
|
||||||
(head)->cqh_last->field.cqe_next = (elm); \
|
|
||||||
(head)->cqh_last = (elm); \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define CIRCLEQ_REMOVE(head, elm, field) do { \
|
|
||||||
if ((elm)->field.cqe_next == (void *)(head)) \
|
|
||||||
(head)->cqh_last = (elm)->field.cqe_prev; \
|
|
||||||
else \
|
|
||||||
(elm)->field.cqe_next->field.cqe_prev = \
|
|
||||||
(elm)->field.cqe_prev; \
|
|
||||||
if ((elm)->field.cqe_prev == (void *)(head)) \
|
|
||||||
(head)->cqh_first = (elm)->field.cqe_next; \
|
|
||||||
else \
|
|
||||||
(elm)->field.cqe_prev->field.cqe_next = \
|
|
||||||
(elm)->field.cqe_next; \
|
|
||||||
} while (/*CONSTCOND*/0)
|
|
||||||
|
|
||||||
#define CIRCLEQ_FOREACH(var, head, field) \
|
|
||||||
for ((var) = ((head)->cqh_first); \
|
|
||||||
(var) != (const void *)(head); \
|
|
||||||
(var) = ((var)->field.cqe_next))
|
|
||||||
|
|
||||||
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
|
||||||
for ((var) = ((head)->cqh_last); \
|
|
||||||
(var) != (const void *)(head); \
|
|
||||||
(var) = ((var)->field.cqe_prev))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Circular queue access methods.
|
|
||||||
*/
|
|
||||||
#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head))
|
|
||||||
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
|
||||||
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
|
|
||||||
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
|
|
||||||
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
|
|
||||||
|
|
||||||
#define CIRCLEQ_LOOP_NEXT(head, elm, field) \
|
|
||||||
(((elm)->field.cqe_next == (void *)(head)) \
|
|
||||||
? ((head)->cqh_first) \
|
|
||||||
: (elm->field.cqe_next))
|
|
||||||
#define CIRCLEQ_LOOP_PREV(head, elm, field) \
|
|
||||||
(((elm)->field.cqe_prev == (void *)(head)) \
|
|
||||||
? ((head)->cqh_last) \
|
|
||||||
: (elm->field.cqe_prev))
|
|
||||||
|
|
||||||
#endif /* sys/queue.h */
|
|
||||||
Reference in New Issue
Block a user