Commit d77827b3 authored by winckel's avatar winckel

git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4891 818b1a75-f10b-46b9-bf7c-635c3b92a50f
parent e9c4d622
/usr/share/automake-1.11/COPYING
\ No newline at end of file
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.
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
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
\ No newline at end of file
#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;
}
#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_ */
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
\ No newline at end of file
#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_ */
/*-------------------------------------------------------------------
* 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 */
#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;
}
#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();
}
}
#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 */
#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;
}
#!/bin/sh
autoreconf --force --install -I m4
\ No newline at end of file
## 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";
## 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";
# -------- 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; };
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
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}
"
\ No newline at end of file
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
\ No newline at end of file
/*******************************************************************************
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;
}
/*******************************************************************************
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;
}
/*******************************************************************************
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_ */
#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;
}
-- 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,IHH', 0, 0, 0000000096, 'PxX \Z1x'),
('208920000000008', NULL, NULL, NULL, 'PURGED', 120, 50000000, 100000000, 60, 0000000000, 0, 'G?/Д |hb', 1, 0, 0000027276, '''$y2dm');
/*!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 */;
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
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
\ No newline at end of file
etc/openair-hss/
\ No newline at end of file
openair-hss_1.0.0-1_i386.deb misc optional
conf/hss.conf
conf/hss_fd.conf
db/oai_db.sql
\ No newline at end of file
#!/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:
\ No newline at end of file
/*******************************************************************************
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;
}
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
\ No newline at end of file
/*******************************************************************************
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;
}
/*******************************************************************************
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;
}
/*******************************************************************************
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";
}
/*******************************************************************************
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;
}
/*******************************************************************************
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;
}
/*******************************************************************************
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;
}
/*******************************************************************************
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_ */
/*******************************************************************************
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;
}
/*******************************************************************************
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;
}
/*******************************************************************************
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"
/*******************************************************************************
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_ */
/*******************************************************************************
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;
}
# 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
\ No newline at end of file
#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");
}
}
#ifndef TEST_FD_H_
#define TEST_FD_H_
void s6a_fd_init(void);
void s6a_fd_stop(void);
#endif /* TEST_FD_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_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"));
}
#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);
}
}
}
#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"));
}
#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"));
}
#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"));
}
#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"));
}
/*
* 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;
}
/*
* 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 */
#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");
}
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
#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;
}
#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_ */
/*******************************************************************************
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;
}
/*******************************************************************************
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_ */
/*******************************************************************************
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);
}
/*******************************************************************************
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;
}
%%
/*
* 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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment