Add 'src/shared/libosmocore/' from commit 'ed00fe4449ac2309ad80c32f0ba7aa80b2b8895a'

git-subtree-dir: src/shared/libosmocore
git-subtree-mainline: 231444b548
git-subtree-split: ed00fe4449
This commit is contained in:
Harald Welte 2010-07-12 09:21:13 +02:00
commit 298b361b13
87 changed files with 19052 additions and 0 deletions

30
src/shared/libosmocore/.gitignore vendored Normal file
View File

@ -0,0 +1,30 @@
Makefile
Makefile.in
.deps
.libs
*.o
*.lo
*.la
*.pc
aclocal.m4
m4/*.m4
autom4te.cache
config.h*
config.sub
config.log
config.status
config.guess
configure
depcomp
missing
ltmain.sh
install-sh
stamp-h1
libtool
.tarball-version
.version
tests/sms/sms_test
tests/timer/timer_test

View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@ -0,0 +1,14 @@
AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
ACLOCAL_AMFLAGS = -I m4
INCLUDES = $(all_includes) -I$(top_srcdir)/include
SUBDIRS = include src tests
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libosmocore.pc libosmovty.pc
BUILT_SOURCES = $(top_srcdir)/.version
$(top_srcdir)/.version:
echo $(VERSION) > $@-t && mv $@-t $@
dist-hook:
echo $(VERSION) > $(distdir)/.tarball-version

View File

@ -0,0 +1,72 @@
AC_INIT([libosmocore],
m4_esyscmd([./git-version-gen .tarball-version]),
[openbsc-devel@lists.openbsc.org])
AM_INIT_AUTOMAKE([dist-bzip2])
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl checks for programs
AC_PROG_MAKE_SET
AC_PROG_CC
AC_PROG_INSTALL
LT_INIT
AC_PROG_LIBTOOL
AC_CONFIG_MACRO_DIR([m4])
dnl checks for header files
AC_HEADER_STDC
AC_CHECK_HEADERS(execinfo.h sys/select.h)
# The following test is taken from WebKit's webkit.m4
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -fvisibility=hidden "
AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])
AC_COMPILE_IFELSE([char foo;],
[ AC_MSG_RESULT([yes])
SYMBOL_VISIBILITY="-fvisibility=hidden"],
AC_MSG_RESULT([no]))
CFLAGS="$saved_CFLAGS"
AC_SUBST(SYMBOL_VISIBILITY)
dnl Generate the output
AM_CONFIG_HEADER(config.h)
AC_ARG_ENABLE(talloc,
[ --disable-talloc Disable building talloc memory allocator ],
[enable_talloc=0], [enable_talloc=1])
AM_CONDITIONAL(ENABLE_TALLOC, test "x$enable_talloc" = "x1")
AC_ARG_ENABLE(plugin,
[ --disable-plugin Disable support for dlopen plugins ],
[enable_plugin=0], [enable_plugin=1])
AM_CONDITIONAL(ENABLE_PLUGIN, test "x$enable_plugin" = "x1")
AC_ARG_ENABLE(tests,
[ --disable-tests Disable building test programs ],
[enable_tests=0], [enable_tests=1])
AM_CONDITIONAL(ENABLE_TESTS, test "x$enable_tests" = "x1")
AC_ARG_ENABLE(vty,
[ --disable-vty Disable building VTY telnet interface ],
[enable_vty=0], [enable_vty=1])
AM_CONDITIONAL(ENABLE_VTY, test "x$enable_vty" = "x1")
AC_OUTPUT(
libosmocore.pc
libosmovty.pc
include/osmocom/Makefile
include/osmocom/vty/Makefile
include/osmocom/crypt/Makefile
include/osmocore/Makefile
include/osmocore/protocol/Makefile
include/Makefile
src/Makefile
src/vty/Makefile
tests/Makefile
tests/timer/Makefile
tests/sms/Makefile
Makefile)

View File

@ -0,0 +1,151 @@
#!/bin/sh
# Print a version string.
scriptversion=2010-01-28.01
# Copyright (C) 2007-2010 Free Software Foundation, Inc.
#
# This program 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.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
# It may be run two ways:
# - from a git repository in which the "git describe" command below
# produces useful output (thus requiring at least one signed tag)
# - from a non-git-repo directory containing a .tarball-version file, which
# presumes this script is invoked like "./git-version-gen .tarball-version".
# In order to use intra-version strings in your project, you will need two
# separate generated version string files:
#
# .tarball-version - present only in a distribution tarball, and not in
# a checked-out repository. Created with contents that were learned at
# the last time autoconf was run, and used by git-version-gen. Must not
# be present in either $(srcdir) or $(builddir) for git-version-gen to
# give accurate answers during normal development with a checked out tree,
# but must be present in a tarball when there is no version control system.
# Therefore, it cannot be used in any dependencies. GNUmakefile has
# hooks to force a reconfigure at distribution time to get the value
# correct, without penalizing normal development with extra reconfigures.
#
# .version - present in a checked-out repository and in a distribution
# tarball. Usable in dependencies, particularly for files that don't
# want to depend on config.h but do want to track version changes.
# Delete this file prior to any autoconf run where you want to rebuild
# files to pick up a version string change; and leave it stale to
# minimize rebuild time after unrelated changes to configure sources.
#
# It is probably wise to add these two files to .gitignore, so that you
# don't accidentally commit either generated file.
#
# Use the following line in your configure.ac, so that $(VERSION) will
# automatically be up-to-date each time configure is run (and note that
# since configure.ac no longer includes a version string, Makefile rules
# should not depend on configure.ac for version updates).
#
# AC_INIT([GNU project],
# m4_esyscmd([build-aux/git-version-gen .tarball-version]),
# [bug-project@example])
#
# Then use the following lines in your Makefile.am, so that .version
# will be present for dependencies, and so that .tarball-version will
# exist in distribution tarballs.
#
# BUILT_SOURCES = $(top_srcdir)/.version
# $(top_srcdir)/.version:
# echo $(VERSION) > $@-t && mv $@-t $@
# dist-hook:
# echo $(VERSION) > $(distdir)/.tarball-version
case $# in
1) ;;
*) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version"; exit 1;;
esac
tarball_version_file=$1
nl='
'
# First see if there is a tarball-only version file.
# then try "git describe", then default.
if test -f $tarball_version_file
then
v=`cat $tarball_version_file` || exit 1
case $v in
*$nl*) v= ;; # reject multi-line output
[0-9]*) ;;
*) v= ;;
esac
test -z "$v" \
&& echo "$0: WARNING: $tarball_version_file seems to be damaged" 1>&2
fi
if test -n "$v"
then
: # use $v
elif
v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
|| git describe --abbrev=4 HEAD 2>/dev/null` \
&& case $v in
[0-9]*) ;;
v[0-9]*) ;;
*) (exit 1) ;;
esac
then
# Is this a new git that lists number of commits since the last
# tag or the previous older version that did not?
# Newer: v6.10-77-g0f8faeb
# Older: v6.10-g0f8faeb
case $v in
*-*-*) : git describe is okay three part flavor ;;
*-*)
: git describe is older two part flavor
# Recreate the number of commits and rewrite such that the
# result is the same as if we were using the newer version
# of git describe.
vtag=`echo "$v" | sed 's/-.*//'`
numcommits=`git rev-list "$vtag"..HEAD | wc -l`
v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`;
;;
esac
# Change the first '-' to a '.', so version-comparing tools work properly.
# Remove the "g" in git describe's output string, to save a byte.
v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`;
else
v=UNKNOWN
fi
v=`echo "$v" |sed 's/^v//'`
# Don't declare a version "dirty" merely because a time stamp has changed.
git status > /dev/null 2>&1
dirty=`sh -c 'git diff-index --name-only HEAD' 2>/dev/null` || dirty=
case "$dirty" in
'') ;;
*) # Append the suffix only if there isn't one already.
case $v in
*-dirty) ;;
*) v="$v-dirty" ;;
esac ;;
esac
# Omit the trailing newline, so that m4_esyscmd can use the result directly.
echo "$v" | tr -d '\012'
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

View File

@ -0,0 +1 @@
SUBDIRS = osmocom osmocore

View File

@ -0,0 +1,5 @@
if ENABLE_VTY
SUBDIRS = vty crypt
else
SUBDIRS = crypt
endif

View File

@ -0,0 +1,3 @@
osmocrypt_HEADERS = gprs_cipher.h
osmocryptdir = $(includedir)/osmocom/crypt

View File

@ -0,0 +1,54 @@
#ifndef _GPRS_CIPHER_H
#define _GPRS_CIPHER_H
#include <osmocore/linuxlist.h>
#define GSM0464_CIPH_MAX_BLOCK 1523
enum gprs_ciph_algo {
GPRS_ALGO_GEA0,
GPRS_ALGO_GEA1,
GPRS_ALGO_GEA2,
GPRS_ALGO_GEA3,
_GPRS_ALGO_NUM
};
enum gprs_cipher_direction {
GPRS_CIPH_MS2SGSN,
GPRS_CIPH_SGSN2MS,
};
/* An implementation of a GPRS cipher */
struct gprs_cipher_impl {
struct llist_head list;
enum gprs_ciph_algo algo;
const char *name;
unsigned int priority;
/* As specified in 04.64 Annex A. Uses Kc, IV and direction
* to generate the 1523 bytes cipher stream that need to be
* XORed wit the plaintext for encrypt / ciphertext for decrypt */
int (*run)(uint8_t *out, uint16_t len, uint64_t kc, uint32_t iv,
enum gprs_cipher_direction direction);
};
/* register a cipher with the core (from a plugin) */
int gprs_cipher_register(struct gprs_cipher_impl *ciph);
/* load all available GPRS cipher plugins */
int gprs_cipher_load(const char *path);
/* function to be called by core code */
int gprs_cipher_run(uint8_t *out, uint16_t len, enum gprs_ciph_algo algo,
uint64_t kc, uint32_t iv, enum gprs_cipher_direction dir);
/* Do we have an implementation for this cipher? */
int gprs_cipher_supported(enum gprs_ciph_algo algo);
/* GSM TS 04.64 / Section A.2.1 : Generation of 'input' */
uint32_t gprs_cipher_gen_input_ui(uint32_t iov_ui, uint8_t sapi, uint32_t lfn, uint32_t oc);
/* GSM TS 04.64 / Section A.2.1 : Generation of 'input' */
uint32_t gprs_cipher_gen_input_i(uint32_t iov_i, uint32_t lfn, uint32_t oc);
#endif /* _GPRS_CIPHER_H */

View File

@ -0,0 +1,4 @@
osmovty_HEADERS = buffer.h command.h vector.h vty.h \
telnet_interface.h logging.h
osmovtydir = $(includedir)/osmocom/vty

View File

@ -0,0 +1,102 @@
/*
* Buffering to output and input.
* Copyright (C) 1998 Kunihiro Ishiguro
*
* This file is part of GNU Zebra.
*
* GNU Zebra 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 2, or (at your
* option) any later version.
*
* GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef _ZEBRA_BUFFER_H
#define _ZEBRA_BUFFER_H
#include <sys/types.h>
/* Create a new buffer. Memory will be allocated in chunks of the given
size. If the argument is 0, the library will supply a reasonable
default size suitable for buffering socket I/O. */
struct buffer *buffer_new(void *ctx, size_t);
/* Free all data in the buffer. */
void buffer_reset(struct buffer *);
/* This function first calls buffer_reset to release all buffered data.
Then it frees the struct buffer itself. */
void buffer_free(struct buffer *);
/* Add the given data to the end of the buffer. */
extern void buffer_put(struct buffer *, const void *, size_t);
/* Add a single character to the end of the buffer. */
extern void buffer_putc(struct buffer *, u_char);
/* Add a NUL-terminated string to the end of the buffer. */
extern void buffer_putstr(struct buffer *, const char *);
/* Combine all accumulated (and unflushed) data inside the buffer into a
single NUL-terminated string allocated using XMALLOC(MTYPE_TMP). Note
that this function does not alter the state of the buffer, so the data
is still inside waiting to be flushed. */
char *buffer_getstr(struct buffer *);
/* Returns 1 if there is no pending data in the buffer. Otherwise returns 0. */
int buffer_empty(struct buffer *);
typedef enum {
/* An I/O error occurred. The buffer should be destroyed and the
file descriptor should be closed. */
BUFFER_ERROR = -1,
/* The data was written successfully, and the buffer is now empty
(there is no pending data waiting to be flushed). */
BUFFER_EMPTY = 0,
/* There is pending data in the buffer waiting to be flushed. Please
try flushing the buffer when select indicates that the file descriptor
is writeable. */
BUFFER_PENDING = 1
} buffer_status_t;
/* Try to write this data to the file descriptor. Any data that cannot
be written immediately is added to the buffer queue. */
extern buffer_status_t buffer_write(struct buffer *, int fd,
const void *, size_t);
/* This function attempts to flush some (but perhaps not all) of
the queued data to the given file descriptor. */
extern buffer_status_t buffer_flush_available(struct buffer *, int fd);
/* The following 2 functions (buffer_flush_all and buffer_flush_window)
are for use in lib/vty.c only. They should not be used elsewhere. */
/* Call buffer_flush_available repeatedly until either all data has been
flushed, or an I/O error has been encountered, or the operation would
block. */
extern buffer_status_t buffer_flush_all(struct buffer *, int fd);
/* Attempt to write enough data to the given fd to fill a window of the
given width and height (and remove the data written from the buffer).
If !no_more, then a message saying " --More-- " is appended.
If erase is true, then first overwrite the previous " --More-- " message
with spaces.
Any write error (including EAGAIN or EINTR) will cause this function
to return -1 (because the logic for handling the erase and more features
is too complicated to retry the write later).
*/
extern buffer_status_t buffer_flush_window(struct buffer *, int fd, int width,
int height, int erase, int no_more);
#endif /* _ZEBRA_BUFFER_H */

View File

@ -0,0 +1,349 @@
/*
* Zebra configuration command interface routine
* Copyright (C) 1997, 98 Kunihiro Ishiguro
*
* This file is part of GNU Zebra.
*
* GNU Zebra 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 2, or (at your
* option) any later version.
*
* GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef _ZEBRA_COMMAND_H
#define _ZEBRA_COMMAND_H
#include <stdio.h>
#include <sys/types.h>
#include "vector.h"
#include "vty.h"
/* Host configuration variable */
struct host {
/* Host name of this router. */
char *name;
/* Password for vty interface. */
char *password;
char *password_encrypt;
/* Enable password */
char *enable;
char *enable_encrypt;
/* System wide terminal lines. */
int lines;
/* Log filename. */
char *logfile;
/* config file name of this host */
char *config;
/* Flags for services */
int advanced;
int encrypt;
/* Banner configuration. */
const char *motd;
char *motdfile;
const struct vty_app_info *app_info;
};
/* There are some command levels which called from command node. */
enum node_type {
AUTH_NODE, /* Authentication mode of vty interface. */
VIEW_NODE, /* View node. Default mode of vty interface. */
AUTH_ENABLE_NODE, /* Authentication mode for change enable. */
ENABLE_NODE, /* Enable node. */
CONFIG_NODE, /* Config node. Default mode of config file. */
SERVICE_NODE, /* Service node. */
DEBUG_NODE, /* Debug node. */
VTY_NODE, /* Vty node. */
_LAST_OSMOVTY_NODE
};
/* Node which has some commands and prompt string and configuration
function pointer . */
struct cmd_node {
/* Node index. */
enum node_type node;
/* Prompt character at vty interface. */
const char *prompt;
/* Is this node's configuration goes to vtysh ? */
int vtysh;
/* Node's configuration write function */
int (*func) (struct vty *);
/* Vector of this node's command list. */
vector cmd_vector;
};
enum {
CMD_ATTR_DEPRECATED = 1,
CMD_ATTR_HIDDEN,
};
/* Structure of command element. */
struct cmd_element {
const char *string; /* Command specification by string. */
int (*func) (struct cmd_element *, struct vty *, int, const char *[]);
const char *doc; /* Documentation of this command. */
int daemon; /* Daemon to which this command belong. */
vector strvec; /* Pointing out each description vector. */
unsigned int cmdsize; /* Command index count. */
char *config; /* Configuration string */
vector subconfig; /* Sub configuration string */
u_char attr; /* Command attributes */
};
/* Command description structure. */
struct desc {
const char *cmd; /* Command string. */
const char *str; /* Command's description. */
};
/* Return value of the commands. */
#define CMD_SUCCESS 0
#define CMD_WARNING 1
#define CMD_ERR_NO_MATCH 2
#define CMD_ERR_AMBIGUOUS 3
#define CMD_ERR_INCOMPLETE 4
#define CMD_ERR_EXEED_ARGC_MAX 5
#define CMD_ERR_NOTHING_TODO 6
#define CMD_COMPLETE_FULL_MATCH 7
#define CMD_COMPLETE_MATCH 8
#define CMD_COMPLETE_LIST_MATCH 9
#define CMD_SUCCESS_DAEMON 10
/* Argc max counts. */
#define CMD_ARGC_MAX 25
/* Turn off these macros when uisng cpp with extract.pl */
#ifndef VTYSH_EXTRACT_PL
/* helper defines for end-user DEFUN* macros */
#define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \
static struct cmd_element cmdname = \
{ \
.string = cmdstr, \
.func = funcname, \
.doc = helpstr, \
.attr = attrs, \
.daemon = dnum, \
};
/* global (non static) cmd_element */
#define gDEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \
struct cmd_element cmdname = \
{ \
.string = cmdstr, \
.func = funcname, \
.doc = helpstr, \
.attr = attrs, \
.daemon = dnum, \
};
#define DEFUN_CMD_FUNC_DECL(funcname) \
static int funcname (struct cmd_element *, struct vty *, int, const char *[]); \
#define DEFUN_CMD_FUNC_TEXT(funcname) \
static int funcname \
(struct cmd_element *self, struct vty *vty, int argc, const char *argv[])
/* DEFUN for vty command interafce. Little bit hacky ;-). */
#define DEFUN(funcname, cmdname, cmdstr, helpstr) \
DEFUN_CMD_FUNC_DECL(funcname) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \
DEFUN_CMD_FUNC_TEXT(funcname)
/* global (non static) cmd_element */
#define gDEFUN(funcname, cmdname, cmdstr, helpstr) \
DEFUN_CMD_FUNC_DECL(funcname) \
gDEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \
DEFUN_CMD_FUNC_TEXT(funcname)
#define DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
DEFUN_CMD_FUNC_DECL(funcname) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \
DEFUN_CMD_FUNC_TEXT(funcname)
#define DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
#define DEFUN_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \
DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED) \
/* DEFUN_NOSH for commands that vtysh should ignore */
#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \
DEFUN(funcname, cmdname, cmdstr, helpstr)
/* DEFSH for vtysh. */
#define DEFSH(daemon, cmdname, cmdstr, helpstr) \
DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, 0, daemon) \
/* DEFUN + DEFSH */
#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \
DEFUN_CMD_FUNC_DECL(funcname) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon) \
DEFUN_CMD_FUNC_TEXT(funcname)
/* DEFUN + DEFSH with attributes */
#define DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, attr) \
DEFUN_CMD_FUNC_DECL(funcname) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, daemon) \
DEFUN_CMD_FUNC_TEXT(funcname)
#define DEFUNSH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \
DEFUNSH_ATTR (daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
#define DEFUNSH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \
DEFUNSH_ATTR (daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED)
/* ALIAS macro which define existing command's alias. */
#define ALIAS(funcname, cmdname, cmdstr, helpstr) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0)
/* global (non static) cmd_element */
#define gALIAS(funcname, cmdname, cmdstr, helpstr) \
gDEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0)
#define ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0)
#define ALIAS_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, 0)
#define ALIAS_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, 0)
#define ALIAS_SH(daemon, funcname, cmdname, cmdstr, helpstr) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon)
#define ALIAS_SH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, daemon)
#define ALIAS_SH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, daemon)
#endif /* VTYSH_EXTRACT_PL */
/* Some macroes */
#define CMD_OPTION(S) ((S[0]) == '[')
#define CMD_VARIABLE(S) (((S[0]) >= 'A' && (S[0]) <= 'Z') || ((S[0]) == '<'))
#define CMD_VARARG(S) ((S[0]) == '.')
#define CMD_RANGE(S) ((S[0] == '<'))
#define CMD_IPV4(S) ((strcmp ((S), "A.B.C.D") == 0))
#define CMD_IPV4_PREFIX(S) ((strcmp ((S), "A.B.C.D/M") == 0))
#define CMD_IPV6(S) ((strcmp ((S), "X:X::X:X") == 0))
#define CMD_IPV6_PREFIX(S) ((strcmp ((S), "X:X::X:X/M") == 0))
/* Common descriptions. */
#define SHOW_STR "Show running system information\n"
#define IP_STR "IP information\n"
#define IPV6_STR "IPv6 information\n"
#define NO_STR "Negate a command or set its defaults\n"
#define CLEAR_STR "Reset functions\n"
#define RIP_STR "RIP information\n"
#define BGP_STR "BGP information\n"
#define OSPF_STR "OSPF information\n"
#define NEIGHBOR_STR "Specify neighbor router\n"
#define DEBUG_STR "Debugging functions (see also 'undebug')\n"
#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n"
#define ROUTER_STR "Enable a routing process\n"
#define AS_STR "AS number\n"
#define MBGP_STR "MBGP information\n"
#define MATCH_STR "Match values from routing table\n"
#define SET_STR "Set values in destination routing protocol\n"
#define OUT_STR "Filter outgoing routing updates\n"
#define IN_STR "Filter incoming routing updates\n"
#define V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)\n"
#define OSPF6_NUMBER_STR "Specify by number\n"
#define INTERFACE_STR "Interface infomation\n"
#define IFNAME_STR "Interface name(e.g. ep0)\n"
#define IP6_STR "IPv6 Information\n"
#define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n"
#define OSPF6_ROUTER_STR "Enable a routing process\n"
#define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n"
#define SECONDS_STR "<1-65535> Seconds\n"
#define ROUTE_STR "Routing Table\n"
#define PREFIX_LIST_STR "Build a prefix list\n"
#define OSPF6_DUMP_TYPE_LIST \
"(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)"
#define ISIS_STR "IS-IS information\n"
#define AREA_TAG_STR "[area tag]\n"
#define CONF_BACKUP_EXT ".sav"
/* IPv4 only machine should not accept IPv6 address for peer's IP
address. So we replace VTY command string like below. */
#ifdef HAVE_IPV6
#define NEIGHBOR_CMD "neighbor (A.B.C.D|X:X::X:X) "
#define NO_NEIGHBOR_CMD "no neighbor (A.B.C.D|X:X::X:X) "
#define NEIGHBOR_ADDR_STR "Neighbor address\nIPv6 address\n"
#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|X:X::X:X|WORD) "
#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|X:X::X:X|WORD) "
#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
#else
#define NEIGHBOR_CMD "neighbor A.B.C.D "
#define NO_NEIGHBOR_CMD "no neighbor A.B.C.D "
#define NEIGHBOR_ADDR_STR "Neighbor address\n"
#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|WORD) "
#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|WORD) "
#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor tag\n"
#endif /* HAVE_IPV6 */
/* Prototypes. */
void install_node(struct cmd_node *, int (*)(struct vty *));
void install_default(enum node_type);
void install_element(enum node_type, struct cmd_element *);
void install_element_ve(struct cmd_element *cmd);
void sort_node();
/* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated
string with a space between each element (allocated using
XMALLOC(MTYPE_TMP)). Returns NULL if shift >= argc. */
char *argv_concat(const char **argv, int argc, int shift);
vector cmd_make_strvec(const char *);
void cmd_free_strvec(vector);
vector cmd_describe_command();
char **cmd_complete_command();
const char *cmd_prompt(enum node_type);
int config_from_file(struct vty *, FILE *);
enum node_type node_parent(enum node_type);
int cmd_execute_command(vector, struct vty *, struct cmd_element **, int);
int cmd_execute_command_strict(vector, struct vty *, struct cmd_element **);
void config_replace_string(struct cmd_element *, char *, ...);
void cmd_init(int);
/* Export typical functions. */
extern struct cmd_element config_exit_cmd;
extern struct cmd_element config_help_cmd;
extern struct cmd_element config_list_cmd;
char *host_config_file();
void host_config_set(const char *);
/* This is called from main when a daemon is invoked with -v or --version. */
void print_version(int print_copyright);
extern void *tall_vty_cmd_ctx;
#endif /* _ZEBRA_COMMAND_H */

View File

@ -0,0 +1,7 @@
#ifndef _VTY_LOGGING_H
#define _VTY_LOGGING_H
#define LOGGING_STR "Configure log message to this terminal\n"
#define FILTER_STR "Filter log messages\n"
#endif /* _VTY_LOGGING_H */

View File

@ -0,0 +1,40 @@
/* minimalistic telnet/network interface it might turn into a wire interface */
/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef TELNET_INTERFACE_H
#define TELNET_INTERFACE_H
#include <osmocore/logging.h>
#include <osmocore/select.h>
#include <osmocom/vty/vty.h>
struct telnet_connection {
struct llist_head entry;
void *priv;
struct bsc_fd fd;
struct vty *vty;
struct log_target *dbg;
};
int telnet_init(void *tall_ctx, void *priv, int port);
#endif

View File

@ -0,0 +1,64 @@
/*
* Generic vector interface header.
* Copyright (C) 1997, 98 Kunihiro Ishiguro
*
* This file is part of GNU Zebra.
*
* GNU Zebra 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 2, or (at your option) any
* later version.
*
* GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef _ZEBRA_VECTOR_H
#define _ZEBRA_VECTOR_H
/* struct for vector */
struct _vector {
unsigned int active; /* number of active slots */
unsigned int alloced; /* number of allocated slot */
void **index; /* index to data */
};
typedef struct _vector *vector;
#define VECTOR_MIN_SIZE 1
/* (Sometimes) usefull macros. This macro convert index expression to
array expression. */
/* Reference slot at given index, caller must ensure slot is active */
#define vector_slot(V,I) ((V)->index[(I)])
/* Number of active slots.
* Note that this differs from vector_count() as it the count returned
* will include any empty slots
*/
#define vector_active(V) ((V)->active)
/* Prototypes. */
vector vector_init(unsigned int size);
void vector_ensure(vector v, unsigned int num);
int vector_empty_slot(vector v);
int vector_set(vector v, void *val);
int vector_set_index(vector v, unsigned int i, void *val);
void vector_unset(vector v, unsigned int i);
unsigned int vector_count(vector v);
void vector_only_wrapper_free(vector v);
void vector_only_index_free(void *index);
void vector_free(vector v);
vector vector_copy(vector v);
void *vector_lookup(vector, unsigned int);
void *vector_lookup_ensure(vector, unsigned int);
extern void *tall_vty_vec_ctx;
#endif /* _ZEBRA_VECTOR_H */

View File

@ -0,0 +1,159 @@
#ifndef _VTY_H
#define _VTY_H
#include <stdio.h>
#include <stdarg.h>
/* GCC have printf type attribute check. */
#ifdef __GNUC__
#define VTY_PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
#else
#define VTY_PRINTF_ATTRIBUTE(a,b)
#endif /* __GNUC__ */
/* Does the I/O error indicate that the operation should be retried later? */
#define ERRNO_IO_RETRY(EN) \
(((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR))
/* Vty read buffer size. */
#define VTY_READ_BUFSIZ 512
#define VTY_BUFSIZ 512
#define VTY_MAXHIST 20
/* Vty events */
enum event {
VTY_SERV,
VTY_READ,
VTY_WRITE,
VTY_CLOSED,
VTY_TIMEOUT_RESET,
#ifdef VTYSH
VTYSH_SERV,
VTYSH_READ,
VTYSH_WRITE
#endif /* VTYSH */
};
struct vty {
FILE *file;
/* private data, specified by creator */
void *priv;
/* File descripter of this vty. */
int fd;
/* Is this vty connect to file or not */
enum { VTY_TERM, VTY_FILE, VTY_SHELL, VTY_SHELL_SERV } type;
/* Node status of this vty */
int node;
/* Failure count */
int fail;
/* Output buffer. */
struct buffer *obuf;
/* Command input buffer */
char *buf;
/* Command cursor point */
int cp;
/* Command length */
int length;
/* Command max length. */
int max;
/* Histry of command */
char *hist[VTY_MAXHIST];
/* History lookup current point */
int hp;
/* History insert end point */
int hindex;
/* For current referencing point of interface, route-map,
access-list etc... */
void *index;
/* For multiple level index treatment such as key chain and key. */
void *index_sub;
/* For escape character. */
unsigned char escape;
/* Current vty status. */
enum { VTY_NORMAL, VTY_CLOSE, VTY_MORE, VTY_MORELINE } status;
/* IAC handling: was the last character received the IAC
* (interpret-as-command) escape character (and therefore the next
* character will be the command code)? Refer to Telnet RFC 854. */
unsigned char iac;
/* IAC SB (option subnegotiation) handling */
unsigned char iac_sb_in_progress;
/* At the moment, we care only about the NAWS (window size) negotiation,
* and that requires just a 5-character buffer (RFC 1073):
* <NAWS char> <16-bit width> <16-bit height> */
#define TELNET_NAWS_SB_LEN 5
unsigned char sb_buf[TELNET_NAWS_SB_LEN];
/* How many subnegotiation characters have we received? We just drop
* those that do not fit in the buffer. */
size_t sb_len;
/* Window width/height. */
int width;
int height;
/* Configure lines. */
int lines;
int monitor;
/* In configure mode. */
int config;
};
/* Small macro to determine newline is newline only or linefeed needed. */
#define VTY_NEWLINE ((vty->type == VTY_TERM) ? "\r\n" : "\n")
static inline char *vty_newline(struct vty *vty)
{
return VTY_NEWLINE;
}
struct vty_app_info {
const char *name;
const char *version;
const char *copyright;
void *tall_ctx;
enum node_type (*go_parent_cb)(struct vty *vty);
};
/* Prototypes. */
void vty_init(struct vty_app_info *app_info);
int vty_read_config_file(const char *file_name, void *priv);
void vty_init_vtysh (void);
void vty_reset (void);
struct vty *vty_new (void);
struct vty *vty_create (int vty_sock, void *priv);
int vty_out (struct vty *, const char *, ...) VTY_PRINTF_ATTRIBUTE(2, 3);
int vty_out_newline(struct vty *);
int vty_read(struct vty *vty);
//void vty_time_print (struct vty *, int);
void vty_close (struct vty *);
char *vty_get_cwd (void);
void vty_log (const char *level, const char *proto, const char *fmt, va_list);
int vty_config_lock (struct vty *);
int vty_config_unlock (struct vty *);
int vty_shell (struct vty *);
int vty_shell_serv (struct vty *);
void vty_hello (struct vty *);
void *tall_vty_ctx;
#endif

View File

@ -0,0 +1,13 @@
osmocore_HEADERS = signal.h linuxlist.h timer.h select.h msgb.h \
tlv.h bitvec.h comp128.h statistics.h gsm_utils.h utils.h \
gsmtap.h write_queue.h rsl.h gsm48.h rxlev_stat.h mncc.h \
gsm48_ie.h logging.h gsm0808.h rate_ctr.h gsmtap_util.h \
plugin.h
if ENABLE_TALLOC
osmocore_HEADERS += talloc.h
endif
osmocoredir = $(includedir)/osmocore
SUBDIRS = protocol

View File

@ -0,0 +1,75 @@
#ifndef _BITVEC_H
#define _BITVEC_H
/* bit vector utility routines */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
/* In GSM mac blocks, every bit can be 0 or 1, or L or H. L/H are
* defined relative to the 0x2b padding pattern */
enum bit_value {
ZERO = 0,
ONE = 1,
L = 2,
H = 3,
};
struct bitvec {
unsigned int cur_bit; /* curser to the next unused bit */
unsigned int data_len; /* length of data array in bytes */
uint8_t *data; /* pointer to data array */
};
/* check if the bit is 0 or 1 for a given position inside a bitvec */
enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr);
/* check if the bit is L or H for a given position inside a bitvec */
enum bit_value bitvec_get_bit_pos_high(const struct bitvec *bv,
unsigned int bitnr);
/* get the Nth set bit inside the bit vector */
unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n);
/* Set a bit at given position */
int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnum,
enum bit_value bit);
/* Set the next bit in the vector */
int bitvec_set_bit(struct bitvec *bv, enum bit_value bit);
/* get the next bit (low/high) inside a bitvec */
int bitvec_get_bit_high(struct bitvec *bv);
/* Set multiple bits at the current position */
int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count);
/* Add an unsigned integer (of length count bits) to current position */
int bitvec_set_uint(struct bitvec *bv, unsigned int in, int count);
/* get multiple bits (based on numeric value) from current pos */
int bitvec_get_uint(struct bitvec *bv, int num_bits);
/* Pad the bit vector up to a certain bit position */
int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit);
#endif /* _BITVEC_H */

View File

@ -0,0 +1,22 @@
/*
* COMP128 header
*
* See comp128.c for details
*/
#ifndef __COMP128_H__
#define __COMP128_H__
#include <stdint.h>
/*
* Performs the COMP128 algorithm (used as A3/A8)
* ki : uint8_t [16]
* srand : uint8_t [16]
* sres : uint8_t [4]
* kc : uint8_t [8]
*/
void comp128(uint8_t *ki, uint8_t *srand, uint8_t *sres, uint8_t *kc);
#endif /* __COMP128_H__ */

View File

@ -0,0 +1,43 @@
/* (C) 2009,2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009,2010 by On-Waves
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef OSMOCORE_GSM0808_H
#define OSMOCORE_GSM0808_H
#include "tlv.h"
struct msgb;
struct msgb *gsm0808_create_layer3(struct msgb *msg, uint16_t netcode, uint16_t countrycode, int lac, int ci);
struct msgb *gsm0808_create_reset(void);
struct msgb *gsm0808_create_clear_complete(void);
struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id);
struct msgb *gsm0808_create_cipher_reject(uint8_t cause);
struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark, uint8_t length);
struct msgb *gsm0808_create_sapi_reject(uint8_t link_id);
struct msgb *gsm0808_create_assignment_completed(struct gsm_lchan *lchan, uint8_t rr_cause,
uint8_t chosen_channel, uint8_t encr_alg_id,
uint8_t speech_mode);
struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause);
void gsm0808_prepend_dtap_header(struct msgb *msg, uint8_t link_id);
const struct tlv_definition *gsm0808_att_tlvdef();
#endif

View File

@ -0,0 +1,36 @@
#ifndef _OSMOCORE_GSM48_H
#define _OSMOCORE_GSM48_H
#include <osmocore/tlv.h>
#include <osmocore/protocol/gsm_04_08.h>
#include <osmocore/gsm48_ie.h>
/* A parsed GPRS routing area */
struct gprs_ra_id {
uint16_t mnc;
uint16_t mcc;
uint16_t lac;
uint8_t rac;
};
extern const struct tlv_definition gsm48_att_tlvdef;
extern const struct tlv_definition gsm48_rr_att_tlvdef;
extern const struct tlv_definition gsm48_mm_att_tlvdef;
const char *gsm48_cc_state_name(uint8_t state);
const char *gsm48_cc_msg_name(uint8_t msgtype);
const char *rr_cause_name(uint8_t cause);
void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc,
uint16_t mnc, uint16_t lac);
int gsm48_generate_mid_from_tmsi(uint8_t *buf, uint32_t tmsi);
int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi);
/* Convert Mobile Identity (10.5.1.4) to string */
int gsm48_mi_to_string(char *string, const int str_len,
const uint8_t *mi, const int mi_len);
/* Parse Routeing Area Identifier */
void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf);
int gsm48_construct_ra(uint8_t *buf, const struct gprs_ra_id *raid);
#endif

View File

@ -0,0 +1,107 @@
#ifndef _OSMOCORE_GSM48_IE_H
#define _OSMOCORE_GSM48_IE_H
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <osmocore/msgb.h>
#include <osmocore/tlv.h>
#include <osmocore/mncc.h>
#include <osmocore/protocol/gsm_04_08.h>
/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */
int gsm48_decode_bcd_number(char *output, int output_len,
const uint8_t *bcd_lv, int h_len);
/* convert a ASCII phone number to 'called/calling/connect party BCD number' */
int gsm48_encode_bcd_number(uint8_t *bcd_lv, uint8_t max_len,
int h_len, const char *input);
/* decode 'bearer capability' */
int gsm48_decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
const uint8_t *lv);
/* encode 'bearer capability' */
int gsm48_encode_bearer_cap(struct msgb *msg, int lv_only,
const struct gsm_mncc_bearer_cap *bcap);
/* decode 'call control cap' */
int gsm48_decode_cccap(struct gsm_mncc_cccap *ccap, const uint8_t *lv);
/* encode 'call control cap' */
int gsm48_encode_cccap(struct msgb *msg,
const struct gsm_mncc_cccap *ccap);
/* decode 'called party BCD number' */
int gsm48_decode_called(struct gsm_mncc_number *called,
const uint8_t *lv);
/* encode 'called party BCD number' */
int gsm48_encode_called(struct msgb *msg,
const struct gsm_mncc_number *called);
/* decode callerid of various IEs */
int gsm48_decode_callerid(struct gsm_mncc_number *callerid,
const uint8_t *lv);
/* encode callerid of various IEs */
int gsm48_encode_callerid(struct msgb *msg, int ie, int max_len,
const struct gsm_mncc_number *callerid);
/* decode 'cause' */
int gsm48_decode_cause(struct gsm_mncc_cause *cause,
const uint8_t *lv);
/* encode 'cause' */
int gsm48_encode_cause(struct msgb *msg, int lv_only,
const struct gsm_mncc_cause *cause);
/* decode 'calling number' */
int gsm48_decode_calling(struct gsm_mncc_number *calling,
const uint8_t *lv);
/* encode 'calling number' */
int gsm48_encode_calling(struct msgb *msg,
const struct gsm_mncc_number *calling);
/* decode 'connected number' */
int gsm48_decode_connected(struct gsm_mncc_number *connected,
const uint8_t *lv);
/* encode 'connected number' */
int gsm48_encode_connected(struct msgb *msg,
const struct gsm_mncc_number *connected);
/* decode 'redirecting number' */
int gsm48_decode_redirecting(struct gsm_mncc_number *redirecting,
const uint8_t *lv);
/* encode 'redirecting number' */
int gsm48_encode_redirecting(struct msgb *msg,
const struct gsm_mncc_number *redirecting);
/* decode 'facility' */
int gsm48_decode_facility(struct gsm_mncc_facility *facility,
const uint8_t *lv);
/* encode 'facility' */
int gsm48_encode_facility(struct msgb *msg, int lv_only,
const struct gsm_mncc_facility *facility);
/* decode 'notify' */
int gsm48_decode_notify(int *notify, const uint8_t *v);
/* encode 'notify' */
int gsm48_encode_notify(struct msgb *msg, int notify);
/* decode 'signal' */
int gsm48_decode_signal(int *signal, const uint8_t *v);
/* encode 'signal' */
int gsm48_encode_signal(struct msgb *msg, int signal);
/* decode 'keypad' */
int gsm48_decode_keypad(int *keypad, const uint8_t *lv);
/* encode 'keypad' */
int gsm48_encode_keypad(struct msgb *msg, int keypad);
/* decode 'progress' */
int gsm48_decode_progress(struct gsm_mncc_progress *progress,
const uint8_t *lv);
/* encode 'progress' */
int gsm48_encode_progress(struct msgb *msg, int lv_only,
const struct gsm_mncc_progress *p);
/* decode 'user-user' */
int gsm48_decode_useruser(struct gsm_mncc_useruser *uu,
const uint8_t *lv);
/* encode 'useruser' */
int gsm48_encode_useruser(struct msgb *msg, int lv_only,
const struct gsm_mncc_useruser *uu);
/* decode 'ss version' */
int gsm48_decode_ssversion(struct gsm_mncc_ssversion *ssv,
const uint8_t *lv);
/* encode 'ss version' */
int gsm48_encode_ssversion(struct msgb *msg,
const struct gsm_mncc_ssversion *ssv);
/* decode 'more data' does not require a function, because it has no value */
/* encode 'more data' */
int gsm48_encode_more(struct msgb *msg);
#endif

View File

@ -0,0 +1,117 @@
/* GSM utility functions, e.g. coding and decoding */
/*
* (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef GSM_UTILS_H
#define GSM_UTILS_H
#include <stdint.h>
#define ADD_MODULO(sum, delta, modulo) do { \
if ((sum += delta) >= modulo) \
sum -= modulo; \
} while (0)
#define GSM_MAX_FN (26*51*2048)
struct gsm_time {
uint32_t fn; /* FN count */
uint16_t t1; /* FN div (26*51) */
uint8_t t2; /* FN modulo 26 */
uint8_t t3; /* FN modulo 51 */
uint8_t tc;
};
enum gsm_band {
GSM_BAND_850 = 1,
GSM_BAND_900 = 2,
GSM_BAND_1800 = 4,
GSM_BAND_1900 = 8,
GSM_BAND_450 = 0x10,
GSM_BAND_480 = 0x20,
GSM_BAND_750 = 0x40,
GSM_BAND_810 = 0x80,
};
const char *gsm_band_name(enum gsm_band band);
enum gsm_band gsm_band_parse(const char *mhz);
int gsm_7bit_decode(char *decoded, const uint8_t *user_data, uint8_t length);
int gsm_7bit_encode(uint8_t *result, const char *data);
int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm);
int ms_pwr_dbm(enum gsm_band band, uint8_t lvl);
/* According to TS 08.05 Chapter 8.1.4 */
int rxlev2dbm(uint8_t rxlev);
uint8_t dbm2rxlev(int dbm);
/* According to GSM 04.08 Chapter 10.5.1.6 */
static inline int ms_cm2_a5n_support(uint8_t *cm2, int n) {
switch (n) {
case 0: return 1;
case 1: return (cm2[0] & (1<<3)) ? 0 : 1;
case 2: return (cm2[2] & (1<<0)) ? 1 : 0;
case 3: return (cm2[2] & (1<<1)) ? 1 : 0;
default:
return 0;
}
}
/* According to GSM 04.08 Chapter 10.5.2.29 */
static inline int rach_max_trans_val2raw(int val) { return (val >> 1) & 3; }
static inline int rach_max_trans_raw2val(int raw) {
const int tbl[4] = { 1, 2, 4, 7 };
return tbl[raw & 3];
}
#define ARFCN_PCS 0x8000
#define ARFCN_UPLINK 0x4000
enum gsm_band gsm_arfcn2band(uint16_t arfcn);
/* Convert an ARFCN to the frequency in MHz * 10 */
uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink);
/* Convert from frame number to GSM time */
void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn);
/* Convert from GSM time to frame number */
uint32_t gsm_gsmtime2fn(struct gsm_time *time);
/* GSM TS 03.03 Chapter 2.6 */
enum gprs_tlli_type {
TLLI_LOCAL,
TLLI_FOREIGN,
TLLI_RANDOM,
TLLI_AUXILIARY,
TLLI_RESERVED,
};
/* TS 03.03 Chapter 2.6 */
int gprs_tlli_type(uint32_t tlli);
uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type);
void generate_backtrace();
#endif

View File

@ -0,0 +1,72 @@
#ifndef _GSMTAP_H
#define _GSMTAP_H
/* gsmtap header, pseudo-header in front of the actua GSM payload */
/* GSMTAP is a generic header format for GSM protocol captures,
* it uses the IANA-assigned UDP port number 4729 and carries
* payload in various formats of GSM interfaces such as Um MAC
* blocks or Um bursts.
*
* Example programs generating GSMTAP data are airprobe
* (http://airprobe.org/) or OsmocomBB (http://bb.osmocom.org/)
*/
#include <stdint.h>
#define GSMTAP_VERSION 0x02
#define GSMTAP_TYPE_UM 0x01
#define GSMTAP_TYPE_ABIS 0x02
#define GSMTAP_TYPE_UM_BURST 0x03 /* raw burst bits */
#define GSMTAP_BURST_UNKNOWN 0x00
#define GSMTAP_BURST_FCCH 0x01
#define GSMTAP_BURST_PARTIAL_SCH 0x02
#define GSMTAP_BURST_SCH 0x03
#define GSMTAP_BURST_CTS_SCH 0x04
#define GSMTAP_BURST_COMPACT_SCH 0x05
#define GSMTAP_BURST_NORMAL 0x06
#define GSMTAP_BURST_DUMMY 0x07
#define GSMTAP_BURST_ACCESS 0x08
#define GSMTAP_BURST_NONE 0x09
#define GSMTAP_CHANNEL_UNKNOWN 0x00
#define GSMTAP_CHANNEL_BCCH 0x01
#define GSMTAP_CHANNEL_CCCH 0x02
#define GSMTAP_CHANNEL_RACH 0x03
#define GSMTAP_CHANNEL_AGCH 0x04
#define GSMTAP_CHANNEL_PCH 0x05
#define GSMTAP_CHANNEL_SDCCH 0x06
#define GSMTAP_CHANNEL_SDCCH4 0x07
#define GSMTAP_CHANNEL_SDCCH8 0x08
#define GSMTAP_CHANNEL_TCH_F 0x09
#define GSMTAP_CHANNEL_TCH_H 0x0a
#define GSMTAP_CHANNEL_ACCH 0x80
#define GSMTAP_ARFCN_F_PCS 0x8000
#define GSMTAP_ARFCN_F_UPLINK 0x4000
#define GSMTAP_ARFCN_MASK 0x3fff
#define GSMTAP_UDP_PORT 4729
struct gsmtap_hdr {
uint8_t version; /* version, set to 0x01 currently */
uint8_t hdr_len; /* length in number of 32bit words */
uint8_t type; /* see GSMTAP_TYPE_* */
uint8_t timeslot; /* timeslot (0..7 on Um) */
uint16_t arfcn; /* ARFCN (frequency) */
int8_t signal_dbm; /* signal level in dBm */
int8_t snr_db; /* signal/noise ratio in dB */
uint32_t frame_number; /* GSM Frame Number (FN) */
uint8_t sub_type; /* Type of burst/channel, see above */
uint8_t antenna_nr; /* Antenna Number */
uint8_t sub_slot; /* sub-slot within timeslot */
uint8_t res; /* reserved for future use (RFU) */
} __attribute__((packed));
#endif /* _GSMTAP_H */

View File

@ -0,0 +1,21 @@
#ifndef _GSMTAP_UTIL_H
#define _GSMTAP_UTIL_H
#include <stdint.h>
/* convert RSL channel number to GSMTAP channel type */
uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t rsl_link_id);
/* receive a message from L1/L2 and put it in GSMTAP */
struct msgb *gsmtap_makemsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type,
uint8_t ss, uint32_t fn, int8_t signal_dbm,
uint8_t snr, const uint8_t *data, unsigned int len);
/* receive a message from L1/L2 and put it in GSMTAP */
int gsmtap_sendmsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type, uint8_t ss,
uint32_t fn, int8_t signal_dbm, uint8_t snr,
const uint8_t *data, unsigned int len);
int gsmtap_init(uint32_t dst_ip);
#endif /* _GSMTAP_UTIL_H */

View File

@ -0,0 +1,360 @@
#ifndef _LINUX_LLIST_H
#define _LINUX_LLIST_H
#include <stddef.h>
#ifndef inline
#define inline __inline__
#endif
static inline void prefetch(const void *x) {;}
/**
* container_of - cast a member of a structure out to the containing structure
*
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (typeof( ((type *)0)->member ) *)(ptr); \
(type *)( (char *)__mptr - offsetof(type, member) );})
/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized llist entries.
*/
#define LLIST_POISON1 ((void *) 0x00100100)
#define LLIST_POISON2 ((void *) 0x00200200)
/*
* Simple doubly linked llist implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole llists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct llist_head {
struct llist_head *next, *prev;
};
#define LLIST_HEAD_INIT(name) { &(name), &(name) }
#define LLIST_HEAD(name) \
struct llist_head name = LLIST_HEAD_INIT(name)
#define INIT_LLIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal llist manipulation where we know
* the prev/next entries already!
*/
static inline void __llist_add(struct llist_head *_new,
struct llist_head *prev,
struct llist_head *next)
{
next->prev = _new;
_new->next = next;
_new->prev = prev;
prev->next = _new;
}
/**
* llist_add - add a new entry
* @new: new entry to be added
* @head: llist head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void llist_add(struct llist_head *_new, struct llist_head *head)
{
__llist_add(_new, head, head->next);
}
/**
* llist_add_tail - add a new entry
* @new: new entry to be added
* @head: llist head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void llist_add_tail(struct llist_head *_new, struct llist_head *head)
{
__llist_add(_new, head->prev, head);
}
/*
* Delete a llist entry by making the prev/next entries
* point to each other.
*
* This is only for internal llist manipulation where we know
* the prev/next entries already!
*/
static inline void __llist_del(struct llist_head * prev, struct llist_head * next)
{
next->prev = prev;
prev->next = next;
}
/**
* llist_del - deletes entry from llist.
* @entry: the element to delete from the llist.
* Note: llist_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
static inline void llist_del(struct llist_head *entry)
{
__llist_del(entry->prev, entry->next);
entry->next = (struct llist_head *)LLIST_POISON1;
entry->prev = (struct llist_head *)LLIST_POISON2;
}
/**
* llist_del_init - deletes entry from llist and reinitialize it.
* @entry: the element to delete from the llist.
*/
static inline void llist_del_init(struct llist_head *entry)
{
__llist_del(entry->prev, entry->next);
INIT_LLIST_HEAD(entry);
}
/**
* llist_move - delete from one llist and add as another's head
* @llist: the entry to move
* @head: the head that will precede our entry
*/
static inline void llist_move(struct llist_head *llist, struct llist_head *head)
{
__llist_del(llist->prev, llist->next);
llist_add(llist, head);
}
/**
* llist_move_tail - delete from one llist and add as another's tail
* @llist: the entry to move
* @head: the head that will follow our entry
*/
static inline void llist_move_tail(struct llist_head *llist,
struct llist_head *head)
{
__llist_del(llist->prev, llist->next);
llist_add_tail(llist, head);
}
/**
* llist_empty - tests whether a llist is empty
* @head: the llist to test.
*/
static inline int llist_empty(const struct llist_head *head)
{
return head->next == head;
}
static inline void __llist_splice(struct llist_head *llist,
struct llist_head *head)
{
struct llist_head *first = llist->next;
struct llist_head *last = llist->prev;
struct llist_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
/**
* llist_splice - join two llists
* @llist: the new llist to add.
* @head: the place to add it in the first llist.
*/
static inline void llist_splice(struct llist_head *llist, struct llist_head *head)
{
if (!llist_empty(llist))
__llist_splice(llist, head);
}
/**
* llist_splice_init - join two llists and reinitialise the emptied llist.
* @llist: the new llist to add.
* @head: the place to add it in the first llist.
*
* The llist at @llist is reinitialised
*/
static inline void llist_splice_init(struct llist_head *llist,
struct llist_head *head)
{
if (!llist_empty(llist)) {
__llist_splice(llist, head);
INIT_LLIST_HEAD(llist);
}
}
/**
* llist_entry - get the struct for this entry
* @ptr: the &struct llist_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the llist_struct within the struct.
*/
#define llist_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* llist_for_each - iterate over a llist
* @pos: the &struct llist_head to use as a loop counter.
* @head: the head for your llist.
*/
#define llist_for_each(pos, head) \
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
pos = pos->next, prefetch(pos->next))
/**
* __llist_for_each - iterate over a llist
* @pos: the &struct llist_head to use as a loop counter.
* @head: the head for your llist.
*
* This variant differs from llist_for_each() in that it's the
* simplest possible llist iteration code, no prefetching is done.
* Use this for code that knows the llist to be very short (empty
* or 1 entry) most of the time.
*/
#define __llist_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* llist_for_each_prev - iterate over a llist backwards
* @pos: the &struct llist_head to use as a loop counter.
* @head: the head for your llist.
*/
#define llist_for_each_prev(pos, head) \
for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
pos = pos->prev, prefetch(pos->prev))
/**
* llist_for_each_safe - iterate over a llist safe against removal of llist entry
* @pos: the &struct llist_head to use as a loop counter.
* @n: another &struct llist_head to use as temporary storage
* @head: the head for your llist.
*/
#define llist_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/**
* llist_for_each_entry - iterate over llist of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your llist.
* @member: the name of the llist_struct within the struct.
*/
#define llist_for_each_entry(pos, head, member) \
for (pos = llist_entry((head)->next, typeof(*pos), member), \
prefetch(pos->member.next); \
&pos->member != (head); \
pos = llist_entry(pos->member.next, typeof(*pos), member), \
prefetch(pos->member.next))
/**
* llist_for_each_entry_reverse - iterate backwards over llist of given type.
* @pos: the type * to use as a loop counter.
* @head: the head for your llist.
* @member: the name of the llist_struct within the struct.
*/
#define llist_for_each_entry_reverse(pos, head, member) \
for (pos = llist_entry((head)->prev, typeof(*pos), member), \
prefetch(pos->member.prev); \
&pos->member != (head); \
pos = llist_entry(pos->member.prev, typeof(*pos), member), \
prefetch(pos->member.prev))
/**
* llist_for_each_entry_continue - iterate over llist of given type
* continuing after existing point
* @pos: the type * to use as a loop counter.
* @head: the head for your llist.
* @member: the name of the llist_struct within the struct.
*/
#define llist_for_each_entry_continue(pos, head, member) \
for (pos = llist_entry(pos->member.next, typeof(*pos), member), \
prefetch(pos->member.next); \
&pos->member != (head); \
pos = llist_entry(pos->member.next, typeof(*pos), member), \
prefetch(pos->member.next))
/**
* llist_for_each_entry_safe - iterate over llist of given type safe against removal of llist entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your llist.
* @member: the name of the llist_struct within the struct.
*/
#define llist_for_each_entry_safe(pos, n, head, member) \
for (pos = llist_entry((head)->next, typeof(*pos), member), \
n = llist_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = llist_entry(n->member.next, typeof(*n), member))
/**
* llist_for_each_rcu - iterate over an rcu-protected llist
* @pos: the &struct llist_head to use as a loop counter.
* @head: the head for your llist.
*/
#define llist_for_each_rcu(pos, head) \
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next))
#define __llist_for_each_rcu(pos, head) \
for (pos = (head)->next; pos != (head); \
pos = pos->next, ({ smp_read_barrier_depends(); 0;}))
/**
* llist_for_each_safe_rcu - iterate over an rcu-protected llist safe
* against removal of llist entry
* @pos: the &struct llist_head to use as a loop counter.
* @n: another &struct llist_head to use as temporary storage
* @head: the head for your llist.
*/
#define llist_for_each_safe_rcu(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next)
/**
* llist_for_each_entry_rcu - iterate over rcu llist of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your llist.
* @member: the name of the llist_struct within the struct.
*/
#define llist_for_each_entry_rcu(pos, head, member) \
for (pos = llist_entry((head)->next, typeof(*pos), member), \
prefetch(pos->member.next); \
&pos->member != (head); \
pos = llist_entry(pos->member.next, typeof(*pos), member), \
({ smp_read_barrier_depends(); 0;}), \
prefetch(pos->member.next))
/**
* llist_for_each_continue_rcu - iterate over an rcu-protected llist
* continuing after existing point.
* @pos: the &struct llist_head to use as a loop counter.
* @head: the head for your llist.
*/
#define llist_for_each_continue_rcu(pos, head) \
for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
(pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next))
#endif

View File

@ -0,0 +1,135 @@
#ifndef _OSMOCORE_LOGGING_H
#define _OSMOCORE_LOGGING_H
#include <stdio.h>
#include <stdint.h>
#include <osmocore/linuxlist.h>
#define LOG_MAX_CATEGORY 32
#define LOG_MAX_CTX 8
#define LOG_MAX_FILTERS 8
#define DEBUG
#ifdef DEBUG
#define DEBUGP(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 0, fmt, ## args)
#define DEBUGPC(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 1, fmt, ## args)
#else
#define DEBUGP(xss, fmt, args...)
#define DEBUGPC(ss, fmt, args...)
#endif
#define static_assert(exp, name) typedef int dummy##name [(exp) ? 1 : -1];
char *hexdump(const unsigned char *buf, int len);
void logp(unsigned int subsys, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
/* new logging interface */
#define LOGP(ss, level, fmt, args...) \
logp2(ss, level, __FILE__, __LINE__, 0, fmt, ##args)
#define LOGPC(ss, level, fmt, args...) \
logp2(ss, level, __FILE__, __LINE__, 1, fmt, ##args)
/* different levels */
#define LOGL_DEBUG 1 /* debugging information */
#define LOGL_INFO 3
#define LOGL_NOTICE 5 /* abnormal/unexpected condition */
#define LOGL_ERROR 7 /* error condition, requires user action */
#define LOGL_FATAL 8 /* fatal, program aborted */
#define LOG_FILTER_ALL 0x0001
struct log_category {
uint8_t loglevel;
uint8_t enabled;
};
struct log_info_cat {
const char *name;
const char *color;
const char *description;
uint8_t loglevel;
uint8_t enabled;
};
/* log context information, passed to filter */
struct log_context {
void *ctx[LOG_MAX_CTX+1];
};
struct log_target;
typedef int log_filter(const struct log_context *ctx,
struct log_target *target);
struct log_info {
/* filter callback function */
log_filter *filter_fn;
/* per-category information */
const struct log_info_cat *cat;
unsigned int num_cat;
};
struct log_target {
struct llist_head entry;
int filter_map;
void *filter_data[LOG_MAX_FILTERS+1];
struct log_category categories[LOG_MAX_CATEGORY+1];
uint8_t loglevel;
int use_color:1;
int print_timestamp:1;
union {
struct {
FILE *out;
} tgt_stdout;
struct {
int priority;
} tgt_syslog;
struct {
void *vty;
} tgt_vty;
};
void (*output) (struct log_target *target, const char *string);
};
/* use the above macros */
void logp2(unsigned int subsys, unsigned int level, char *file,
int line, int cont, const char *format, ...)
__attribute__ ((format (printf, 6, 7)));
void log_init(const struct log_info *cat);
/* context management */
void log_reset_context(void);
int log_set_context(uint8_t ctx, void *value);
/* filter on the targets */
void log_set_all_filter(struct log_target *target, int);
void log_set_use_color(struct log_target *target, int);
void log_set_print_timestamp(struct log_target *target, int);
void log_set_log_level(struct log_target *target, int log_level);
void log_parse_category_mask(struct log_target *target, const char* mask);
int log_parse_level(const char *lvl);
const char *log_level_str(unsigned int lvl);
int log_parse_category(const char *category);
void log_set_category_filter(struct log_target *target, int category,
int enable, int level);
/* management of the targets */
struct log_target *log_target_create(void);
struct log_target *log_target_create_stderr(void);
void log_add_target(struct log_target *target);
void log_del_target(struct log_target *target);
/* Gernerate command argument strings for VTY use */
const char *log_vty_category_string(struct log_info *info);
const char *log_vty_level_string(struct log_info *info);
#endif /* _OSMOCORE_LOGGING_H */

View File

@ -0,0 +1,71 @@
#ifndef _OSMOCORE_MNCC_H
#define _OSMOCORE_MNCC_H
#define GSM_MAX_FACILITY 128
#define GSM_MAX_SSVERSION 128
#define GSM_MAX_USERUSER 128
/* Expanded fields from GSM TS 04.08, Table 10.5.102 */
struct gsm_mncc_bearer_cap {
int transfer; /* Information Transfer Capability */
int mode; /* Transfer Mode */
int coding; /* Coding Standard */
int radio; /* Radio Channel Requirement */
int speech_ctm; /* CTM text telephony indication */
int speech_ver[8]; /* Speech version indication */
};
struct gsm_mncc_number {
int type;
int plan;
int present;
int screen;
char number[33];
};
struct gsm_mncc_cause {
int location;
int coding;
int rec;
int rec_val;
int value;
int diag_len;
char diag[32];
};
struct gsm_mncc_useruser {
int proto;
char info[GSM_MAX_USERUSER + 1]; /* + termination char */
};
struct gsm_mncc_progress {
int coding;
int location;
int descr;
};
struct gsm_mncc_facility {
int len;
char info[GSM_MAX_FACILITY];
};
struct gsm_mncc_ssversion {
int len;
char info[GSM_MAX_SSVERSION];
};
struct gsm_mncc_cccap {
int dtmf;
int pcp;
};
enum {
GSM_MNCC_BCAP_SPEECH = 0,
GSM_MNCC_BCAP_UNR_DIG = 1,
GSM_MNCC_BCAP_AUDIO = 2,
GSM_MNCC_BCAP_FAX_G3 = 3,
GSM_MNCC_BCAP_OTHER_ITC = 5,
GSM_MNCC_BCAP_RESERVED = 7,
};
#endif

View File

@ -0,0 +1,165 @@
#ifndef _MSGB_H
#define _MSGB_H
/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdint.h>
#include "linuxlist.h"
struct msgb {
struct llist_head list;
/* Part of which TRX logical channel we were received / transmitted */
/* FIXME: move them into the control buffer */
struct gsm_bts_trx *trx;
struct gsm_lchan *lchan;
/* the Layer1 header (if any) */
unsigned char *l1h;
/* the A-bis layer 2 header: OML, RSL(RLL), NS */
unsigned char *l2h;
/* the layer 3 header. For OML: FOM; RSL: 04.08; GPRS: BSSGP */
unsigned char *l3h;
/* the layer 4 header */
unsigned char *l4h;
/* the 'control buffer', large enough to contain 5 pointers */
unsigned long cb[5];
uint16_t data_len;
uint16_t len;
unsigned char *head;
unsigned char *tail;
unsigned char *data;
unsigned char _data[0];
};
extern struct msgb *msgb_alloc(uint16_t size, const char *name);
extern void msgb_free(struct msgb *m);
extern void msgb_enqueue(struct llist_head *queue, struct msgb *msg);
extern struct msgb *msgb_dequeue(struct llist_head *queue);
extern void msgb_reset(struct msgb *m);
#define msgb_l1(m) ((void *)(m->l1h))
#define msgb_l2(m) ((void *)(m->l2h))
#define msgb_l3(m) ((void *)(m->l3h))
#define msgb_sms(m) ((void *)(m->l4h))
static inline unsigned int msgb_l1len(const struct msgb *msgb)
{
return msgb->tail - (uint8_t *)msgb_l1(msgb);
}
static inline unsigned int msgb_l2len(const struct msgb *msgb)
{
return msgb->tail - (uint8_t *)msgb_l2(msgb);
}
static inline unsigned int msgb_l3len(const struct msgb *msgb)
{
return msgb->tail - (uint8_t *)msgb_l3(msgb);
}
static inline unsigned int msgb_headlen(const struct msgb *msgb)
{
return msgb->len - msgb->data_len;
}
static inline unsigned char *msgb_put(struct msgb *msgb, unsigned int len)
{
unsigned char *tmp = msgb->tail;
msgb->tail += len;
msgb->len += len;
return tmp;
}
static inline void msgb_put_u8(struct msgb *msgb, uint8_t word)
{
uint8_t *space = msgb_put(msgb, 1);
space[0] = word & 0xFF;
}
static inline void msgb_put_u16(struct msgb *msgb, uint16_t word)
{
uint8_t *space = msgb_put(msgb, 2);
space[0] = word >> 8 & 0xFF;
space[1] = word & 0xFF;
}
static inline void msgb_put_u32(struct msgb *msgb, uint32_t word)
{
uint8_t *space = msgb_put(msgb, 4);
space[0] = word >> 24 & 0xFF;
space[1] = word >> 16 & 0xFF;
space[2] = word >> 8 & 0xFF;
space[3] = word & 0xFF;
}
static inline unsigned char *msgb_get(struct msgb *msgb, unsigned int len)
{
unsigned char *tmp = msgb->data;
msgb->data += len;
msgb->len -= len;
return tmp;
}
static inline uint8_t msgb_get_u8(struct msgb *msgb)
{
uint8_t *space = msgb_get(msgb, 1);
return space[0];
}
static inline uint16_t msgb_get_u16(struct msgb *msgb)
{
uint8_t *space = msgb_get(msgb, 2);
return space[0] << 8 | space[1];
}
static inline uint32_t msgb_get_u32(struct msgb *msgb)
{
uint8_t *space = msgb_get(msgb, 4);
return space[0] << 24 | space[1] << 16 | space[2] << 8 | space[3];
}
static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len)
{
msgb->data -= len;
msgb->len += len;
return msgb->data;
}
static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len)
{
msgb->len -= len;
return msgb->data += len;
}
static inline int msgb_tailroom(const struct msgb *msgb)
{
return (msgb->head + msgb->data_len) - msgb->tail;
}
/* increase the headroom of an empty msgb, reducing the tailroom */
static inline void msgb_reserve(struct msgb *msg, int len)
{
msg->data += len;
msg->tail += len;
}
static inline struct msgb *msgb_alloc_headroom(int size, int headroom,
const char *name)
{
struct msgb *msg = msgb_alloc(size, name);
if (msg)
msgb_reserve(msg, headroom);
return msg;
}
#endif /* _MSGB_H */

View File

@ -0,0 +1,6 @@
#ifndef _OSMO_PLUGIN_H
#define _OSMO_PLUGIN_H
int plugin_load_all(const char *directory);
#endif

View File

@ -0,0 +1,3 @@
osmocore_proto_HEADERS = gsm_04_08.h gsm_04_11.h gsm_04_80.h gsm_08_58.h gsm_12_21.h gsm_08_08.h
osmocore_protodir = $(includedir)/osmocore/protocol

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,188 @@
#ifndef PROTO_GSM_04_11_H
#define PROTO_GSM_04_11_H
#include <stdint.h>
/* GSM TS 04.11 definitions */
/* Chapter 5.2.3: SMC-CS states at the network side */
enum gsm411_cp_state {
GSM411_CPS_IDLE = 0,
GSM411_CPS_MM_CONN_PENDING = 1, /* only MT ! */
GSM411_CPS_WAIT_CP_ACK = 2,
GSM411_CPS_MM_ESTABLISHED = 3,
};
/* Chapter 6.2.2: SMR states at the network side */
enum gsm411_rp_state {
GSM411_RPS_IDLE = 0,
GSM411_RPS_WAIT_FOR_RP_ACK = 1,
GSM411_RPS_WAIT_TO_TX_RP_ACK = 3,
};
/* Chapter 8.1.2 (refers to GSM 04.07 Chapter 11.2.3.1.1 */
#define GSM411_PDISC_SMS 0x09
/* Chapter 8.1.3 */
#define GSM411_MT_CP_DATA 0x01
#define GSM411_MT_CP_ACK 0x04
#define GSM411_MT_CP_ERROR 0x10
enum gsm411_cp_ie {
GSM411_CP_IE_USER_DATA = 0x01, /* 8.1.4.1 */
GSM411_CP_IE_CAUSE = 0x02, /* 8.1.4.2. */
};
/* Section 8.1.4.2 / Table 8.2 */
enum gsm411_cp_cause {
GSM411_CP_CAUSE_NET_FAIL = 17,
GSM411_CP_CAUSE_CONGESTION = 22,
GSM411_CP_CAUSE_INV_TRANS_ID = 81,
GSM411_CP_CAUSE_SEMANT_INC_MSG = 95,
GSM411_CP_CAUSE_INV_MAND_INF = 96,
GSM411_CP_CAUSE_MSGTYPE_NOTEXIST= 97,
GSM411_CP_CAUSE_MSG_INCOMP_STATE= 98,
GSM411_CP_CAUSE_IE_NOTEXIST = 99,
GSM411_CP_CAUSE_PROTOCOL_ERR = 111,
};
/* Chapter 8.2.2 */
#define GSM411_MT_RP_DATA_MO 0x00
#define GSM411_MT_RP_DATA_MT 0x01
#define GSM411_MT_RP_ACK_MO 0x02
#define GSM411_MT_RP_ACK_MT 0x03
#define GSM411_MT_RP_ERROR_MO 0x04
#define GSM411_MT_RP_ERROR_MT 0x05
#define GSM411_MT_RP_SMMA_MO 0x06
enum gsm411_rp_ie {
GSM411_IE_RP_USER_DATA = 0x41, /* 8.2.5.3 */
GSM411_IE_RP_CAUSE = 0x42, /* 8.2.5.4 */
};
/* Chapter 8.2.5.4 Table 8.4 */
enum gsm411_rp_cause {
/* valid only for MO */
GSM411_RP_CAUSE_MO_NUM_UNASSIGNED = 1,
GSM411_RP_CAUSE_MO_OP_DET_BARR = 8,
GSM411_RP_CAUSE_MO_CALL_BARRED = 10,
GSM411_RP_CAUSE_MO_SMS_REJECTED = 21,
GSM411_RP_CAUSE_MO_DEST_OUT_OF_ORDER = 27,
GSM411_RP_CAUSE_MO_UNIDENTIFIED_SUBSCR = 28,
GSM411_RP_CAUSE_MO_FACILITY_REJ = 29,
GSM411_RP_CAUSE_MO_UNKNOWN_SUBSCR = 30,
GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER = 38,
GSM411_RP_CAUSE_MO_TEMP_FAIL = 41,
GSM411_RP_CAUSE_MO_CONGESTION = 42,
GSM411_RP_CAUSE_MO_RES_UNAVAIL = 47,
GSM411_RP_CAUSE_MO_REQ_FAC_NOTSUBSCR = 50,
GSM411_RP_CAUSE_MO_REQ_FAC_NOTIMPL = 69,
GSM411_RP_CAUSE_MO_INTERWORKING = 127,
/* valid only for MT */
GSM411_RP_CAUSE_MT_MEM_EXCEEDED = 22,
/* valid for both directions */
GSM411_RP_CAUSE_INV_TRANS_REF = 81,
GSM411_RP_CAUSE_SEMANT_INC_MSG = 95,
GSM411_RP_CAUSE_INV_MAND_INF = 96,
GSM411_RP_CAUSE_MSGTYPE_NOTEXIST = 97,
GSM411_RP_CAUSE_MSG_INCOMP_STATE = 98,
GSM411_RP_CAUSE_IE_NOTEXIST = 99,
GSM411_RP_CAUSE_PROTOCOL_ERR = 111,
};
/* Chapter 10: Timers */
#define GSM411_TMR_TR1M 40, 0 /* 35 < x < 45 seconds */
#define GSM411_TMR_TRAM 30, 0 /* 25 < x < 35 seconds */
#define GSM411_TMR_TR2M 15, 0 /* 12 < x < 20 seconds */
#define GSM411_TMR_TC1A 30, 0
/* Chapter 8.2.1 */
struct gsm411_rp_hdr {
uint8_t len;
uint8_t msg_type;
uint8_t msg_ref;
uint8_t data[0];
} __attribute__ ((packed));
/* our own enum, not related to on-air protocol */
enum sms_alphabet {
DCS_NONE,
DCS_7BIT_DEFAULT,
DCS_UCS2,
DCS_8BIT_DATA,
};
/* GSM 03.40 / Chapter 9.2.3.1: TP-Message-Type-Indicator */
#define GSM340_SMS_DELIVER_SC2MS 0x00
#define GSM340_SMS_DELIVER_REP_MS2SC 0x00
#define GSM340_SMS_STATUS_REP_SC2MS 0x02
#define GSM340_SMS_COMMAND_MS2SC 0x02
#define GSM340_SMS_SUBMIT_MS2SC 0x01
#define GSM340_SMS_SUBMIT_REP_SC2MS 0x01
#define GSM340_SMS_RESSERVED 0x03
/* GSM 03.40 / Chapter 9.2.3.2: TP-More-Messages-to-Send */
#define GSM340_TP_MMS_MORE 0
#define GSM340_TP_MMS_NO_MORE 1
/* GSM 03.40 / Chapter 9.2.3.3: TP-Validity-Period-Format */
#define GSM340_TP_VPF_NONE 0
#define GSM340_TP_VPF_RELATIVE 2
#define GSM340_TP_VPF_ENHANCED 1
#define GSM340_TP_VPF_ABSOLUTE 3
/* GSM 03.40 / Chapter 9.2.3.4: TP-Status-Report-Indication */
#define GSM340_TP_SRI_NONE 0
#define GSM340_TP_SRI_PRESENT 1
/* GSM 03.40 / Chapter 9.2.3.5: TP-Status-Report-Request */
#define GSM340_TP_SRR_NONE 0
#define GSM340_TP_SRR_REQUESTED 1
/* GSM 03.40 / Chapter 9.2.3.9: TP-Protocol-Identifier */
/* telematic interworking (001 or 111 in bits 7-5) */
#define GSM340_TP_PID_IMPLICIT 0x00
#define GSM340_TP_PID_TELEX 0x01
#define GSM340_TP_PID_FAX_G3 0x02
#define GSM340_TP_PID_FAX_G4 0x03
#define GSM340_TP_PID_VOICE 0x04
#define GSM430_TP_PID_ERMES 0x05
#define GSM430_TP_PID_NATIONAL_PAGING 0x06
#define GSM430_TP_PID_VIDEOTEX 0x07
#define GSM430_TP_PID_TELETEX_UNSPEC 0x08
#define GSM430_TP_PID_TELETEX_PSPDN 0x09
#define GSM430_TP_PID_TELETEX_CSPDN 0x0a
#define GSM430_TP_PID_TELETEX_PSTN 0x0b
#define GSM430_TP_PID_TELETEX_ISDN 0x0c
#define GSM430_TP_PID_TELETEX_UCI 0x0d
#define GSM430_TP_PID_MSG_HANDLING 0x10
#define GSM430_TP_PID_MSG_X400 0x11
#define GSM430_TP_PID_EMAIL 0x12
#define GSM430_TP_PID_GSM_MS 0x1f
/* if bit 7 = 0 and bit 6 = 1 */
#define GSM430_TP_PID_SMS_TYPE_0 0
#define GSM430_TP_PID_SMS_TYPE_1 1
#define GSM430_TP_PID_SMS_TYPE_2 2
#define GSM430_TP_PID_SMS_TYPE_3 3
#define GSM430_TP_PID_SMS_TYPE_4 4
#define GSM430_TP_PID_SMS_TYPE_5 5
#define GSM430_TP_PID_SMS_TYPE_6 6
#define GSM430_TP_PID_SMS_TYPE_7 7
#define GSM430_TP_PID_RETURN_CALL_MSG 0x1f
#define GSM430_TP_PID_ME_DATA_DNLOAD 0x3d
#define GSM430_TP_PID_ME_DE_PERSONAL 0x3e
#define GSM430_TP_PID_ME_SIM_DNLOAD 0x3f
/* GSM 03.38 Chapter 4: SMS Data Coding Scheme */
#define GSM338_DCS_00_
#define GSM338_DCS_1110_7BIT (0 << 2)
#define GSM338_DCS_1111_7BIT (0 << 2)
#define GSM338_DCS_1111_8BIT_DATA (1 << 2)
#define GSM338_DCS_1111_CLASS0 0
#define GSM338_DCS_1111_CLASS1_ME 1
#define GSM338_DCS_1111_CLASS2_SIM 2
#define GSM338_DCS_1111_CLASS3_TE 3 /* See TS 07.05 */
#endif /* PROTO_GSM_04_11_H */

View File

@ -0,0 +1,126 @@
#ifndef PROTO_GSM_04_80_H
#define PROTO_GSM_04_80_H
/* GSM TS 04.80 definitions (Supplementary Services Specification, Formats and Coding) */
/* Section 3.4 */
#define GSM0480_MTYPE_RELEASE_COMPLETE 0x2A
#define GSM0480_MTYPE_FACILITY 0x3A
#define GSM0480_MTYPE_REGISTER 0x3B
/* Section 3.5 */
#define GSM0480_IE_FACILITY 0x1C
#define GSM0480_IE_SS_VERSION 0x7F
/* Section 3.6.2 */
#define GSM0480_CTYPE_INVOKE 0xA1
#define GSM0480_CTYPE_RETURN_RESULT 0xA2
#define GSM0480_CTYPE_RETURN_ERROR 0xA3
#define GSM0480_CTYPE_REJECT 0xA4
/* Section 3.6.3 */
#define GSM0480_COMPIDTAG_INVOKE_ID 0x02
#define GSM0480_COMPIDTAG_LINKED_ID 0x80
/* Section 3.6.4 */
#define GSM0480_OPERATION_CODE 0x02
/* Section 3.6.5 */
#define GSM_0480_SEQUENCE_TAG 0x30
#define GSM_0480_SET_TAG 0x31
/* Section 3.6.6 */
#define GSM_0480_ERROR_CODE_TAG 0x02
/* Section 3.6.7 */
/* Table 3.13 */
#define GSM_0480_PROBLEM_CODE_TAG_GENERAL 0x80
#define GSM_0480_PROBLEM_CODE_TAG_INVOKE 0x81
#define GSM_0480_PROBLEM_CODE_TAG_RETURN_RESULT 0x82
#define GSM_0480_PROBLEM_CODE_TAG_RETURN_ERROR 0x83
/* Table 3.14 */
#define GSM_0480_GEN_PROB_CODE_UNRECOGNISED 0x00
#define GSM_0480_GEN_PROB_CODE_MISTYPED 0x01
#define GSM_0480_GEN_PROB_CODE_BAD_STRUCTURE 0x02
/* Table 3.15 */
#define GSM_0480_INVOKE_PROB_CODE_DUPLICATE_INVOKE_ID 0x00
#define GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_OPERATION 0x01
#define GSM_0480_INVOKE_PROB_CODE_MISTYPED_PARAMETER 0x02
#define GSM_0480_INVOKE_PROB_CODE_RESOURCE_LIMITATION 0x03
#define GSM_0480_INVOKE_PROB_CODE_INITIATING_RELEASE 0x04
#define GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_LINKED_ID 0x05
#define GSM_0480_INVOKE_PROB_CODE_UNEXPECTED_LINKED_RESPONSE 0x06
#define GSM_0480_INVOKE_PROB_CODE_UNEXPECTED_LINKED_OPERATION 0x07
/* Table 3.16 */
#define GSM_0480_RESULT_PROB_CODE_UNRECOGNISED_INVOKE_ID 0x00
#define GSM_0480_RESULT_PROB_CODE_RETURN_RESULT_UNEXPECTED 0x01
#define GSM_0480_RESULT_PROB_CODE_MISTYPED_PARAMETER 0x02
/* Table 3.17 */
#define GSM_0480_ERROR_PROB_CODE_UNRECOGNISED_INVOKE_ID 0x00
#define GSM_0480_ERROR_PROB_CODE_RETURN_ERROR_UNEXPECTED 0x01
#define GSM_0480_ERROR_PROB_CODE_UNRECOGNISED_ERROR 0x02
#define GSM_0480_ERROR_PROB_CODE_UNEXPECTED_ERROR 0x03
#define GSM_0480_ERROR_PROB_CODE_MISTYPED_PARAMETER 0x04
/* Section 4.5 */
#define GSM0480_OP_CODE_REGISTER_SS 0x0A
#define GSM0480_OP_CODE_ERASE_SS 0x0B
#define GSM0480_OP_CODE_ACTIVATE_SS 0x0C
#define GSM0480_OP_CODE_DEACTIVATE_SS 0x0D
#define GSM0480_OP_CODE_INTERROGATE_SS 0x0E
#define GSM0480_OP_CODE_NOTIFY_SS 0x10
#define GSM0480_OP_CODE_REGISTER_PASSWORD 0x11
#define GSM0480_OP_CODE_GET_PASSWORD 0x12
#define GSM0480_OP_CODE_PROCESS_USS_DATA 0x13
#define GSM0480_OP_CODE_FORWARD_CHECK_SS_IND 0x26
#define GSM0480_OP_CODE_PROCESS_USS_REQ 0x3B
#define GSM0480_OP_CODE_USS_REQUEST 0x3C
#define GSM0480_OP_CODE_USS_NOTIFY 0x3D
#define GSM0480_OP_CODE_FORWARD_CUG_INFO 0x78
#define GSM0480_OP_CODE_SPLIT_MPTY 0x79
#define GSM0480_OP_CODE_RETRIEVE_MPTY 0x7A
#define GSM0480_OP_CODE_HOLD_MPTY 0x7B
#define GSM0480_OP_CODE_BUILD_MPTY 0x7C
#define GSM0480_OP_CODE_FORWARD_CHARGE_ADVICE 0x7D
#define GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER 0x01
#define GSM0480_ERR_CODE_ILLEGAL_SUBSCRIBER 0x09
#define GSM0480_ERR_CODE_BEARER_SERVICE_NOT_PROVISIONED 0x0A
#define GSM0480_ERR_CODE_TELESERVICE_NOT_PROVISIONED 0x0B
#define GSM0480_ERR_CODE_ILLEGAL_EQUIPMENT 0x0C
#define GSM0480_ERR_CODE_CALL_BARRED 0x0D
#define GSM0480_ERR_CODE_ILLEGAL_SS_OPERATION 0x10
#define GSM0480_ERR_CODE_SS_ERROR_STATUS 0x11
#define GSM0480_ERR_CODE_SS_NOT_AVAILABLE 0x12
#define GSM0480_ERR_CODE_SS_SUBSCRIPTION_VIOLATION 0x13
#define GSM0480_ERR_CODE_SS_INCOMPATIBILITY 0x14
#define GSM0480_ERR_CODE_FACILITY_NOT_SUPPORTED 0x15
#define GSM0480_ERR_CODE_ABSENT_SUBSCRIBER 0x1B
#define GSM0480_ERR_CODE_SYSTEM_FAILURE 0x22
#define GSM0480_ERR_CODE_DATA_MISSING 0x23
#define GSM0480_ERR_CODE_UNEXPECTED_DATA_VALUE 0x24
#define GSM0480_ERR_CODE_PW_REGISTRATION_FAILURE 0x25
#define GSM0480_ERR_CODE_NEGATIVE_PW_CHECK 0x26
#define GSM0480_ERR_CODE_NUM_PW_ATTEMPTS_VIOLATION 0x2B
#define GSM0480_ERR_CODE_UNKNOWN_ALPHABET 0x47
#define GSM0480_ERR_CODE_USSD_BUSY 0x48
#define GSM0480_ERR_CODE_MAX_MPTY_PARTICIPANTS 0x7E
#define GSM0480_ERR_CODE_RESOURCES_NOT_AVAILABLE 0x7F
/* ASN.1 type-tags */
#define ASN1_BOOLEAN_TAG 0x01
#define ASN1_INTEGER_TAG 0x02
#define ASN1_BIT_STRING_TAG 0x03
#define ASN1_OCTET_STRING_TAG 0x04
#define ASN1_NULL_TYPE_TAG 0x05
#define ASN1_OBJECT_ID_TAG 0x06
#define ASN1_UTF8_STRING_TAG 0x0C
#define ASN1_PRINTABLE_STRING_TAG 0x13
#define ASN1_IA5_STRING_TAG 0x16
#define ASN1_UNICODE_STRING_TAG 0x1E
#endif /* PROTO_GSM_04_80_H */

View File

@ -0,0 +1,303 @@
/* From GSM08.08 */
#ifndef GSM_0808_H
#define GSM_0808_H
#include <stdlib.h>
/*
* this is from GSM 03.03 CGI but is copied in GSM 08.08
* in § 3.2.2.27 for Cell Identifier List
*/
enum CELL_IDENT {
CELL_IDENT_WHOLE_GLOBAL = 0,
CELL_IDENT_LAC_AND_CI = 1,
CELL_IDENT_CI = 2,
CELL_IDENT_NO_CELL = 3,
CELL_IDENT_LAI_AND_LAC = 4,
CELL_IDENT_LAC = 5,
CELL_IDENT_BSS = 6,
CELL_IDENT_UTRAN_PLMN_LAC_RNC = 8,
CELL_IDENT_UTRAN_RNC = 9,
CELL_IDENT_UTRAN_LAC_RNC = 10,
};
/* GSM 08.06 § 6.3 */
enum BSSAP_MSG_TYPE {
BSSAP_MSG_BSS_MANAGEMENT = 0x0,
BSSAP_MSG_DTAP = 0x1,
};
struct bssmap_header {
uint8_t type;
uint8_t length;
} __attribute__((packed));
struct dtap_header {
uint8_t type;
uint8_t link_id;
uint8_t length;
} __attribute__((packed));
enum BSS_MAP_MSG_TYPE {
BSS_MAP_MSG_RESERVED_0 = 0,
/* ASSIGNMENT MESSAGES */
BSS_MAP_MSG_ASSIGMENT_RQST = 1,
BSS_MAP_MSG_ASSIGMENT_COMPLETE = 2,
BSS_MAP_MSG_ASSIGMENT_FAILURE = 3,
/* HANDOVER MESSAGES */
BSS_MAP_MSG_HANDOVER_RQST = 16,
BSS_MAP_MSG_HANDOVER_REQUIRED = 17,
BSS_MAP_MSG_HANDOVER_RQST_ACKNOWLEDGE= 18,
BSS_MAP_MSG_HANDOVER_CMD = 19,
BSS_MAP_MSG_HANDOVER_COMPLETE = 20,
BSS_MAP_MSG_HANDOVER_SUCCEEDED = 21,
BSS_MAP_MSG_HANDOVER_FAILURE = 22,
BSS_MAP_MSG_HANDOVER_PERFORMED = 23,
BSS_MAP_MSG_HANDOVER_CANDIDATE_ENQUIRE = 24,
BSS_MAP_MSG_HANDOVER_CANDIDATE_RESPONSE = 25,
BSS_MAP_MSG_HANDOVER_REQUIRED_REJECT = 26,
BSS_MAP_MSG_HANDOVER_DETECT = 27,
/* RELEASE MESSAGES */
BSS_MAP_MSG_CLEAR_CMD = 32,
BSS_MAP_MSG_CLEAR_COMPLETE = 33,
BSS_MAP_MSG_CLEAR_RQST = 34,
BSS_MAP_MSG_RESERVED_1 = 35,
BSS_MAP_MSG_RESERVED_2 = 36,
BSS_MAP_MSG_SAPI_N_REJECT = 37,
BSS_MAP_MSG_CONFUSION = 38,
/* OTHER CONNECTION RELATED MESSAGES */
BSS_MAP_MSG_SUSPEND = 40,
BSS_MAP_MSG_RESUME = 41,
BSS_MAP_MSG_CONNECTION_ORIENTED_INFORMATION = 42,
BSS_MAP_MSG_PERFORM_LOCATION_RQST = 43,
BSS_MAP_MSG_LSA_INFORMATION = 44,
BSS_MAP_MSG_PERFORM_LOCATION_RESPONSE = 45,
BSS_MAP_MSG_PERFORM_LOCATION_ABORT = 46,
BSS_MAP_MSG_COMMON_ID = 47,
/* GENERAL MESSAGES */
BSS_MAP_MSG_RESET = 48,
BSS_MAP_MSG_RESET_ACKNOWLEDGE = 49,
BSS_MAP_MSG_OVERLOAD = 50,
BSS_MAP_MSG_RESERVED_3 = 51,
BSS_MAP_MSG_RESET_CIRCUIT = 52,
BSS_MAP_MSG_RESET_CIRCUIT_ACKNOWLEDGE = 53,
BSS_MAP_MSG_MSC_INVOKE_TRACE = 54,
BSS_MAP_MSG_BSS_INVOKE_TRACE = 55,
BSS_MAP_MSG_CONNECTIONLESS_INFORMATION = 58,
/* TERRESTRIAL RESOURCE MESSAGES */
BSS_MAP_MSG_BLOCK = 64,
BSS_MAP_MSG_BLOCKING_ACKNOWLEDGE = 65,
BSS_MAP_MSG_UNBLOCK = 66,
BSS_MAP_MSG_UNBLOCKING_ACKNOWLEDGE = 67,
BSS_MAP_MSG_CIRCUIT_GROUP_BLOCK = 68,
BSS_MAP_MSG_CIRCUIT_GROUP_BLOCKING_ACKNOWLEDGE = 69,
BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCK = 70,
BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCKING_ACKNOWLEDGE = 71,
BSS_MAP_MSG_UNEQUIPPED_CIRCUIT = 72,
BSS_MAP_MSG_CHANGE_CIRCUIT = 78,
BSS_MAP_MSG_CHANGE_CIRCUIT_ACKNOWLEDGE = 79,
/* RADIO RESOURCE MESSAGES */
BSS_MAP_MSG_RESOURCE_RQST = 80,
BSS_MAP_MSG_RESOURCE_INDICATION = 81,
BSS_MAP_MSG_PAGING = 82,
BSS_MAP_MSG_CIPHER_MODE_CMD = 83,
BSS_MAP_MSG_CLASSMARK_UPDATE = 84,
BSS_MAP_MSG_CIPHER_MODE_COMPLETE = 85,
BSS_MAP_MSG_QUEUING_INDICATION = 86,
BSS_MAP_MSG_COMPLETE_LAYER_3 = 87,
BSS_MAP_MSG_CLASSMARK_RQST = 88,
BSS_MAP_MSG_CIPHER_MODE_REJECT = 89,
BSS_MAP_MSG_LOAD_INDICATION = 90,
/* VGCS/VBS */
BSS_MAP_MSG_VGCS_VBS_SETUP = 4,
BSS_MAP_MSG_VGCS_VBS_SETUP_ACK = 5,
BSS_MAP_MSG_VGCS_VBS_SETUP_REFUSE = 6,
BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RQST = 7,
BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RESULT = 28,
BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_FAILURE = 29,
BSS_MAP_MSG_VGCS_VBS_QUEUING_INDICATION = 30,
BSS_MAP_MSG_UPLINK_RQST = 31,
BSS_MAP_MSG_UPLINK_RQST_ACKNOWLEDGE = 39,
BSS_MAP_MSG_UPLINK_RQST_CONFIRMATION = 73,
BSS_MAP_MSG_UPLINK_RELEASE_INDICATION = 74,
BSS_MAP_MSG_UPLINK_REJECT_CMD = 75,
BSS_MAP_MSG_UPLINK_RELEASE_CMD = 76,
BSS_MAP_MSG_UPLINK_SEIZED_CMD = 77,
};
enum GSM0808_IE_CODING {
GSM0808_IE_CIRCUIT_IDENTITY_CODE = 1,
GSM0808_IE_RESERVED_0 = 2,
GSM0808_IE_RESOURCE_AVAILABLE = 3,
GSM0808_IE_CAUSE = 4,
GSM0808_IE_CELL_IDENTIFIER = 5,
GSM0808_IE_PRIORITY = 6,
GSM0808_IE_LAYER_3_HEADER_INFORMATION = 7,
GSM0808_IE_IMSI = 8,
GSM0808_IE_TMSI = 9,
GSM0808_IE_ENCRYPTION_INFORMATION = 10,
GSM0808_IE_CHANNEL_TYPE = 11,
GSM0808_IE_PERIODICITY = 12,
GSM0808_IE_EXTENDED_RESOURCE_INDICATOR = 13,
GSM0808_IE_NUMBER_OF_MSS = 14,
GSM0808_IE_RESERVED_1 = 15,
GSM0808_IE_RESERVED_2 = 16,
GSM0808_IE_RESERVED_3 = 17,
GSM0808_IE_CLASSMARK_INFORMATION_T2 = 18,
GSM0808_IE_CLASSMARK_INFORMATION_T3 = 19,
GSM0808_IE_INTERFERENCE_BAND_TO_USE = 20,
GSM0808_IE_RR_CAUSE = 21,
GSM0808_IE_RESERVED_4 = 22,
GSM0808_IE_LAYER_3_INFORMATION = 23,
GSM0808_IE_DLCI = 24,
GSM0808_IE_DOWNLINK_DTX_FLAG = 25,
GSM0808_IE_CELL_IDENTIFIER_LIST = 26,
GSM0808_IE_RESPONSE_RQST = 27,
GSM0808_IE_RESOURCE_INDICATION_METHOD = 28,
GSM0808_IE_CLASSMARK_INFORMATION_TYPE_1 = 29,
GSM0808_IE_CIRCUIT_IDENTITY_CODE_LIST = 30,
GSM0808_IE_DIAGNOSTIC = 31,
GSM0808_IE_LAYER_3_MESSAGE_CONTENTS = 32,
GSM0808_IE_CHOSEN_CHANNEL = 33,
GSM0808_IE_TOTAL_RESOURCE_ACCESSIBLE = 34,
GSM0808_IE_CIPHER_RESPONSE_MODE = 35,
GSM0808_IE_CHANNEL_NEEDED = 36,
GSM0808_IE_TRACE_TYPE = 37,
GSM0808_IE_TRIGGERID = 38,
GSM0808_IE_TRACE_REFERENCE = 39,
GSM0808_IE_TRANSACTIONID = 40,
GSM0808_IE_MOBILE_IDENTITY = 41,
GSM0808_IE_OMCID = 42,
GSM0808_IE_FORWARD_INDICATOR = 43,
GSM0808_IE_CHOSEN_ENCR_ALG = 44,
GSM0808_IE_CIRCUIT_POOL = 45,
GSM0808_IE_CIRCUIT_POOL_LIST = 46,
GSM0808_IE_TIME_INDICATION = 47,
GSM0808_IE_RESOURCE_SITUATION = 48,
GSM0808_IE_CURRENT_CHANNEL_TYPE_1 = 49,
GSM0808_IE_QUEUEING_INDICATOR = 50,
GSM0808_IE_SPEECH_VERSION = 64,
GSM0808_IE_ASSIGNMENT_REQUIREMENT = 51,
GSM0808_IE_TALKER_FLAG = 53,
GSM0808_IE_CONNECTION_RELEASE_RQSTED = 54,
GSM0808_IE_GROUP_CALL_REFERENCE = 55,
GSM0808_IE_EMLPP_PRIORITY = 56,
GSM0808_IE_CONFIG_EVO_INDI = 57,
GSM0808_IE_OLD_BSS_TO_NEW_BSS_INFORMATION = 58,
GSM0808_IE_LSA_IDENTIFIER = 59,
GSM0808_IE_LSA_IDENTIFIER_LIST = 60,
GSM0808_IE_LSA_INFORMATION = 61,
GSM0808_IE_LCS_QOS = 62,
GSM0808_IE_LSA_ACCESS_CTRL_SUPPR = 63,
GSM0808_IE_LCS_PRIORITY = 67,
GSM0808_IE_LOCATION_TYPE = 68,
GSM0808_IE_LOCATION_ESTIMATE = 69,
GSM0808_IE_POSITIONING_DATA = 70,
GSM0808_IE_LCS_CAUSE = 71,
GSM0808_IE_LCS_CLIENT_TYPE = 72,
GSM0808_IE_APDU = 73,
GSM0808_IE_NETWORK_ELEMENT_IDENTITY = 74,
GSM0808_IE_GPS_ASSISTANCE_DATA = 75,
GSM0808_IE_DECIPHERING_KEYS = 76,
GSM0808_IE_RETURN_ERROR_RQST = 77,
GSM0808_IE_RETURN_ERROR_CAUSE = 78,
GSM0808_IE_SEGMENTATION = 79,
GSM0808_IE_SERVICE_HANDOVER = 80,
GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_UMTS = 81,
GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_CDMA2000= 82,
GSM0808_IE_RESERVED_5 = 65,
GSM0808_IE_RESERVED_6 = 66,
};
enum gsm0808_cause {
GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE = 0,
GSM0808_CAUSE_RADIO_INTERFACE_FAILURE = 1,
GSM0808_CAUSE_UPLINK_QUALITY = 2,
GSM0808_CAUSE_UPLINK_STRENGTH = 3,
GSM0808_CAUSE_DOWNLINK_QUALITY = 4,
GSM0808_CAUSE_DOWNLINK_STRENGTH = 5,
GSM0808_CAUSE_DISTANCE = 6,
GSM0808_CAUSE_O_AND_M_INTERVENTION = 7,
GSM0808_CAUSE_RESPONSE_TO_MSC_INVOCATION = 8,
GSM0808_CAUSE_CALL_CONTROL = 9,
GSM0808_CAUSE_RADIO_INTERFACE_FAILURE_REVERSION = 10,
GSM0808_CAUSE_HANDOVER_SUCCESSFUL = 11,
GSM0808_CAUSE_BETTER_CELL = 12,
GSM0808_CAUSE_DIRECTED_RETRY = 13,
GSM0808_CAUSE_JOINED_GROUP_CALL_CHANNEL = 14,
GSM0808_CAUSE_TRAFFIC = 15,
GSM0808_CAUSE_EQUIPMENT_FAILURE = 32,
GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE = 33,
GSM0808_CAUSE_RQSTED_TERRESTRIAL_RESOURCE_UNAVAILABLE = 34,
GSM0808_CAUSE_CCCH_OVERLOAD = 35,
GSM0808_CAUSE_PROCESSOR_OVERLOAD = 36,
GSM0808_CAUSE_BSS_NOT_EQUIPPED = 37,
GSM0808_CAUSE_MS_NOT_EQUIPPED = 38,
GSM0808_CAUSE_INVALID_CELL = 39,
GSM0808_CAUSE_TRAFFIC_LOAD = 40,
GSM0808_CAUSE_PREEMPTION = 41,
GSM0808_CAUSE_RQSTED_TRANSCODING_RATE_ADAPTION_UNAVAILABLE = 48,
GSM0808_CAUSE_CIRCUIT_POOL_MISMATCH = 49,
GSM0808_CAUSE_SWITCH_CIRCUIT_POOL = 50,
GSM0808_CAUSE_RQSTED_SPEECH_VERSION_UNAVAILABLE = 51,
GSM0808_CAUSE_LSA_NOT_ALLOWED = 52,
GSM0808_CAUSE_CIPHERING_ALGORITHM_NOT_SUPPORTED = 64,
GSM0808_CAUSE_TERRESTRIAL_CIRCUIT_ALREADY_ALLOCATED = 80,
GSM0808_CAUSE_INVALID_MESSAGE_CONTENTS = 81,
GSM0808_CAUSE_INFORMATION_ELEMENT_OR_FIELD_MISSING = 82,
GSM0808_CAUSE_INCORRECT_VALUE = 83,
GSM0808_CAUSE_UNKNOWN_MESSAGE_TYPE = 84,
GSM0808_CAUSE_UNKNOWN_INFORMATION_ELEMENT = 85,
GSM0808_CAUSE_PROTOCOL_ERROR_BETWEEN_BSS_AND_MSC = 96,
};
/* GSM 08.08 3.2.2.11 Channel Type */
enum gsm0808_chan_indicator {
GSM0808_CHAN_SPEECH = 1,
GSM0808_CHAN_DATA = 2,
GSM0808_CHAN_SIGN = 3,
};
enum gsm0808_chan_rate_type_data {
GSM0808_DATA_FULL_BM = 0x8,
GSM0808_DATA_HALF_LM = 0x9,
GSM0808_DATA_FULL_RPREF = 0xa,
GSM0808_DATA_HALF_PREF = 0xb,
GSM0808_DATA_FULL_PREF_NO_CHANGE = 0x1a,
GSM0808_DATA_HALF_PREF_NO_CHANGE = 0x1b,
GSM0808_DATA_MULTI_MASK = 0x20,
GSM0808_DATA_MULTI_MASK_NO_CHANGE = 0x30,
};
enum gsm0808_chan_rate_type_speech {
GSM0808_SPEECH_FULL_BM = 0x8,
GSM0808_SPEECH_HALF_LM = 0x9,
GSM0808_SPEECH_FULL_PREF= 0xa,
GSM0808_SPEECH_HALF_PREF= 0xb,
GSM0808_SPEECH_FULL_PREF_NO_CHANGE = 0x1a,
GSM0808_SPEECH_HALF_PREF_NO_CHANGE = 0x1b,
GSM0808_SPEECH_PERM = 0xf,
GSM0808_SPEECH_PERM_NO_CHANGE = 0x1f,
};
enum gsm0808_permitted_speech {
GSM0808_PERM_FR1 = 0x01,
GSM0808_PERM_FR2 = 0x11,
GSM0808_PERM_FR3 = 0x21,
GSM0808_PERM_HR1 = GSM0808_PERM_FR1 | 0x4,
GSM0808_PERM_HR2 = GSM0808_PERM_FR2 | 0x4,
GSM0808_PERM_HR3 = GSM0808_PERM_FR3 | 0x4,
};
#endif

View File

@ -0,0 +1,516 @@
#ifndef PROTO_GSM_08_58_H
#define PROTO_GSM_08_58_H
/* GSM Radio Signalling Link messages on the A-bis interface
* 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */
/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdint.h>
struct abis_rsl_common_hdr {
uint8_t msg_discr;
uint8_t msg_type;
uint8_t data[0];
} __attribute__ ((packed));
/* Chapter 8.3 */
struct abis_rsl_rll_hdr {
struct abis_rsl_common_hdr c;
uint8_t ie_chan;
uint8_t chan_nr;
uint8_t ie_link_id;
uint8_t link_id;
uint8_t data[0];
} __attribute__ ((packed));
/* Chapter 8.3 and 8.4 */
struct abis_rsl_dchan_hdr {
struct abis_rsl_common_hdr c;
uint8_t ie_chan;
uint8_t chan_nr;
uint8_t data[0];
} __attribute__ ((packed));
/* Chapter 9.1 */
#define ABIS_RSL_MDISC_RLL 0x02
#define ABIS_RSL_MDISC_DED_CHAN 0x08
#define ABIS_RSL_MDISC_COM_CHAN 0x0c
#define ABIS_RSL_MDISC_TRX 0x10
#define ABIS_RSL_MDISC_LOC 0x20
#define ABIS_RSL_MDISC_IPACCESS 0x7e
#define ABIS_RSL_MDISC_TRANSP 0x01
#define ABIS_RSL_MDISC_IS_TRANSP(x) (x & 0x01)
/* Chapter 9.1 */
enum abis_rsl_msgtype {
/* Radio Link Layer Management */
RSL_MT_DATA_REQ = 0x01,
RSL_MT_DATA_IND,
RSL_MT_ERROR_IND,
RSL_MT_EST_REQ,
RSL_MT_EST_CONF,
RSL_MT_EST_IND,
RSL_MT_REL_REQ,
RSL_MT_REL_CONF,
RSL_MT_REL_IND,
RSL_MT_UNIT_DATA_REQ,
RSL_MT_UNIT_DATA_IND, /* 0x0b */
RSL_MT_SUSP_REQ, /* non-standard elements */
RSL_MT_SUSP_CONF,
RSL_MT_RES_REQ,
RSL_MT_RECON_REQ, /* 0x0f */
/* Common Channel Management / TRX Management */
RSL_MT_BCCH_INFO = 0x11,
RSL_MT_CCCH_LOAD_IND,
RSL_MT_CHAN_RQD,
RSL_MT_DELETE_IND,
RSL_MT_PAGING_CMD,
RSL_MT_IMMEDIATE_ASSIGN_CMD,
RSL_MT_SMS_BC_REQ,
/* empty */
RSL_MT_RF_RES_IND = 0x19,
RSL_MT_SACCH_FILL,
RSL_MT_OVERLOAD,
RSL_MT_ERROR_REPORT,
RSL_MT_SMS_BC_CMD,
RSL_MT_CBCH_LOAD_IND,
RSL_MT_NOT_CMD, /* 0x1f */
/* Dedicate Channel Management */
RSL_MT_CHAN_ACTIV = 0x21,
RSL_MT_CHAN_ACTIV_ACK,
RSL_MT_CHAN_ACTIV_NACK,
RSL_MT_CONN_FAIL,
RSL_MT_DEACTIVATE_SACCH,
RSL_MT_ENCR_CMD,
RSL_MT_HANDO_DET,
RSL_MT_MEAS_RES,
RSL_MT_MODE_MODIFY_REQ,
RSL_MT_MODE_MODIFY_ACK,
RSL_MT_MODE_MODIFY_NACK,
RSL_MT_PHY_CONTEXT_REQ,
RSL_MT_PHY_CONTEXT_CONF,
RSL_MT_RF_CHAN_REL,
RSL_MT_MS_POWER_CONTROL,
RSL_MT_BS_POWER_CONTROL, /* 0x30 */
RSL_MT_PREPROC_CONFIG,
RSL_MT_PREPROC_MEAS_RES,
RSL_MT_RF_CHAN_REL_ACK,
RSL_MT_SACCH_INFO_MODIFY,
RSL_MT_TALKER_DET,
RSL_MT_LISTENER_DET,
RSL_MT_REMOTE_CODEC_CONF_REP,
RSL_MT_RTD_REP,
RSL_MT_PRE_HANDO_NOTIF,
RSL_MT_MR_CODEC_MOD_REQ,
RSL_MT_MR_CODEC_MOD_ACK,
RSL_MT_MR_CODEC_MOD_NACK,
RSL_MT_MR_CODEC_MOD_PER,
RSL_MT_TFO_REP,
RSL_MT_TFO_MOD_REQ, /* 0x3f */
RSL_MT_LOCATION_INFO = 0x41,
/* ip.access specific RSL message types */
RSL_MT_IPAC_DIR_RETR_ENQ = 0x40,
RSL_MT_IPAC_PDCH_ACT = 0x48,
RSL_MT_IPAC_PDCH_ACT_ACK,
RSL_MT_IPAC_PDCH_ACT_NACK,
RSL_MT_IPAC_PDCH_DEACT = 0x4b,
RSL_MT_IPAC_PDCH_DEACT_ACK,
RSL_MT_IPAC_PDCH_DEACT_NACK,
RSL_MT_IPAC_CONNECT_MUX = 0x50,
RSL_MT_IPAC_CONNECT_MUX_ACK,
RSL_MT_IPAC_CONNECT_MUX_NACK,
RSL_MT_IPAC_BIND_MUX = 0x53,
RSL_MT_IPAC_BIND_MUX_ACK,
RSL_MT_IPAC_BIND_MUX_NACK,
RSL_MT_IPAC_DISC_MUX = 0x56,
RSL_MT_IPAC_DISC_MUX_ACK,
RSL_MT_IPAC_DISC_MUX_NACK,
RSL_MT_IPAC_CRCX = 0x70, /* Bind to local BTS RTP port */
RSL_MT_IPAC_CRCX_ACK,
RSL_MT_IPAC_CRCX_NACK,
RSL_MT_IPAC_MDCX = 0x73,
RSL_MT_IPAC_MDCX_ACK,
RSL_MT_IPAC_MDCX_NACK,
RSL_MT_IPAC_DLCX_IND = 0x76,
RSL_MT_IPAC_DLCX = 0x77,
RSL_MT_IPAC_DLCX_ACK,
RSL_MT_IPAC_DLCX_NACK,
};
/* Siemens vendor-specific */
enum abis_rsl_msgtype_siemens {
RSL_MT_SIEMENS_MRPCI = 0x41,
RSL_MT_SIEMENS_INTRAC_HO_COND_IND = 0x42,
RSL_MT_SIEMENS_INTERC_HO_COND_IND = 0x43,
RSL_MT_SIEMENS_FORCED_HO_REQ = 0x44,
RSL_MT_SIEMENS_PREF_AREA_REQ = 0x45,
RSL_MT_SIEMENS_PREF_AREA = 0x46,
RSL_MT_SIEMENS_START_TRACE = 0x47,
RSL_MT_SIEMENS_START_TRACE_ACK = 0x48,
RSL_MT_SIEMENS_STOP_TRACE = 0x49,
RSL_MT_SIEMENS_TRMR = 0x4a,
RSL_MT_SIEMENS_HO_FAIL_IND = 0x4b,
RSL_MT_SIEMENS_STOP_TRACE_ACK = 0x4c,
RSL_MT_SIEMENS_UPLF = 0x4d,
RSL_MT_SIEMENS_UPLB = 0x4e,
RSL_MT_SIEMENS_SET_SYS_INFO_10 = 0x4f,
RSL_MT_SIEMENS_MODIF_COND_IND = 0x50,
};
/* Chapter 9.3 */
enum abis_rsl_ie {
RSL_IE_CHAN_NR = 0x01,
RSL_IE_LINK_IDENT,
RSL_IE_ACT_TYPE,
RSL_IE_BS_POWER,
RSL_IE_CHAN_IDENT,
RSL_IE_CHAN_MODE,
RSL_IE_ENCR_INFO,
RSL_IE_FRAME_NUMBER,
RSL_IE_HANDO_REF,
RSL_IE_L1_INFO,
RSL_IE_L3_INFO,
RSL_IE_MS_IDENTITY,
RSL_IE_MS_POWER,
RSL_IE_PAGING_GROUP,
RSL_IE_PAGING_LOAD,
RSL_IE_PYHS_CONTEXT = 0x10,
RSL_IE_ACCESS_DELAY,
RSL_IE_RACH_LOAD,
RSL_IE_REQ_REFERENCE,
RSL_IE_RELEASE_MODE,
RSL_IE_RESOURCE_INFO,
RSL_IE_RLM_CAUSE,
RSL_IE_STARTNG_TIME,
RSL_IE_TIMING_ADVANCE,
RSL_IE_UPLINK_MEAS,
RSL_IE_CAUSE,
RSL_IE_MEAS_RES_NR,
RSL_IE_MSG_ID,
/* reserved */
RSL_IE_SYSINFO_TYPE = 0x1e,
RSL_IE_MS_POWER_PARAM,
RSL_IE_BS_POWER_PARAM,
RSL_IE_PREPROC_PARAM,
RSL_IE_PREPROC_MEAS,
RSL_IE_IMM_ASS_INFO, /* Phase 1 (3.6.0), later Full below */
RSL_IE_SMSCB_INFO = 0x24,
RSL_IE_MS_TIMING_OFFSET,
RSL_IE_ERR_MSG,
RSL_IE_FULL_BCCH_INFO,
RSL_IE_CHAN_NEEDED,
RSL_IE_CB_CMD_TYPE,
RSL_IE_SMSCB_MSG,
RSL_IE_FULL_IMM_ASS_INFO,
RSL_IE_SACCH_INFO,
RSL_IE_CBCH_LOAD_INFO,
RSL_IE_SMSCB_CHAN_INDICATOR,
RSL_IE_GROUP_CALL_REF,
RSL_IE_CHAN_DESC = 0x30,
RSL_IE_NCH_DRX_INFO,
RSL_IE_CMD_INDICATOR,
RSL_IE_EMLPP_PRIO,
RSL_IE_UIC,
RSL_IE_MAIN_CHAN_REF,
RSL_IE_MR_CONFIG,
RSL_IE_MR_CONTROL,
RSL_IE_SUP_CODEC_TYPES,
RSL_IE_CODEC_CONFIG,
RSL_IE_RTD,
RSL_IE_TFO_STATUS,
RSL_IE_LLP_APDU,
/* Siemens vendor-specific */
RSL_IE_SIEMENS_MRPCI = 0x40,
RSL_IE_SIEMENS_PREF_AREA_TYPE = 0x43,
RSL_IE_SIEMENS_ININ_CELL_HO_PAR = 0x45,
RSL_IE_SIEMENS_TRACE_REF_NR = 0x46,
RSL_IE_SIEMENS_INT_TRACE_IDX = 0x47,
RSL_IE_SIEMENS_L2_HDR_INFO = 0x48,
RSL_IE_SIEMENS_HIGHEST_RATE = 0x4e,
RSL_IE_SIEMENS_SUGGESTED_RATE = 0x4f,
/* ip.access */
RSL_IE_IPAC_SRTP_CONFIG = 0xe0,
RSL_IE_IPAC_PROXY_UDP = 0xe1,
RSL_IE_IPAC_BSCMPL_TOUT = 0xe2,
RSL_IE_IPAC_REMOTE_IP = 0xf0,
RSL_IE_IPAC_REMOTE_PORT = 0xf1,
RSL_IE_IPAC_RTP_PAYLOAD = 0xf2,
RSL_IE_IPAC_LOCAL_PORT = 0xf3,
RSL_IE_IPAC_SPEECH_MODE = 0xf4,
RSL_IE_IPAC_LOCAL_IP = 0xf5,
RSL_IE_IPAC_CONN_STAT = 0xf6,
RSL_IE_IPAC_HO_C_PARMS = 0xf7,
RSL_IE_IPAC_CONN_ID = 0xf8,
RSL_IE_IPAC_RTP_CSD_FMT = 0xf9,
RSL_IE_IPAC_RTP_JIT_BUF = 0xfa,
RSL_IE_IPAC_RTP_COMPR = 0xfb,
RSL_IE_IPAC_RTP_PAYLOAD2= 0xfc,
RSL_IE_IPAC_RTP_MPLEX = 0xfd,
RSL_IE_IPAC_RTP_MPLEX_ID= 0xfe,
};
/* Chapter 9.3.1 */
#define RSL_CHAN_NR_MASK 0xf8
#define RSL_CHAN_Bm_ACCHs 0x08
#define RSL_CHAN_Lm_ACCHs 0x10 /* .. 0x18 */
#define RSL_CHAN_SDCCH4_ACCH 0x20 /* .. 0x38 */
#define RSL_CHAN_SDCCH8_ACCH 0x40 /* ...0x78 */
#define RSL_CHAN_BCCH 0x80
#define RSL_CHAN_RACH 0x88
#define RSL_CHAN_PCH_AGCH 0x90
/* Chapter 9.3.3 */
#define RSL_ACT_TYPE_INITIAL 0x00
#define RSL_ACT_TYPE_REACT 0x80
#define RSL_ACT_INTRA_IMM_ASS 0x00
#define RSL_ACT_INTRA_NORM_ASS 0x01
#define RSL_ACT_INTER_ASYNC 0x02
#define RSL_ACT_INTER_SYNC 0x03
#define RSL_ACT_SECOND_ADD 0x04
#define RSL_ACT_SECOND_MULTI 0x05
/* Chapter 9.3.6 */
struct rsl_ie_chan_mode {
uint8_t dtx_dtu;
uint8_t spd_ind;
uint8_t chan_rt;
uint8_t chan_rate;
} __attribute__ ((packed));
#define RSL_CMOD_DTXu 0x01 /* uplink */
#define RSL_CMOD_DTXd 0x02 /* downlink */
enum rsl_cmod_spd {
RSL_CMOD_SPD_SPEECH = 0x01,
RSL_CMOD_SPD_DATA = 0x02,
RSL_CMOD_SPD_SIGN = 0x03,
};
#define RSL_CMOD_CRT_SDCCH 0x01
#define RSL_CMOD_CRT_TCH_Bm 0x08 /* full-rate */
#define RSL_CMOD_CRT_TCH_Lm 0x09 /* half-rate */
/* FIXME: More CRT types */
/* Speech */
#define RSL_CMOD_SP_GSM1 0x01
#define RSL_CMOD_SP_GSM2 0x11
#define RSL_CMOD_SP_GSM3 0x21
/* Data */
#define RSL_CMOD_SP_NT_14k5 0x58
#define RSL_CMOD_SP_NT_12k0 0x50
#define RSL_CMOD_SP_NT_6k0 0x51
/* Chapter 9.3.5 */
struct rsl_ie_chan_ident {
/* GSM 04.08 10.5.2.5 */
struct {
uint8_t iei;
uint8_t chan_nr; /* enc_chan_nr */
uint8_t oct3;
uint8_t oct4;
} chan_desc;
#if 0 /* spec says we need this but Abissim doesn't use it */
struct {
uint8_t tag;
uint8_t len;
} mobile_alloc;
#endif
} __attribute__ ((packed));
/* Chapter 9.3.22 */
#define RLL_CAUSE_T200_EXPIRED 0x01
#define RLL_CAUSE_REEST_REQ 0x02
#define RLL_CAUSE_UNSOL_UA_RESP 0x03
#define RLL_CAUSE_UNSOL_DM_RESP 0x04
#define RLL_CAUSE_UNSOL_DM_RESP_MF 0x05
#define RLL_CAUSE_UNSOL_SPRV_RESP 0x06
#define RLL_CAUSE_SEQ_ERR 0x07
#define RLL_CAUSE_UFRM_INC_PARAM 0x08
#define RLL_CAUSE_SFRM_INC_PARAM 0x09
#define RLL_CAUSE_IFRM_INC_MBITS 0x0a
#define RLL_CAUSE_IFRM_INC_LEN 0x0b
#define RLL_CAUSE_FRM_UNIMPL 0x0c
#define RLL_CAUSE_SABM_MF 0x0d
#define RLL_CAUSE_SABM_INFO_NOTALL 0x0e
/* Chapter 9.3.26 */
#define RSL_ERRCLS_NORMAL 0x00
#define RSL_ERRCLS_RESOURCE_UNAVAIL 0x20
#define RSL_ERRCLS_SERVICE_UNAVAIL 0x30
#define RSL_ERRCLS_SERVICE_UNIMPL 0x40
#define RSL_ERRCLS_INVAL_MSG 0x50
#define RSL_ERRCLS_PROTO_ERROR 0x60
#define RSL_ERRCLS_INTERWORKING 0x70
/* normal event */
#define RSL_ERR_RADIO_IF_FAIL 0x00
#define RSL_ERR_RADIO_LINK_FAIL 0x01
#define RSL_ERR_HANDOVER_ACC_FAIL 0x02
#define RSL_ERR_TALKER_ACC_FAIL 0x03
#define RSL_ERR_OM_INTERVENTION 0x07
#define RSL_ERR_NORMAL_UNSPEC 0x0f
#define RSL_ERR_T_MSRFPCI_EXP 0x18
/* resource unavailable */
#define RSL_ERR_EQUIPMENT_FAIL 0x20
#define RSL_ERR_RR_UNAVAIL 0x21
#define RSL_ERR_TERR_CH_FAIL 0x22
#define RSL_ERR_CCCH_OVERLOAD 0x23
#define RSL_ERR_ACCH_OVERLOAD 0x24
#define RSL_ERR_PROCESSOR_OVERLOAD 0x25
#define RSL_ERR_RES_UNAVAIL 0x2f
/* service or option not available */
#define RSL_ERR_TRANSC_UNAVAIL 0x30
#define RSL_ERR_SERV_OPT_UNAVAIL 0x3f
/* service or option not implemented */
#define RSL_ERR_ENCR_UNIMPL 0x40
#define RSL_ERR_SERV_OPT_UNIMPL 0x4f
/* invalid message */
#define RSL_ERR_RCH_ALR_ACTV_ALLOC 0x50
#define RSL_ERR_INVALID_MESSAGE 0x5f
/* protocol error */
#define RSL_ERR_MSG_DISCR 0x60
#define RSL_ERR_MSG_TYPE 0x61
#define RSL_ERR_MSG_SEQ 0x62
#define RSL_ERR_IE_ERROR 0x63
#define RSL_ERR_MAND_IE_ERROR 0x64
#define RSL_ERR_OPT_IE_ERROR 0x65
#define RSL_ERR_IE_NONEXIST 0x66
#define RSL_ERR_IE_LENGTH 0x67
#define RSL_ERR_IE_CONTENT 0x68
#define RSL_ERR_PROTO 0x6f
/* interworking */
#define RSL_ERR_INTERWORKING 0x7f
/* Chapter 9.3.30 */
#define RSL_SYSTEM_INFO_8 0x00
#define RSL_SYSTEM_INFO_1 0x01
#define RSL_SYSTEM_INFO_2 0x02
#define RSL_SYSTEM_INFO_3 0x03
#define RSL_SYSTEM_INFO_4 0x04
#define RSL_SYSTEM_INFO_5 0x05
#define RSL_SYSTEM_INFO_6 0x06
#define RSL_SYSTEM_INFO_7 0x07
#define RSL_SYSTEM_INFO_16 0x08
#define RSL_SYSTEM_INFO_17 0x09
#define RSL_SYSTEM_INFO_2bis 0x0a
#define RSL_SYSTEM_INFO_2ter 0x0b
#define RSL_SYSTEM_INFO_5bis 0x0d
#define RSL_SYSTEM_INFO_5ter 0x0e
#define RSL_SYSTEM_INFO_10 0x0f
#define REL_EXT_MEAS_ORDER 0x47
#define RSL_MEAS_INFO 0x48
#define RSL_SYSTEM_INFO_13 0x28
#define RSL_SYSTEM_INFO_2quater 0x29
#define RSL_SYSTEM_INFO_9 0x2a
#define RSL_SYSTEM_INFO_18 0x2b
#define RSL_SYSTEM_INFO_19 0x2c
#define RSL_SYSTEM_INFO_20 0x2d
/* Chapter 9.3.40 */
#define RSL_CHANNEED_ANY 0x00
#define RSL_CHANNEED_SDCCH 0x01
#define RSL_CHANNEED_TCH_F 0x02
#define RSL_CHANNEED_TCH_ForH 0x03
/* Chapter 3.3.2.3 Brocast control channel */
/* CCCH-CONF, NC is not combined */
#define RSL_BCCH_CCCH_CONF_1_NC 0x00
#define RSL_BCCH_CCCH_CONF_1_C 0x01
#define RSL_BCCH_CCCH_CONF_2_NC 0x02
#define RSL_BCCH_CCCH_CONF_3_NC 0x04
#define RSL_BCCH_CCCH_CONF_4_NC 0x06
/* BS-PA-MFRMS */
#define RSL_BS_PA_MFRMS_2 0x00
#define RSL_BS_PA_MFRMS_3 0x01
#define RSL_BS_PA_MFRMS_4 0x02
#define RSL_BS_PA_MFRMS_5 0x03
#define RSL_BS_PA_MFRMS_6 0x04
#define RSL_BS_PA_MFRMS_7 0x05
#define RSL_BS_PA_MFRMS_8 0x06
#define RSL_BS_PA_MFRMS_9 0x07
/* RSL_IE_IPAC_RTP_PAYLOAD[2] */
enum rsl_ipac_rtp_payload {
RSL_IPAC_RTP_GSM = 1,
RSL_IPAC_RTP_EFR,
RSL_IPAC_RTP_AMR,
RSL_IPAC_RTP_CSD,
RSL_IPAC_RTP_MUX,
};
/* RSL_IE_IPAC_SPEECH_MODE, lower four bits */
enum rsl_ipac_speech_mode_s {
RSL_IPAC_SPEECH_GSM_FR = 0, /* GSM FR (Type 1, FS) */
RSL_IPAC_SPEECH_GSM_EFR = 1, /* GSM EFR (Type 2, FS) */
RSL_IPAC_SPEECH_GSM_AMR_FR = 2, /* GSM AMR/FR (Type 3, FS) */
RSL_IPAC_SPEECH_GSM_HR = 3, /* GSM HR (Type 1, HS) */
RSL_IPAC_SPEECH_GSM_AMR_HR = 5, /* GSM AMR/hr (Type 3, HS) */
RSL_IPAC_SPEECH_AS_RTP = 0xf, /* As specified by RTP Payload IE */
};
/* RSL_IE_IPAC_SPEECH_MODE, upper four bits */
enum rsl_ipac_speech_mode_m {
RSL_IPAC_SPEECH_M_RXTX = 0, /* Send and Receive */
RSL_IPAC_SPEECH_M_RX = 1, /* Receive only */
RSL_IPAC_SPEECH_M_TX = 2, /* Send only */
};
/* RSL_IE_IPAC_RTP_CSD_FMT, lower four bits */
enum rsl_ipac_rtp_csd_format_d {
RSL_IPAC_RTP_CSD_EXT_TRAU = 0,
RSL_IPAC_RTP_CSD_NON_TRAU = 1,
RSL_IPAC_RTP_CSD_TRAU_BTS = 2,
RSL_IPAC_RTP_CSD_IWF_FREE = 3,
};
/* RSL_IE_IPAC_RTP_CSD_FMT, upper four bits */
enum rsl_ipac_rtp_csd_format_ir {
RSL_IPAC_RTP_CSD_IR_8k = 0,
RSL_IPAC_RTP_CSD_IR_16k = 1,
RSL_IPAC_RTP_CSD_IR_32k = 2,
RSL_IPAC_RTP_CSD_IR_64k = 3,
};
/* Siemens vendor-specific RSL extensions */
struct rsl_mrpci {
uint8_t power_class:3,
vgcs_capable:1,
vbs_capable:1,
gsm_phase:2;
} __attribute__ ((packed));
enum rsl_mrpci_pwrclass {
RSL_MRPCI_PWRC_1 = 0,
RSL_MRPCI_PWRC_2 = 1,
RSL_MRPCI_PWRC_3 = 2,
RSL_MRPCI_PWRC_4 = 3,
RSL_MRPCI_PWRC_5 = 4,
};
enum rsl_mrpci_phase {
RSL_MRPCI_PHASE_1 = 0,
/* reserved */
RSL_MRPCI_PHASE_2 = 2,
RSL_MRPCI_PHASE_2PLUS = 3,
};
#endif /* PROTO_GSM_08_58_H */

View File

@ -0,0 +1,713 @@
#ifndef PROTO_GSM_12_21_H
#define PROTO_GSM_12_21_H
/* GSM Network Management messages on the A-bis interface
* 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdint.h>
#include <osmocore/tlv.h>
/* generic header in front of every OML message according to TS 08.59 */
struct abis_om_hdr {
uint8_t mdisc;
uint8_t placement;
uint8_t sequence;
uint8_t length;
uint8_t data[0];
} __attribute__ ((packed));
#define ABIS_OM_MDISC_FOM 0x80
#define ABIS_OM_MDISC_MMI 0x40
#define ABIS_OM_MDISC_TRAU 0x20
#define ABIS_OM_MDISC_MANUF 0x10
#define ABIS_OM_PLACEMENT_ONLY 0x80
#define ABIS_OM_PLACEMENT_FIRST 0x40
#define ABIS_OM_PLACEMENT_MIDDLE 0x20
#define ABIS_OM_PLACEMENT_LAST 0x10
struct abis_om_obj_inst {
uint8_t bts_nr;
uint8_t trx_nr;
uint8_t ts_nr;
} __attribute__ ((packed));
struct abis_om_fom_hdr {
uint8_t msg_type;
uint8_t obj_class;
struct abis_om_obj_inst obj_inst;
uint8_t data[0];
} __attribute__ ((packed));
#define ABIS_OM_FOM_HDR_SIZE (sizeof(struct abis_om_hdr) + sizeof(struct abis_om_fom_hdr))
/* Section 9.1: Message Types */
enum abis_nm_msgtype {
/* SW Download Management Messages */
NM_MT_LOAD_INIT = 0x01,
NM_MT_LOAD_INIT_ACK,
NM_MT_LOAD_INIT_NACK,
NM_MT_LOAD_SEG,
NM_MT_LOAD_SEG_ACK,
NM_MT_LOAD_ABORT,
NM_MT_LOAD_END,
NM_MT_LOAD_END_ACK,
NM_MT_LOAD_END_NACK,
NM_MT_SW_ACT_REQ, /* BTS->BSC */
NM_MT_SW_ACT_REQ_ACK,
NM_MT_SW_ACT_REQ_NACK,
NM_MT_ACTIVATE_SW, /* BSC->BTS */
NM_MT_ACTIVATE_SW_ACK,
NM_MT_ACTIVATE_SW_NACK,
NM_MT_SW_ACTIVATED_REP, /* 0x10 */
/* A-bis Interface Management Messages */
NM_MT_ESTABLISH_TEI = 0x21,
NM_MT_ESTABLISH_TEI_ACK,
NM_MT_ESTABLISH_TEI_NACK,
NM_MT_CONN_TERR_SIGN,
NM_MT_CONN_TERR_SIGN_ACK,
NM_MT_CONN_TERR_SIGN_NACK,
NM_MT_DISC_TERR_SIGN,
NM_MT_DISC_TERR_SIGN_ACK,
NM_MT_DISC_TERR_SIGN_NACK,
NM_MT_CONN_TERR_TRAF,
NM_MT_CONN_TERR_TRAF_ACK,
NM_MT_CONN_TERR_TRAF_NACK,
NM_MT_DISC_TERR_TRAF,
NM_MT_DISC_TERR_TRAF_ACK,
NM_MT_DISC_TERR_TRAF_NACK,
/* Transmission Management Messages */
NM_MT_CONN_MDROP_LINK = 0x31,
NM_MT_CONN_MDROP_LINK_ACK,
NM_MT_CONN_MDROP_LINK_NACK,
NM_MT_DISC_MDROP_LINK,
NM_MT_DISC_MDROP_LINK_ACK,
NM_MT_DISC_MDROP_LINK_NACK,
/* Air Interface Management Messages */
NM_MT_SET_BTS_ATTR = 0x41,
NM_MT_SET_BTS_ATTR_ACK,
NM_MT_SET_BTS_ATTR_NACK,
NM_MT_SET_RADIO_ATTR,
NM_MT_SET_RADIO_ATTR_ACK,
NM_MT_SET_RADIO_ATTR_NACK,
NM_MT_SET_CHAN_ATTR,
NM_MT_SET_CHAN_ATTR_ACK,
NM_MT_SET_CHAN_ATTR_NACK,
/* Test Management Messages */
NM_MT_PERF_TEST = 0x51,
NM_MT_PERF_TEST_ACK,
NM_MT_PERF_TEST_NACK,
NM_MT_TEST_REP,
NM_MT_SEND_TEST_REP,
NM_MT_SEND_TEST_REP_ACK,
NM_MT_SEND_TEST_REP_NACK,
NM_MT_STOP_TEST,
NM_MT_STOP_TEST_ACK,
NM_MT_STOP_TEST_NACK,
/* State Management and Event Report Messages */
NM_MT_STATECHG_EVENT_REP = 0x61,
NM_MT_FAILURE_EVENT_REP,
NM_MT_STOP_EVENT_REP,
NM_MT_STOP_EVENT_REP_ACK,
NM_MT_STOP_EVENT_REP_NACK,
NM_MT_REST_EVENT_REP,
NM_MT_REST_EVENT_REP_ACK,
NM_MT_REST_EVENT_REP_NACK,
NM_MT_CHG_ADM_STATE,
NM_MT_CHG_ADM_STATE_ACK,
NM_MT_CHG_ADM_STATE_NACK,
NM_MT_CHG_ADM_STATE_REQ,
NM_MT_CHG_ADM_STATE_REQ_ACK,
NM_MT_CHG_ADM_STATE_REQ_NACK,
NM_MT_REP_OUTST_ALARMS = 0x93,
NM_MT_REP_OUTST_ALARMS_ACK,
NM_MT_REP_OUTST_ALARMS_NACK,
/* Equipment Management Messages */
NM_MT_CHANGEOVER = 0x71,
NM_MT_CHANGEOVER_ACK,
NM_MT_CHANGEOVER_NACK,
NM_MT_OPSTART,
NM_MT_OPSTART_ACK,
NM_MT_OPSTART_NACK,
NM_MT_REINIT,
NM_MT_REINIT_ACK,
NM_MT_REINIT_NACK,
NM_MT_SET_SITE_OUT, /* BS11: get alarm ?!? */
NM_MT_SET_SITE_OUT_ACK,
NM_MT_SET_SITE_OUT_NACK,
NM_MT_CHG_HW_CONF = 0x90,
NM_MT_CHG_HW_CONF_ACK,
NM_MT_CHG_HW_CONF_NACK,
/* Measurement Management Messages */
NM_MT_MEAS_RES_REQ = 0x8a,
NM_MT_MEAS_RES_RESP,
NM_MT_STOP_MEAS,
NM_MT_START_MEAS,
/* Other Messages */
NM_MT_GET_ATTR = 0x81,
NM_MT_GET_ATTR_RESP,
NM_MT_GET_ATTR_NACK,
NM_MT_SET_ALARM_THRES,
NM_MT_SET_ALARM_THRES_ACK,
NM_MT_SET_ALARM_THRES_NACK,
};
enum abis_nm_msgtype_bs11 {
NM_MT_BS11_RESET_RESOURCE = 0x74,
NM_MT_BS11_BEGIN_DB_TX = 0xa3,
NM_MT_BS11_BEGIN_DB_TX_ACK,
NM_MT_BS11_BEGIN_DB_TX_NACK,
NM_MT_BS11_END_DB_TX = 0xa6,
NM_MT_BS11_END_DB_TX_ACK,
NM_MT_BS11_END_DB_TX_NACK,
NM_MT_BS11_CREATE_OBJ = 0xa9,
NM_MT_BS11_CREATE_OBJ_ACK,
NM_MT_BS11_CREATE_OBJ_NACK,
NM_MT_BS11_DELETE_OBJ = 0xac,
NM_MT_BS11_DELETE_OBJ_ACK,
NM_MT_BS11_DELETE_OBJ_NACK,
NM_MT_BS11_SET_ATTR = 0xd0,
NM_MT_BS11_SET_ATTR_ACK,
NM_MT_BS11_SET_ATTR_NACK,
NM_MT_BS11_LMT_SESSION = 0xdc,
NM_MT_BS11_GET_STATE = 0xe3,
NM_MT_BS11_GET_STATE_ACK,
NM_MT_BS11_LMT_LOGON = 0xe5,
NM_MT_BS11_LMT_LOGON_ACK,
NM_MT_BS11_RESTART = 0xe7,
NM_MT_BS11_RESTART_ACK,
NM_MT_BS11_DISCONNECT = 0xe9,
NM_MT_BS11_DISCONNECT_ACK,
NM_MT_BS11_LMT_LOGOFF = 0xec,
NM_MT_BS11_LMT_LOGOFF_ACK,
NM_MT_BS11_RECONNECT = 0xf1,
NM_MT_BS11_RECONNECT_ACK,
};
enum abis_nm_msgtype_ipacc {
NM_MT_IPACC_RESTART = 0x87,
NM_MT_IPACC_RESTART_ACK,
NM_MT_IPACC_RESTART_NACK,
NM_MT_IPACC_RSL_CONNECT = 0xe0,
NM_MT_IPACC_RSL_CONNECT_ACK,
NM_MT_IPACC_RSL_CONNECT_NACK,
NM_MT_IPACC_RSL_DISCONNECT = 0xe3,
NM_MT_IPACC_RSL_DISCONNECT_ACK,
NM_MT_IPACC_RSL_DISCONNECT_NACK,
NM_MT_IPACC_CONN_TRAF = 0xe6,
NM_MT_IPACC_CONN_TRAF_ACK,
NM_MT_IPACC_CONN_TRAF_NACK,
NM_MT_IPACC_DEF_BOOT_SW = 0xec,
NM_MT_IPACC_DEF_BOOT_SW_ACK,
MN_MT_IPACC_DEF_BOOT_SW_NACK,
NM_MT_IPACC_SET_NVATTR = 0xef,
NM_MT_IPACC_SET_NVATTR_ACK,
NM_MT_IPACC_SET_NVATTR_NACK,
NM_MT_IPACC_GET_NVATTR = 0xf2,
NM_MT_IPACC_GET_NVATTR_ACK,
NM_MT_IPACC_GET_NVATTR_NACK,
NM_MT_IPACC_SET_ATTR = 0xf5,
NM_MT_IPACC_SET_ATTR_ACK,
NM_MT_IPACC_SET_ATTR_NACK,
};
enum abis_nm_bs11_cell_alloc {
NM_BS11_CANR_GSM = 0x00,
NM_BS11_CANR_DCS1800 = 0x01,
};
/* Section 9.2: Object Class */
enum abis_nm_obj_class {
NM_OC_SITE_MANAGER = 0x00,
NM_OC_BTS,
NM_OC_RADIO_CARRIER,
NM_OC_CHANNEL,
NM_OC_BASEB_TRANSC,
/* RFU: 05-FE */
NM_OC_IPAC_E1_TRUNK = 0x0e,
NM_OC_IPAC_E1_PORT = 0x0f,
NM_OC_IPAC_E1_CHAN = 0x10,
NM_OC_IPAC_CLK_MODULE = 0x22,
NM_OC_BS11_ADJC = 0xa0,
NM_OC_BS11_HANDOVER = 0xa1,
NM_OC_BS11_PWR_CTRL = 0xa2,
NM_OC_BS11_BTSE = 0xa3, /* LMT? */
NM_OC_BS11_RACK = 0xa4,
NM_OC_BS11 = 0xa5, /* 01: ALCO */
NM_OC_BS11_TEST = 0xa6,
NM_OC_BS11_ENVABTSE = 0xa8,
NM_OC_BS11_BPORT = 0xa9,
NM_OC_GPRS_NSE = 0xf0,
NM_OC_GPRS_CELL = 0xf1,
NM_OC_GPRS_NSVC = 0xf2,
NM_OC_NULL = 0xff,
};
/* Section 9.4: Attributes */
enum abis_nm_attr {
NM_ATT_ABIS_CHANNEL = 0x01,
NM_ATT_ADD_INFO,
NM_ATT_ADD_TEXT,
NM_ATT_ADM_STATE,
NM_ATT_ARFCN_LIST,
NM_ATT_AUTON_REPORT,
NM_ATT_AVAIL_STATUS,
NM_ATT_BCCH_ARFCN,
NM_ATT_BSIC,
NM_ATT_BTS_AIR_TIMER,
NM_ATT_CCCH_L_I_P,
NM_ATT_CCCH_L_T,
NM_ATT_CHAN_COMB,
NM_ATT_CONN_FAIL_CRIT,
NM_ATT_DEST,
/* res */
NM_ATT_EVENT_TYPE = 0x11, /* BS11: file data ?!? */
NM_ATT_FILE_ID,
NM_ATT_FILE_VERSION,
NM_ATT_GSM_TIME,
NM_ATT_HSN,
NM_ATT_HW_CONFIG,
NM_ATT_HW_DESC,
NM_ATT_INTAVE_PARAM,
NM_ATT_INTERF_BOUND,
NM_ATT_LIST_REQ_ATTR,
NM_ATT_MAIO,
NM_ATT_MANUF_STATE,
NM_ATT_MANUF_THRESH,
NM_ATT_MANUF_ID,
NM_ATT_MAX_TA,
NM_ATT_MDROP_LINK, /* 0x20 */
NM_ATT_MDROP_NEXT,
NM_ATT_NACK_CAUSES,
NM_ATT_NY1,
NM_ATT_OPER_STATE,
NM_ATT_OVERL_PERIOD,
NM_ATT_PHYS_CONF,
NM_ATT_POWER_CLASS,
NM_ATT_POWER_THRESH,
NM_ATT_PROB_CAUSE,
NM_ATT_RACH_B_THRESH,
NM_ATT_LDAVG_SLOTS,
NM_ATT_RAD_SUBC,
NM_ATT_RF_MAXPOWR_R,
NM_ATT_SITE_INPUTS,
NM_ATT_SITE_OUTPUTS,
NM_ATT_SOURCE, /* 0x30 */
NM_ATT_SPEC_PROB,
NM_ATT_START_TIME,
NM_ATT_T200,
NM_ATT_TEI,
NM_ATT_TEST_DUR,
NM_ATT_TEST_NO,
NM_ATT_TEST_REPORT,
NM_ATT_VSWR_THRESH,
NM_ATT_WINDOW_SIZE,
/* Res */
NM_ATT_BS11_RSSI_OFFS = 0x3d,
NM_ATT_BS11_TXPWR = 0x3e,
NM_ATT_BS11_DIVERSITY = 0x3f,
/* Res */
NM_ATT_TSC = 0x40,
NM_ATT_SW_CONFIG,
NM_ATT_SW_DESCR,
NM_ATT_SEVERITY,
NM_ATT_GET_ARI,
NM_ATT_HW_CONF_CHG,
NM_ATT_OUTST_ALARM,
NM_ATT_FILE_DATA,
NM_ATT_MEAS_RES,
NM_ATT_MEAS_TYPE,
NM_ATT_BS11_ESN_FW_CODE_NO = 0x4c,
NM_ATT_BS11_ESN_HW_CODE_NO = 0x4f,
NM_ATT_BS11_ESN_PCB_SERIAL = 0x55,
NM_ATT_BS11_EXCESSIVE_DISTANCE = 0x58,
NM_ATT_BS11_ALL_TEST_CATG = 0x60,
NM_ATT_BS11_BTSLS_HOPPING,
NM_ATT_BS11_CELL_ALLOC_NR,
NM_ATT_BS11_CELL_GLOBAL_ID,
NM_ATT_BS11_ENA_INTERF_CLASS = 0x66,
NM_ATT_BS11_ENA_INT_INTEC_HANDO = 0x67,
NM_ATT_BS11_ENA_INT_INTRC_HANDO = 0x68,
NM_ATT_BS11_ENA_MS_PWR_CTRL = 0x69,
NM_ATT_BS11_ENA_PWR_BDGT_HO = 0x6a,
NM_ATT_BS11_ENA_PWR_CTRL_RLFW = 0x6b,
NM_ATT_BS11_ENA_RXLEV_HO = 0x6c,
NM_ATT_BS11_ENA_RXQUAL_HO = 0x6d,
NM_ATT_BS11_FACCH_QUAL = 0x6e,
NM_ATT_IPACC_DST_IP = 0x80,
NM_ATT_IPACC_DST_IP_PORT = 0x81,
NM_ATT_IPACC_SSRC = 0x82,
NM_ATT_IPACC_RTP_PAYLD_TYPE = 0x83,
NM_ATT_IPACC_BASEB_ID = 0x84,
NM_ATT_IPACC_STREAM_ID = 0x85,
NM_ATT_IPACC_NV_FLAGS = 0x86,
NM_ATT_IPACC_FREQ_CTRL = 0x87,
NM_ATT_IPACC_PRIM_OML_CFG = 0x88,
NM_ATT_IPACC_SEC_OML_CFG = 0x89,
NM_ATT_IPACC_IP_IF_CFG = 0x8a, /* IP interface */
NM_ATT_IPACC_IP_GW_CFG = 0x8b, /* IP gateway */
NM_ATT_IPACC_IN_SERV_TIME = 0x8c,
NM_ATT_IPACC_TRX_BTS_ASS = 0x8d,
NM_ATT_IPACC_LOCATION = 0x8e, /* string describing location */
NM_ATT_IPACC_PAGING_CFG = 0x8f,
NM_ATT_IPACC_FILE_DATA = 0x90,
NM_ATT_IPACC_UNIT_ID = 0x91, /* Site/BTS/TRX */
NM_ATT_IPACC_PARENT_UNIT_ID = 0x92,
NM_ATT_IPACC_UNIT_NAME = 0x93, /* default: nbts-<mac-as-string> */
NM_ATT_IPACC_SNMP_CFG = 0x94,
NM_ATT_IPACC_PRIM_OML_CFG_LIST = 0x95,
NM_ATT_IPACC_PRIM_OML_FB_TOUT = 0x96,
NM_ATT_IPACC_CUR_SW_CFG = 0x97,
NM_ATT_IPACC_TIMING_BUS = 0x98,
NM_ATT_IPACC_CGI = 0x99,
NM_ATT_IPACC_RAC = 0x9a,
NM_ATT_IPACC_OBJ_VERSION = 0x9b,
NM_ATT_IPACC_GPRS_PAGING_CFG = 0x9c,
NM_ATT_IPACC_NSEI = 0x9d,
NM_ATT_IPACC_BVCI = 0x9e,
NM_ATT_IPACC_NSVCI = 0x9f,
NM_ATT_IPACC_NS_CFG = 0xa0,
NM_ATT_IPACC_BSSGP_CFG = 0xa1,
NM_ATT_IPACC_NS_LINK_CFG = 0xa2,
NM_ATT_IPACC_RLC_CFG = 0xa3,
NM_ATT_IPACC_ALM_THRESH_LIST = 0xa4,
NM_ATT_IPACC_MONIT_VAL_LIST = 0xa5,
NM_ATT_IPACC_TIB_CONTROL = 0xa6,
NM_ATT_IPACC_SUPP_FEATURES = 0xa7,
NM_ATT_IPACC_CODING_SCHEMES = 0xa8,
NM_ATT_IPACC_RLC_CFG_2 = 0xa9,
NM_ATT_IPACC_HEARTB_TOUT = 0xaa,
NM_ATT_IPACC_UPTIME = 0xab,
NM_ATT_IPACC_RLC_CFG_3 = 0xac,
NM_ATT_IPACC_SSL_CFG = 0xad,
NM_ATT_IPACC_SEC_POSSIBLE = 0xae,
NM_ATT_IPACC_IML_SSL_STATE = 0xaf,
NM_ATT_IPACC_REVOC_DATE = 0xb0,
NM_ATT_BS11_RF_RES_IND_PER = 0x8f,
NM_ATT_BS11_RX_LEV_MIN_CELL = 0x90,
NM_ATT_BS11_ABIS_EXT_TIME = 0x91,
NM_ATT_BS11_TIMER_HO_REQUEST = 0x92,
NM_ATT_BS11_TIMER_NCELL = 0x93,
NM_ATT_BS11_TSYNC = 0x94,
NM_ATT_BS11_TTRAU = 0x95,
NM_ATT_BS11_EMRG_CFG_MEMBER = 0x9b,
NM_ATT_BS11_TRX_AREA = 0x9f,
NM_ATT_BS11_BCCH_RECONF = 0xd7,
NM_ATT_BS11_BIT_ERR_THESH = 0xa0,
NM_ATT_BS11_BOOT_SW_VERS = 0xa1,
NM_ATT_BS11_CCLK_ACCURACY = 0xa3,
NM_ATT_BS11_CCLK_TYPE = 0xa4,
NM_ATT_BS11_INP_IMPEDANCE = 0xaa,
NM_ATT_BS11_L1_PROT_TYPE = 0xab,
NM_ATT_BS11_LINE_CFG = 0xac,
NM_ATT_BS11_LI_PORT_1 = 0xad,
NM_ATT_BS11_LI_PORT_2 = 0xae,
NM_ATT_BS11_L1_REM_ALM_TYPE = 0xb0,
NM_ATT_BS11_SW_LOAD_INTENDED = 0xbb,
NM_ATT_BS11_SW_LOAD_SAFETY = 0xbc,
NM_ATT_BS11_SW_LOAD_STORED = 0xbd,
NM_ATT_BS11_VENDOR_NAME = 0xc1,
NM_ATT_BS11_HOPPING_MODE = 0xc5,
NM_ATT_BS11_LMT_LOGON_SESSION = 0xc6,
NM_ATT_BS11_LMT_LOGIN_TIME = 0xc7,
NM_ATT_BS11_LMT_USER_ACC_LEV = 0xc8,
NM_ATT_BS11_LMT_USER_NAME = 0xc9,
NM_ATT_BS11_L1_CONTROL_TS = 0xd8,
NM_ATT_BS11_RADIO_MEAS_GRAN = 0xdc, /* in SACCH multiframes */
NM_ATT_BS11_RADIO_MEAS_REP = 0xdd,
NM_ATT_BS11_SH_LAPD_INT_TIMER = 0xe8,
NM_ATT_BS11_BTS_STATE = 0xf0,
NM_ATT_BS11_E1_STATE = 0xf1,
NM_ATT_BS11_PLL = 0xf2,
NM_ATT_BS11_RX_OFFSET = 0xf3,
NM_ATT_BS11_ANT_TYPE = 0xf4,
NM_ATT_BS11_PLL_MODE = 0xfc,
NM_ATT_BS11_PASSWORD = 0xfd,
};
#define NM_ATT_BS11_FILE_DATA NM_ATT_EVENT_TYPE
/* Section 9.4.4: Administrative State */
enum abis_nm_adm_state {
NM_STATE_LOCKED = 0x01,
NM_STATE_UNLOCKED = 0x02,
NM_STATE_SHUTDOWN = 0x03,
NM_STATE_NULL = 0xff,
};
/* Section 9.4.7: Administrative State */
enum abis_nm_avail_state {
NM_AVSTATE_IN_TEST = 1,
NM_AVSTATE_POWER_OFF = 2,
NM_AVSTATE_OFF_LINE = 3,
NM_AVSTATE_DEPENDENCY = 5,
NM_AVSTATE_DEGRADED = 6,
NM_AVSTATE_NOT_INSTALLED= 7,
NM_AVSTATE_OK = 0xff,
};
enum abis_nm_op_state {
NM_OPSTATE_DISABLED = 1,
NM_OPSTATE_ENABLED = 2,
NM_OPSTATE_NULL = 0xff,
};
/* Section 9.4.13: Channel Combination */
enum abis_nm_chan_comb {
NM_CHANC_TCHFull = 0x00, /* TCH/F + TCH/H + SACCH/TF */
NM_CHANC_TCHHalf = 0x01, /* TCH/H(0,1) + FACCH/H(0,1) +
SACCH/TH(0,1) */
NM_CHANC_TCHHalf2 = 0x02, /* TCH/H(0) + FACCH/H(0) + SACCH/TH(0) +
TCH/H(1) */
NM_CHANC_SDCCH = 0x03, /* SDCCH/8 + SACCH/8 */
NM_CHANC_mainBCCH = 0x04, /* FCCH + SCH + BCCH + CCCH */
NM_CHANC_BCCHComb = 0x05, /* FCCH + SCH + BCCH + CCCH + SDCCH/4 +
SACCH/C4 */
NM_CHANC_BCCH = 0x06, /* BCCH + CCCH */
NM_CHANC_BCCH_CBCH = 0x07, /* CHANC_BCCHComb + CBCH */
NM_CHANC_SDCCH_CBCH = 0x08, /* CHANC_SDCCH8 + CBCH */
/* ip.access */
NM_CHANC_IPAC_bPDCH = 0x0b, /* PBCCH + PCCCH + PDTCH/F + PACCH/F +
PTCCH/F */
NM_CHANC_IPAC_cPDCH = 0x0c, /* PBCCH + PDTCH/F + PACCH/F + PTCCH/F */
NM_CHANC_IPAC_PDCH = 0x0d, /* PDTCH/F + PACCH/F + PTCCH/F */
NM_CHANC_IPAC_TCHFull_PDCH = 0x80,
NM_CHANC_IPAC_TCHFull_TCHHalf = 0x81,
};
/* Section 9.4.16: Event Type */
enum abis_nm_event_type {
NM_EVT_COMM_FAIL = 0x00,
NM_EVT_QOS_FAIL = 0x01,
NM_EVT_PROC_FAIL = 0x02,
NM_EVT_EQUIP_FAIL = 0x03,
NM_EVT_ENV_FAIL = 0x04,
};
/* Section: 9.4.63: Perceived Severity */
enum abis_nm_severity {
NM_SEVER_CEASED = 0x00,
NM_SEVER_CRITICAL = 0x01,
NM_SEVER_MAJOR = 0x02,
NM_SEVER_MINOR = 0x03,
NM_SEVER_WARNING = 0x04,
NM_SEVER_INDETERMINATE = 0x05,
};
/* Section 9.4.43: Probable Cause Type */
enum abis_nm_pcause_type {
NM_PCAUSE_T_X721 = 0x01,
NM_PCAUSE_T_GSM = 0x02,
NM_PCAUSE_T_MANUF = 0x03,
};
/* Section 9.4.36: NACK Causes */
enum abis_nm_nack_cause {
/* General Nack Causes */
NM_NACK_INCORR_STRUCT = 0x01,
NM_NACK_MSGTYPE_INVAL = 0x02,
NM_NACK_OBJCLASS_INVAL = 0x05,
NM_NACK_OBJCLASS_NOTSUPP = 0x06,
NM_NACK_BTSNR_UNKN = 0x07,
NM_NACK_TRXNR_UNKN = 0x08,
NM_NACK_OBJINST_UNKN = 0x09,
NM_NACK_ATTRID_INVAL = 0x0c,
NM_NACK_ATTRID_NOTSUPP = 0x0d,
NM_NACK_PARAM_RANGE = 0x0e,
NM_NACK_ATTRLIST_INCONSISTENT = 0x0f,
NM_NACK_SPEC_IMPL_NOTSUPP = 0x10,
NM_NACK_CANT_PERFORM = 0x11,
/* Specific Nack Causes */
NM_NACK_RES_NOTIMPL = 0x19,
NM_NACK_RES_NOTAVAIL = 0x1a,
NM_NACK_FREQ_NOTAVAIL = 0x1b,
NM_NACK_TEST_NOTSUPP = 0x1c,
NM_NACK_CAPACITY_RESTR = 0x1d,
NM_NACK_PHYSCFG_NOTPERFORM = 0x1e,
NM_NACK_TEST_NOTINIT = 0x1f,
NM_NACK_PHYSCFG_NOTRESTORE = 0x20,
NM_NACK_TEST_NOSUCH = 0x21,
NM_NACK_TEST_NOSTOP = 0x22,
NM_NACK_MSGINCONSIST_PHYSCFG = 0x23,
NM_NACK_FILE_INCOMPLETE = 0x25,
NM_NACK_FILE_NOTAVAIL = 0x26,
NM_NACK_FILE_NOTACTIVATE = 0x27,
NM_NACK_REQ_NOT_GRANT = 0x28,
NM_NACK_WAIT = 0x29,
NM_NACK_NOTH_REPORT_EXIST = 0x2a,
NM_NACK_MEAS_NOTSUPP = 0x2b,
NM_NACK_MEAS_NOTSTART = 0x2c,
};
/* Section 9.4.1 */
struct abis_nm_channel {
uint8_t attrib;
uint8_t bts_port;
uint8_t timeslot;
uint8_t subslot;
} __attribute__ ((packed));
/* Siemens BS-11 specific objects in the SienemsHW (0xA5) object class */
enum abis_bs11_objtype {
BS11_OBJ_ALCO = 0x01,
BS11_OBJ_BBSIG = 0x02, /* obj_class: 0,1 */
BS11_OBJ_TRX1 = 0x03, /* only DEACTIVATE TRX1 */
BS11_OBJ_CCLK = 0x04,
BS11_OBJ_GPSU = 0x06,
BS11_OBJ_LI = 0x07,
BS11_OBJ_PA = 0x09, /* obj_class: 0, 1*/
};
enum abis_bs11_trx_power {
BS11_TRX_POWER_GSM_2W = 0x06,
BS11_TRX_POWER_GSM_250mW= 0x07,
BS11_TRX_POWER_GSM_80mW = 0x08,
BS11_TRX_POWER_GSM_30mW = 0x09,
BS11_TRX_POWER_DCS_3W = 0x0a,
BS11_TRX_POWER_DCS_1W6 = 0x0b,
BS11_TRX_POWER_DCS_500mW= 0x0c,
BS11_TRX_POWER_DCS_160mW= 0x0d,
};
enum abis_bs11_li_pll_mode {
BS11_LI_PLL_LOCKED = 2,
BS11_LI_PLL_STANDALONE = 3,
};
enum abis_bs11_line_cfg {
BS11_LINE_CFG_STAR = 0x00,
BS11_LINE_CFG_MULTIDROP = 0x01,
BS11_LINE_CFG_LOOP = 0x02,
};
enum abis_bs11_phase {
BS11_STATE_SOFTWARE_RQD = 0x01,
BS11_STATE_LOAD_SMU_INTENDED = 0x11,
BS11_STATE_LOAD_SMU_SAFETY = 0x21,
BS11_STATE_LOAD_FAILED = 0x31,
BS11_STATE_LOAD_DIAGNOSTIC = 0x41,
BS11_STATE_WARM_UP = 0x51,
BS11_STATE_WARM_UP_2 = 0x52,
BS11_STATE_WAIT_MIN_CFG = 0x62,
BS11_STATE_MAINTENANCE = 0x72,
BS11_STATE_LOAD_MBCCU = 0x92,
BS11_STATE_WAIT_MIN_CFG_2 = 0xA2,
BS11_STATE_NORMAL = 0x03,
BS11_STATE_ABIS_LOAD = 0x13,
};
enum abis_nm_ipacc_test_no {
NM_IPACC_TESTNO_RLOOP_ANT = 0x01,
NM_IPACC_TESTNO_RLOOP_XCVR = 0x02,
NM_IPACC_TESTNO_FUNC_OBJ = 0x03,
NM_IPACC_TESTNO_CHAN_USAGE = 0x40,
NM_IPACC_TESTNO_BCCH_CHAN_USAGE = 0x41,
NM_IPACC_TESTNO_FREQ_SYNC = 0x42,
NM_IPACC_TESTNO_BCCH_INFO = 0x43,
NM_IPACC_TESTNO_TX_BEACON = 0x44,
NM_IPACC_TESTNO_SYSINFO_MONITOR = 0x45,
NM_IPACC_TESTNO_BCCCH_MONITOR = 0x46,
};
/* first byte after length inside NM_ATT_TEST_REPORT */
enum abis_nm_ipacc_test_res {
NM_IPACC_TESTRES_SUCCESS = 0,
NM_IPACC_TESTRES_TIMEOUT = 1,
NM_IPACC_TESTRES_NO_CHANS = 2,
NM_IPACC_TESTRES_PARTIAL = 3,
NM_IPACC_TESTRES_STOPPED = 4,
};
/* internal IE inside NM_ATT_TEST_REPORT */
enum abis_nm_ipacc_testres_ie {
NM_IPACC_TR_IE_FREQ_ERR_LIST = 3,
NM_IPACC_TR_IE_CHAN_USAGE = 4,
NM_IPACC_TR_IE_BCCH_INFO = 6,
NM_IPACC_TR_IE_RESULT_DETAILS = 8,
NM_IPACC_TR_IE_FREQ_ERR = 18,
};
enum ipac_eie {
NM_IPAC_EIE_ARFCN_WHITE = 0x01,
NM_IPAC_EIE_ARFCH_BLACK = 0x02,
NM_IPAC_EIE_FREQ_ERR_LIST = 0x03,
NM_IPAC_EIE_CHAN_USE_LIST = 0x04,
NM_IPAC_EIE_BCCH_INFO_TYPE = 0x05,
NM_IPAC_EIE_BCCH_INFO = 0x06,
NM_IPAC_EIE_CONFIG = 0x07,
NM_IPAC_EIE_RES_DETAILS = 0x08,
NM_IPAC_EIE_RXLEV_THRESH = 0x09,
NM_IPAC_EIE_FREQ_SYNC_OPTS = 0x0a,
NM_IPAC_EIE_MAC_ADDR = 0x0b,
NM_IPAC_EIE_HW_SW_COMPAT_NR = 0x0c,
NM_IPAC_EIE_MANUF_SER_NR = 0x0d,
NM_IPAC_EIE_OEM_ID = 0x0e,
NM_IPAC_EIE_DATE_TIME_MANUF = 0x0f,
NM_IPAC_EIE_DATE_TIME_CALIB = 0x10,
NM_IPAC_EIE_BEACON_INFO = 0x11,
NM_IPAC_EIE_FREQ_ERR = 0x12,
/* FIXME */
NM_IPAC_EIE_FREQ_BANDS = 0x1c,
NM_IPAC_EIE_MAX_TA = 0x1d,
NM_IPAC_EIE_CIPH_ALGOS = 0x1e,
NM_IPAC_EIE_CHAN_TYPES = 0x1f,
NM_IPAC_EIE_CHAN_MODES = 0x20,
NM_IPAC_EIE_GPRS_CODING = 0x21,
NM_IPAC_EIE_RTP_FEATURES = 0x22,
NM_IPAC_EIE_RSL_FEATURES = 0x23,
NM_IPAC_EIE_BTS_HW_CLASS = 0x24,
NM_IPAC_EIE_BTS_ID = 0x25,
};
enum ipac_bcch_info_type {
IPAC_BINF_RXLEV = (1 << 8),
IPAC_BINF_RXQUAL = (1 << 9),
IPAC_BINF_FREQ_ERR_QUAL = (1 << 10),
IPAC_BINF_FRAME_OFFSET = (1 << 11),
IPAC_BINF_FRAME_NR_OFFSET = (1 << 12),
IPAC_BINF_BSIC = (1 << 13),
IPAC_BINF_CGI = (1 << 14),
IPAC_BINF_NEIGH_BA_SI2 = (1 << 15),
IPAC_BINF_NEIGH_BA_SI2bis = (1 << 0),
IPAC_BINF_NEIGH_BA_SI2ter = (1 << 1),
IPAC_BINF_CELL_ALLOC = (1 << 2),
};
#endif /* PROTO_GSM_12_21_H */

View File

@ -0,0 +1,81 @@
#ifndef _RATE_CTR_H
#define _RATE_CTR_H
#include <stdint.h>
#include <osmocore/linuxlist.h>
#define RATE_CTR_INTV_NUM 4
enum rate_ctr_intv {
RATE_CTR_INTV_SEC,
RATE_CTR_INTV_MIN,
RATE_CTR_INTV_HOUR,
RATE_CTR_INTV_DAY,
};
/* for each of the intervals, we keep the following values */
struct rate_ctr_per_intv {
uint64_t last;
uint64_t rate;
};
/* for each actual value, we keep the following data */
struct rate_ctr {
uint64_t current;
struct rate_ctr_per_intv intv[RATE_CTR_INTV_NUM];
};
struct rate_ctr_desc {
const char *name;
const char *description;
};
/* Describe a counter group class */
struct rate_ctr_group_desc {
/* The prefix to the name of all counters in this group */
const char *group_name_prefix;
/* The human-readable description of the group */
const char *group_description;
/* The number of counters in this group */
const unsigned int num_ctr;
/* Pointer to array of counter names */
const struct rate_ctr_desc *ctr_desc;
};
/* One instance of a counter group class */
struct rate_ctr_group {
/* Linked list of all counter groups in the system */
struct llist_head list;
/* Pointer to the counter group class */
const struct rate_ctr_group_desc *desc;
/* The index of this ctr_group within its class */
unsigned int idx;
/* Actual counter structures below */
struct rate_ctr ctr[0];
};
/* Allocate a new group of counters according to description */
struct rate_ctr_group *rate_ctr_group_alloc(void *ctx,
const struct rate_ctr_group_desc *desc,
unsigned int idx);
/* Free the memory for the specified group of counters */
void rate_ctr_group_free(struct rate_ctr_group *grp);
/* Add a number to the counter */
void rate_ctr_add(struct rate_ctr *ctr, int inc);
/* Increment the counter by 1 */
static inline void rate_ctr_inc(struct rate_ctr *ctr)
{
rate_ctr_add(ctr, 1);
}
/* Initialize the counter module */
int rate_ctr_init(void *tall_ctx);
struct vty;
void vty_out_rate_ctr_group(struct vty *vty, const char *prefix,
struct rate_ctr_group *ctrg);
#endif /* RATE_CTR_H */

View File

@ -0,0 +1,32 @@
#ifndef _OSMOCORE_RSL_H
#define _OSMOCORE_RSL_H
#include <stdint.h>
#include <osmocore/utils.h>
#include <osmocore/protocol/gsm_08_58.h>
void rsl_init_rll_hdr(struct abis_rsl_rll_hdr *dh, uint8_t msg_type);
extern const struct tlv_definition rsl_att_tlvdef;
#define rsl_tlv_parse(dec, buf, len) \
tlv_parse(dec, &rsl_att_tlvdef, buf, len, 0, 0)
/* encode channel number as per Section 9.3.1 */
uint8_t rsl_enc_chan_nr(uint8_t type, uint8_t subch, uint8_t timeslot);
/* decode channel number as per Section 9.3.1 */
int rsl_dec_chan_nr(uint8_t chan_nr, uint8_t *type, uint8_t *subch, uint8_t *timeslot);
const char *rsl_err_name(uint8_t err);
const char *rsl_rlm_cause_name(uint8_t err);
/* Section 3.3.2.3 TS 05.02. I think this looks like a table */
int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf);
/* Push a RSL RLL header with L3_INFO IE */
void rsl_rll_push_l3(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr,
uint8_t link_id, int transparent);
/* Allocate msgb and fill with simple RSL RLL header */
struct msgb *rsl_rll_simple(uint8_t msg_type, uint8_t chan_nr,
uint8_t link_id, int transparent);
#endif /* _OSMOCORE_RSL_H */

View File

@ -0,0 +1,22 @@
#ifndef _OSMOCORE_RXLEV_STATS_H
#define _OSMOCORE_RXLEV_STATS_H
#define NUM_RXLEVS 32
#define NUM_ARFCNS 1024
struct rxlev_stats {
/* the maximum number of ARFCN's is 1024, and there are 32 RxLevels,
* so in we keep one 1024bit-bitvec for each RxLev */
uint8_t rxlev_buckets[NUM_RXLEVS][NUM_ARFCNS/8];
};
void rxlev_stat_input(struct rxlev_stats *st, uint16_t arfcn, uint8_t rxlev);
/* get the next ARFCN that has the specified Rxlev */
int16_t rxlev_stat_get_next(const struct rxlev_stats *st, uint8_t rxlev, int16_t arfcn);
void rxlev_stat_reset(struct rxlev_stats *st);
void rxlev_stat_dump(const struct rxlev_stats *st);
#endif /* _OSMOCORE_RXLEV_STATS_H */

View File

@ -0,0 +1,22 @@
#ifndef _BSC_SELECT_H
#define _BSC_SELECT_H
#include "linuxlist.h"
#define BSC_FD_READ 0x0001
#define BSC_FD_WRITE 0x0002
#define BSC_FD_EXCEPT 0x0004
struct bsc_fd {
struct llist_head list;
int fd;
unsigned int when;
int (*cb)(struct bsc_fd *fd, unsigned int what);
void *data;
unsigned int priv_nr;
};
int bsc_register_fd(struct bsc_fd *fd);
void bsc_unregister_fd(struct bsc_fd *fd);
int bsc_select_main(int polling);
#endif /* _BSC_SELECT_H */

View File

@ -0,0 +1,15 @@
#ifndef OSMOCORE_SIGNAL_H
#define OSMOCORE_SIGNAL_H
typedef int signal_cbfn(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data);
/* Management */
int register_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data);
void unregister_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data);
/* Dispatch */
void dispatch_signal(unsigned int subsys, unsigned int signal, void *signal_data);
#endif /* OSMOCORE_SIGNAL_H */

View File

@ -0,0 +1,31 @@
#ifndef _STATISTICS_H
#define _STATISTICS_H
struct counter {
struct llist_head list;
const char *name;
const char *description;
unsigned long value;
};
static inline void counter_inc(struct counter *ctr)
{
ctr->value++;
}
static inline unsigned long counter_get(struct counter *ctr)
{
return ctr->value;
}
static inline void counter_reset(struct counter *ctr)
{
ctr->value = 0;
}
struct counter *counter_alloc(const char *name);
void counter_free(struct counter *ctr);
int counters_for_each(int (*handle_counter)(struct counter *, void *), void *data);
#endif /* _STATISTICS_H */

View File

@ -0,0 +1,192 @@
#ifndef _TALLOC_H_
#define _TALLOC_H_
/*
Unix SMB/CIFS implementation.
Samba temporary memory allocation functions
Copyright (C) Andrew Tridgell 2004-2005
Copyright (C) Stefan Metzmacher 2006
** NOTE! The following LGPL license applies to the talloc
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#define HAVE_VA_COPY
/* this is only needed for compatibility with the old talloc */
typedef void TALLOC_CTX;
/*
this uses a little trick to allow __LINE__ to be stringified
*/
#ifndef __location__
#define __TALLOC_STRING_LINE1__(s) #s
#define __TALLOC_STRING_LINE2__(s) __TALLOC_STRING_LINE1__(s)
#define __TALLOC_STRING_LINE3__ __TALLOC_STRING_LINE2__(__LINE__)
#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__
#endif
#ifndef TALLOC_DEPRECATED
#define TALLOC_DEPRECATED 0
#endif
#ifndef PRINTF_ATTRIBUTE
#if (__GNUC__ >= 3)
/** Use gcc attribute to check printf fns. a1 is the 1-based index of
* the parameter containing the format, and a2 the index of the first
* argument. Note that some gcc 2.x versions don't handle this
* properly **/
#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
#else
#define PRINTF_ATTRIBUTE(a1, a2)
#endif
#endif
/* try to make talloc_set_destructor() and talloc_steal() type safe,
if we have a recent gcc */
#if (__GNUC__ >= 3)
#define _TALLOC_TYPEOF(ptr) __typeof__(ptr)
#define talloc_set_destructor(ptr, function) \
do { \
int (*_talloc_destructor_fn)(_TALLOC_TYPEOF(ptr)) = (function); \
_talloc_set_destructor((ptr), (int (*)(void *))_talloc_destructor_fn); \
} while(0)
/* this extremely strange macro is to avoid some braindamaged warning
stupidity in gcc 4.1.x */
#define talloc_steal(ctx, ptr) ({ _TALLOC_TYPEOF(ptr) __talloc_steal_ret = (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr)); __talloc_steal_ret; })
#else
#define talloc_set_destructor(ptr, function) \
_talloc_set_destructor((ptr), (int (*)(void *))(function))
#define _TALLOC_TYPEOF(ptr) void *
#define talloc_steal(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr))
#endif
#define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference((ctx),(ptr))
#define talloc_move(ctx, ptr) (_TALLOC_TYPEOF(*(ptr)))_talloc_move((ctx),(void *)(ptr))
/* useful macros for creating type checked pointers */
#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
#define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr)))
#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__)
#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count)
#define talloc_array_length(ctx) (talloc_get_size(ctx)/sizeof(*ctx))
#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__)
#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
#define talloc_get_type_abort(ptr, type) (type *)_talloc_get_type_abort(ptr, #type, __location__)
#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type)
#if TALLOC_DEPRECATED
#define talloc_zero_p(ctx, type) talloc_zero(ctx, type)
#define talloc_p(ctx, type) talloc(ctx, type)
#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count)
#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count)
#define talloc_destroy(ctx) talloc_free(ctx)
#define talloc_append_string(c, s, a) (s?talloc_strdup_append(s,a):talloc_strdup(c, a))
#endif
#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
/* The following definitions come from talloc.c */
void *_talloc(const void *context, size_t size);
void *talloc_pool(const void *context, size_t size);
void _talloc_set_destructor(const void *ptr, int (*_destructor)(void *));
int talloc_increase_ref_count(const void *ptr);
size_t talloc_reference_count(const void *ptr);
void *_talloc_reference(const void *context, const void *ptr);
int talloc_unlink(const void *context, void *ptr);
const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
void talloc_set_name_const(const void *ptr, const char *name);
void *talloc_named(const void *context, size_t size,
const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
void *talloc_named_const(const void *context, size_t size, const char *name);
const char *talloc_get_name(const void *ptr);
void *talloc_check_name(const void *ptr, const char *name);
void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location);
void *talloc_parent(const void *ptr);
const char *talloc_parent_name(const void *ptr);
void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
int talloc_free(void *ptr);
void talloc_free_children(void *ptr);
void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
void *_talloc_steal(const void *new_ctx, const void *ptr);
void *_talloc_move(const void *new_ctx, const void *pptr);
size_t talloc_total_size(const void *ptr);
size_t talloc_total_blocks(const void *ptr);
void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
void (*callback)(const void *ptr,
int depth, int max_depth,
int is_ref,
void *private_data),
void *private_data);
void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f);
void talloc_report_full(const void *ptr, FILE *f);
void talloc_report(const void *ptr, FILE *f);
void talloc_enable_null_tracking(void);
void talloc_disable_null_tracking(void);
void talloc_enable_leak_report(void);
void talloc_enable_leak_report_full(void);
void *_talloc_zero(const void *ctx, size_t size, const char *name);
void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name);
void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
void *talloc_realloc_fn(const void *context, void *ptr, size_t size);
void *talloc_autofree_context(void);
size_t talloc_get_size(const void *ctx);
void *talloc_find_parent_byname(const void *ctx, const char *name);
void talloc_show_parents(const void *context, FILE *file);
int talloc_is_parent(const void *context, const void *ptr);
char *talloc_strdup(const void *t, const char *p);
char *talloc_strdup_append(char *s, const char *a);
char *talloc_strdup_append_buffer(char *s, const char *a);
char *talloc_strndup(const void *t, const char *p, size_t n);
char *talloc_strndup_append(char *s, const char *a, size_t n);
char *talloc_strndup_append_buffer(char *s, const char *a, size_t n);
char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
void talloc_set_abort_fn(void (*abort_fn)(const char *reason));
#endif

View File

@ -0,0 +1,72 @@
/*
* (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef TIMER_H
#define TIMER_H
#include <sys/time.h>
#include "linuxlist.h"
/**
* Timer management:
* - Create a struct timer_list
* - Fill out timeout and use add_timer or
* use schedule_timer to schedule a timer in
* x seconds and microseconds from now...
* - Use del_timer to remove the timer
*
* Internally:
* - We hook into select.c to give a timeval of the
* nearest timer. On already passed timers we give
* it a 0 to immediately fire after the select
* - update_timers will call the callbacks and remove
* the timers.
*
*/
struct timer_list {
struct llist_head entry;
struct timeval timeout;
unsigned int active : 1;
unsigned int handled : 1;
unsigned int in_list : 1;
void (*cb)(void*);
void *data;
};
/**
* timer management
*/
void bsc_add_timer(struct timer_list *timer);
void bsc_schedule_timer(struct timer_list *timer, int seconds, int microseconds);
void bsc_del_timer(struct timer_list *timer);
int bsc_timer_pending(struct timer_list *timer);
/**
* internal timer list management
*/
struct timeval *bsc_nearest_timer();
void bsc_prepare_timers();
int bsc_update_timers();
int bsc_timer_check(void);
#endif

View File

@ -0,0 +1,245 @@
#ifndef _TLV_H
#define _TLV_H
#include <stdint.h>
#include <string.h>
#include <osmocore/msgb.h>
/* Terminology / wording
tag length value (in bits)
V - - 8
LV - 8 N * 8
TLV 8 8 N * 8
TL16V 8 16 N * 8
TLV16 8 8 N * 16
TvLV 8 8/16 N * 8
*/
#define LV_GROSS_LEN(x) (x+1)
#define TLV_GROSS_LEN(x) (x+2)
#define TLV16_GROSS_LEN(x) ((2*x)+2)
#define TL16V_GROSS_LEN(x) (x+3)
#define L16TV_GROSS_LEN(x) (x+3)
#define TVLV_MAX_ONEBYTE 0x7f
static inline uint16_t TVLV_GROSS_LEN(uint16_t len)
{
if (len <= TVLV_MAX_ONEBYTE)
return TLV_GROSS_LEN(len);
else
return TL16V_GROSS_LEN(len);
}
/* TLV generation */
static inline uint8_t *lv_put(uint8_t *buf, uint8_t len,
const uint8_t *val)
{
*buf++ = len;
memcpy(buf, val, len);
return buf + len;
}
static inline uint8_t *tlv_put(uint8_t *buf, uint8_t tag, uint8_t len,
const uint8_t *val)
{
*buf++ = tag;
*buf++ = len;
memcpy(buf, val, len);
return buf + len;
}
static inline uint8_t *tlv16_put(uint8_t *buf, uint8_t tag, uint8_t len,
const uint16_t *val)
{
*buf++ = tag;
*buf++ = len;
memcpy(buf, val, len*2);
return buf + len*2;
}
static inline uint8_t *tl16v_put(uint8_t *buf, uint8_t tag, uint16_t len,
const uint8_t *val)
{
*buf++ = tag;
*buf++ = len >> 8;
*buf++ = len & 0xff;
memcpy(buf, val, len);
return buf + len*2;
}
static inline uint8_t *tvlv_put(uint8_t *buf, uint8_t tag, uint16_t len,
const uint8_t *val)
{
uint8_t *ret;
if (len <= TVLV_MAX_ONEBYTE) {
ret = tlv_put(buf, tag, len, val);
buf[1] |= 0x80;
} else
ret = tl16v_put(buf, tag, len, val);
return ret;
}
static inline uint8_t *msgb_tlv16_put(struct msgb *msg, uint8_t tag, uint8_t len, const uint16_t *val)
{
uint8_t *buf = msgb_put(msg, TLV16_GROSS_LEN(len));
return tlv16_put(buf, tag, len, val);
}
static inline uint8_t *msgb_tl16v_put(struct msgb *msg, uint8_t tag, uint16_t len,
const uint8_t *val)
{
uint8_t *buf = msgb_put(msg, TL16V_GROSS_LEN(len));
return tl16v_put(buf, tag, len, val);
}
static inline uint8_t *msgb_tvlv_put(struct msgb *msg, uint8_t tag, uint16_t len,
const uint8_t *val)
{
uint8_t *buf = msgb_put(msg, TVLV_GROSS_LEN(len));
return tvlv_put(buf, tag, len, val);
}
static inline uint8_t *msgb_l16tv_put(struct msgb *msg, uint16_t len, uint8_t tag,
const uint8_t *val)
{
uint8_t *buf = msgb_put(msg, L16TV_GROSS_LEN(len));
*buf++ = len >> 8;
*buf++ = len & 0xff;
*buf++ = tag;
memcpy(buf, val, len);
return buf + len;
}
static inline uint8_t *v_put(uint8_t *buf, uint8_t val)
{
*buf++ = val;
return buf;
}
static inline uint8_t *tv_put(uint8_t *buf, uint8_t tag,
uint8_t val)
{
*buf++ = tag;
*buf++ = val;
return buf;
}
/* 'val' is still in host byte order! */
static inline uint8_t *tv16_put(uint8_t *buf, uint8_t tag,
uint16_t val)
{
*buf++ = tag;
*buf++ = val >> 8;
*buf++ = val & 0xff;
return buf;
}
static inline uint8_t *msgb_lv_put(struct msgb *msg, uint8_t len, const uint8_t *val)
{
uint8_t *buf = msgb_put(msg, LV_GROSS_LEN(len));
return lv_put(buf, len, val);
}
static inline uint8_t *msgb_tlv_put(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val)
{
uint8_t *buf = msgb_put(msg, TLV_GROSS_LEN(len));
return tlv_put(buf, tag, len, val);
}
static inline uint8_t *msgb_tv_put(struct msgb *msg, uint8_t tag, uint8_t val)
{
uint8_t *buf = msgb_put(msg, 2);
return tv_put(buf, tag, val);
}
static inline uint8_t *msgb_v_put(struct msgb *msg, uint8_t val)
{
uint8_t *buf = msgb_put(msg, 1);
return v_put(buf, val);
}
static inline uint8_t *msgb_tv16_put(struct msgb *msg, uint8_t tag, uint16_t val)
{
uint8_t *buf = msgb_put(msg, 3);
return tv16_put(buf, tag, val);
}
static inline uint8_t *msgb_tlv_push(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val)
{
uint8_t *buf = msgb_push(msg, TLV_GROSS_LEN(len));
return tlv_put(buf, tag, len, val);
}
static inline uint8_t *msgb_tv_push(struct msgb *msg, uint8_t tag, uint8_t val)
{
uint8_t *buf = msgb_push(msg, 2);
return tv_put(buf, tag, val);
}
static inline uint8_t *msgb_tv16_push(struct msgb *msg, uint8_t tag, uint16_t val)
{
uint8_t *buf = msgb_push(msg, 3);
return tv16_put(buf, tag, val);
}
static inline uint8_t *msgb_tvlv_push(struct msgb *msg, uint8_t tag, uint16_t len,
const uint8_t *val)
{
uint8_t *buf = msgb_push(msg, TVLV_GROSS_LEN(len));
return tvlv_put(buf, tag, len, val);
}
/* TLV parsing */
struct tlv_p_entry {
uint16_t len;
const uint8_t *val;
};
enum tlv_type {
TLV_TYPE_NONE,
TLV_TYPE_FIXED,
TLV_TYPE_T,
TLV_TYPE_TV,
TLV_TYPE_TLV,
TLV_TYPE_TL16V,
TLV_TYPE_TvLV,
TLV_TYPE_SINGLE_TV
};
struct tlv_def {
enum tlv_type type;
uint8_t fixed_len;
};
struct tlv_definition {
struct tlv_def def[0xff];
};
struct tlv_parsed {
struct tlv_p_entry lv[0xff];
};
extern struct tlv_definition tvlv_att_def;
int tlv_parse_one(uint8_t *o_tag, uint16_t *o_len, const uint8_t **o_val,
const struct tlv_definition *def,
const uint8_t *buf, int buf_len);
int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
const uint8_t *buf, int buf_len, uint8_t lv_tag, uint8_t lv_tag2);
/* take a master (src) tlvdev and fill up all empty slots in 'dst' */
void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src);
#define TLVP_PRESENT(x, y) ((x)->lv[y].val)
#define TLVP_LEN(x, y) (x)->lv[y].len
#define TLVP_VAL(x, y) (x)->lv[y].val
#endif /* _TLV_H */

View File

@ -0,0 +1,20 @@
#ifndef OSMOCORE_UTIL_H
#define OSMOCORE_UTIL_H
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#include <stdint.h>
struct value_string {
unsigned int value;
const char *str;
};
const char *get_value_string(const struct value_string *vs, uint32_t val);
int get_string_value(const struct value_string *vs, const char *str);
char bcd2char(uint8_t bcd);
/* only works for numbers in ascci */
uint8_t char2bcd(char c);
#endif

View File

@ -0,0 +1,46 @@
/* Generic write queue implementation */
/*
* (C) 2010 by Holger Hans Peter Freyther
* (C) 2010 by On-Waves
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef write_queue_h
#define write_queue_h
#include "select.h"
#include "msgb.h"
struct write_queue {
struct bsc_fd bfd;
unsigned int max_length;
unsigned int current_length;
struct llist_head msg_queue;
int (*read_cb)(struct bsc_fd *fd);
int (*write_cb)(struct bsc_fd *fd, struct msgb *msg);
int (*except_cb)(struct bsc_fd *fd);
};
void write_queue_init(struct write_queue *queue, int max_length);
void write_queue_clear(struct write_queue *queue);
int write_queue_enqueue(struct write_queue *queue, struct msgb *data);
int write_queue_bfd_cb(struct bsc_fd *fd, unsigned int what);
#endif

View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: Osmocom Core Library
Description: C Utility Library
Version: @VERSION@
Libs: -L${libdir} -losmocore
Cflags: -I${includedir}/

View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: Osmocom VTY Interface Library
Description: C Utility Library
Version: @VERSION@
Libs: -L${libdir} -losmovty
Cflags: -I${includedir}/

View File

@ -0,0 +1 @@
Dummply placeholder.

View File

@ -0,0 +1,25 @@
SUBDIRS=vty
# This is _NOT_ the library release version, it's an API version.
# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification
LIBVERSION=0:0:0
INCLUDES = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS = -fPIC -Wall
lib_LTLIBRARIES = libosmocore.la
libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c rxlev_stat.c \
tlv_parser.c bitvec.c comp128.c gsm_utils.c statistics.c \
write_queue.c utils.c rsl.c gsm48.c gsm48_ie.c \
logging.c gsm0808.c rate_ctr.c gsmtap_util.c \
gprs_cipher_core.c
if ENABLE_PLUGIN
libosmocore_la_SOURCES += plugin.c
libosmocore_la_LDFLAGS = -ldl
endif
if ENABLE_TALLOC
libosmocore_la_SOURCES += talloc.c
endif

View File

@ -0,0 +1,219 @@
/* bit vector utility routines */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <errno.h>
#include <stdint.h>
#include <osmocore/bitvec.h>
#define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit)
static inline unsigned int bytenum_from_bitnum(unsigned int bitnum)
{
unsigned int bytenum = bitnum / 8;
return bytenum;
}
/* convert ZERO/ONE/L/H to a bitmask at given pos in a byte */
static uint8_t bitval2mask(enum bit_value bit, uint8_t bitnum)
{
int bitval;
switch (bit) {
case ZERO:
bitval = (0 << bitnum);
break;
case ONE:
bitval = (1 << bitnum);
break;
case L:
bitval = ((0x2b ^ (0 << bitnum)) & (1 << bitnum));
break;
case H:
bitval = ((0x2b ^ (1 << bitnum)) & (1 << bitnum));
break;
default:
return 0;
}
return bitval;
}
/* check if the bit is 0 or 1 for a given position inside a bitvec */
enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr)
{
unsigned int bytenum = bytenum_from_bitnum(bitnr);
unsigned int bitnum = 7 - (bitnr % 8);
uint8_t bitval;
if (bytenum >= bv->data_len)
return -EINVAL;
bitval = bitval2mask(ONE, bitnum);
if (bv->data[bytenum] & bitval)
return ONE;
return ZERO;
}
/* check if the bit is L or H for a given position inside a bitvec */
enum bit_value bitvec_get_bit_pos_high(const struct bitvec *bv,
unsigned int bitnr)
{
unsigned int bytenum = bytenum_from_bitnum(bitnr);
unsigned int bitnum = 7 - (bitnr % 8);
uint8_t bitval;
if (bytenum >= bv->data_len)
return -EINVAL;
bitval = bitval2mask(H, bitnum);
if (bv->data[bytenum] & bitval)
return H;
return L;
}
/* get the Nth set bit inside the bit vector */
unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n)
{
unsigned int i, k = 0;
for (i = 0; i < bv->data_len*8; i++) {
if (bitvec_get_bit_pos(bv, i) == ONE) {
k++;
if (k == n)
return i;
}
}
return 0;
}
/* set the bit at a given position inside a bitvec */
int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr,
enum bit_value bit)
{
unsigned int bytenum = bytenum_from_bitnum(bitnr);
unsigned int bitnum = 7 - (bitnr % 8);
uint8_t bitval;
if (bytenum >= bv->data_len)
return -EINVAL;
/* first clear the bit */
bitval = bitval2mask(ONE, bitnum);
bv->data[bytenum] &= ~bitval;
/* then set it to desired value */
bitval = bitval2mask(bit, bitnum);
bv->data[bytenum] |= bitval;
return 0;
}
/* set the next bit inside a bitvec */
int bitvec_set_bit(struct bitvec *bv, enum bit_value bit)
{
int rc;
rc = bitvec_set_bit_pos(bv, bv->cur_bit, bit);
if (!rc)
bv->cur_bit++;
return rc;
}
/* get the next bit (low/high) inside a bitvec */
int bitvec_get_bit_high(struct bitvec *bv)
{
int rc;
rc = bitvec_get_bit_pos_high(bv, bv->cur_bit);
if (rc >= 0)
bv->cur_bit++;
return rc;
}
/* set multiple bits (based on array of bitvals) at current pos */
int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count)
{
int i, rc;
for (i = 0; i < count; i++) {
rc = bitvec_set_bit(bv, bits[i]);
if (rc)
return rc;
}
return 0;
}
/* set multiple bits (based on numeric value) at current pos */
int bitvec_set_uint(struct bitvec *bv, unsigned int ui, int num_bits)
{
int i, rc;
for (i = 0; i < num_bits; i++) {
int bit = 0;
if (ui & (1 << (num_bits - i - 1)))
bit = 1;
rc = bitvec_set_bit(bv, bit);
if (rc)
return rc;
}
return 0;
}
/* get multiple bits (based on numeric value) from current pos */
int bitvec_get_uint(struct bitvec *bv, int num_bits)
{
int i;
unsigned int ui = 0;
for (i = 0; i < num_bits; i++) {
int bit = bitvec_get_bit_pos(bv, bv->cur_bit);
if (bit < 0)
return bit;
if (bit)
ui |= (1 << (num_bits - i - 1));
bv->cur_bit++;
}
return ui;
}
/* pad all remaining bits up to num_bits */
int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit)
{
unsigned int i;
for (i = bv->cur_bit; i <= up_to_bit; i++)
bitvec_set_bit(bv, L);
return 0;
}

View File

@ -0,0 +1,230 @@
/*
* COMP128 implementation
*
*
* This code is inspired by original code from :
* Marc Briceno <marc@scard.org>, Ian Goldberg <iang@cs.berkeley.edu>,
* and David Wagner <daw@cs.berkeley.edu>
*
* But it has been fully rewritten from various PDFs found online describing
* the algorithm because the licence of the code referenced above was unclear.
* A comment snippet from the original code is included below, it describes
* where the doc came from and how the algorithm was reverse engineered.
*
*
* (C) 2009 by Sylvain Munaut <tnt@246tNt.com>
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
/*
* --- SNIP ---
*
* This code derived from a leaked document from the GSM standards.
* Some missing pieces were filled in by reverse-engineering a working SIM.
* We have verified that this is the correct COMP128 algorithm.
*
* The first page of the document identifies it as
* _Technical Information: GSM System Security Study_.
* 10-1617-01, 10th June 1988.
* The bottom of the title page is marked
* Racal Research Ltd.
* Worton Drive, Worton Grange Industrial Estate,
* Reading, Berks. RG2 0SB, England.
* Telephone: Reading (0734) 868601 Telex: 847152
* The relevant bits are in Part I, Section 20 (pages 66--67). Enjoy!
*
* Note: There are three typos in the spec (discovered by
* reverse-engineering).
* First, "z = (2 * x[n] + x[n]) mod 2^(9-j)" should clearly read
* "z = (2 * x[m] + x[n]) mod 2^(9-j)".
* Second, the "k" loop in the "Form bits from bytes" section is severely
* botched: the k index should run only from 0 to 3, and clearly the range
* on "the (8-k)th bit of byte j" is also off (should be 0..7, not 1..8,
* to be consistent with the subsequent section).
* Third, SRES is taken from the first 8 nibbles of x[], not the last 8 as
* claimed in the document. (And the document doesn't specify how Kc is
* derived, but that was also easily discovered with reverse engineering.)
* All of these typos have been corrected in the following code.
*
* --- /SNIP ---
*/
#include <string.h>
#include <stdint.h>
/* The compression tables (just copied ...) */
static const uint8_t table_0[512] = {
102, 177, 186, 162, 2, 156, 112, 75, 55, 25, 8, 12, 251, 193, 246, 188,
109, 213, 151, 53, 42, 79, 191, 115, 233, 242, 164, 223, 209, 148, 108, 161,
252, 37, 244, 47, 64, 211, 6, 237, 185, 160, 139, 113, 76, 138, 59, 70,
67, 26, 13, 157, 63, 179, 221, 30, 214, 36, 166, 69, 152, 124, 207, 116,
247, 194, 41, 84, 71, 1, 49, 14, 95, 35, 169, 21, 96, 78, 215, 225,
182, 243, 28, 92, 201, 118, 4, 74, 248, 128, 17, 11, 146, 132, 245, 48,
149, 90, 120, 39, 87, 230, 106, 232, 175, 19, 126, 190, 202, 141, 137, 176,
250, 27, 101, 40, 219, 227, 58, 20, 51, 178, 98, 216, 140, 22, 32, 121,
61, 103, 203, 72, 29, 110, 85, 212, 180, 204, 150, 183, 15, 66, 172, 196,
56, 197, 158, 0, 100, 45, 153, 7, 144, 222, 163, 167, 60, 135, 210, 231,
174, 165, 38, 249, 224, 34, 220, 229, 217, 208, 241, 68, 206, 189, 125, 255,
239, 54, 168, 89, 123, 122, 73, 145, 117, 234, 143, 99, 129, 200, 192, 82,
104, 170, 136, 235, 93, 81, 205, 173, 236, 94, 105, 52, 46, 228, 198, 5,
57, 254, 97, 155, 142, 133, 199, 171, 187, 50, 65, 181, 127, 107, 147, 226,
184, 218, 131, 33, 77, 86, 31, 44, 88, 62, 238, 18, 24, 43, 154, 23,
80, 159, 134, 111, 9, 114, 3, 91, 16, 130, 83, 10, 195, 240, 253, 119,
177, 102, 162, 186, 156, 2, 75, 112, 25, 55, 12, 8, 193, 251, 188, 246,
213, 109, 53, 151, 79, 42, 115, 191, 242, 233, 223, 164, 148, 209, 161, 108,
37, 252, 47, 244, 211, 64, 237, 6, 160, 185, 113, 139, 138, 76, 70, 59,
26, 67, 157, 13, 179, 63, 30, 221, 36, 214, 69, 166, 124, 152, 116, 207,
194, 247, 84, 41, 1, 71, 14, 49, 35, 95, 21, 169, 78, 96, 225, 215,
243, 182, 92, 28, 118, 201, 74, 4, 128, 248, 11, 17, 132, 146, 48, 245,
90, 149, 39, 120, 230, 87, 232, 106, 19, 175, 190, 126, 141, 202, 176, 137,
27, 250, 40, 101, 227, 219, 20, 58, 178, 51, 216, 98, 22, 140, 121, 32,
103, 61, 72, 203, 110, 29, 212, 85, 204, 180, 183, 150, 66, 15, 196, 172,
197, 56, 0, 158, 45, 100, 7, 153, 222, 144, 167, 163, 135, 60, 231, 210,
165, 174, 249, 38, 34, 224, 229, 220, 208, 217, 68, 241, 189, 206, 255, 125,
54, 239, 89, 168, 122, 123, 145, 73, 234, 117, 99, 143, 200, 129, 82, 192,
170, 104, 235, 136, 81, 93, 173, 205, 94, 236, 52, 105, 228, 46, 5, 198,
254, 57, 155, 97, 133, 142, 171, 199, 50, 187, 181, 65, 107, 127, 226, 147,
218, 184, 33, 131, 86, 77, 44, 31, 62, 88, 18, 238, 43, 24, 23, 154,
159, 80, 111, 134, 114, 9, 91, 3, 130, 16, 10, 83, 240, 195, 119, 253,
}, table_1[256] = {
19, 11, 80, 114, 43, 1, 69, 94, 39, 18, 127, 117, 97, 3, 85, 43,
27, 124, 70, 83, 47, 71, 63, 10, 47, 89, 79, 4, 14, 59, 11, 5,
35, 107, 103, 68, 21, 86, 36, 91, 85, 126, 32, 50, 109, 94, 120, 6,
53, 79, 28, 45, 99, 95, 41, 34, 88, 68, 93, 55, 110, 125, 105, 20,
90, 80, 76, 96, 23, 60, 89, 64, 121, 56, 14, 74, 101, 8, 19, 78,
76, 66, 104, 46, 111, 50, 32, 3, 39, 0, 58, 25, 92, 22, 18, 51,
57, 65, 119, 116, 22, 109, 7, 86, 59, 93, 62, 110, 78, 99, 77, 67,
12, 113, 87, 98, 102, 5, 88, 33, 38, 56, 23, 8, 75, 45, 13, 75,
95, 63, 28, 49, 123, 120, 20, 112, 44, 30, 15, 98, 106, 2, 103, 29,
82, 107, 42, 124, 24, 30, 41, 16, 108, 100, 117, 40, 73, 40, 7, 114,
82, 115, 36, 112, 12, 102, 100, 84, 92, 48, 72, 97, 9, 54, 55, 74,
113, 123, 17, 26, 53, 58, 4, 9, 69, 122, 21, 118, 42, 60, 27, 73,
118, 125, 34, 15, 65, 115, 84, 64, 62, 81, 70, 1, 24, 111, 121, 83,
104, 81, 49, 127, 48, 105, 31, 10, 6, 91, 87, 37, 16, 54, 116, 126,
31, 38, 13, 0, 72, 106, 77, 61, 26, 67, 46, 29, 96, 37, 61, 52,
101, 17, 44, 108, 71, 52, 66, 57, 33, 51, 25, 90, 2, 119, 122, 35,
}, table_2[128] = {
52, 50, 44, 6, 21, 49, 41, 59, 39, 51, 25, 32, 51, 47, 52, 43,
37, 4, 40, 34, 61, 12, 28, 4, 58, 23, 8, 15, 12, 22, 9, 18,
55, 10, 33, 35, 50, 1, 43, 3, 57, 13, 62, 14, 7, 42, 44, 59,
62, 57, 27, 6, 8, 31, 26, 54, 41, 22, 45, 20, 39, 3, 16, 56,
48, 2, 21, 28, 36, 42, 60, 33, 34, 18, 0, 11, 24, 10, 17, 61,
29, 14, 45, 26, 55, 46, 11, 17, 54, 46, 9, 24, 30, 60, 32, 0,
20, 38, 2, 30, 58, 35, 1, 16, 56, 40, 23, 48, 13, 19, 19, 27,
31, 53, 47, 38, 63, 15, 49, 5, 37, 53, 25, 36, 63, 29, 5, 7,
}, table_3[64] = {
1, 5, 29, 6, 25, 1, 18, 23, 17, 19, 0, 9, 24, 25, 6, 31,
28, 20, 24, 30, 4, 27, 3, 13, 15, 16, 14, 18, 4, 3, 8, 9,
20, 0, 12, 26, 21, 8, 28, 2, 29, 2, 15, 7, 11, 22, 14, 10,
17, 21, 12, 30, 26, 27, 16, 31, 11, 7, 13, 23, 10, 5, 22, 19,
}, table_4[32] = {
15, 12, 10, 4, 1, 14, 11, 7, 5, 0, 14, 7, 1, 2, 13, 8,
10, 3, 4, 9, 6, 0, 3, 2, 5, 6, 8, 9, 11, 13, 15, 12,
};
static const uint8_t *_comp128_table[5] = { table_0, table_1, table_2, table_3, table_4 };
static inline void
_comp128_compression_round(uint8_t *x, int n, const uint8_t *tbl)
{
int i, j, m, a, b, y, z;
m = 4 - n;
for (i=0; i<(1<<n); i++)
for (j=0; j<(1<<m); j++) {
a = j + i * (2<<m);
b = a + (1<<m);
y = (x[a] + (x[b]<<1)) & ((32<<m)-1);
z = ((x[a]<<1) + x[b]) & ((32<<m)-1);
x[a] = tbl[y];
x[b] = tbl[z];
}
}
static inline void
_comp128_compression(uint8_t *x)
{
int n;
for (n=0; n<5; n++)
_comp128_compression_round(x, n, _comp128_table[n]);
}
static inline void
_comp128_bitsfrombytes(uint8_t *x, uint8_t *bits)
{
int i;
memset(bits, 0x00, 128);
for (i=0; i<128; i++)
if (x[i>>2] & (1<<(3-(i&3))))
bits[i] = 1;
}
static inline void
_comp128_permutation(uint8_t *x, uint8_t *bits)
{
int i;
memset(&x[16], 0x00, 16);
for (i=0; i<128; i++)
x[(i>>3)+16] |= bits[(i*17) & 127] << (7-(i&7));
}
void
comp128(uint8_t *ki, uint8_t *rand, uint8_t *sres, uint8_t *kc)
{
int i;
uint8_t x[32], bits[128];
/* x[16-31] = RAND */
memcpy(&x[16], rand, 16);
/* Round 1-7 */
for (i=0; i<7; i++) {
/* x[0-15] = Ki */
memcpy(x, ki, 16);
/* Compression */
_comp128_compression(x);
/* FormBitFromBytes */
_comp128_bitsfrombytes(x, bits);
/* Permutation */
_comp128_permutation(x, bits);
}
/* Round 8 (final) */
/* x[0-15] = Ki */
memcpy(x, ki, 16);
/* Compression */
_comp128_compression(x);
/* Output stage */
for (i=0; i<8; i+=2)
sres[i>>1] = x[i]<<4 | x[i+1];
for (i=0; i<12; i+=2)
kc[i>>1] = (x[i + 18] << 6) |
(x[i + 19] << 2) |
(x[i + 20] >> 2);
kc[6] = (x[30]<<6) | (x[31]<<2);
kc[7] = 0;
}

View File

@ -0,0 +1,99 @@
/* GPRS LLC cipher core infrastructure */
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <errno.h>
#include <stdint.h>
#include <osmocore/utils.h>
#include <osmocore/linuxlist.h>
#include <osmocore/plugin.h>
#include <osmocom/crypt/gprs_cipher.h>
static LLIST_HEAD(gprs_ciphers);
static struct gprs_cipher_impl *selected_ciphers[_GPRS_ALGO_NUM];
/* register a cipher with the core */
int gprs_cipher_register(struct gprs_cipher_impl *ciph)
{
if (ciph->algo > ARRAY_SIZE(selected_ciphers))
return -ERANGE;
llist_add_tail(&ciph->list, &gprs_ciphers);
/* check if we want to select this implementation over others */
if (!selected_ciphers[ciph->algo] ||
(selected_ciphers[ciph->algo]->priority > ciph->priority))
selected_ciphers[ciph->algo] = ciph;
return 0;
}
/* load all available GPRS cipher plugins */
int gprs_cipher_load(const char *path)
{
/* load all plugins available from path */
return plugin_load_all(path);
}
/* function to be called by core code */
int gprs_cipher_run(uint8_t *out, uint16_t len, enum gprs_ciph_algo algo,
uint64_t kc, uint32_t iv, enum gprs_cipher_direction dir)
{
if (algo > ARRAY_SIZE(selected_ciphers))
return -ERANGE;
if (!selected_ciphers[algo])
return -EINVAL;
if (len > GSM0464_CIPH_MAX_BLOCK)
return -ERANGE;
/* run the actual cipher from the plugin */
return selected_ciphers[algo]->run(out, len, kc, iv, dir);
}
int gprs_cipher_supported(enum gprs_ciph_algo algo)
{
if (algo > ARRAY_SIZE(selected_ciphers))
return -ERANGE;
if (selected_ciphers[algo])
return 1;
return 0;
}
/* GSM TS 04.64 / Section A.2.1 : Generation of 'input' */
uint32_t gprs_cipher_gen_input_ui(uint32_t iov_ui, uint8_t sapi, uint32_t lfn, uint32_t oc)
{
uint32_t sx = ((1<<27) * sapi) + (1<<31);
return (iov_ui ^ sx) + lfn + oc;
}
/* GSM TS 04.64 / Section A.2.1 : Generation of 'input' */
uint32_t gprs_cipher_gen_input_i(uint32_t iov_i, uint32_t lfn, uint32_t oc)
{
return iov_i + lfn + oc;
}

View File

@ -0,0 +1,306 @@
/* (C) 2009,2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009,2010 by On-Waves
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <osmocore/gsm0808.h>
#include <osmocore/protocol/gsm_08_08.h>
#include <osmocore/gsm48.h>
#include <arpa/inet.h>
#define BSSMAP_MSG_SIZE 512
#define BSSMAP_MSG_HEADROOM 128
struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc, uint16_t cc, int lac, int _ci)
{
uint8_t *data;
uint16_t *ci;
struct msgb* msg;
struct gsm48_loc_area_id *lai;
msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
"bssmap cmpl l3");
if (!msg)
return NULL;
/* create the bssmap header */
msg->l3h = msgb_put(msg, 2);
msg->l3h[0] = 0x0;
/* create layer 3 header */
data = msgb_put(msg, 1);
data[0] = BSS_MAP_MSG_COMPLETE_LAYER_3;
/* create the cell header */
data = msgb_put(msg, 3);
data[0] = GSM0808_IE_CELL_IDENTIFIER;
data[1] = 1 + sizeof(*lai) + 2;
data[2] = CELL_IDENT_WHOLE_GLOBAL;
lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
gsm48_generate_lai(lai, cc, nc, lac);
ci = (uint16_t *) msgb_put(msg, 2);
*ci = htons(_ci);
/* copy the layer3 data */
data = msgb_put(msg, msgb_l3len(msg_l3) + 2);
data[0] = GSM0808_IE_LAYER_3_INFORMATION;
data[1] = msgb_l3len(msg_l3);
memcpy(&data[2], msg_l3->l3h, data[1]);
/* update the size */
msg->l3h[1] = msgb_l3len(msg) - 2;
return msg;
}
struct msgb *gsm0808_create_reset(void)
{
struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
"bssmap: reset");
if (!msg)
return NULL;
msg->l3h = msgb_put(msg, 6);
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
msg->l3h[1] = 0x04;
msg->l3h[2] = 0x30;
msg->l3h[3] = 0x04;
msg->l3h[4] = 0x01;
msg->l3h[5] = 0x20;
return msg;
}
struct msgb *gsm0808_create_clear_complete(void)
{
struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
"bssmap: clear complete");
if (!msg)
return NULL;
msg->l3h = msgb_put(msg, 3);
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
msg->l3h[1] = 1;
msg->l3h[2] = BSS_MAP_MSG_CLEAR_COMPLETE;
return msg;
}
struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id)
{
struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
"cipher-complete");
if (!msg)
return NULL;
/* send response with BSS override for A5/1... cheating */
msg->l3h = msgb_put(msg, 3);
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
msg->l3h[1] = 0xff;
msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_COMPLETE;
/* include layer3 in case we have at least two octets */
if (layer3 && msgb_l3len(layer3) > 2) {
msg->l4h = msgb_put(msg, msgb_l3len(layer3) + 2);
msg->l4h[0] = GSM0808_IE_LAYER_3_MESSAGE_CONTENTS;
msg->l4h[1] = msgb_l3len(layer3);
memcpy(&msg->l4h[2], layer3->l3h, msgb_l3len(layer3));
}
/* and the optional BSS message */
msg->l4h = msgb_put(msg, 2);
msg->l4h[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
msg->l4h[1] = alg_id;
/* update the size */
msg->l3h[1] = msgb_l3len(msg) - 2;
return msg;
}
struct msgb *gsm0808_create_cipher_reject(uint8_t cause)
{
struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
"bssmap: clear complete");
if (!msg)
return NULL;
msg->l3h = msgb_put(msg, 3);
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
msg->l3h[1] = 2;
msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_REJECT;
msg->l3h[3] = cause;
return msg;
}
struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark_data, uint8_t length)
{
struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
"classmark-update");
if (!msg)
return NULL;
msg->l3h = msgb_put(msg, 3);
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
msg->l3h[1] = 0xff;
msg->l3h[2] = BSS_MAP_MSG_CLASSMARK_UPDATE;
msg->l4h = msgb_put(msg, length);
memcpy(msg->l4h, classmark_data, length);
/* update the size */
msg->l3h[1] = msgb_l3len(msg) - 2;
return msg;
}
struct msgb *gsm0808_create_sapi_reject(uint8_t link_id)
{
struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
"bssmap: sapi 'n' reject");
if (!msg)
return NULL;
msg->l3h = msgb_put(msg, 5);
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
msg->l3h[1] = 3;
msg->l3h[2] = BSS_MAP_MSG_SAPI_N_REJECT;
msg->l3h[3] = link_id;
msg->l3h[4] = GSM0808_CAUSE_BSS_NOT_EQUIPPED;
return msg;
}
struct msgb *gsm0808_create_assignment_completed(struct gsm_lchan *lchan, uint8_t rr_cause,
uint8_t chosen_channel, uint8_t encr_alg_id,
uint8_t speech_mode)
{
uint8_t *data;
struct msgb *msg = msgb_alloc(35, "bssmap: ass compl");
if (!msg)
return NULL;
msg->l3h = msgb_put(msg, 3);
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
msg->l3h[1] = 0xff;
msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_COMPLETE;
/* write 3.2.2.22 */
data = msgb_put(msg, 2);
data[0] = GSM0808_IE_RR_CAUSE;
data[1] = rr_cause;
/* write cirtcuit identity code 3.2.2.2 */
/* write cell identifier 3.2.2.17 */
/* write chosen channel 3.2.2.33 when BTS picked it */
data = msgb_put(msg, 2);
data[0] = GSM0808_IE_CHOSEN_CHANNEL;
data[1] = chosen_channel;
/* write chosen encryption algorithm 3.2.2.44 */
data = msgb_put(msg, 2);
data[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
data[1] = encr_alg_id;
/* write circuit pool 3.2.2.45 */
/* write speech version chosen: 3.2.2.51 when BTS picked it */
if (speech_mode != 0) {
data = msgb_put(msg, 2);
data[0] = GSM0808_IE_SPEECH_VERSION;
data[1] = speech_mode;
}
/* write LSA identifier 3.2.2.15 */
/* update the size */
msg->l3h[1] = msgb_l3len(msg) - 2;
return msg;
}
struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause)
{
uint8_t *data;
struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
"bssmap: ass fail");
if (!msg)
return NULL;
msg->l3h = msgb_put(msg, 6);
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
msg->l3h[1] = 0xff;
msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE;
msg->l3h[3] = GSM0808_IE_CAUSE;
msg->l3h[4] = 1;
msg->l3h[5] = cause;
/* RR cause 3.2.2.22 */
if (rr_cause) {
data = msgb_put(msg, 2);
data[0] = GSM0808_IE_RR_CAUSE;
data[1] = *rr_cause;
}
/* Circuit pool 3.22.45 */
/* Circuit pool list 3.2.2.46 */
/* update the size */
msg->l3h[1] = msgb_l3len(msg) - 2;
return msg;
}
void gsm0808_prepend_dtap_header(struct msgb *msg, uint8_t link_id)
{
uint8_t *hh = msgb_push(msg, 3);
hh[0] = BSSAP_MSG_DTAP;
hh[1] = link_id;
hh[2] = msg->len - 3;
}
static const struct tlv_definition bss_att_tlvdef = {
.def = {
[GSM0808_IE_IMSI] = { TLV_TYPE_TLV },
[GSM0808_IE_TMSI] = { TLV_TYPE_TLV },
[GSM0808_IE_CELL_IDENTIFIER_LIST] = { TLV_TYPE_TLV },
[GSM0808_IE_CHANNEL_NEEDED] = { TLV_TYPE_TV },
[GSM0808_IE_EMLPP_PRIORITY] = { TLV_TYPE_TV },
[GSM0808_IE_CHANNEL_TYPE] = { TLV_TYPE_TLV },
[GSM0808_IE_PRIORITY] = { TLV_TYPE_TLV },
[GSM0808_IE_CIRCUIT_IDENTITY_CODE] = { TLV_TYPE_TV },
[GSM0808_IE_DOWNLINK_DTX_FLAG] = { TLV_TYPE_TV },
[GSM0808_IE_INTERFERENCE_BAND_TO_USE] = { TLV_TYPE_TV },
[GSM0808_IE_CLASSMARK_INFORMATION_T2] = { TLV_TYPE_TLV },
[GSM0808_IE_GROUP_CALL_REFERENCE] = { TLV_TYPE_TLV },
[GSM0808_IE_TALKER_FLAG] = { TLV_TYPE_T },
[GSM0808_IE_CONFIG_EVO_INDI] = { TLV_TYPE_TV },
[GSM0808_IE_LSA_ACCESS_CTRL_SUPPR] = { TLV_TYPE_TV },
[GSM0808_IE_SERVICE_HANDOVER] = { TLV_TYPE_TV},
[GSM0808_IE_ENCRYPTION_INFORMATION] = { TLV_TYPE_TLV },
[GSM0808_IE_CIPHER_RESPONSE_MODE] = { TLV_TYPE_TV },
[GSM0808_IE_CELL_IDENTIFIER] = { TLV_TYPE_TLV },
[GSM0808_IE_CHOSEN_CHANNEL] = { TLV_TYPE_TV },
[GSM0808_IE_LAYER_3_INFORMATION] = { TLV_TYPE_TLV },
},
};
const struct tlv_definition *gsm0808_att_tlvdef()
{
return &bss_att_tlvdef;
}

View File

@ -0,0 +1,415 @@
/* GSM Mobile Radio Interface Layer 3 messages
* 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <osmocore/utils.h>
#include <osmocore/tlv.h>
#include <osmocore/gsm48.h>
#include <osmocore/protocol/gsm_04_08.h>
const struct tlv_definition gsm48_att_tlvdef = {
.def = {
[GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV },
[GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV },
[GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV },
[GSM48_IE_UTC] = { TLV_TYPE_TV },
[GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 },
[GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV },
[GSM48_IE_BEARER_CAP] = { TLV_TYPE_TLV },
[GSM48_IE_CAUSE] = { TLV_TYPE_TLV },
[GSM48_IE_CC_CAP] = { TLV_TYPE_TLV },
[GSM48_IE_ALERT] = { TLV_TYPE_TLV },
[GSM48_IE_FACILITY] = { TLV_TYPE_TLV },
[GSM48_IE_PROGR_IND] = { TLV_TYPE_TLV },
[GSM48_IE_AUX_STATUS] = { TLV_TYPE_TLV },
[GSM48_IE_NOTIFY] = { TLV_TYPE_TV },
[GSM48_IE_KPD_FACILITY] = { TLV_TYPE_TV },
[GSM48_IE_SIGNAL] = { TLV_TYPE_TV },
[GSM48_IE_CONN_BCD] = { TLV_TYPE_TLV },
[GSM48_IE_CONN_SUB] = { TLV_TYPE_TLV },
[GSM48_IE_CALLING_BCD] = { TLV_TYPE_TLV },
[GSM48_IE_CALLING_SUB] = { TLV_TYPE_TLV },
[GSM48_IE_CALLED_BCD] = { TLV_TYPE_TLV },
[GSM48_IE_CALLED_SUB] = { TLV_TYPE_TLV },
[GSM48_IE_REDIR_BCD] = { TLV_TYPE_TLV },
[GSM48_IE_REDIR_SUB] = { TLV_TYPE_TLV },
[GSM48_IE_LOWL_COMPAT] = { TLV_TYPE_TLV },
[GSM48_IE_HIGHL_COMPAT] = { TLV_TYPE_TLV },
[GSM48_IE_USER_USER] = { TLV_TYPE_TLV },
[GSM48_IE_SS_VERS] = { TLV_TYPE_TLV },
[GSM48_IE_MORE_DATA] = { TLV_TYPE_T },
[GSM48_IE_CLIR_SUPP] = { TLV_TYPE_T },
[GSM48_IE_CLIR_INVOC] = { TLV_TYPE_T },
[GSM48_IE_REV_C_SETUP] = { TLV_TYPE_T },
[GSM48_IE_REPEAT_CIR] = { TLV_TYPE_T },
[GSM48_IE_REPEAT_SEQ] = { TLV_TYPE_T },
/* FIXME: more elements */
},
};
/* RR elements */
const struct tlv_definition gsm48_rr_att_tlvdef = {
.def = {
/* NOTE: Don't add IE 17 = MOBILE_ID here, it already used. */
[GSM48_IE_VGCS_TARGET] = { TLV_TYPE_TLV },
[GSM48_IE_FRQSHORT_AFTER] = { TLV_TYPE_FIXED, 9 },
[GSM48_IE_MUL_RATE_CFG] = { TLV_TYPE_TLV },
[GSM48_IE_FREQ_L_AFTER] = { TLV_TYPE_TLV },
[GSM48_IE_MSLOT_DESC] = { TLV_TYPE_TLV },
[GSM48_IE_CHANMODE_2] = { TLV_TYPE_TV },
[GSM48_IE_FRQSHORT_BEFORE] = { TLV_TYPE_FIXED, 9 },
[GSM48_IE_CHANMODE_3] = { TLV_TYPE_TV },
[GSM48_IE_CHANMODE_4] = { TLV_TYPE_TV },
[GSM48_IE_CHANMODE_5] = { TLV_TYPE_TV },
[GSM48_IE_CHANMODE_6] = { TLV_TYPE_TV },
[GSM48_IE_CHANMODE_7] = { TLV_TYPE_TV },
[GSM48_IE_CHANMODE_8] = { TLV_TYPE_TV },
[GSM48_IE_FREQ_L_BEFORE] = { TLV_TYPE_TLV },
[GSM48_IE_CH_DESC_1_BEFORE] = { TLV_TYPE_FIXED, 3 },
[GSM48_IE_CH_DESC_2_BEFORE] = { TLV_TYPE_FIXED, 3 },
[GSM48_IE_F_CH_SEQ_BEFORE] = { TLV_TYPE_FIXED, 9 },
[GSM48_IE_CLASSMARK3] = { TLV_TYPE_TLV },
[GSM48_IE_MA_BEFORE] = { TLV_TYPE_TLV },
[GSM48_IE_RR_PACKET_UL] = { TLV_TYPE_TLV },
[GSM48_IE_RR_PACKET_DL] = { TLV_TYPE_TLV },
[GSM48_IE_CELL_CH_DESC] = { TLV_TYPE_FIXED, 16 },
[GSM48_IE_CHANMODE_1] = { TLV_TYPE_TV },
[GSM48_IE_CHDES_2_AFTER] = { TLV_TYPE_FIXED, 3 },
[GSM48_IE_MODE_SEC_CH] = { TLV_TYPE_TV },
[GSM48_IE_F_CH_SEQ_AFTER] = { TLV_TYPE_FIXED, 9 },
[GSM48_IE_MA_AFTER] = { TLV_TYPE_TLV },
[GSM48_IE_BA_RANGE] = { TLV_TYPE_TLV },
[GSM48_IE_GROUP_CHDES] = { TLV_TYPE_TLV },
[GSM48_IE_BA_LIST_PREF] = { TLV_TYPE_TLV },
[GSM48_IE_MOB_OVSERV_DIF] = { TLV_TYPE_TLV },
[GSM48_IE_REALTIME_DIFF] = { TLV_TYPE_TLV },
[GSM48_IE_START_TIME] = { TLV_TYPE_FIXED, 2 },
[GSM48_IE_TIMING_ADVANCE] = { TLV_TYPE_TV },
[GSM48_IE_GROUP_CIP_SEQ] = { TLV_TYPE_SINGLE_TV },
[GSM48_IE_CIP_MODE_SET] = { TLV_TYPE_SINGLE_TV },
[GSM48_IE_GPRS_RESUMPT] = { TLV_TYPE_SINGLE_TV },
[GSM48_IE_SYNC_IND] = { TLV_TYPE_SINGLE_TV },
},
};
/* MM elements */
const struct tlv_definition gsm48_mm_att_tlvdef = {
.def = {
[GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV },
[GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV },
[GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV },
[GSM48_IE_UTC] = { TLV_TYPE_TV },
[GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 },
[GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV },
[GSM48_IE_LOCATION_AREA] = { TLV_TYPE_FIXED, 5 },
[GSM48_IE_PRIORITY_LEV] = { TLV_TYPE_SINGLE_TV },
[GSM48_IE_FOLLOW_ON_PROC] = { TLV_TYPE_T },
[GSM48_IE_CTS_PERMISSION] = { TLV_TYPE_T },
},
};
static const struct value_string rr_cause_names[] = {
{ GSM48_RR_CAUSE_NORMAL, "Normal event" },
{ GSM48_RR_CAUSE_ABNORMAL_UNSPEC, "Abnormal release, unspecified" },
{ GSM48_RR_CAUSE_ABNORMAL_UNACCT, "Abnormal release, channel unacceptable" },
{ GSM48_RR_CAUSE_ABNORMAL_TIMER, "Abnormal release, timer expired" },
{ GSM48_RR_CAUSE_ABNORMAL_NOACT, "Abnormal release, no activity on radio path" },
{ GSM48_RR_CAUSE_PREMPTIVE_REL, "Preemptive release" },
{ GSM48_RR_CAUSE_HNDOVER_IMP, "Handover impossible, timing advance out of range" },
{ GSM48_RR_CAUSE_CHAN_MODE_UNACCT, "Channel mode unacceptable" },
{ GSM48_RR_CAUSE_FREQ_NOT_IMPL, "Frequency not implemented" },
{ GSM48_RR_CAUSE_CALL_CLEARED, "Call already cleared" },
{ GSM48_RR_CAUSE_SEMANT_INCORR, "Semantically incorrect message" },
{ GSM48_RR_CAUSE_INVALID_MAND_INF, "Invalid mandatory information" },
{ GSM48_RR_CAUSE_MSG_TYPE_N, "Message type non-existant or not implemented" },
{ GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT, "Message type not compatible with protocol state" },
{ GSM48_RR_CAUSE_COND_IE_ERROR, "Conditional IE error" },
{ GSM48_RR_CAUSE_NO_CELL_ALLOC_A, "No cell allocation available" },
{ GSM48_RR_CAUSE_PROT_ERROR_UNSPC, "Protocol error unspecified" },
{ 0, NULL },
};
/* FIXME: convert to value_string */
static const char *cc_state_names[32] = {
"NULL",
"INITIATED",
"MM_CONNECTION_PEND",
"MO_CALL_PROC",
"CALL_DELIVERED",
"illegal state 5",
"CALL_PRESENT",
"CALL_RECEIVED",
"CONNECT_REQUEST",
"MO_TERM_CALL_CONF",
"ACTIVE",
"DISCONNECT_REQ",
"DISCONNECT_IND",
"illegal state 13",
"illegal state 14",
"illegal state 15",
"illegal state 16",
"illegal state 17",
"illegal state 18",
"RELEASE_REQ",
"illegal state 20",
"illegal state 21",
"illegal state 22",
"illegal state 23",
"illegal state 24",
"illegal state 25",
"MO_ORIG_MODIFY",
"MO_TERM_MODIFY",
"CONNECT_IND",
"illegal state 29",
"illegal state 30",
"illegal state 31",
};
const char *gsm48_cc_state_name(uint8_t state)
{
if (state < ARRAY_SIZE(cc_state_names))
return cc_state_names[state];
return "invalid";
}
static const struct value_string cc_msg_names[] = {
{ GSM48_MT_CC_ALERTING, "ALERTING" },
{ GSM48_MT_CC_CALL_PROC, "CALL_PROC" },
{ GSM48_MT_CC_PROGRESS, "PROGRESS" },
{ GSM48_MT_CC_ESTAB, "ESTAB" },
{ GSM48_MT_CC_SETUP, "SETUP" },
{ GSM48_MT_CC_ESTAB_CONF, "ESTAB_CONF" },
{ GSM48_MT_CC_CONNECT, "CONNECT" },
{ GSM48_MT_CC_CALL_CONF, "CALL_CONF" },
{ GSM48_MT_CC_START_CC, "START_CC" },
{ GSM48_MT_CC_RECALL, "RECALL" },
{ GSM48_MT_CC_EMERG_SETUP, "EMERG_SETUP" },
{ GSM48_MT_CC_CONNECT_ACK, "CONNECT_ACK" },
{ GSM48_MT_CC_USER_INFO, "USER_INFO" },
{ GSM48_MT_CC_MODIFY_REJECT, "MODIFY_REJECT" },
{ GSM48_MT_CC_MODIFY, "MODIFY" },
{ GSM48_MT_CC_HOLD, "HOLD" },
{ GSM48_MT_CC_HOLD_ACK, "HOLD_ACK" },
{ GSM48_MT_CC_HOLD_REJ, "HOLD_REJ" },
{ GSM48_MT_CC_RETR, "RETR" },
{ GSM48_MT_CC_RETR_ACK, "RETR_ACK" },
{ GSM48_MT_CC_RETR_REJ, "RETR_REJ" },
{ GSM48_MT_CC_MODIFY_COMPL, "MODIFY_COMPL" },
{ GSM48_MT_CC_DISCONNECT, "DISCONNECT" },
{ GSM48_MT_CC_RELEASE_COMPL, "RELEASE_COMPL" },
{ GSM48_MT_CC_RELEASE, "RELEASE" },
{ GSM48_MT_CC_STOP_DTMF, "STOP_DTMF" },
{ GSM48_MT_CC_STOP_DTMF_ACK, "STOP_DTMF_ACK" },
{ GSM48_MT_CC_STATUS_ENQ, "STATUS_ENQ" },
{ GSM48_MT_CC_START_DTMF, "START_DTMF" },
{ GSM48_MT_CC_START_DTMF_ACK, "START_DTMF_ACK" },
{ GSM48_MT_CC_START_DTMF_REJ, "START_DTMF_REJ" },
{ GSM48_MT_CC_CONG_CTRL, "CONG_CTRL" },
{ GSM48_MT_CC_FACILITY, "FACILITY" },
{ GSM48_MT_CC_STATUS, "STATUS" },
{ GSM48_MT_CC_NOTIFY, "NOTFIY" },
{ 0, NULL }
};
const char *gsm48_cc_msg_name(uint8_t msgtype)
{
return get_value_string(cc_msg_names, msgtype);
}
const char *rr_cause_name(uint8_t cause)
{
return get_value_string(rr_cause_names, cause);
}
static void to_bcd(uint8_t *bcd, uint16_t val)
{
bcd[2] = val % 10;
val = val / 10;
bcd[1] = val % 10;
val = val / 10;
bcd[0] = val % 10;
val = val / 10;
}
void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc,
uint16_t mnc, uint16_t lac)
{
uint8_t bcd[3];
to_bcd(bcd, mcc);
lai48->digits[0] = bcd[0] | (bcd[1] << 4);
lai48->digits[1] = bcd[2];
to_bcd(bcd, mnc);
/* FIXME: do we need three-digit MNC? See Table 10.5.3 */
if (mnc > 99) {
lai48->digits[1] |= bcd[2] << 4;
lai48->digits[2] = bcd[0] | (bcd[1] << 4);
} else {
lai48->digits[1] |= 0xf << 4;
lai48->digits[2] = bcd[1] | (bcd[2] << 4);
}
lai48->lac = htons(lac);
}
int gsm48_generate_mid_from_tmsi(uint8_t *buf, uint32_t tmsi)
{
uint32_t *tptr = (uint32_t *) &buf[3];
buf[0] = GSM48_IE_MOBILE_ID;
buf[1] = GSM48_TMSI_LEN;
buf[2] = 0xf0 | GSM_MI_TYPE_TMSI;
*tptr = htonl(tmsi);
return 7;
}
int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi)
{
unsigned int length = strlen(imsi), i, off = 0;
uint8_t odd = (length & 0x1) == 1;
buf[0] = GSM48_IE_MOBILE_ID;
buf[2] = char2bcd(imsi[0]) << 4 | GSM_MI_TYPE_IMSI | (odd << 3);
/* if the length is even we will fill half of the last octet */
if (odd)
buf[1] = (length + 1) >> 1;
else
buf[1] = (length + 2) >> 1;
for (i = 1; i < buf[1]; ++i) {
uint8_t lower, upper;
lower = char2bcd(imsi[++off]);
if (!odd && off + 1 == length)
upper = 0x0f;
else
upper = char2bcd(imsi[++off]) & 0x0f;
buf[2 + i] = (upper << 4) | lower;
}
return 2 + buf[1];
}
/* Convert Mobile Identity (10.5.1.4) to string */
int gsm48_mi_to_string(char *string, const int str_len, const uint8_t *mi,
const int mi_len)
{
int i;
uint8_t mi_type;
char *str_cur = string;
uint32_t tmsi;
mi_type = mi[0] & GSM_MI_TYPE_MASK;
switch (mi_type) {
case GSM_MI_TYPE_NONE:
break;
case GSM_MI_TYPE_TMSI:
/* Table 10.5.4.3, reverse generate_mid_from_tmsi */
if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
memcpy(&tmsi, &mi[1], 4);
tmsi = ntohl(tmsi);
return snprintf(string, str_len, "%u", tmsi);
}
break;
case GSM_MI_TYPE_IMSI:
case GSM_MI_TYPE_IMEI:
case GSM_MI_TYPE_IMEISV:
*str_cur++ = bcd2char(mi[0] >> 4);
for (i = 1; i < mi_len; i++) {
if (str_cur + 2 >= string + str_len)
return str_cur - string;
*str_cur++ = bcd2char(mi[i] & 0xf);
/* skip last nibble in last input byte when GSM_EVEN */
if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
*str_cur++ = bcd2char(mi[i] >> 4);
}
break;
default:
break;
}
*str_cur++ = '\0';
return str_cur - string;
}
void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf)
{
raid->mcc = (buf[0] & 0xf) * 100;
raid->mcc += (buf[0] >> 4) * 10;
raid->mcc += (buf[1] & 0xf) * 1;
/* I wonder who came up with the stupidity of encoding the MNC
* differently depending on how many digits its decimal number has! */
if ((buf[1] >> 4) == 0xf) {
raid->mnc = (buf[2] & 0xf) * 10;
raid->mnc += (buf[2] >> 4) * 1;
} else {
raid->mnc = (buf[2] & 0xf) * 100;
raid->mnc += (buf[2] >> 4) * 10;
raid->mnc += (buf[1] >> 4) * 1;
}
raid->lac = ntohs(*(uint16_t *)(buf + 3));
raid->rac = buf[5];
}
int gsm48_construct_ra(uint8_t *buf, const struct gprs_ra_id *raid)
{
uint16_t mcc = raid->mcc;
uint16_t mnc = raid->mnc;
buf[0] = ((mcc / 100) % 10) | (((mcc / 10) % 10) << 4);
buf[1] = (mcc % 10);
/* I wonder who came up with the stupidity of encoding the MNC
* differently depending on how many digits its decimal number has! */
if (mnc < 100) {
buf[1] |= 0xf0;
buf[2] = ((mnc / 10) % 10) | ((mnc % 10) << 4);
} else {
buf[1] |= (mnc % 10) << 4;
buf[2] = ((mnc / 100) % 10) | (((mcc / 10) % 10) << 4);
}
*(uint16_t *)(buf+3) = htons(raid->lac);
buf[5] = raid->rac;
return 6;
}

View File

@ -0,0 +1,659 @@
/* GSM Mobile Radio Interface Layer 3 messages
* 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
* (C) 2009-2010 by Andreas Eversberg
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <osmocore/utils.h>
#include <osmocore/msgb.h>
#include <osmocore/tlv.h>
#include <osmocore/mncc.h>
#include <osmocore/protocol/gsm_04_08.h>
static const char bcd_num_digits[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '*', '#', 'a', 'b', 'c', '\0'
};
/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */
int gsm48_decode_bcd_number(char *output, int output_len,
const uint8_t *bcd_lv, int h_len)
{
uint8_t in_len = bcd_lv[0];
int i;
for (i = 1 + h_len; i <= in_len; i++) {
/* lower nibble */
output_len--;
if (output_len <= 1)
break;
*output++ = bcd_num_digits[bcd_lv[i] & 0xf];
/* higher nibble */
output_len--;
if (output_len <= 1)
break;
*output++ = bcd_num_digits[bcd_lv[i] >> 4];
}
if (output_len >= 1)
*output++ = '\0';
return 0;
}
/* convert a single ASCII character to call-control BCD */
static int asc_to_bcd(const char asc)
{
int i;
for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) {
if (bcd_num_digits[i] == asc)
return i;
}
return -EINVAL;
}
/* convert a ASCII phone number to 'called/calling/connect party BCD number' */
int gsm48_encode_bcd_number(uint8_t *bcd_lv, uint8_t max_len,
int h_len, const char *input)
{
int in_len = strlen(input);
int i;
uint8_t *bcd_cur = bcd_lv + 1 + h_len;
/* two digits per byte, plus type byte */
bcd_lv[0] = in_len/2 + h_len;
if (in_len % 2)
bcd_lv[0]++;
if (bcd_lv[0] > max_len)
return -EIO;
for (i = 0; i < in_len; i++) {
int rc = asc_to_bcd(input[i]);
if (rc < 0)
return rc;
if (i % 2 == 0)
*bcd_cur = rc;
else
*bcd_cur++ |= (rc << 4);
}
/* append padding nibble in case of odd length */
if (i % 2)
*bcd_cur++ |= 0xf0;
/* return how many bytes we used */
return (bcd_cur - bcd_lv);
}
/* decode 'bearer capability' */
int gsm48_decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
const uint8_t *lv)
{
uint8_t in_len = lv[0];
int i, s;
if (in_len < 1)
return -EINVAL;
bcap->speech_ver[0] = -1; /* end of list, of maximum 7 values */
/* octet 3 */
bcap->transfer = lv[1] & 0x07;
bcap->mode = (lv[1] & 0x08) >> 3;
bcap->coding = (lv[1] & 0x10) >> 4;
bcap->radio = (lv[1] & 0x60) >> 5;
if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) {
i = 1;
s = 0;
while(!(lv[i] & 0x80)) {
i++; /* octet 3a etc */
if (in_len < i)
return 0;
bcap->speech_ver[s++] = lv[i] & 0x0f;
bcap->speech_ver[s] = -1; /* end of list */
if (i == 2) /* octet 3a */
bcap->speech_ctm = (lv[i] & 0x20) >> 5;
if (s == 7) /* maximum speech versions + end of list */
return 0;
}
} else {
i = 1;
while (!(lv[i] & 0x80)) {
i++; /* octet 3a etc */
if (in_len < i)
return 0;
/* ignore them */
}
/* FIXME: implement OCTET 4+ parsing */
}
return 0;
}
/* encode 'bearer capability' */
int gsm48_encode_bearer_cap(struct msgb *msg, int lv_only,
const struct gsm_mncc_bearer_cap *bcap)
{
uint8_t lv[32 + 1];
int i = 1, s;
lv[1] = bcap->transfer;
lv[1] |= bcap->mode << 3;
lv[1] |= bcap->coding << 4;
lv[1] |= bcap->radio << 5;
if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) {
for (s = 0; bcap->speech_ver[s] >= 0; s++) {
i++; /* octet 3a etc */
lv[i] = bcap->speech_ver[s];
if (i == 2) /* octet 3a */
lv[i] |= bcap->speech_ctm << 5;
}
lv[i] |= 0x80; /* last IE of octet 3 etc */
} else {
/* FIXME: implement OCTET 4+ encoding */
}
lv[0] = i;
if (lv_only)
msgb_lv_put(msg, lv[0], lv+1);
else
msgb_tlv_put(msg, GSM48_IE_BEARER_CAP, lv[0], lv+1);
return 0;
}
/* decode 'call control cap' */
int gsm48_decode_cccap(struct gsm_mncc_cccap *ccap, const uint8_t *lv)
{
uint8_t in_len = lv[0];
if (in_len < 1)
return -EINVAL;
/* octet 3 */
ccap->dtmf = lv[1] & 0x01;
ccap->pcp = (lv[1] & 0x02) >> 1;
return 0;
}
/* encode 'call control cap' */
int gsm48_encode_cccap(struct msgb *msg,
const struct gsm_mncc_cccap *ccap)
{
uint8_t lv[2];
lv[0] = 1;
lv[1] = 0;
if (ccap->dtmf)
lv [1] |= 0x01;
if (ccap->pcp)
lv [1] |= 0x02;
msgb_tlv_put(msg, GSM48_IE_CC_CAP, lv[0], lv+1);
return 0;
}
/* decode 'called party BCD number' */
int gsm48_decode_called(struct gsm_mncc_number *called,
const uint8_t *lv)
{
uint8_t in_len = lv[0];
if (in_len < 1)
return -EINVAL;
/* octet 3 */
called->plan = lv[1] & 0x0f;
called->type = (lv[1] & 0x70) >> 4;
/* octet 4..N */
gsm48_decode_bcd_number(called->number, sizeof(called->number), lv, 1);
return 0;
}
/* encode 'called party BCD number' */
int gsm48_encode_called(struct msgb *msg,
const struct gsm_mncc_number *called)
{
uint8_t lv[18];
int ret;
/* octet 3 */
lv[1] = called->plan;
lv[1] |= called->type << 4;
/* octet 4..N, octet 2 */
ret = gsm48_encode_bcd_number(lv, sizeof(lv), 1, called->number);
if (ret < 0)
return ret;
msgb_tlv_put(msg, GSM48_IE_CALLED_BCD, lv[0], lv+1);
return 0;
}
/* decode callerid of various IEs */
int gsm48_decode_callerid(struct gsm_mncc_number *callerid,
const uint8_t *lv)
{
uint8_t in_len = lv[0];
int i = 1;
if (in_len < 1)
return -EINVAL;
/* octet 3 */
callerid->plan = lv[1] & 0x0f;
callerid->type = (lv[1] & 0x70) >> 4;
/* octet 3a */
if (!(lv[1] & 0x80)) {
callerid->screen = lv[2] & 0x03;
callerid->present = (lv[2] & 0x60) >> 5;
i = 2;
}
/* octet 4..N */
gsm48_decode_bcd_number(callerid->number, sizeof(callerid->number), lv, i);
return 0;
}
/* encode callerid of various IEs */
int gsm48_encode_callerid(struct msgb *msg, int ie, int max_len,
const struct gsm_mncc_number *callerid)
{
uint8_t lv[max_len - 1];
int h_len = 1;
int ret;
/* octet 3 */
lv[1] = callerid->plan;
lv[1] |= callerid->type << 4;
if (callerid->present || callerid->screen) {
/* octet 3a */
lv[2] = callerid->screen;
lv[2] |= callerid->present << 5;
lv[2] |= 0x80;
h_len++;
} else
lv[1] |= 0x80;
/* octet 4..N, octet 2 */
ret = gsm48_encode_bcd_number(lv, sizeof(lv), h_len, callerid->number);
if (ret < 0)
return ret;
msgb_tlv_put(msg, ie, lv[0], lv+1);
return 0;
}
/* decode 'cause' */
int gsm48_decode_cause(struct gsm_mncc_cause *cause,
const uint8_t *lv)
{
uint8_t in_len = lv[0];
int i;
if (in_len < 2)
return -EINVAL;
cause->diag_len = 0;
/* octet 3 */
cause->location = lv[1] & 0x0f;
cause->coding = (lv[1] & 0x60) >> 5;
i = 1;
if (!(lv[i] & 0x80)) {
i++; /* octet 3a */
if (in_len < i+1)
return 0;
cause->rec = 1;
cause->rec_val = lv[i] & 0x7f;
}
i++;
/* octet 4 */
cause->value = lv[i] & 0x7f;
i++;
if (in_len < i) /* no diag */
return 0;
if (in_len - (i-1) > 32) /* maximum 32 octets */
return 0;
/* octet 5-N */
memcpy(cause->diag, lv + i, in_len - (i-1));
cause->diag_len = in_len - (i-1);
return 0;
}
/* encode 'cause' */
int gsm48_encode_cause(struct msgb *msg, int lv_only,
const struct gsm_mncc_cause *cause)
{
uint8_t lv[32+4];
int i;
if (cause->diag_len > 32)
return -EINVAL;
/* octet 3 */
lv[1] = cause->location;
lv[1] |= cause->coding << 5;
i = 1;
if (cause->rec) {
i++; /* octet 3a */
lv[i] = cause->rec_val;
}
lv[i] |= 0x80; /* end of octet 3 */
/* octet 4 */
i++;
lv[i] = 0x80 | cause->value;
/* octet 5-N */
if (cause->diag_len) {
memcpy(lv + i, cause->diag, cause->diag_len);
i += cause->diag_len;
}
lv[0] = i;
if (lv_only)
msgb_lv_put(msg, lv[0], lv+1);
else
msgb_tlv_put(msg, GSM48_IE_CAUSE, lv[0], lv+1);
return 0;
}
/* decode 'calling number' */
int gsm48_decode_calling(struct gsm_mncc_number *calling,
const uint8_t *lv)
{
return gsm48_decode_callerid(calling, lv);
}
/* encode 'calling number' */
int gsm48_encode_calling(struct msgb *msg,
const struct gsm_mncc_number *calling)
{
return gsm48_encode_callerid(msg, GSM48_IE_CALLING_BCD, 14, calling);
}
/* decode 'connected number' */
int gsm48_decode_connected(struct gsm_mncc_number *connected,
const uint8_t *lv)
{
return gsm48_decode_callerid(connected, lv);
}
/* encode 'connected number' */
int gsm48_encode_connected(struct msgb *msg,
const struct gsm_mncc_number *connected)
{
return gsm48_encode_callerid(msg, GSM48_IE_CONN_BCD, 14, connected);
}
/* decode 'redirecting number' */
int gsm48_decode_redirecting(struct gsm_mncc_number *redirecting,
const uint8_t *lv)
{
return gsm48_decode_callerid(redirecting, lv);
}
/* encode 'redirecting number' */
int gsm48_encode_redirecting(struct msgb *msg,
const struct gsm_mncc_number *redirecting)
{
return gsm48_encode_callerid(msg, GSM48_IE_REDIR_BCD, 19, redirecting);
}
/* decode 'facility' */
int gsm48_decode_facility(struct gsm_mncc_facility *facility,
const uint8_t *lv)
{
uint8_t in_len = lv[0];
if (in_len < 1)
return -EINVAL;
if (in_len > sizeof(facility->info))
return -EINVAL;
memcpy(facility->info, lv+1, in_len);
facility->len = in_len;
return 0;
}
/* encode 'facility' */
int gsm48_encode_facility(struct msgb *msg, int lv_only,
const struct gsm_mncc_facility *facility)
{
uint8_t lv[GSM_MAX_FACILITY + 1];
if (facility->len < 1 || facility->len > GSM_MAX_FACILITY)
return -EINVAL;
memcpy(lv+1, facility->info, facility->len);
lv[0] = facility->len;
if (lv_only)
msgb_lv_put(msg, lv[0], lv+1);
else
msgb_tlv_put(msg, GSM48_IE_FACILITY, lv[0], lv+1);
return 0;
}
/* decode 'notify' */
int gsm48_decode_notify(int *notify, const uint8_t *v)
{
*notify = v[0] & 0x7f;
return 0;
}
/* encode 'notify' */
int gsm48_encode_notify(struct msgb *msg, int notify)
{
msgb_v_put(msg, notify | 0x80);
return 0;
}
/* decode 'signal' */
int gsm48_decode_signal(int *signal, const uint8_t *v)
{
*signal = v[0];
return 0;
}
/* encode 'signal' */
int gsm48_encode_signal(struct msgb *msg, int signal)
{
msgb_tv_put(msg, GSM48_IE_SIGNAL, signal);
return 0;
}
/* decode 'keypad' */
int gsm48_decode_keypad(int *keypad, const uint8_t *lv)
{
uint8_t in_len = lv[0];
if (in_len < 1)
return -EINVAL;
*keypad = lv[1] & 0x7f;
return 0;
}
/* encode 'keypad' */
int gsm48_encode_keypad(struct msgb *msg, int keypad)
{
msgb_tv_put(msg, GSM48_IE_KPD_FACILITY, keypad);
return 0;
}
/* decode 'progress' */
int gsm48_decode_progress(struct gsm_mncc_progress *progress,
const uint8_t *lv)
{
uint8_t in_len = lv[0];
if (in_len < 2)
return -EINVAL;
progress->coding = (lv[1] & 0x60) >> 5;
progress->location = lv[1] & 0x0f;
progress->descr = lv[2] & 0x7f;
return 0;
}
/* encode 'progress' */
int gsm48_encode_progress(struct msgb *msg, int lv_only,
const struct gsm_mncc_progress *p)
{
uint8_t lv[3];
lv[0] = 2;
lv[1] = 0x80 | ((p->coding & 0x3) << 5) | (p->location & 0xf);
lv[2] = 0x80 | (p->descr & 0x7f);
if (lv_only)
msgb_lv_put(msg, lv[0], lv+1);
else
msgb_tlv_put(msg, GSM48_IE_PROGR_IND, lv[0], lv+1);
return 0;
}
/* decode 'user-user' */
int gsm48_decode_useruser(struct gsm_mncc_useruser *uu,
const uint8_t *lv)
{
uint8_t in_len = lv[0];
char *info = uu->info;
int info_len = sizeof(uu->info);
int i;
if (in_len < 1)
return -EINVAL;
uu->proto = lv[1];
for (i = 2; i <= in_len; i++) {
info_len--;
if (info_len <= 1)
break;
*info++ = lv[i];
}
if (info_len >= 1)
*info++ = '\0';
return 0;
}
/* encode 'useruser' */
int gsm48_encode_useruser(struct msgb *msg, int lv_only,
const struct gsm_mncc_useruser *uu)
{
uint8_t lv[GSM_MAX_USERUSER + 2];
if (strlen(uu->info) > GSM_MAX_USERUSER)
return -EINVAL;
lv[0] = 1 + strlen(uu->info);
lv[1] = uu->proto;
memcpy(lv + 2, uu->info, strlen(uu->info));
if (lv_only)
msgb_lv_put(msg, lv[0], lv+1);
else
msgb_tlv_put(msg, GSM48_IE_USER_USER, lv[0], lv+1);
return 0;
}
/* decode 'ss version' */
int gsm48_decode_ssversion(struct gsm_mncc_ssversion *ssv,
const uint8_t *lv)
{
uint8_t in_len = lv[0];
if (in_len < 1 || in_len < sizeof(ssv->info))
return -EINVAL;
memcpy(ssv->info, lv + 1, in_len);
ssv->len = in_len;
return 0;
}
/* encode 'ss version' */
int gsm48_encode_ssversion(struct msgb *msg,
const struct gsm_mncc_ssversion *ssv)
{
uint8_t lv[GSM_MAX_SSVERSION + 1];
if (ssv->len > GSM_MAX_SSVERSION)
return -EINVAL;
lv[0] = ssv->len;
memcpy(lv + 1, ssv->info, ssv->len);
msgb_tlv_put(msg, GSM48_IE_SS_VERS, lv[0], lv+1);
return 0;
}
/* decode 'more data' does not require a function, because it has no value */
/* encode 'more data' */
int gsm48_encode_more(struct msgb *msg)
{
uint8_t *ie;
ie = msgb_put(msg, 1);
ie[0] = GSM48_IE_MORE_DATA;
return 0;
}

View File

@ -0,0 +1,393 @@
/*
* (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
//#include <openbsc/gsm_data.h>
#include <osmocore/utils.h>
#include <osmocore/gsm_utils.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include "../config.h"
/* GSM 03.38 6.2.1 Charachter packing */
int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t length)
{
int i = 0;
int l = 0;
/* FIXME: We need to account for user data headers here */
i += l;
for (; i < length; i ++)
*(text ++) =
((user_data[(i * 7 + 7) >> 3] <<
(7 - ((i * 7 + 7) & 7))) |
(user_data[(i * 7) >> 3] >>
((i * 7) & 7))) & 0x7f;
*text = '\0';
return i - l;
}
/* GSM 03.38 6.2.1 Charachter packing */
int gsm_7bit_encode(uint8_t *result, const char *data)
{
int i,j = 0;
unsigned char ch1, ch2;
int shift = 0;
for ( i=0; i<strlen(data); i++ ) {
ch1 = data[i] & 0x7F;
ch1 = ch1 >> shift;
ch2 = data[(i+1)] & 0x7F;
ch2 = ch2 << (7-shift);
ch1 = ch1 | ch2;
result[j++] = ch1;
shift++;
if ((shift == 7) && (i+1<strlen(data))) {
shift = 0;
i++;
}
}
return i;
}
/* determine power control level for given dBm value, as indicated
* by the tables in chapter 4.1.1 of GSM TS 05.05 */
int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
{
switch (band) {
case GSM_BAND_450:
case GSM_BAND_480:
case GSM_BAND_750:
case GSM_BAND_900:
case GSM_BAND_810:
case GSM_BAND_850:
if (dbm >= 39)
return 0;
else if (dbm < 5)
return 19;
else {
/* we are guaranteed to have (5 <= dbm < 39) */
return 2 + ((39 - dbm) / 2);
}
break;
case GSM_BAND_1800:
if (dbm >= 36)
return 29;
else if (dbm >= 34)
return 30;
else if (dbm >= 32)
return 31;
else if (dbm == 31)
return 0;
else {
/* we are guaranteed to have (0 <= dbm < 31) */
return (30 - dbm) / 2;
}
break;
case GSM_BAND_1900:
if (dbm >= 33)
return 30;
else if (dbm >= 32)
return 31;
else if (dbm == 31)
return 0;
else {
/* we are guaranteed to have (0 <= dbm < 31) */
return (30 - dbm) / 2;
}
break;
}
return -EINVAL;
}
int ms_pwr_dbm(enum gsm_band band, uint8_t lvl)
{
lvl &= 0x1f;
switch (band) {
case GSM_BAND_450:
case GSM_BAND_480:
case GSM_BAND_750:
case GSM_BAND_900:
case GSM_BAND_810:
case GSM_BAND_850:
if (lvl < 2)
return 39;
else if (lvl < 20)
return 39 - ((lvl - 2) * 2) ;
else
return 5;
break;
case GSM_BAND_1800:
if (lvl < 16)
return 30 - (lvl * 2);
else if (lvl < 29)
return 0;
else
return 36 - ((lvl - 29) * 2);
break;
case GSM_BAND_1900:
if (lvl < 16)
return 30 - (lvl * 2);
else if (lvl < 30)
return -EINVAL;
else
return 33 - (lvl - 30);
break;
}
return -EINVAL;
}
/* According to TS 08.05 Chapter 8.1.4 */
int rxlev2dbm(uint8_t rxlev)
{
if (rxlev > 63)
rxlev = 63;
return -110 + rxlev;
}
/* According to TS 08.05 Chapter 8.1.4 */
uint8_t dbm2rxlev(int dbm)
{
int rxlev = dbm + 110;
if (rxlev > 63)
rxlev = 63;
else if (rxlev < 0)
rxlev = 0;
return rxlev;
}
const char *gsm_band_name(enum gsm_band band)
{
switch (band) {
case GSM_BAND_450:
return "GSM450";
case GSM_BAND_480:
return "GSM480";
case GSM_BAND_750:
return "GSM750";
case GSM_BAND_810:
return "GSM810";
case GSM_BAND_850:
return "GSM850";
case GSM_BAND_900:
return "GSM900";
case GSM_BAND_1800:
return "DCS1800";
case GSM_BAND_1900:
return "PCS1900";
}
return "invalid";
}
enum gsm_band gsm_band_parse(const char* mhz)
{
while (*mhz && !isdigit(*mhz))
mhz++;
if (*mhz == '\0')
return -EINVAL;
switch (strtol(mhz, NULL, 10)) {
case 450:
return GSM_BAND_450;
case 480:
return GSM_BAND_480;
case 750:
return GSM_BAND_750;
case 810:
return GSM_BAND_810;
case 850:
return GSM_BAND_850;
case 900:
return GSM_BAND_900;
case 1800:
return GSM_BAND_1800;
case 1900:
return GSM_BAND_1900;
default:
return -EINVAL;
}
}
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
void generate_backtrace()
{
int i, nptrs;
void *buffer[100];
char **strings;
nptrs = backtrace(buffer, ARRAY_SIZE(buffer));
printf("backtrace() returned %d addresses\n", nptrs);
strings = backtrace_symbols(buffer, nptrs);
if (!strings)
return;
for (i = 1; i < nptrs; i++)
printf("%s\n", strings[i]);
free(strings);
}
#endif
enum gsm_band gsm_arfcn2band(uint16_t arfcn)
{
if (arfcn & ARFCN_PCS)
return GSM_BAND_1900;
else if (arfcn <= 124)
return GSM_BAND_900;
else if (arfcn >= 955 && arfcn <= 1023)
return GSM_BAND_900;
else if (arfcn >= 128 && arfcn <= 251)
return GSM_BAND_850;
else if (arfcn >= 512 && arfcn <= 885)
return GSM_BAND_1800;
else if (arfcn >= 259 && arfcn <= 293)
return GSM_BAND_450;
else if (arfcn >= 306 && arfcn <= 340)
return GSM_BAND_480;
else if (arfcn >= 350 && arfcn <= 425)
return GSM_BAND_810;
else if (arfcn >= 438 && arfcn <= 511)
return GSM_BAND_750;
else
return GSM_BAND_1800;
}
/* Convert an ARFCN to the frequency in MHz * 10 */
uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink)
{
uint16_t freq10_ul;
uint16_t freq10_dl;
if (arfcn & ARFCN_PCS) {
/* DCS 1900 */
arfcn &= ~ARFCN_PCS;
freq10_ul = 18502 + 2 * (arfcn-512);
freq10_dl = freq10_ul + 800;
} else if (arfcn <= 124) {
/* Primary GSM + ARFCN 0 of E-GSM */
freq10_ul = 8900 + 2 * arfcn;
freq10_dl = freq10_ul + 450;
} else if (arfcn >= 955 && arfcn <= 1023) {
/* E-GSM and R-GSM */
freq10_ul = 8900 + 2 * (arfcn - 1024);
freq10_dl = freq10_ul + 450;
} else if (arfcn >= 128 && arfcn <= 251) {
/* GSM 850 */
freq10_ul = 8242 + 2 * (arfcn - 128);
freq10_dl = freq10_ul + 450;
} else if (arfcn >= 512 && arfcn <= 885) {
/* DCS 1800 */
freq10_ul = 17102 + 2 * (arfcn - 512);
freq10_dl = freq10_ul + 950;
} else if (arfcn >= 259 && arfcn <= 293) {
/* GSM 450 */
freq10_ul = 4506 + 2 * (arfcn - 259);
freq10_dl = freq10_ul + 100;
} else if (arfcn >= 306 && arfcn <= 340) {
/* GSM 480 */
freq10_ul = 4790 + 2 * (arfcn - 306);
freq10_dl = freq10_ul + 100;
} else if (arfcn >= 350 && arfcn <= 425) {
/* GSM 810 */
freq10_ul = 8060 + 2 * (arfcn - 350);
freq10_dl = freq10_ul + 450;
} else if (arfcn >= 438 && arfcn <= 511) {
/* GSM 750 */
freq10_ul = 7472 + 2 * (arfcn - 438);
freq10_dl = freq10_ul + 300;
} else
return 0xffff;
if (uplink)
return freq10_ul;
else
return freq10_dl;
}
void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn)
{
time->fn = fn;
time->t1 = time->fn / (26*51);
time->t2 = time->fn % 26;
time->t3 = time->fn % 51;
time->tc = (time->fn / 51) % 8;
}
uint32_t gsm_gsmtime2fn(struct gsm_time *time)
{
/* TS 05.02 Chapter 4.3.3 TDMA frame number */
return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));
}
/* TS 03.03 Chapter 2.6 */
int gprs_tlli_type(uint32_t tlli)
{
if ((tlli & 0xc0000000) == 0xc0000000)
return TLLI_LOCAL;
else if ((tlli & 0xc0000000) == 0x80000000)
return TLLI_FOREIGN;
else if ((tlli & 0xf8000000) == 0x78000000)
return TLLI_RANDOM;
else if ((tlli & 0xf8000000) == 0x70000000)
return TLLI_AUXILIARY;
return TLLI_RESERVED;
}
uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type)
{
uint32_t tlli;
switch (type) {
case TLLI_LOCAL:
tlli = p_tmsi | 0xc0000000;
break;
case TLLI_FOREIGN:
tlli = (p_tmsi & 0x3fffffff) | 0x80000000;
break;
default:
tlli = 0;
break;
}
return tlli;
}

View File

@ -0,0 +1,200 @@
/* GSMTAP output for Osmocom Layer2 (will only work on the host PC) */
/*
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "../config.h"
#ifdef HAVE_SYS_SELECT_H
#include <osmocore/gsmtap_util.h>
#include <osmocore/logging.h>
#include <osmocore/protocol/gsm_04_08.h>
#include <osmocore/gsmtap.h>
#include <osmocore/msgb.h>
#include <osmocore/rsl.h>
#include <osmocore/select.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
static struct bsc_fd gsmtap_bfd = { .fd = -1 };
static LLIST_HEAD(gsmtap_txqueue);
uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t link_id)
{
uint8_t ret = GSMTAP_CHANNEL_UNKNOWN;
switch (rsl_chantype) {
case RSL_CHAN_Bm_ACCHs:
ret = GSMTAP_CHANNEL_TCH_F;
break;
case RSL_CHAN_Lm_ACCHs:
ret = GSMTAP_CHANNEL_TCH_H;
break;
case RSL_CHAN_SDCCH4_ACCH:
ret = GSMTAP_CHANNEL_SDCCH4;
break;
case RSL_CHAN_SDCCH8_ACCH:
ret = GSMTAP_CHANNEL_SDCCH8;
break;
case RSL_CHAN_BCCH:
ret = GSMTAP_CHANNEL_BCCH;
break;
case RSL_CHAN_RACH:
ret = GSMTAP_CHANNEL_RACH;
break;
case RSL_CHAN_PCH_AGCH:
/* it could also be AGCH... */
ret = GSMTAP_CHANNEL_PCH;
break;
}
if (link_id & 0x40)
ret |= GSMTAP_CHANNEL_ACCH;
return ret;
}
/* receive a message from L1/L2 and put it in GSMTAP */
struct msgb *gsmtap_makemsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type,
uint8_t ss, uint32_t fn, int8_t signal_dbm,
uint8_t snr, const uint8_t *data, unsigned int len)
{
struct msgb *msg;
struct gsmtap_hdr *gh;
uint8_t *dst;
msg = msgb_alloc(sizeof(*gh) + len, "gsmtap_tx");
if (!msg)
return NULL;
gh = (struct gsmtap_hdr *) msgb_put(msg, sizeof(*gh));
gh->version = GSMTAP_VERSION;
gh->hdr_len = sizeof(*gh)/4;
gh->type = GSMTAP_TYPE_UM;
gh->timeslot = ts;
gh->sub_slot = ss;
gh->arfcn = htons(arfcn);
gh->snr_db = snr;
gh->signal_dbm = signal_dbm;
gh->frame_number = htonl(fn);
gh->sub_type = chan_type;
gh->antenna_nr = 0;
dst = msgb_put(msg, len);
memcpy(dst, data, len);
return msg;
}
/* receive a message from L1/L2 and put it in GSMTAP */
int gsmtap_sendmsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type, uint8_t ss,
uint32_t fn, int8_t signal_dbm, uint8_t snr,
const uint8_t *data, unsigned int len)
{
struct msgb *msg;
/* gsmtap was never initialized, so don't try to send anything */
if (gsmtap_bfd.fd == -1)
return 0;
msg = gsmtap_makemsg(arfcn, ts, chan_type, ss, fn, signal_dbm,
snr, data, len);
if (!msg)
return -ENOMEM;
msgb_enqueue(&gsmtap_txqueue, msg);
gsmtap_bfd.when |= BSC_FD_WRITE;
return 0;
}
/* Callback from select layer if we can write to the socket */
static int gsmtap_fd_cb(struct bsc_fd *fd, unsigned int flags)
{
struct msgb *msg;
int rc;
if (!(flags & BSC_FD_WRITE))
return 0;
msg = msgb_dequeue(&gsmtap_txqueue);
if (!msg) {
/* no more messages in the queue, disable READ cb */
gsmtap_bfd.when = 0;
return 0;
}
rc = write(gsmtap_bfd.fd, msg->data, msg->len);
if (rc < 0) {
perror("writing msgb to gsmtap fd");
msgb_free(msg);
return rc;
}
if (rc != msg->len) {
perror("short write to gsmtap fd");
msgb_free(msg);
return -EIO;
}
msgb_free(msg);
return 0;
}
int gsmtap_init(uint32_t dst_ip)
{
int rc;
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(GSMTAP_UDP_PORT);
sin.sin_addr.s_addr = htonl(dst_ip);
/* FIXME: create socket */
rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (rc < 0) {
perror("creating UDP socket");
return rc;
}
gsmtap_bfd.fd = rc;
rc = connect(rc, (struct sockaddr *)&sin, sizeof(sin));
if (rc < 0) {
perror("connecting UDP socket");
close(gsmtap_bfd.fd);
gsmtap_bfd.fd = 0;
return rc;
}
gsmtap_bfd.when = BSC_FD_WRITE;
gsmtap_bfd.cb = gsmtap_fd_cb;
gsmtap_bfd.data = NULL;
return bsc_register_fd(&gsmtap_bfd);
}
#endif /* HAVE_SYS_SELECT_H */

View File

@ -0,0 +1,419 @@
/* Debugging/Logging support code */
/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "../config.h"
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include <time.h>
#include <errno.h>
#include <osmocore/talloc.h>
#include <osmocore/utils.h>
#include <osmocore/logging.h>
const struct log_info *osmo_log_info;
static struct log_context log_context;
static void *tall_log_ctx = NULL;
static LLIST_HEAD(target_list);
static const struct value_string loglevel_strs[] = {
{ 0, "EVERYTHING" },
{ LOGL_DEBUG, "DEBUG" },
{ LOGL_INFO, "INFO" },
{ LOGL_NOTICE, "NOTICE" },
{ LOGL_ERROR, "ERROR" },
{ LOGL_FATAL, "FATAL" },
{ 0, NULL },
};
int log_parse_level(const char *lvl)
{
return get_string_value(loglevel_strs, lvl);
}
const char *log_level_str(unsigned int lvl)
{
return get_value_string(loglevel_strs, lvl);
}
int log_parse_category(const char *category)
{
int i;
for (i = 0; i < osmo_log_info->num_cat; ++i) {
if (!strcasecmp(osmo_log_info->cat[i].name+1, category))
return i;
}
return -EINVAL;
}
/*
* Parse the category mask.
* The format can be this: category1:category2:category3
* or category1,2:category2,3:...
*/
void log_parse_category_mask(struct log_target* target, const char *_mask)
{
int i = 0;
char *mask = strdup(_mask);
char *category_token = NULL;
/* Disable everything to enable it afterwards */
for (i = 0; i < ARRAY_SIZE(target->categories); ++i)
target->categories[i].enabled = 0;
category_token = strtok(mask, ":");
do {
for (i = 0; i < osmo_log_info->num_cat; ++i) {
char* colon = strstr(category_token, ",");
int length = strlen(category_token);
if (colon)
length = colon - category_token;
if (strncasecmp(osmo_log_info->cat[i].name,
category_token, length) == 0) {
int level = 0;
if (colon)
level = atoi(colon+1);
target->categories[i].enabled = 1;
target->categories[i].loglevel = level;
}
}
} while ((category_token = strtok(NULL, ":")));
free(mask);
}
static const char* color(int subsys)
{
if (subsys < osmo_log_info->num_cat)
return osmo_log_info->cat[subsys].color;
return NULL;
}
static void _output(struct log_target *target, unsigned int subsys,
char *file, int line, int cont, const char *format,
va_list ap)
{
char col[30];
char sub[30];
char tim[30];
char buf[4096];
char final[4096];
/* prepare the data */
col[0] = '\0';
sub[0] = '\0';
tim[0] = '\0';
buf[0] = '\0';
/* are we using color */
if (target->use_color) {
const char *c = color(subsys);
if (c) {
snprintf(col, sizeof(col), "%s", color(subsys));
col[sizeof(col)-1] = '\0';
}
}
vsnprintf(buf, sizeof(buf), format, ap);
buf[sizeof(buf)-1] = '\0';
if (!cont) {
if (target->print_timestamp) {
char *timestr;
time_t tm;
tm = time(NULL);
timestr = ctime(&tm);
timestr[strlen(timestr)-1] = '\0';
snprintf(tim, sizeof(tim), "%s ", timestr);
tim[sizeof(tim)-1] = '\0';
}
snprintf(sub, sizeof(sub), "<%4.4x> %s:%d ", subsys, file, line);
sub[sizeof(sub)-1] = '\0';
}
snprintf(final, sizeof(final), "%s%s%s%s\033[0;m", col, tim, sub, buf);
final[sizeof(final)-1] = '\0';
target->output(target, final);
}
static void _logp(unsigned int subsys, int level, char *file, int line,
int cont, const char *format, va_list ap)
{
struct log_target *tar;
llist_for_each_entry(tar, &target_list, entry) {
struct log_category *category;
int output = 0;
category = &tar->categories[subsys];
/* subsystem is not supposed to be logged */
if (!category->enabled)
continue;
/* Check the global log level */
if (tar->loglevel != 0 && level < tar->loglevel)
continue;
/* Check the category log level */
if (tar->loglevel == 0 && category->loglevel != 0 &&
level < category->loglevel)
continue;
/* Apply filters here... if that becomes messy we will
* need to put filters in a list and each filter will
* say stop, continue, output */
if ((tar->filter_map & LOG_FILTER_ALL) != 0)
output = 1;
else if (osmo_log_info->filter_fn)
output = osmo_log_info->filter_fn(&log_context,
tar);
if (output) {
/* FIXME: copying the va_list is an ugly
* workaround against a bug hidden somewhere in
* _output. If we do not copy here, the first
* call to _output() will corrupt the va_list
* contents, and any further _output() calls
* with the same va_list will segfault */
va_list bp;
va_copy(bp, ap);
_output(tar, subsys, file, line, cont, format, bp);
va_end(bp);
}
}
}
void logp(unsigned int subsys, char *file, int line, int cont,
const char *format, ...)
{
va_list ap;
va_start(ap, format);
_logp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
va_end(ap);
}
void logp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
{
va_list ap;
va_start(ap, format);
_logp(subsys, level, file, line, cont, format, ap);
va_end(ap);
}
static char hexd_buff[4096];
char *hexdump(const unsigned char *buf, int len)
{
int i;
char *cur = hexd_buff;
hexd_buff[0] = 0;
for (i = 0; i < len; i++) {
int len_remain = sizeof(hexd_buff) - (cur - hexd_buff);
int rc = snprintf(cur, len_remain, "%02x ", buf[i]);
if (rc <= 0)
break;
cur += rc;
}
hexd_buff[sizeof(hexd_buff)-1] = 0;
return hexd_buff;
}
void log_add_target(struct log_target *target)
{
llist_add_tail(&target->entry, &target_list);
}
void log_del_target(struct log_target *target)
{
llist_del(&target->entry);
}
void log_reset_context(void)
{
memset(&log_context, 0, sizeof(log_context));
}
int log_set_context(uint8_t ctx_nr, void *value)
{
if (ctx_nr > LOG_MAX_CTX)
return -EINVAL;
log_context.ctx[ctx_nr] = value;
return 0;
}
void log_set_all_filter(struct log_target *target, int all)
{
if (all)
target->filter_map |= LOG_FILTER_ALL;
else
target->filter_map &= ~LOG_FILTER_ALL;
}
void log_set_use_color(struct log_target *target, int use_color)
{
target->use_color = use_color;
}
void log_set_print_timestamp(struct log_target *target, int print_timestamp)
{
target->print_timestamp = print_timestamp;
}
void log_set_log_level(struct log_target *target, int log_level)
{
target->loglevel = log_level;
}
void log_set_category_filter(struct log_target *target, int category,
int enable, int level)
{
if (category >= osmo_log_info->num_cat)
return;
target->categories[category].enabled = !!enable;
target->categories[category].loglevel = level;
}
/* since C89/C99 says stderr is a macro, we can safely do this! */
#ifdef stderr
static void _stderr_output(struct log_target *target, const char *log)
{
fprintf(target->tgt_stdout.out, "%s", log);
fflush(target->tgt_stdout.out);
}
#endif
struct log_target *log_target_create(void)
{
struct log_target *target;
unsigned int i;
target = talloc_zero(tall_log_ctx, struct log_target);
if (!target)
return NULL;
INIT_LLIST_HEAD(&target->entry);
/* initialize the per-category enabled/loglevel from defaults */
for (i = 0; i < osmo_log_info->num_cat; i++) {
struct log_category *cat = &target->categories[i];
cat->enabled = osmo_log_info->cat[i].enabled;
cat->loglevel = osmo_log_info->cat[i].loglevel;
}
/* global settings */
target->use_color = 1;
target->print_timestamp = 0;
/* global log level */
target->loglevel = 0;
return target;
}
struct log_target *log_target_create_stderr(void)
{
/* since C89/C99 says stderr is a macro, we can safely do this! */
#ifdef stderr
struct log_target *target;
target = log_target_create();
if (!target)
return NULL;
target->tgt_stdout.out = stderr;
target->output = _stderr_output;
return target;
#else
return NULL;
#endif /* stderr */
}
const char *log_vty_level_string(struct log_info *info)
{
const struct value_string *vs;
unsigned int len = 3; /* ()\0 */
char *str;
for (vs = loglevel_strs; vs->value || vs->str; vs++)
len += strlen(vs->str) + 1;
str = talloc_zero_size(NULL, len);
if (!str)
return NULL;
str[0] = '(';
for (vs = loglevel_strs; vs->value || vs->str; vs++) {
strcat(str, vs->str);
strcat(str, "|");
}
str[strlen(str)-1] = ')';
return str;
}
const char *log_vty_category_string(struct log_info *info)
{
unsigned int len = 3; /* "()\0" */
unsigned int i;
char *str;
for (i = 0; i < info->num_cat; i++)
len += strlen(info->cat[i].name) + 1;
str = talloc_zero_size(NULL, len);
if (!str)
return NULL;
str[0] = '(';
for (i = 0; i < info->num_cat; i++) {
strcat(str, info->cat[i].name+1);
strcat(str, "|");
}
str[strlen(str)-1] = ')';
return str;
}
void log_init(const struct log_info *cat)
{
tall_log_ctx = talloc_named_const(NULL, 1, "logging");
osmo_log_info = cat;
}

View File

@ -0,0 +1,90 @@
/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <osmocore/msgb.h>
//#include <openbsc/gsm_data.h>
#include <osmocore/talloc.h>
//#include <openbsc/debug.h>
void *tall_msgb_ctx;
struct msgb *msgb_alloc(uint16_t size, const char *name)
{
struct msgb *msg;
msg = _talloc_zero(tall_msgb_ctx, sizeof(*msg) + size, name);
if (!msg) {
//LOGP(DRSL, LOGL_FATAL, "unable to allocate msgb\n");
return NULL;
}
msg->data_len = size;
msg->len = 0;
msg->data = msg->_data;
msg->head = msg->_data;
msg->tail = msg->_data;
return msg;
}
void msgb_free(struct msgb *m)
{
talloc_free(m);
}
void msgb_enqueue(struct llist_head *queue, struct msgb *msg)
{
llist_add_tail(&msg->list, queue);
}
struct msgb *msgb_dequeue(struct llist_head *queue)
{
struct llist_head *lh;
if (llist_empty(queue))
return NULL;
lh = queue->next;
llist_del(lh);
return llist_entry(lh, struct msgb, list);
}
void msgb_reset(struct msgb *msg)
{
msg->len = 0;
msg->data = msg->_data;
msg->head = msg->_data;
msg->tail = msg->_data;
msg->trx = NULL;
msg->lchan = NULL;
msg->l2h = NULL;
msg->l3h = NULL;
msg->l4h = NULL;
memset(&msg->cb, 0, sizeof(msg->cb));
}

View File

@ -0,0 +1,62 @@
/* plugin infrastructure */
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "../config.h"
#if HAVE_DLFCN_H
#include <sys/types.h>
#include <dirent.h>
#include <dlfcn.h>
#include <stdio.h>
#include <errno.h>
#include <osmocore/plugin.h>
int plugin_load_all(const char *directory)
{
unsigned int num = 0;
char fname[PATH_MAX];
DIR *dir;
struct dirent *entry;
dir = opendir(directory);
if (!dir)
return -errno;
while ((entry = readdir(dir))) {
snprintf(fname, sizeof(fname), "%s/%s", directory,
entry->d_name);
if (dlopen(fname, RTLD_NOW))
num++;
}
closedir(dir);
return num;
}
#else
int plugin_load_all(const char *directory)
{
return 0;
}
#endif /* HAVE_DLFCN_H */

View File

@ -0,0 +1,128 @@
/* utility routines for keeping conters about events and the event rates */
/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <osmocore/utils.h>
#include <osmocore/linuxlist.h>
#include <osmocore/talloc.h>
#include <osmocore/timer.h>
#include <osmocore/rate_ctr.h>
static LLIST_HEAD(rate_ctr_groups);
static void *tall_rate_ctr_ctx;
struct rate_ctr_group *rate_ctr_group_alloc(void *ctx,
const struct rate_ctr_group_desc *desc,
unsigned int idx)
{
unsigned int size;
struct rate_ctr_group *group;
size = sizeof(struct rate_ctr_group) +
desc->num_ctr * sizeof(struct rate_ctr);
if (!ctx)
ctx = tall_rate_ctr_ctx;
group = talloc_zero_size(ctx, size);
if (!group)
return NULL;
group->desc = desc;
group->idx = idx;
llist_add(&group->list, &rate_ctr_groups);
return group;
}
void rate_ctr_group_free(struct rate_ctr_group *grp)
{
llist_del(&grp->list);
talloc_free(grp);
}
void rate_ctr_add(struct rate_ctr *ctr, int inc)
{
ctr->current += inc;
}
static void interval_expired(struct rate_ctr *ctr, enum rate_ctr_intv intv)
{
/* calculate rate over last interval */
ctr->intv[intv].rate = ctr->current - ctr->intv[intv].last;
/* save current counter for next interval */
ctr->intv[intv].last = ctr->current;
/* update the rate of the next bigger interval. This will
* be overwritten when that next larger interval expires */
if (intv + 1 < ARRAY_SIZE(ctr->intv))
ctr->intv[intv+1].rate += ctr->intv[intv].rate;
}
static struct timer_list rate_ctr_timer;
static uint64_t timer_ticks;
/* The one-second interval has expired */
static void rate_ctr_group_intv(struct rate_ctr_group *grp)
{
unsigned int i;
for (i = 0; i < grp->desc->num_ctr; i++) {
struct rate_ctr *ctr = &grp->ctr[i];
interval_expired(ctr, RATE_CTR_INTV_SEC);
if ((timer_ticks % 60) == 0)
interval_expired(ctr, RATE_CTR_INTV_MIN);
if ((timer_ticks % (60*60)) == 0)
interval_expired(ctr, RATE_CTR_INTV_HOUR);
if ((timer_ticks % (24*60*60)) == 0)
interval_expired(ctr, RATE_CTR_INTV_DAY);
}
}
static void rate_ctr_timer_cb(void *data)
{
struct rate_ctr_group *ctrg;
/* Increment number of ticks before we calculate intervals,
* as a counter value of 0 would already wrap all counters */
timer_ticks++;
llist_for_each_entry(ctrg, &rate_ctr_groups, list)
rate_ctr_group_intv(ctrg);
bsc_schedule_timer(&rate_ctr_timer, 1, 0);
}
int rate_ctr_init(void *tall_ctx)
{
tall_rate_ctr_ctx = tall_ctx;
rate_ctr_timer.cb = rate_ctr_timer_cb;
bsc_schedule_timer(&rate_ctr_timer, 1, 0);
return 0;
}

View File

@ -0,0 +1,329 @@
/* GSM Radio Signalling Link messages on the A-bis interface
* 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */
/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdint.h>
#include <errno.h>
#include <osmocore/tlv.h>
#include <osmocore/rsl.h>
#define RSL_ALLOC_SIZE 200
#define RSL_ALLOC_HEADROOM 56
void rsl_init_rll_hdr(struct abis_rsl_rll_hdr *dh, uint8_t msg_type)
{
dh->c.msg_discr = ABIS_RSL_MDISC_RLL;
dh->c.msg_type = msg_type;
dh->ie_chan = RSL_IE_CHAN_NR;
dh->ie_link_id = RSL_IE_LINK_IDENT;
}
const struct tlv_definition rsl_att_tlvdef = {
.def = {
[RSL_IE_CHAN_NR] = { TLV_TYPE_TV },
[RSL_IE_LINK_IDENT] = { TLV_TYPE_TV },
[RSL_IE_ACT_TYPE] = { TLV_TYPE_TV },
[RSL_IE_BS_POWER] = { TLV_TYPE_TV },
[RSL_IE_CHAN_IDENT] = { TLV_TYPE_TLV },
[RSL_IE_CHAN_MODE] = { TLV_TYPE_TLV },
[RSL_IE_ENCR_INFO] = { TLV_TYPE_TLV },
[RSL_IE_FRAME_NUMBER] = { TLV_TYPE_FIXED, 2 },
[RSL_IE_HANDO_REF] = { TLV_TYPE_TV },
[RSL_IE_L1_INFO] = { TLV_TYPE_FIXED, 2 },
[RSL_IE_L3_INFO] = { TLV_TYPE_TL16V },
[RSL_IE_MS_IDENTITY] = { TLV_TYPE_TLV },
[RSL_IE_MS_POWER] = { TLV_TYPE_TV },
[RSL_IE_PAGING_GROUP] = { TLV_TYPE_TV },
[RSL_IE_PAGING_LOAD] = { TLV_TYPE_FIXED, 2 },
[RSL_IE_PYHS_CONTEXT] = { TLV_TYPE_TLV },
[RSL_IE_ACCESS_DELAY] = { TLV_TYPE_TV },
[RSL_IE_RACH_LOAD] = { TLV_TYPE_TLV },
[RSL_IE_REQ_REFERENCE] = { TLV_TYPE_FIXED, 3 },
[RSL_IE_RELEASE_MODE] = { TLV_TYPE_TV },
[RSL_IE_RESOURCE_INFO] = { TLV_TYPE_TLV },
[RSL_IE_RLM_CAUSE] = { TLV_TYPE_TLV },
[RSL_IE_STARTNG_TIME] = { TLV_TYPE_FIXED, 2 },
[RSL_IE_TIMING_ADVANCE] = { TLV_TYPE_TV },
[RSL_IE_UPLINK_MEAS] = { TLV_TYPE_TLV },
[RSL_IE_CAUSE] = { TLV_TYPE_TLV },
[RSL_IE_MEAS_RES_NR] = { TLV_TYPE_TV },
[RSL_IE_MSG_ID] = { TLV_TYPE_TV },
[RSL_IE_SYSINFO_TYPE] = { TLV_TYPE_TV },
[RSL_IE_MS_POWER_PARAM] = { TLV_TYPE_TLV },
[RSL_IE_BS_POWER_PARAM] = { TLV_TYPE_TLV },
[RSL_IE_PREPROC_PARAM] = { TLV_TYPE_TLV },
[RSL_IE_PREPROC_MEAS] = { TLV_TYPE_TLV },
[RSL_IE_IMM_ASS_INFO] = { TLV_TYPE_TLV },
[RSL_IE_SMSCB_INFO] = { TLV_TYPE_FIXED, 23 },
[RSL_IE_MS_TIMING_OFFSET] = { TLV_TYPE_TV },
[RSL_IE_ERR_MSG] = { TLV_TYPE_TLV },
[RSL_IE_FULL_BCCH_INFO] = { TLV_TYPE_TLV },
[RSL_IE_CHAN_NEEDED] = { TLV_TYPE_TV },
[RSL_IE_CB_CMD_TYPE] = { TLV_TYPE_TV },
[RSL_IE_SMSCB_MSG] = { TLV_TYPE_TLV },
[RSL_IE_FULL_IMM_ASS_INFO] = { TLV_TYPE_TLV },
[RSL_IE_SACCH_INFO] = { TLV_TYPE_TLV },
[RSL_IE_CBCH_LOAD_INFO] = { TLV_TYPE_TV },
[RSL_IE_SMSCB_CHAN_INDICATOR] = { TLV_TYPE_TV },
[RSL_IE_GROUP_CALL_REF] = { TLV_TYPE_TLV },
[RSL_IE_CHAN_DESC] = { TLV_TYPE_TLV },
[RSL_IE_NCH_DRX_INFO] = { TLV_TYPE_TLV },
[RSL_IE_CMD_INDICATOR] = { TLV_TYPE_TLV },
[RSL_IE_EMLPP_PRIO] = { TLV_TYPE_TV },
[RSL_IE_UIC] = { TLV_TYPE_TLV },
[RSL_IE_MAIN_CHAN_REF] = { TLV_TYPE_TV },
[RSL_IE_MR_CONFIG] = { TLV_TYPE_TLV },
[RSL_IE_MR_CONTROL] = { TLV_TYPE_TV },
[RSL_IE_SUP_CODEC_TYPES] = { TLV_TYPE_TLV },
[RSL_IE_CODEC_CONFIG] = { TLV_TYPE_TLV },
[RSL_IE_RTD] = { TLV_TYPE_TV },
[RSL_IE_TFO_STATUS] = { TLV_TYPE_TV },
[RSL_IE_LLP_APDU] = { TLV_TYPE_TLV },
[RSL_IE_SIEMENS_MRPCI] = { TLV_TYPE_TV },
[RSL_IE_IPAC_PROXY_UDP] = { TLV_TYPE_FIXED, 2 },
[RSL_IE_IPAC_BSCMPL_TOUT] = { TLV_TYPE_TV },
[RSL_IE_IPAC_REMOTE_IP] = { TLV_TYPE_FIXED, 4 },
[RSL_IE_IPAC_REMOTE_PORT] = { TLV_TYPE_FIXED, 2 },
[RSL_IE_IPAC_RTP_PAYLOAD] = { TLV_TYPE_TV },
[RSL_IE_IPAC_LOCAL_PORT] = { TLV_TYPE_FIXED, 2 },
[RSL_IE_IPAC_SPEECH_MODE] = { TLV_TYPE_TV },
[RSL_IE_IPAC_LOCAL_IP] = { TLV_TYPE_FIXED, 4 },
[RSL_IE_IPAC_CONN_ID] = { TLV_TYPE_FIXED, 2 },
[RSL_IE_IPAC_RTP_CSD_FMT] = { TLV_TYPE_TV },
[RSL_IE_IPAC_RTP_JIT_BUF] = { TLV_TYPE_FIXED, 2 },
[RSL_IE_IPAC_RTP_COMPR] = { TLV_TYPE_TV },
[RSL_IE_IPAC_RTP_PAYLOAD2] = { TLV_TYPE_TV },
[RSL_IE_IPAC_RTP_MPLEX] = { TLV_TYPE_FIXED, 8 },
[RSL_IE_IPAC_RTP_MPLEX_ID] = { TLV_TYPE_TV },
},
};
/* encode channel number as per Section 9.3.1 */
uint8_t rsl_enc_chan_nr(uint8_t type, uint8_t subch, uint8_t timeslot)
{
uint8_t ret;
ret = (timeslot & 0x07) | type;
switch (type) {
case RSL_CHAN_Lm_ACCHs:
subch &= 0x01;
break;
case RSL_CHAN_SDCCH4_ACCH:
subch &= 0x03;
break;
case RSL_CHAN_SDCCH8_ACCH:
subch &= 0x07;
break;
default:
/* no subchannels allowed */
subch = 0x00;
break;
}
ret |= (subch << 3);
return ret;
}
int rsl_dec_chan_nr(uint8_t chan_nr, uint8_t *type, uint8_t *subch, uint8_t *timeslot)
{
*timeslot = chan_nr & 0x7;
if ((chan_nr & 0xf8) == RSL_CHAN_Bm_ACCHs) {
*type = RSL_CHAN_Bm_ACCHs;
*subch = 0;
} else if ((chan_nr & 0xf0) == RSL_CHAN_Lm_ACCHs) {
*type = RSL_CHAN_Lm_ACCHs;
*subch = (chan_nr >> 3) & 0x1;
} else if ((chan_nr & 0xe0) == RSL_CHAN_SDCCH4_ACCH) {
*type = RSL_CHAN_SDCCH4_ACCH;
*subch = (chan_nr >> 3) & 0x3;
} else if ((chan_nr & 0xc0) == RSL_CHAN_SDCCH8_ACCH) {
*type = RSL_CHAN_SDCCH8_ACCH;
*subch = (chan_nr >> 3) & 0x7;
} else if ((chan_nr & 0xf8) == RSL_CHAN_BCCH) {
*type = RSL_CHAN_BCCH;
*subch = 0;
} else if ((chan_nr & 0xf8) == RSL_CHAN_RACH) {
*type = RSL_CHAN_RACH;
*subch = 0;
} else if ((chan_nr & 0xf8) == RSL_CHAN_PCH_AGCH) {
*type = RSL_CHAN_PCH_AGCH;
*subch = 0;
} else
return -EINVAL;
return 0;
}
static const struct value_string rsl_err_vals[] = {
{ RSL_ERR_RADIO_IF_FAIL, "Radio Interface Failure" },
{ RSL_ERR_RADIO_LINK_FAIL, "Radio Link Failure" },
{ RSL_ERR_HANDOVER_ACC_FAIL, "Handover Access Failure" },
{ RSL_ERR_TALKER_ACC_FAIL, "Talker Access Failure" },
{ RSL_ERR_OM_INTERVENTION, "O&M Intervention" },
{ RSL_ERR_NORMAL_UNSPEC, "Normal event, unspecified" },
{ RSL_ERR_T_MSRFPCI_EXP, "Siemens: T_MSRFPCI Expired" },
{ RSL_ERR_EQUIPMENT_FAIL, "Equipment Failure" },
{ RSL_ERR_RR_UNAVAIL, "Radio Resource not available" },
{ RSL_ERR_TERR_CH_FAIL, "Terrestrial Channel Failure" },
{ RSL_ERR_CCCH_OVERLOAD, "CCCH Overload" },
{ RSL_ERR_ACCH_OVERLOAD, "ACCH Overload" },
{ RSL_ERR_PROCESSOR_OVERLOAD, "Processor Overload" },
{ RSL_ERR_RES_UNAVAIL, "Resource not available, unspecified" },
{ RSL_ERR_TRANSC_UNAVAIL, "Transcoding not available" },
{ RSL_ERR_SERV_OPT_UNAVAIL, "Service or Option not available" },
{ RSL_ERR_ENCR_UNIMPL, "Encryption algorithm not implemented" },
{ RSL_ERR_SERV_OPT_UNIMPL, "Service or Option not implemented" },
{ RSL_ERR_RCH_ALR_ACTV_ALLOC, "Radio channel already activated" },
{ RSL_ERR_INVALID_MESSAGE, "Invalid Message, unspecified" },
{ RSL_ERR_MSG_DISCR, "Message Discriminator Error" },
{ RSL_ERR_MSG_TYPE, "Message Type Error" },
{ RSL_ERR_MSG_SEQ, "Message Sequence Error" },
{ RSL_ERR_IE_ERROR, "General IE error" },
{ RSL_ERR_MAND_IE_ERROR, "Mandatory IE error" },
{ RSL_ERR_OPT_IE_ERROR, "Optional IE error" },
{ RSL_ERR_IE_NONEXIST, "IE non-existent" },
{ RSL_ERR_IE_LENGTH, "IE length error" },
{ RSL_ERR_IE_CONTENT, "IE content error" },
{ RSL_ERR_PROTO, "Protocol error, unspecified" },
{ RSL_ERR_INTERWORKING, "Interworking error, unspecified" },
{ 0, NULL }
};
const char *rsl_err_name(uint8_t err)
{
return get_value_string(rsl_err_vals, err);
}
static const struct value_string rsl_rlm_cause_strs[] = {
{ RLL_CAUSE_T200_EXPIRED, "Timer T200 expired (N200+1) times" },
{ RLL_CAUSE_REEST_REQ, "Re-establishment request" },
{ RLL_CAUSE_UNSOL_UA_RESP, "Unsolicited UA response" },
{ RLL_CAUSE_UNSOL_DM_RESP, "Unsolicited DM response" },
{ RLL_CAUSE_UNSOL_DM_RESP_MF, "Unsolicited DM response, multiple frame" },
{ RLL_CAUSE_UNSOL_SPRV_RESP, "Unsolicited supervisory response" },
{ RLL_CAUSE_SEQ_ERR, "Sequence Error" },
{ RLL_CAUSE_UFRM_INC_PARAM, "U-Frame with incorrect parameters" },
{ RLL_CAUSE_SFRM_INC_PARAM, "S-Frame with incorrect parameters" },
{ RLL_CAUSE_IFRM_INC_MBITS, "I-Frame with incorrect use of M bit" },
{ RLL_CAUSE_IFRM_INC_LEN, "I-Frame with incorrect length" },
{ RLL_CAUSE_FRM_UNIMPL, "Fraeme not implemented" },
{ RLL_CAUSE_SABM_MF, "SABM command, multiple frame established state" },
{ RLL_CAUSE_SABM_INFO_NOTALL, "SABM frame with information not allowed in this state" },
{ 0, NULL },
};
const char *rsl_rlm_cause_name(uint8_t err)
{
return get_value_string(rsl_rlm_cause_strs, err);
}
/* Section 3.3.2.3 TS 05.02. I think this looks like a table */
int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf)
{
switch (ccch_conf) {
case RSL_BCCH_CCCH_CONF_1_NC:
return 1;
case RSL_BCCH_CCCH_CONF_1_C:
return 1;
case RSL_BCCH_CCCH_CONF_2_NC:
return 2;
case RSL_BCCH_CCCH_CONF_3_NC:
return 3;
case RSL_BCCH_CCCH_CONF_4_NC:
return 4;
default:
return -1;
}
}
/* Section 3.3.2.3 TS 05.02 */
int rsl_ccch_conf_to_bs_ccch_sdcch_comb(int ccch_conf)
{
switch (ccch_conf) {
case RSL_BCCH_CCCH_CONF_1_NC:
return 0;
case RSL_BCCH_CCCH_CONF_1_C:
return 1;
case RSL_BCCH_CCCH_CONF_2_NC:
return 0;
case RSL_BCCH_CCCH_CONF_3_NC:
return 0;
case RSL_BCCH_CCCH_CONF_4_NC:
return 0;
default:
return -1;
}
}
/* Push a RSL RLL header with L3_INFO IE */
void rsl_rll_push_l3(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr,
uint8_t link_id, int transparent)
{
uint8_t l3_len = msg->tail - (uint8_t *)msgb_l3(msg);
struct abis_rsl_rll_hdr *rh;
/* construct a RSLms RLL message (DATA INDICATION, UNIT DATA
* INDICATION) and send it off via RSLms */
/* Push the L3 IE tag and lengh */
msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len);
/* Then push the RSL header */
rh = (struct abis_rsl_rll_hdr *) msgb_push(msg, sizeof(*rh));
rsl_init_rll_hdr(rh, msg_type);
if (transparent)
rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP;
rh->chan_nr = chan_nr;
rh->link_id = link_id;
/* set the l2 header pointer */
msg->l2h = (uint8_t *)rh;
}
struct msgb *rsl_rll_simple(uint8_t msg_type, uint8_t chan_nr,
uint8_t link_id, int transparent)
{
struct abis_rsl_rll_hdr *rh;
struct msgb *msg;
msg = msgb_alloc_headroom(RSL_ALLOC_SIZE+RSL_ALLOC_HEADROOM,
RSL_ALLOC_HEADROOM, "rsl_rll_simple");
if (!msg)
return NULL;
/* put the RSL header */
rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh));
rsl_init_rll_hdr(rh, msg_type);
if (transparent)
rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP;
rh->chan_nr = chan_nr;
rh->link_id = link_id;
/* set the l2 header pointer */
msg->l2h = (uint8_t *)rh;
return msg;
}

View File

@ -0,0 +1,94 @@
/* Rx Level statistics */
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <osmocore/bitvec.h>
#include <osmocore/rxlev_stat.h>
int bitvec_find_bit_pos(const struct bitvec *bv, unsigned int n, enum bit_value val)
{
unsigned int i;
for (i = n; i < bv->data_len*8; i++) {
if (bitvec_get_bit_pos(bv, i) == val)
return i;
}
return -1;
}
void rxlev_stat_input(struct rxlev_stats *st, uint16_t arfcn, uint8_t rxlev)
{
struct bitvec bv;
if (rxlev >= NUM_RXLEVS)
rxlev = NUM_RXLEVS-1;
bv.data_len = NUM_ARFCNS/8;
bv.data = st->rxlev_buckets[rxlev];
bitvec_set_bit_pos(&bv, arfcn, ONE);
}
/* get the next ARFCN that has the specified Rxlev */
int16_t rxlev_stat_get_next(const struct rxlev_stats *st, uint8_t rxlev, int16_t arfcn)
{
struct bitvec bv;
if (rxlev >= NUM_RXLEVS)
rxlev = NUM_RXLEVS-1;
bv.data_len = NUM_ARFCNS/8;
if (arfcn < 0)
arfcn = -1;
bv.data = st->rxlev_buckets[rxlev];
return bitvec_find_bit_pos(&bv, arfcn+1, ONE);
}
void rxlev_stat_reset(struct rxlev_stats *st)
{
memset(st, 0, sizeof(*st));
}
void rxlev_stat_dump(const struct rxlev_stats *st)
{
int i;
for (i = NUM_RXLEVS-1; i >= 0; i--) {
int16_t arfcn = -1;
printf("ARFCN with RxLev %u: ", i);
while ((arfcn = rxlev_stat_get_next(st, i, arfcn)) >= 0) {
printf("%u ", arfcn);
}
printf("\n");
}
}

View File

@ -0,0 +1,131 @@
/* select filedescriptor handling, taken from:
* userspace logging daemon for the iptables ULOG target
* of the linux 2.4 netfilter subsystem.
*
* (C) 2000-2009 by Harald Welte <laforge@gnumonks.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <fcntl.h>
#include <osmocore/select.h>
#include <osmocore/linuxlist.h>
#include <osmocore/timer.h>
#include "../config.h"
#ifdef HAVE_SYS_SELECT_H
static int maxfd = 0;
static LLIST_HEAD(bsc_fds);
static int unregistered_count;
int bsc_register_fd(struct bsc_fd *fd)
{
int flags;
/* make FD nonblocking */
flags = fcntl(fd->fd, F_GETFL);
if (flags < 0)
return flags;
flags |= O_NONBLOCK;
flags = fcntl(fd->fd, F_SETFL, flags);
if (flags < 0)
return flags;
/* Register FD */
if (fd->fd > maxfd)
maxfd = fd->fd;
llist_add_tail(&fd->list, &bsc_fds);
return 0;
}
void bsc_unregister_fd(struct bsc_fd *fd)
{
unregistered_count++;
llist_del(&fd->list);
}
int bsc_select_main(int polling)
{
struct bsc_fd *ufd, *tmp;
fd_set readset, writeset, exceptset;
int work = 0, rc;
struct timeval no_time = {0, 0};
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_ZERO(&exceptset);
/* prepare read and write fdsets */
llist_for_each_entry(ufd, &bsc_fds, list) {
if (ufd->when & BSC_FD_READ)
FD_SET(ufd->fd, &readset);
if (ufd->when & BSC_FD_WRITE)
FD_SET(ufd->fd, &writeset);
if (ufd->when & BSC_FD_EXCEPT)
FD_SET(ufd->fd, &exceptset);
}
bsc_timer_check();
if (!polling)
bsc_prepare_timers();
rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : bsc_nearest_timer());
if (rc < 0)
return 0;
/* fire timers */
bsc_update_timers();
/* call registered callback functions */
restart:
unregistered_count = 0;
llist_for_each_entry_safe(ufd, tmp, &bsc_fds, list) {
int flags = 0;
if (FD_ISSET(ufd->fd, &readset)) {
flags |= BSC_FD_READ;
FD_CLR(ufd->fd, &readset);
}
if (FD_ISSET(ufd->fd, &writeset)) {
flags |= BSC_FD_WRITE;
FD_CLR(ufd->fd, &writeset);
}
if (FD_ISSET(ufd->fd, &exceptset)) {
flags |= BSC_FD_EXCEPT;
FD_CLR(ufd->fd, &exceptset);
}
if (flags) {
work = 1;
ufd->cb(ufd, flags);
}
/* ugly, ugly hack. If more than one filedescriptors were
* unregistered, they might have been consecutive and
* llist_for_each_entry_safe() is no longer safe */
/* this seems to happen with the last element of the list as well */
if (unregistered_count >= 1)
goto restart;
}
return work;
}
#endif /* _HAVE_SYS_SELECT_H */

View File

@ -0,0 +1,84 @@
/* Generic signalling/notification infrastructure */
/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <osmocore/signal.h>
#include <osmocore/talloc.h>
#include <osmocore/linuxlist.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
void *tall_sigh_ctx;
static LLIST_HEAD(signal_handler_list);
struct signal_handler {
struct llist_head entry;
unsigned int subsys;
signal_cbfn *cbfn;
void *data;
};
int register_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data)
{
struct signal_handler *sig_data;
sig_data = talloc(tall_sigh_ctx, struct signal_handler);
if (!sig_data)
return -ENOMEM;
memset(sig_data, 0, sizeof(*sig_data));
sig_data->subsys = subsys;
sig_data->data = data;
sig_data->cbfn = cbfn;
/* FIXME: check if we already have a handler for this subsys/cbfn/data */
llist_add_tail(&sig_data->entry, &signal_handler_list);
return 0;
}
void unregister_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data)
{
struct signal_handler *handler;
llist_for_each_entry(handler, &signal_handler_list, entry) {
if (handler->cbfn == cbfn && handler->data == data
&& subsys == handler->subsys) {
llist_del(&handler->entry);
talloc_free(handler);
break;
}
}
}
void dispatch_signal(unsigned int subsys, unsigned int signal, void *signal_data)
{
struct signal_handler *handler;
llist_for_each_entry(handler, &signal_handler_list, entry) {
if (handler->subsys != subsys)
continue;
(*handler->cbfn)(subsys, signal, handler->data, signal_data);
}
}

View File

@ -0,0 +1,66 @@
/* utility routines for keeping some statistics */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <sys/types.h>
#include <osmocore/linuxlist.h>
#include <osmocore/talloc.h>
#include <osmocore/statistics.h>
static LLIST_HEAD(counters);
void *tall_ctr_ctx;
struct counter *counter_alloc(const char *name)
{
struct counter *ctr = talloc_zero(tall_ctr_ctx, struct counter);
if (!ctr)
return NULL;
ctr->name = name;
llist_add_tail(&ctr->list, &counters);
return ctr;
}
void counter_free(struct counter *ctr)
{
llist_del(&ctr->list);
talloc_free(ctr);
}
int counters_for_each(int (*handle_counter)(struct counter *, void *), void *data)
{
struct counter *ctr;
int rc = 0;
llist_for_each_entry(ctr, &counters, list) {
rc = handle_counter(ctr, data);
if (rc < 0)
return rc;
}
return rc;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,185 @@
/*
* (C) 2008,2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <assert.h>
#include <string.h>
#include <osmocore/timer.h>
static LLIST_HEAD(timer_list);
static struct timeval s_nearest_time;
static struct timeval s_select_time;
#define MICRO_SECONDS 1000000LL
#define TIME_SMALLER(left, right) \
(left.tv_sec*MICRO_SECONDS+left.tv_usec) <= (right.tv_sec*MICRO_SECONDS+right.tv_usec)
void bsc_add_timer(struct timer_list *timer)
{
struct timer_list *list_timer;
/* TODO: Optimize and remember the closest item... */
timer->active = 1;
/* this might be called from within update_timers */
llist_for_each_entry(list_timer, &timer_list, entry)
if (timer == list_timer)
return;
timer->in_list = 1;
llist_add(&timer->entry, &timer_list);
}
void bsc_schedule_timer(struct timer_list *timer, int seconds, int microseconds)
{
struct timeval current_time;
gettimeofday(&current_time, NULL);
unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
currentTime += seconds * MICRO_SECONDS + microseconds;
timer->timeout.tv_sec = currentTime / MICRO_SECONDS;
timer->timeout.tv_usec = currentTime % MICRO_SECONDS;
bsc_add_timer(timer);
}
void bsc_del_timer(struct timer_list *timer)
{
if (timer->in_list) {
timer->active = 0;
timer->in_list = 0;
llist_del(&timer->entry);
}
}
int bsc_timer_pending(struct timer_list *timer)
{
return timer->active;
}
/*
* if we have a nearest time return the delta between the current
* time and the time of the nearest timer.
* If the nearest timer timed out return NULL and then we will
* dispatch everything after the select
*/
struct timeval *bsc_nearest_timer()
{
struct timeval current_time;
if (s_nearest_time.tv_sec == 0 && s_nearest_time.tv_usec == 0)
return NULL;
if (gettimeofday(&current_time, NULL) == -1)
return NULL;
unsigned long long nearestTime = s_nearest_time.tv_sec * MICRO_SECONDS + s_nearest_time.tv_usec;
unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
if (nearestTime < currentTime) {
s_select_time.tv_sec = 0;
s_select_time.tv_usec = 0;
} else {
s_select_time.tv_sec = (nearestTime - currentTime) / MICRO_SECONDS;
s_select_time.tv_usec = (nearestTime - currentTime) % MICRO_SECONDS;
}
return &s_select_time;
}
/*
* Find the nearest time and update s_nearest_time
*/
void bsc_prepare_timers()
{
struct timer_list *timer, *nearest_timer = NULL;
llist_for_each_entry(timer, &timer_list, entry) {
if (!nearest_timer || TIME_SMALLER(timer->timeout, nearest_timer->timeout)) {
nearest_timer = timer;
}
}
if (nearest_timer) {
s_nearest_time = nearest_timer->timeout;
} else {
memset(&s_nearest_time, 0, sizeof(struct timeval));
}
}
/*
* fire all timers... and remove them
*/
int bsc_update_timers()
{
struct timeval current_time;
struct timer_list *timer, *tmp;
int work = 0;
gettimeofday(&current_time, NULL);
/*
* The callbacks might mess with our list and in this case
* even llist_for_each_entry_safe is not safe to use. To allow
* del_timer, add_timer, schedule_timer to be called from within
* the callback we jump through some loops.
*
* First we set the handled flag of each active timer to zero,
* then we iterate over the list and execute the callbacks. As the
* list might have been changed (specially the next) from within
* the callback we have to start over again. Once every callback
* is dispatched we will remove the non-active from the list.
*
* TODO: If this is a performance issue we can poison a global
* variable in add_timer and del_timer and only then restart.
*/
llist_for_each_entry(timer, &timer_list, entry) {
timer->handled = 0;
}
restart:
llist_for_each_entry(timer, &timer_list, entry) {
if (!timer->handled && TIME_SMALLER(timer->timeout, current_time)) {
timer->handled = 1;
timer->active = 0;
(*timer->cb)(timer->data);
work = 1;
goto restart;
}
}
llist_for_each_entry_safe(timer, tmp, &timer_list, entry) {
timer->handled = 0;
if (!timer->active) {
bsc_del_timer(timer);
}
}
return work;
}
int bsc_timer_check(void)
{
struct timer_list *timer;
int i = 0;
llist_for_each_entry(timer, &timer_list, entry) {
i++;
}
return i;
}

View File

@ -0,0 +1,179 @@
#include <stdio.h>
#include <stdint.h>
#include <osmocore/utils.h>
#include <osmocore/tlv.h>
struct tlv_definition tvlv_att_def;
int tlv_dump(struct tlv_parsed *dec)
{
int i;
for (i = 0; i <= 0xff; i++) {
if (!dec->lv[i].val)
continue;
printf("T=%02x L=%d\n", i, dec->lv[i].len);
}
return 0;
}
/* o_tag: output: tag found
* o_len: output: length of the data
* o_val: output: pointer to the data
* def: input: a structure defining the valid TLV tags / configurations
* buf: input: the input data buffer to be parsed
* buf_len: input: the length of the input data buffer
*
* Also, returns the number of bytes consumed by the TLV entry
*/
int tlv_parse_one(uint8_t *o_tag, uint16_t *o_len, const uint8_t **o_val,
const struct tlv_definition *def,
const uint8_t *buf, int buf_len)
{
uint8_t tag;
int len;
tag = *buf;
*o_tag = tag;
/* single octet TV IE */
if (def->def[tag & 0xf0].type == TLV_TYPE_SINGLE_TV) {
*o_tag = tag & 0xf0;
*o_val = buf;
*o_len = 1;
return 1;
}
/* FIXME: use tables for knwon IEI */
switch (def->def[tag].type) {
case TLV_TYPE_T:
/* GSM TS 04.07 11.2.4: Type 1 TV or Type 2 T */
*o_val = buf;
*o_len = 0;
len = 1;
break;
case TLV_TYPE_TV:
*o_val = buf+1;
*o_len = 1;
len = 2;
break;
case TLV_TYPE_FIXED:
*o_val = buf+1;
*o_len = def->def[tag].fixed_len;
len = def->def[tag].fixed_len + 1;
break;
case TLV_TYPE_TLV:
/* GSM TS 04.07 11.2.4: Type 4 TLV */
if (buf + 1 > buf + buf_len)
return -1;
*o_val = buf+2;
*o_len = *(buf+1);
len = *o_len + 2;
if (len > buf_len)
return -2;
break;
case TLV_TYPE_TvLV:
if (*(buf+1) & 0x80) {
/* like TLV, but without highest bit of len */
if (buf + 1 > buf + buf_len)
return -1;
*o_val = buf+2;
*o_len = *(buf+1) & 0x7f;
len = *o_len + 2;
if (len > buf_len)
return -2;
break;
}
/* like TL16V, fallthrough */
case TLV_TYPE_TL16V:
if (2 > buf_len)
return -1;
*o_val = buf+3;
*o_len = *(buf+1) << 8 | *(buf+2);
len = *o_len + 3;
if (len > buf_len)
return -2;
break;
default:
return -3;
}
return len;
}
/* dec: output: a caller-allocated pointer to a struct tlv_parsed,
* def: input: a structure defining the valid TLV tags / configurations
* buf: input: the input data buffer to be parsed
* buf_len: input: the length of the input data buffer
* lv_tag: input: an initial LV tag at the start of the buffer
* lv_tag2: input: a second initial LV tag following lv_tag
*/
int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
const uint8_t *buf, int buf_len, uint8_t lv_tag,
uint8_t lv_tag2)
{
int ofs = 0, num_parsed = 0;
uint16_t len;
memset(dec, 0, sizeof(*dec));
if (lv_tag) {
if (ofs > buf_len)
return -1;
dec->lv[lv_tag].val = &buf[ofs+1];
dec->lv[lv_tag].len = buf[ofs];
len = dec->lv[lv_tag].len + 1;
if (ofs + len > buf_len)
return -2;
num_parsed++;
ofs += len;
}
if (lv_tag2) {
if (ofs > buf_len)
return -1;
dec->lv[lv_tag2].val = &buf[ofs+1];
dec->lv[lv_tag2].len = buf[ofs];
len = dec->lv[lv_tag2].len + 1;
if (ofs + len > buf_len)
return -2;
num_parsed++;
ofs += len;
}
while (ofs < buf_len) {
int rv;
uint8_t tag;
const uint8_t *val;
rv = tlv_parse_one(&tag, &len, &val, def,
&buf[ofs], buf_len-ofs);
if (rv < 0)
return rv;
dec->lv[tag].val = val;
dec->lv[tag].len = len;
ofs += rv;
num_parsed++;
}
//tlv_dump(dec);
return num_parsed;
}
/* take a master (src) tlvdev and fill up all empty slots in 'dst' */
void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src)
{
int i;
for (i = 0; i < ARRAY_SIZE(dst->def); i++) {
if (src->def[i].type == TLV_TYPE_NONE)
continue;
if (dst->def[i].type == TLV_TYPE_NONE)
dst->def[i] = src->def[i];
}
}
static __attribute__((constructor)) void on_dso_load_tlv(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(tvlv_att_def.def); i++)
tvlv_att_def.def[i].type = TLV_TYPE_TvLV;
}

View File

@ -0,0 +1,50 @@
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <stdio.h>
#include <osmocore/utils.h>
static char namebuf[255];
const char *get_value_string(const struct value_string *vs, uint32_t val)
{
int i;
for (i = 0;; i++) {
if (vs[i].value == 0 && vs[i].str == NULL)
break;
if (vs[i].value == val)
return vs[i].str;
}
snprintf(namebuf, sizeof(namebuf), "unknown 0x%x", val);
return namebuf;
}
int get_string_value(const struct value_string *vs, const char *str)
{
int i;
for (i = 0;; i++) {
if (vs[i].value == 0 && vs[i].str == NULL)
break;
if (!strcasecmp(vs[i].str, str))
return vs[i].value;
}
return -EINVAL;
}
char bcd2char(uint8_t bcd)
{
if (bcd < 0xa)
return '0' + bcd;
else
return 'A' + (bcd - 0xa);
}
/* only works for numbers in ascci */
uint8_t char2bcd(char c)
{
return c - 0x30;
}

View File

@ -0,0 +1,13 @@
# This is _NOT_ the library release version, it's an API version.
# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification
LIBVERSION=0:0:0
INCLUDES = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS = -fPIC -Wall
if ENABLE_VTY
lib_LTLIBRARIES = libosmovty.la
libosmovty_la_SOURCES = buffer.c command.c vty.c vector.c utils.c \
telnet_interface.c logging_vty.c
endif

View File

@ -0,0 +1,463 @@
/*
* Buffering of output and input.
* Copyright (C) 1998 Kunihiro Ishiguro
*
* This file is part of GNU Zebra.
*
* GNU Zebra 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 2, or (at your
* option) any later version.
*
* GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stddef.h>
#include <sys/uio.h>
#include <osmocore/talloc.h>
#include <osmocom/vty/buffer.h>
#include <osmocom/vty/vty.h>
/* Buffer master. */
struct buffer {
/* Data list. */
struct buffer_data *head;
struct buffer_data *tail;
/* Size of each buffer_data chunk. */
size_t size;
};
/* Data container. */
struct buffer_data {
struct buffer_data *next;
/* Location to add new data. */
size_t cp;
/* Pointer to data not yet flushed. */
size_t sp;
/* Actual data stream (variable length). */
unsigned char data[0]; /* real dimension is buffer->size */
};
/* It should always be true that: 0 <= sp <= cp <= size */
/* Default buffer size (used if none specified). It is rounded up to the
next page boundery. */
#define BUFFER_SIZE_DEFAULT 4096
#define BUFFER_DATA_FREE(D) talloc_free((D))
/* Make new buffer. */
struct buffer *buffer_new(void *ctx, size_t size)
{
struct buffer *b;
b = talloc_zero(ctx, struct buffer);
if (size)
b->size = size;
else {
static size_t default_size;
if (!default_size) {
long pgsz = sysconf(_SC_PAGESIZE);
default_size =
((((BUFFER_SIZE_DEFAULT - 1) / pgsz) + 1) * pgsz);
}
b->size = default_size;
}
return b;
}
/* Free buffer. */
void buffer_free(struct buffer *b)
{
buffer_reset(b);
talloc_free(b);
}
/* Make string clone. */
char *buffer_getstr(struct buffer *b)
{
size_t totlen = 0;
struct buffer_data *data;
char *s;
char *p;
for (data = b->head; data; data = data->next)
totlen += data->cp - data->sp;
if (!(s = _talloc_zero(tall_vty_ctx, (totlen + 1), "buffer_getstr")))
return NULL;
p = s;
for (data = b->head; data; data = data->next) {
memcpy(p, data->data + data->sp, data->cp - data->sp);
p += data->cp - data->sp;
}
*p = '\0';
return s;
}
/* Return 1 if buffer is empty. */
int buffer_empty(struct buffer *b)
{
return (b->head == NULL);
}
/* Clear and free all allocated data. */
void buffer_reset(struct buffer *b)
{
struct buffer_data *data;
struct buffer_data *next;
for (data = b->head; data; data = next) {
next = data->next;
BUFFER_DATA_FREE(data);
}
b->head = b->tail = NULL;
}
/* Add buffer_data to the end of buffer. */
static struct buffer_data *buffer_add(struct buffer *b)
{
struct buffer_data *d;
d = _talloc_zero(b,
offsetof(struct buffer_data, data[b->size]),
"buffer_add");
if (!d)
return NULL;
d->cp = d->sp = 0;
d->next = NULL;
if (b->tail)
b->tail->next = d;
else
b->head = d;
b->tail = d;
return d;
}
/* Write data to buffer. */
void buffer_put(struct buffer *b, const void *p, size_t size)
{
struct buffer_data *data = b->tail;
const char *ptr = p;
/* We use even last one byte of data buffer. */
while (size) {
size_t chunk;
/* If there is no data buffer add it. */
if (data == NULL || data->cp == b->size)
data = buffer_add(b);
chunk =
((size <=
(b->size - data->cp)) ? size : (b->size - data->cp));
memcpy((data->data + data->cp), ptr, chunk);
size -= chunk;
ptr += chunk;
data->cp += chunk;
}
}
/* Insert character into the buffer. */
void buffer_putc(struct buffer *b, u_char c)
{
buffer_put(b, &c, 1);
}
/* Put string to the buffer. */
void buffer_putstr(struct buffer *b, const char *c)
{
buffer_put(b, c, strlen(c));
}
/* Keep flushing data to the fd until the buffer is empty or an error is
encountered or the operation would block. */
buffer_status_t buffer_flush_all(struct buffer *b, int fd)
{
buffer_status_t ret;
struct buffer_data *head;
size_t head_sp;
if (!b->head)
return BUFFER_EMPTY;
head_sp = (head = b->head)->sp;
/* Flush all data. */
while ((ret = buffer_flush_available(b, fd)) == BUFFER_PENDING) {
if ((b->head == head) && (head_sp == head->sp)
&& (errno != EINTR))
/* No data was flushed, so kernel buffer must be full. */
return ret;
head_sp = (head = b->head)->sp;
}
return ret;
}
#if 0
/* Flush enough data to fill a terminal window of the given scene (used only
by vty telnet interface). */
buffer_status_t
buffer_flush_window(struct buffer * b, int fd, int width, int height,
int erase_flag, int no_more_flag)
{
int nbytes;
int iov_alloc;
int iov_index;
struct iovec *iov;
struct iovec small_iov[3];
char more[] = " --More-- ";
char erase[] =
{ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
};
struct buffer_data *data;
int column;
if (!b->head)
return BUFFER_EMPTY;
if (height < 1) {
zlog_warn
("%s called with non-positive window height %d, forcing to 1",
__func__, height);
height = 1;
} else if (height >= 2)
height--;
if (width < 1) {
zlog_warn
("%s called with non-positive window width %d, forcing to 1",
__func__, width);
width = 1;
}
/* For erase and more data add two to b's buffer_data count. */
if (b->head->next == NULL) {
iov_alloc = sizeof(small_iov) / sizeof(small_iov[0]);
iov = small_iov;
} else {
iov_alloc = ((height * (width + 2)) / b->size) + 10;
iov = XMALLOC(MTYPE_TMP, iov_alloc * sizeof(*iov));
}
iov_index = 0;
/* Previously print out is performed. */
if (erase_flag) {
iov[iov_index].iov_base = erase;
iov[iov_index].iov_len = sizeof erase;
iov_index++;
}
/* Output data. */
column = 1; /* Column position of next character displayed. */
for (data = b->head; data && (height > 0); data = data->next) {
size_t cp;
cp = data->sp;
while ((cp < data->cp) && (height > 0)) {
/* Calculate lines remaining and column position after displaying
this character. */
if (data->data[cp] == '\r')
column = 1;
else if ((data->data[cp] == '\n') || (column == width)) {
column = 1;
height--;
} else
column++;
cp++;
}
iov[iov_index].iov_base = (char *)(data->data + data->sp);
iov[iov_index++].iov_len = cp - data->sp;
data->sp = cp;
if (iov_index == iov_alloc)
/* This should not ordinarily happen. */
{
iov_alloc *= 2;
if (iov != small_iov) {
zlog_warn("%s: growing iov array to %d; "
"width %d, height %d, size %lu",
__func__, iov_alloc, width, height,
(u_long) b->size);
iov =
XREALLOC(MTYPE_TMP, iov,
iov_alloc * sizeof(*iov));
} else {
/* This should absolutely never occur. */
zlog_err
("%s: corruption detected: iov_small overflowed; "
"head %p, tail %p, head->next %p",
__func__, b->head, b->tail, b->head->next);
iov =
XMALLOC(MTYPE_TMP,
iov_alloc * sizeof(*iov));
memcpy(iov, small_iov, sizeof(small_iov));
}
}
}
/* In case of `more' display need. */
if (b->tail && (b->tail->sp < b->tail->cp) && !no_more_flag) {
iov[iov_index].iov_base = more;
iov[iov_index].iov_len = sizeof more;
iov_index++;
}
#ifdef IOV_MAX
/* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
example: Solaris2.6 are defined IOV_MAX size at 16. */
{
struct iovec *c_iov = iov;
nbytes = 0; /* Make sure it's initialized. */
while (iov_index > 0) {
int iov_size;
iov_size =
((iov_index > IOV_MAX) ? IOV_MAX : iov_index);
if ((nbytes = writev(fd, c_iov, iov_size)) < 0) {
zlog_warn("%s: writev to fd %d failed: %s",
__func__, fd, safe_strerror(errno));
break;
}
/* move pointer io-vector */
c_iov += iov_size;
iov_index -= iov_size;
}
}
#else /* IOV_MAX */
if ((nbytes = writev(fd, iov, iov_index)) < 0)
zlog_warn("%s: writev to fd %d failed: %s",
__func__, fd, safe_strerror(errno));
#endif /* IOV_MAX */
/* Free printed buffer data. */
while (b->head && (b->head->sp == b->head->cp)) {
struct buffer_data *del;
if (!(b->head = (del = b->head)->next))
b->tail = NULL;
BUFFER_DATA_FREE(del);
}
if (iov != small_iov)
XFREE(MTYPE_TMP, iov);
return (nbytes < 0) ? BUFFER_ERROR :
(b->head ? BUFFER_PENDING : BUFFER_EMPTY);
}
#endif
/* This function (unlike other buffer_flush* functions above) is designed
to work with non-blocking sockets. It does not attempt to write out
all of the queued data, just a "big" chunk. It returns 0 if it was
able to empty out the buffers completely, 1 if more flushing is
required later, or -1 on a fatal write error. */
buffer_status_t buffer_flush_available(struct buffer * b, int fd)
{
/* These are just reasonable values to make sure a significant amount of
data is written. There's no need to go crazy and try to write it all
in one shot. */
#ifdef IOV_MAX
#define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX)
#else
#define MAX_CHUNKS 16
#endif
#define MAX_FLUSH 131072
struct buffer_data *d;
size_t written;
struct iovec iov[MAX_CHUNKS];
size_t iovcnt = 0;
size_t nbyte = 0;
for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH);
d = d->next, iovcnt++) {
iov[iovcnt].iov_base = d->data + d->sp;
nbyte += (iov[iovcnt].iov_len = d->cp - d->sp);
}
if (!nbyte)
/* No data to flush: should we issue a warning message? */
return BUFFER_EMPTY;
/* only place where written should be sign compared */
if ((ssize_t) (written = writev(fd, iov, iovcnt)) < 0) {
if (ERRNO_IO_RETRY(errno))
/* Calling code should try again later. */
return BUFFER_PENDING;
return BUFFER_ERROR;
}
/* Free printed buffer data. */
while (written > 0) {
struct buffer_data *d;
if (!(d = b->head))
break;
if (written < d->cp - d->sp) {
d->sp += written;
return BUFFER_PENDING;
}
written -= (d->cp - d->sp);
if (!(b->head = d->next))
b->tail = NULL;
BUFFER_DATA_FREE(d);
}
return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
#undef MAX_CHUNKS
#undef MAX_FLUSH
}
buffer_status_t
buffer_write(struct buffer * b, int fd, const void *p, size_t size)
{
ssize_t nbytes;
#if 0
/* Should we attempt to drain any previously buffered data? This could help reduce latency in pushing out the data if we are stuck in a long-running thread that is preventing the main select loop from calling the flush thread... */
if (b->head && (buffer_flush_available(b, fd) == BUFFER_ERROR))
return BUFFER_ERROR;
#endif
if (b->head)
/* Buffer is not empty, so do not attempt to write the new data. */
nbytes = 0;
else if ((nbytes = write(fd, p, size)) < 0) {
if (ERRNO_IO_RETRY(errno))
nbytes = 0;
else
return BUFFER_ERROR;
}
/* Add any remaining data to the buffer. */
{
size_t written = nbytes;
if (written < size)
buffer_put(b, ((const char *)p) + written,
size - written);
}
return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,347 @@
/* OpenBSC logging helper for the VTY */
/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2009-2010 by Holger Hans Peter Freyther
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdlib.h>
#include <string.h>
#include <osmocore/talloc.h>
#include <osmocore/logging.h>
//#include <openbsc/vty.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/buffer.h>
#include <osmocom/vty/vty.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/logging.h>
extern const struct log_info *osmo_log_info;
static void _vty_output(struct log_target *tgt, const char *line)
{
struct vty *vty = tgt->tgt_vty.vty;
vty_out(vty, "%s", line);
/* This is an ugly hack, but there is no easy way... */
if (strchr(line, '\n'))
vty_out(vty, "\r");
}
struct log_target *log_target_create_vty(struct vty *vty)
{
struct log_target *target;
target = log_target_create();
if (!target)
return NULL;
target->tgt_vty.vty = vty;
target->output = _vty_output;
return target;
}
DEFUN(enable_logging,
enable_logging_cmd,
"logging enable",
LOGGING_STR
"Enables logging to this vty\n")
{
struct telnet_connection *conn;
conn = (struct telnet_connection *) vty->priv;
if (conn->dbg) {
vty_out(vty, "Logging already enabled.%s", VTY_NEWLINE);
return CMD_WARNING;
}
conn->dbg = log_target_create_vty(vty);
if (!conn->dbg)
return CMD_WARNING;
log_add_target(conn->dbg);
return CMD_SUCCESS;
}
DEFUN(logging_fltr_all,
logging_fltr_all_cmd,
"logging filter all (0|1)",
LOGGING_STR FILTER_STR
"Do you want to log all messages?\n"
"Only print messages matched by other filters\n"
"Bypass filter and print all messages\n")
{
struct telnet_connection *conn;
conn = (struct telnet_connection *) vty->priv;
if (!conn->dbg) {
vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
return CMD_WARNING;
}
log_set_all_filter(conn->dbg, atoi(argv[0]));
return CMD_SUCCESS;
}
DEFUN(logging_use_clr,
logging_use_clr_cmd,
"logging color (0|1)",
LOGGING_STR "Configure color-printing for log messages\n"
"Don't use color for printing messages\n"
"Use color for printing messages\n")
{
struct telnet_connection *conn;
conn = (struct telnet_connection *) vty->priv;
if (!conn->dbg) {
vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
return CMD_WARNING;
}
log_set_use_color(conn->dbg, atoi(argv[0]));
return CMD_SUCCESS;
}
DEFUN(logging_prnt_timestamp,
logging_prnt_timestamp_cmd,
"logging timestamp (0|1)",
LOGGING_STR "Configure log message timestamping\n"
"Don't prefix each log message\n"
"Prefix each log message with current timestamp\n")
{
struct telnet_connection *conn;
conn = (struct telnet_connection *) vty->priv;
if (!conn->dbg) {
vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
return CMD_WARNING;
}
log_set_print_timestamp(conn->dbg, atoi(argv[0]));
return CMD_SUCCESS;
}
/* FIXME: those have to be kept in sync with the log levels and categories */
#define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref|gprs|ns|bssgp|llc|sndcp|all)"
#define CATEGORIES_HELP \
"A-bis Radio Link Layer (RLL)\n" \
"Layer3 Call Control (CC)\n" \
"Layer3 Mobility Management (MM)\n" \
"Layer3 Radio Resource (RR)\n" \
"A-bis Radio Signalling Link (RSL)\n" \
"A-bis Network Management / O&M (NM/OML)\n" \
"Layer3 Short Messagaging Service (SMS)\n" \
"Paging Subsystem\n" \
"MNCC API for Call Control application\n" \
"A-bis Input Subsystem\n" \
"A-bis Input Driver for Signalling\n" \
"A-bis Input Driver for B-Channel (voice data)\n" \
"A-bis B-Channel / Sub-channel Multiplexer\n" \
"Radio Measurements\n" \
"SCCP\n" \
"Mobile Switching Center\n" \
"Media Gateway Control Protocol\n" \
"Hand-over\n" \
"Database Layer\n" \
"Reference Counting\n" \
"GPRS Core\n" \
"GPRS Network Service (NS)\n" \
"GPRS BSS Gateway Protocol (BSSGP)\n" \
"GPRS Logical Link Control Protocol (LLC)\n" \
"GPRS Sub-Network Dependent Control Protocol (SNDCP)\n" \
"Global setting for all subsytems\n"
#define VTY_DEBUG_LEVELS "(everything|debug|info|notice|error|fatal)"
#define LEVELS_HELP \
"Log simply everything\n" \
"Log debug messages and higher levels\n" \
"Log informational messages and higher levels\n" \
"Log noticable messages and higher levels\n" \
"Log error messages and higher levels\n" \
"Log only fatal messages\n"
DEFUN(logging_level,
logging_level_cmd,
"logging level " VTY_DEBUG_CATEGORIES " " VTY_DEBUG_LEVELS,
LOGGING_STR
"Set the log level for a specified category\n"
CATEGORIES_HELP
LEVELS_HELP)
{
struct telnet_connection *conn;
int category = log_parse_category(argv[0]);
int level = log_parse_level(argv[1]);
conn = (struct telnet_connection *) vty->priv;
if (!conn->dbg) {
vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
return CMD_WARNING;
}
if (level < 0) {
vty_out(vty, "Invalid level `%s'%s", argv[1], VTY_NEWLINE);
return CMD_WARNING;
}
/* Check for special case where we want to set global log level */
if (!strcmp(argv[0], "all")) {
log_set_log_level(conn->dbg, level);
return CMD_SUCCESS;
}
if (category < 0) {
vty_out(vty, "Invalid category `%s'%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
conn->dbg->categories[category].enabled = 1;
conn->dbg->categories[category].loglevel = level;
return CMD_SUCCESS;
}
DEFUN(logging_set_category_mask,
logging_set_category_mask_cmd,
"logging set log mask MASK",
LOGGING_STR
"Decide which categories to output.\n")
{
struct telnet_connection *conn;
conn = (struct telnet_connection *) vty->priv;
if (!conn->dbg) {
vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
return CMD_WARNING;
}
log_parse_category_mask(conn->dbg, argv[0]);
return CMD_SUCCESS;
}
DEFUN(diable_logging,
disable_logging_cmd,
"logging disable",
LOGGING_STR
"Disables logging to this vty\n")
{
struct telnet_connection *conn;
conn = (struct telnet_connection *) vty->priv;
if (!conn->dbg) {
vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
return CMD_WARNING;
}
log_del_target(conn->dbg);
talloc_free(conn->dbg);
conn->dbg = NULL;
return CMD_SUCCESS;
}
static void vty_print_logtarget(struct vty *vty, const struct log_info *info,
const struct log_target *tgt)
{
unsigned int i;
vty_out(vty, " Global Loglevel: %s%s",
log_level_str(tgt->loglevel), VTY_NEWLINE);
vty_out(vty, " Use color: %s, Print Timestamp: %s%s",
tgt->use_color ? "On" : "Off",
tgt->print_timestamp ? "On" : "Off", VTY_NEWLINE);
vty_out(vty, " Log Level specific information:%s", VTY_NEWLINE);
for (i = 0; i < info->num_cat; i++) {
const struct log_category *cat = &tgt->categories[i];
vty_out(vty, " %-10s %-10s %-8s %s%s",
info->cat[i].name+1, log_level_str(cat->loglevel),
cat->enabled ? "Enabled" : "Disabled",
info->cat[i].description,
VTY_NEWLINE);
}
}
#define SHOW_LOG_STR "Show current logging configuration\n"
DEFUN(show_logging_vty,
show_logging_vty_cmd,
"show logging vty",
SHOW_STR SHOW_LOG_STR
"Show current logging configuration for this vty\n")
{
struct telnet_connection *conn;
conn = (struct telnet_connection *) vty->priv;
if (!conn->dbg) {
vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
return CMD_WARNING;
}
vty_print_logtarget(vty, osmo_log_info, conn->dbg);
return CMD_SUCCESS;
}
gDEFUN(cfg_description, cfg_description_cmd,
"description .TEXT",
"Save human-readable decription of the object\n")
{
char **dptr = vty->index_sub;
if (!dptr) {
vty_out(vty, "vty->index_sub == NULL%s", VTY_NEWLINE);
return CMD_WARNING;
}
*dptr = argv_concat(argv, argc, 0);
if (!dptr)
return CMD_WARNING;
return CMD_SUCCESS;
}
gDEFUN(cfg_no_description, cfg_no_description_cmd,
"no description",
NO_STR
"Remove description of the object\n")
{
char **dptr = vty->index_sub;
if (!dptr) {
vty_out(vty, "vty->index_sub == NULL%s", VTY_NEWLINE);
return CMD_WARNING;
}
if (*dptr) {
talloc_free(*dptr);
*dptr = NULL;
}
return CMD_SUCCESS;
}
void logging_vty_add_cmds()
{
install_element_ve(&enable_logging_cmd);
install_element_ve(&disable_logging_cmd);
install_element_ve(&logging_fltr_all_cmd);
install_element_ve(&logging_use_clr_cmd);
install_element_ve(&logging_prnt_timestamp_cmd);
install_element_ve(&logging_set_category_mask_cmd);
install_element_ve(&logging_level_cmd);
install_element_ve(&show_logging_vty_cmd);
}

View File

@ -0,0 +1,203 @@
/* minimalistic telnet/network interface it might turn into a wire interface */
/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <osmocore/msgb.h>
#include <osmocore/talloc.h>
#include <osmocore/logging.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/buffer.h>
/* per connection data */
LLIST_HEAD(active_connections);
static void *tall_telnet_ctx;
/* per network data */
static int telnet_new_connection(struct bsc_fd *fd, unsigned int what);
static struct bsc_fd server_socket = {
.when = BSC_FD_READ,
.cb = telnet_new_connection,
.priv_nr = 0,
};
int telnet_init(void *tall_ctx, void *priv, int port)
{
struct sockaddr_in sock_addr;
int fd, rc, on = 1;
tall_telnet_ctx = talloc_named_const(tall_ctx, 1,
"telnet_connection");
fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd < 0) {
LOGP(0, LOGL_ERROR, "Telnet interface socket creation failed\n");
return fd;
}
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
memset(&sock_addr, 0, sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
sock_addr.sin_port = htons(port);
sock_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
rc = bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr));
if (bind < 0) {
LOGP(0, LOGL_ERROR, "Telnet interface failed to bind\n");
close(fd);
return rc;
}
rc = listen(fd, 0);
if (rc < 0) {
LOGP(0, LOGL_ERROR, "Telnet interface failed to listen\n");
close(fd);
return rc;
}
server_socket.data = priv;
server_socket.fd = fd;
bsc_register_fd(&server_socket);
return 0;
}
extern const char *openbsc_copyright;
static void print_welcome(int fd)
{
int ret;
static char *msg =
"Welcome to the OpenBSC Control interface\n";
ret = write(fd, msg, strlen(msg));
ret = write(fd, openbsc_copyright, strlen(openbsc_copyright));
}
int telnet_close_client(struct bsc_fd *fd)
{
struct telnet_connection *conn = (struct telnet_connection*)fd->data;
close(fd->fd);
bsc_unregister_fd(fd);
if (conn->dbg) {
log_del_target(conn->dbg);
talloc_free(conn->dbg);
}
llist_del(&conn->entry);
talloc_free(conn);
return 0;
}
static int client_data(struct bsc_fd *fd, unsigned int what)
{
struct telnet_connection *conn = fd->data;
int rc = 0;
if (what & BSC_FD_READ) {
conn->fd.when &= ~BSC_FD_READ;
rc = vty_read(conn->vty);
}
/* vty might have been closed from vithin vty_read() */
if (!conn->vty)
return rc;
if (what & BSC_FD_WRITE) {
rc = buffer_flush_all(conn->vty->obuf, fd->fd);
if (rc == BUFFER_EMPTY)
conn->fd.when &= ~BSC_FD_WRITE;
}
return rc;
}
static int telnet_new_connection(struct bsc_fd *fd, unsigned int what)
{
struct telnet_connection *connection;
struct sockaddr_in sockaddr;
socklen_t len = sizeof(sockaddr);
int new_connection = accept(fd->fd, (struct sockaddr*)&sockaddr, &len);
if (new_connection < 0) {
LOGP(0, LOGL_ERROR, "telnet accept failed\n");
return new_connection;
}
connection = talloc_zero(tall_telnet_ctx, struct telnet_connection);
connection->priv = fd->data;
connection->fd.data = connection;
connection->fd.fd = new_connection;
connection->fd.when = BSC_FD_READ;
connection->fd.cb = client_data;
bsc_register_fd(&connection->fd);
llist_add_tail(&connection->entry, &active_connections);
print_welcome(new_connection);
connection->vty = vty_create(new_connection, connection);
if (!connection->vty) {
LOGP(0, LOGL_ERROR, "couldn't create VTY\n");
close(new_connection);
talloc_free(connection);
return -1;
}
return 0;
}
/* callback from VTY code */
void vty_event(enum event event, int sock, struct vty *vty)
{
struct telnet_connection *connection = vty->priv;
struct bsc_fd *bfd = &connection->fd;
if (vty->type != VTY_TERM)
return;
switch (event) {
case VTY_READ:
bfd->when |= BSC_FD_READ;
break;
case VTY_WRITE:
bfd->when |= BSC_FD_WRITE;
break;
case VTY_CLOSED:
/* vty layer is about to free() vty */
connection->vty = NULL;
telnet_close_client(bfd);
break;
default:
break;
}
}

View File

@ -0,0 +1,50 @@
/* utility routines for printing common objects in the Osmocom world */
/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdint.h>
#include <inttypes.h>
#include <osmocore/linuxlist.h>
#include <osmocore/talloc.h>
#include <osmocore/timer.h>
#include <osmocore/rate_ctr.h>
#include <osmocom/vty/vty.h>
void vty_out_rate_ctr_group(struct vty *vty, const char *prefix,
struct rate_ctr_group *ctrg)
{
unsigned int i;
vty_out(vty, "%s%s:%s", prefix, ctrg->desc->group_description, VTY_NEWLINE);
for (i = 0; i < ctrg->desc->num_ctr; i++) {
struct rate_ctr *ctr = &ctrg->ctr[i];
vty_out(vty, " %s%s: %8" PRIu64 " "
"(%" PRIu64 "/s %" PRIu64 "/m %" PRIu64 "/h %" PRIu64 "/d)%s",
prefix, ctrg->desc->ctr_desc[i].description, ctr->current,
ctr->intv[RATE_CTR_INTV_SEC].rate,
ctr->intv[RATE_CTR_INTV_MIN].rate,
ctr->intv[RATE_CTR_INTV_HOUR].rate,
ctr->intv[RATE_CTR_INTV_DAY].rate,
VTY_NEWLINE);
};
}

View File

@ -0,0 +1,192 @@
/* Generic vector interface routine
* Copyright (C) 1997 Kunihiro Ishiguro
*
* This file is part of GNU Zebra.
*
* GNU Zebra 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 2, or (at your option) any
* later version.
*
* GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <stdlib.h>
#include <unistd.h>
#include <osmocom/vty/vector.h>
#include <osmocom/vty/vty.h>
#include <osmocore/talloc.h>
#include <memory.h>
void *tall_vty_vec_ctx;
/* Initialize vector : allocate memory and return vector. */
vector vector_init(unsigned int size)
{
vector v = talloc_zero(tall_vty_vec_ctx, struct _vector);
if (!v)
return NULL;
/* allocate at least one slot */
if (size == 0)
size = 1;
v->alloced = size;
v->active = 0;
v->index = _talloc_zero(tall_vty_vec_ctx, sizeof(void *) * size,
"vector_init:index");
if (!v->index) {
talloc_free(v);
return NULL;
}
return v;
}
void vector_only_wrapper_free(vector v)
{
talloc_free(v);
}
void vector_only_index_free(void *index)
{
talloc_free(index);
}
void vector_free(vector v)
{
talloc_free(v->index);
talloc_free(v);
}
vector vector_copy(vector v)
{
unsigned int size;
vector new = talloc_zero(tall_vty_vec_ctx, struct _vector);
if (!new)
return NULL;
new->active = v->active;
new->alloced = v->alloced;
size = sizeof(void *) * (v->alloced);
new->index = _talloc_zero(tall_vty_vec_ctx, size, "vector_copy:index");
if (!new->index) {
talloc_free(new);
return NULL;
}
memcpy(new->index, v->index, size);
return new;
}
/* Check assigned index, and if it runs short double index pointer */
void vector_ensure(vector v, unsigned int num)
{
if (v->alloced > num)
return;
v->index = talloc_realloc_size(tall_vty_vec_ctx, v->index,
sizeof(void *) * (v->alloced * 2));
memset(&v->index[v->alloced], 0, sizeof(void *) * v->alloced);
v->alloced *= 2;
if (v->alloced <= num)
vector_ensure(v, num);
}
/* This function only returns next empty slot index. It dose not mean
the slot's index memory is assigned, please call vector_ensure()
after calling this function. */
int vector_empty_slot(vector v)
{
unsigned int i;
if (v->active == 0)
return 0;
for (i = 0; i < v->active; i++)
if (v->index[i] == 0)
return i;
return i;
}
/* Set value to the smallest empty slot. */
int vector_set(vector v, void *val)
{
unsigned int i;
i = vector_empty_slot(v);
vector_ensure(v, i);
v->index[i] = val;
if (v->active <= i)
v->active = i + 1;
return i;
}
/* Set value to specified index slot. */
int vector_set_index(vector v, unsigned int i, void *val)
{
vector_ensure(v, i);
v->index[i] = val;
if (v->active <= i)
v->active = i + 1;
return i;
}
/* Look up vector. */
void *vector_lookup(vector v, unsigned int i)
{
if (i >= v->active)
return NULL;
return v->index[i];
}
/* Lookup vector, ensure it. */
void *vector_lookup_ensure(vector v, unsigned int i)
{
vector_ensure(v, i);
return v->index[i];
}
/* Unset value at specified index slot. */
void vector_unset(vector v, unsigned int i)
{
if (i >= v->alloced)
return;
v->index[i] = NULL;
if (i + 1 == v->active) {
v->active--;
while (i && v->index[--i] == NULL && v->active--) ; /* Is this ugly ? */
}
}
/* Count the number of not emplty slot. */
unsigned int vector_count(vector v)
{
unsigned int i;
unsigned count = 0;
for (i = 0; i < v->active; i++)
if (v->index[i] != NULL)
count++;
return count;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,88 @@
/* Generic write queue implementation */
/*
* (C) 2010 by Holger Hans Peter Freyther
* (C) 2010 by On-Waves
*
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <osmocore/write_queue.h>
int write_queue_bfd_cb(struct bsc_fd *fd, unsigned int what)
{
struct write_queue *queue;
queue = container_of(fd, struct write_queue, bfd);
if (what & BSC_FD_READ)
queue->read_cb(fd);
if (what & BSC_FD_EXCEPT)
queue->except_cb(fd);
if (what & BSC_FD_WRITE) {
struct msgb *msg;
fd->when &= ~BSC_FD_WRITE;
msg = msgb_dequeue(&queue->msg_queue);
if (!msg)
return -1;
--queue->current_length;
queue->write_cb(fd, msg);
msgb_free(msg);
if (!llist_empty(&queue->msg_queue))
fd->when |= BSC_FD_WRITE;
}
return 0;
}
void write_queue_init(struct write_queue *queue, int max_length)
{
queue->max_length = max_length;
queue->current_length = 0;
queue->read_cb = NULL;
queue->write_cb = NULL;
queue->bfd.cb = write_queue_bfd_cb;
INIT_LLIST_HEAD(&queue->msg_queue);
}
int write_queue_enqueue(struct write_queue *queue, struct msgb *data)
{
// if (queue->current_length + 1 >= queue->max_length)
// LOGP(DMSC, LOGL_ERROR, "The queue is full. Dropping not yet implemented.\n");
++queue->current_length;
msgb_enqueue(&queue->msg_queue, data);
queue->bfd.when |= BSC_FD_WRITE;
return 0;
}
void write_queue_clear(struct write_queue *queue)
{
while (!llist_empty(&queue->msg_queue)) {
struct msgb *msg = msgb_dequeue(&queue->msg_queue);
msgb_free(msg);
}
queue->current_length = 0;
queue->bfd.when &= ~BSC_FD_WRITE;
}

View File

@ -0,0 +1,3 @@
if ENABLE_TESTS
SUBDIRS = timer sms
endif

View File

@ -0,0 +1,5 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include
noinst_PROGRAMS = sms_test
sms_test_SOURCES = sms_test.c
sms_test_LDADD = $(top_builddir)/src/libosmocore.la

View File

@ -0,0 +1,47 @@
/*
* (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <osmocore/msgb.h>
#include <osmocore/gsm_utils.h>
int main(int argc, char** argv)
{
printf("SMS testing\n");
struct msgb *msg;
uint8_t *sms;
uint8_t i;
/* test 7-bit coding/decoding */
const char *input = "test text";
uint8_t length;
uint8_t coded[256];
char result[256];
length = gsm_7bit_encode(coded, input);
gsm_7bit_decode(result, coded, length);
if (strcmp(result, input) != 0) {
printf("7 Bit coding failed... life sucks\n");
printf("Wanted: '%s' got '%s'\n", input, result);
}
}

View File

@ -0,0 +1,6 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include
noinst_PROGRAMS = timer_test
timer_test_SOURCES = timer_test.c
timer_test_LDADD = $(top_builddir)/src/libosmocore.la

View File

@ -0,0 +1,77 @@
/*
* (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdio.h>
#include <osmocore/timer.h>
#include <osmocore/select.h>
#include "../../config.h"
static void timer_fired(void *data);
static struct timer_list timer_one = {
.cb = timer_fired,
.data = (void*)1,
};
static struct timer_list timer_two = {
.cb = timer_fired,
.data = (void*)2,
};
static struct timer_list timer_three = {
.cb = timer_fired,
.data = (void*)3,
};
static void timer_fired(void *_data)
{
unsigned long data = (unsigned long) _data;
printf("Fired timer: %lu\n", data);
if (data == 1) {
bsc_schedule_timer(&timer_one, 3, 0);
bsc_del_timer(&timer_two);
} else if (data == 2) {
printf("Should not be fired... bug in del_timer\n");
} else if (data == 3) {
printf("Timer fired not registering again\n");
} else {
printf("wtf... wrong data\n");
}
}
int main(int argc, char** argv)
{
printf("Starting... timer\n");
bsc_schedule_timer(&timer_one, 3, 0);
bsc_schedule_timer(&timer_two, 5, 0);
bsc_schedule_timer(&timer_three, 4, 0);
#ifdef HAVE_SYS_SELECT_H
while (1) {
bsc_select_main(0);
}
#else
printf("Select not supported on this platform!\n");
#endif
}