Merge branch 'on-waves/sccp'
diff --git a/libosmocore/.gitignore b/libosmocore/.gitignore
deleted file mode 100644
index d61cdc5..0000000
--- a/libosmocore/.gitignore
+++ /dev/null
@@ -1,25 +0,0 @@
-Makefile
-Makefile.in
-.deps
-.libs
-*.o
-*.lo
-*.la
-*.pc
-aclocal.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
diff --git a/libosmocore/COPYING b/libosmocore/COPYING
deleted file mode 100644
index d511905..0000000
--- a/libosmocore/COPYING
+++ /dev/null
@@ -1,339 +0,0 @@
-		    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.
diff --git a/libosmocore/Makefile.am b/libosmocore/Makefile.am
deleted file mode 100644
index 2adf502..0000000
--- a/libosmocore/Makefile.am
+++ /dev/null
@@ -1,14 +0,0 @@
-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
-
-BUILT_SOURCES = $(top_srcdir)/.version
-$(top_srcdir)/.version:
-	echo $(VERSION) > $@-t && mv $@-t $@
-dist-hook:
-	echo $(VERSION) > $(distdir)/.tarball-version
diff --git a/libosmocore/configure.in b/libosmocore/configure.in
deleted file mode 100644
index 9879ebc..0000000
--- a/libosmocore/configure.in
+++ /dev/null
@@ -1,56 +0,0 @@
-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(tests,
-	[  --disable-tests Disable building test programs ],
-	[enable_tests=0], [enable_tests=1])
-AM_CONDITIONAL(ENABLE_TESTS, test "x$enable_tests" = "x1")
-
-AC_OUTPUT(
-	libosmocore.pc
-	include/osmocore/Makefile
-	include/osmocore/protocol/Makefile
-	include/Makefile
-	src/Makefile
-	tests/Makefile
-	tests/timer/Makefile
-	tests/sms/Makefile
-	Makefile)
diff --git a/libosmocore/git-version-gen b/libosmocore/git-version-gen
deleted file mode 100755
index 42cf3d2..0000000
--- a/libosmocore/git-version-gen
+++ /dev/null
@@ -1,151 +0,0 @@
-#!/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:
diff --git a/libosmocore/include/Makefile.am b/libosmocore/include/Makefile.am
deleted file mode 100644
index f0015d5..0000000
--- a/libosmocore/include/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-SUBDIRS = osmocore
diff --git a/libosmocore/include/osmocore/Makefile.am b/libosmocore/include/osmocore/Makefile.am
deleted file mode 100644
index fb4f089..0000000
--- a/libosmocore/include/osmocore/Makefile.am
+++ /dev/null
@@ -1,12 +0,0 @@
-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
-
-if ENABLE_TALLOC
-osmocore_HEADERS += talloc.h
-endif
-
-osmocoredir = $(includedir)/osmocore
-
-SUBDIRS = protocol
diff --git a/libosmocore/include/osmocore/bitvec.h b/libosmocore/include/osmocore/bitvec.h
deleted file mode 100644
index 7a26bce..0000000
--- a/libosmocore/include/osmocore/bitvec.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#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);
-
-/* 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);
-
-/* 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);
-
-
-/* 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 */
diff --git a/libosmocore/include/osmocore/comp128.h b/libosmocore/include/osmocore/comp128.h
deleted file mode 100644
index c37808f..0000000
--- a/libosmocore/include/osmocore/comp128.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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__ */
-
diff --git a/libosmocore/include/osmocore/gsm48.h b/libosmocore/include/osmocore/gsm48.h
deleted file mode 100644
index 1e96357..0000000
--- a/libosmocore/include/osmocore/gsm48.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _OSMOCORE_GSM48_H
-
-#include <osmocore/tlv.h>
-#include <osmocore/protocol/gsm_04_08.h>
-#include <osmocore/gsm48_ie.h>
-
-extern const struct tlv_definition gsm48_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);
-
-#endif
diff --git a/libosmocore/include/osmocore/gsm48_ie.h b/libosmocore/include/osmocore/gsm48_ie.h
deleted file mode 100644
index 200619a..0000000
--- a/libosmocore/include/osmocore/gsm48_ie.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#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
diff --git a/libosmocore/include/osmocore/gsm_utils.h b/libosmocore/include/osmocore/gsm_utils.h
deleted file mode 100644
index c87e967..0000000
--- a/libosmocore/include/osmocore/gsm_utils.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* 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>
-
-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.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);
-
-void generate_backtrace();
-#endif
diff --git a/libosmocore/include/osmocore/gsmtap.h b/libosmocore/include/osmocore/gsmtap.h
deleted file mode 100644
index dcd64bd..0000000
--- a/libosmocore/include/osmocore/gsmtap.h
+++ /dev/null
@@ -1,72 +0,0 @@
-#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 */
diff --git a/libosmocore/include/osmocore/linuxlist.h b/libosmocore/include/osmocore/linuxlist.h
deleted file mode 100644
index fb99c5e..0000000
--- a/libosmocore/include/osmocore/linuxlist.h
+++ /dev/null
@@ -1,360 +0,0 @@
-#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
diff --git a/libosmocore/include/osmocore/mncc.h b/libosmocore/include/osmocore/mncc.h
deleted file mode 100644
index a094bb9..0000000
--- a/libosmocore/include/osmocore/mncc.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#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
diff --git a/libosmocore/include/osmocore/msgb.h b/libosmocore/include/osmocore/msgb.h
deleted file mode 100644
index 31db719..0000000
--- a/libosmocore/include/osmocore/msgb.h
+++ /dev/null
@@ -1,175 +0,0 @@
-#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 bts_link;
-
-struct msgb {
-	struct llist_head list;
-
-	/* ptr to the physical E1 link to the BTS(s) */
-	struct gsm_bts_link *bts_link;
-
-	/* Part of which TRX logical channel we were received / transmitted */
-	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 */
-	union {
-		unsigned char *smsh;
-		unsigned char *llch;
-		unsigned char *l4h;
-	};
-
-	/* the layer 5 header, GPRS: GMM header */
-	unsigned char *gmmh;
-	uint32_t tlli;
-
-	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->smsh))
-
-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 */
diff --git a/libosmocore/include/osmocore/protocol/Makefile.am b/libosmocore/include/osmocore/protocol/Makefile.am
deleted file mode 100644
index 6d8883e..0000000
--- a/libosmocore/include/osmocore/protocol/Makefile.am
+++ /dev/null
@@ -1,3 +0,0 @@
-osmocore_proto_HEADERS = gsm_04_08.h gsm_04_11.h gsm_04_80.h gsm_08_58.h gsm_12_21.h
-
-osmocore_protodir = $(includedir)/osmocore/protocol
diff --git a/libosmocore/include/osmocore/protocol/gsm_04_08.h b/libosmocore/include/osmocore/protocol/gsm_04_08.h
deleted file mode 100644
index 801b9b5..0000000
--- a/libosmocore/include/osmocore/protocol/gsm_04_08.h
+++ /dev/null
@@ -1,743 +0,0 @@
-#ifndef PROTO_GSM_04_08_H
-#define PROTO_GSM_04_08_H
-
-#include <stdint.h>
-
-/* GSM TS 04.08  definitions */
-struct gsm_lchan;
-
-struct gsm48_classmark1 {
-	uint8_t spare:1,
-		 rev_level:2,
-		 es_ind:1,
-		 a5_1:1,
-		 pwr_lev:3;
-} __attribute__ ((packed));
-
-/* Chapter 10.5.2.5 */
-struct gsm48_chan_desc {
-	uint8_t chan_nr;
-	union {
-		struct {
-			uint8_t maio_high:4,
-				 h:1,
-				 tsc:3;
-			uint8_t hsn:6,
-				 maio_low:2;
-		} h1;
-		struct {
-			uint8_t arfcn_high:2,
-				 spare:2,
-				 h:1,
-				 tsc:3;
-			uint8_t arfcn_low;
-		} h0;
-	};
-} __attribute__ ((packed));
-
-/* Chapter 10.5.2.21aa */
-struct gsm48_multi_rate_conf {
-	uint8_t smod : 2,
-		 spare: 1,
-		 icmi : 1,
-		 nscb : 1,
-		 ver : 3;
-	uint8_t m4_75 : 1,
-		 m5_15 : 1,
-		 m5_90 : 1,
-		 m6_70 : 1,
-		 m7_40 : 1,
-		 m7_95 : 1,
-		 m10_2 : 1,
-		 m12_2 : 1;
-} __attribute__((packed));
-
-/* Chapter 10.5.2.30 */
-struct gsm48_req_ref {
-	uint8_t ra;
-	uint8_t t3_high:3,
-		 t1_:5;
-	uint8_t t2:5,
-		 t3_low:3;
-} __attribute__ ((packed));
-
-/*
- * Chapter 9.1.5/9.1.6
- *
- * For 9.1.6 the chan_desc has the meaning of 10.5.2.5a
- */
-struct gsm48_chan_mode_modify {
-	struct gsm48_chan_desc chan_desc;
-	uint8_t mode;
-} __attribute__ ((packed));
-
-enum gsm48_chan_mode {
-	GSM48_CMODE_SIGN	= 0x00,
-	GSM48_CMODE_SPEECH_V1	= 0x01,
-	GSM48_CMODE_SPEECH_EFR	= 0x21,
-	GSM48_CMODE_SPEECH_AMR	= 0x41,
-	GSM48_CMODE_DATA_14k5	= 0x0f,
-	GSM48_CMODE_DATA_12k0	= 0x03,
-	GSM48_CMODE_DATA_6k0	= 0x0b,
-	GSM48_CMODE_DATA_3k6	= 0x23,
-};
-
-/* Chapter 9.1.2 */
-struct gsm48_ass_cmd {
-	/* Semantic is from 10.5.2.5a */
-	struct gsm48_chan_desc chan_desc;
-	uint8_t power_command;
-	uint8_t data[0];
-} __attribute__((packed));
-
-/* Chapter 10.5.2.2 */
-struct gsm48_cell_desc {
-	uint8_t bcc:3,
-		 ncc:3,
-		 arfcn_hi:2;
-	uint8_t arfcn_lo;
-} __attribute__((packed));
-
-/* Chapter 9.1.15 */
-struct gsm48_ho_cmd {
-	struct gsm48_cell_desc cell_desc;
-	struct gsm48_chan_desc chan_desc;
-	uint8_t ho_ref;
-	uint8_t power_command;
-	uint8_t data[0];
-} __attribute__((packed));
-
-/* Chapter 9.1.18 */
-struct gsm48_imm_ass {
-	uint8_t l2_plen;
-	uint8_t proto_discr;
-	uint8_t msg_type;
-	uint8_t page_mode;
-	struct gsm48_chan_desc chan_desc;
-	struct gsm48_req_ref req_ref;
-	uint8_t timing_advance;
-	uint8_t mob_alloc_len;
-	uint8_t mob_alloc[0];
-} __attribute__ ((packed));
-
-/* Chapter 10.5.1.3 */
-struct gsm48_loc_area_id {
-	uint8_t digits[3];	/* BCD! */
-	uint16_t lac;
-} __attribute__ ((packed));
-
-/* Section 9.2.2 */
-struct gsm48_auth_req {
-	uint8_t key_seq:4,
-	         spare:4;
-	uint8_t rand[16];
-} __attribute__ ((packed));
-
-/* Section 9.2.15 */
-struct gsm48_loc_upd_req {
-	uint8_t type:4,
-		 key_seq:4;
-	struct gsm48_loc_area_id lai;
-	struct gsm48_classmark1 classmark1;
-	uint8_t mi_len;
-	uint8_t mi[0];
-} __attribute__ ((packed));
-
-/* Section 10.1 */
-struct gsm48_hdr {
-	uint8_t proto_discr;
-	uint8_t msg_type;
-	uint8_t data[0];
-} __attribute__ ((packed));
-
-/* Section 9.1.3x System information Type header */
-struct gsm48_system_information_type_header {
-	uint8_t l2_plen;
-	uint8_t rr_protocol_discriminator :4,
-		skip_indicator:4; 
-	uint8_t system_information;
-} __attribute__ ((packed));
-
-struct gsm48_rach_control {
-	uint8_t re :1,
-		 cell_bar :1,
-		 tx_integer :4,
-		 max_trans :2;
-	uint8_t t2;
-	uint8_t t3;
-} __attribute__ ((packed));
-
-/* Section 10.5.2.4 Cell Selection Parameters */
-struct gsm48_cell_sel_par {
-	uint8_t ms_txpwr_max_ccch:5,	/* GSM 05.08 MS-TXPWR-MAX-CCCH */
-		 cell_resel_hyst:3;	/* GSM 05.08 CELL-RESELECT-HYSTERESIS */
-	uint8_t rxlev_acc_min:6,	/* GSM 05.08 RXLEV-ACCESS-MIN */
-		 neci:1,
-		 acs:1;
-} __attribute__ ((packed));
-
-/* Section 10.5.2.11 Control Channel Description , Figure 10.5.33 */
-struct gsm48_control_channel_descr {
-	uint8_t ccch_conf :3,
-		bs_ag_blks_res :3,
-		att :1,
-		spare1 :1;
-	uint8_t bs_pa_mfrms : 3,
-		spare2 :5;
-	uint8_t t3212;
-} __attribute__ ((packed));
-
-struct gsm48_cell_options {
-	uint8_t radio_link_timeout:4,
-		 dtx:2,
-		 pwrc:1,
-		 spare:1;
-} __attribute__ ((packed));
-
-/* Section 9.2.9 CM service request */
-struct gsm48_service_request {
-	uint8_t cm_service_type : 4,
-		 cipher_key_seq  : 4;
-	/* length + 3 bytes */
-	uint32_t classmark;
-	uint8_t mi_len;
-	uint8_t mi[0];
-	/* optional priority level */
-} __attribute__ ((packed));
-
-/* Section 9.1.31 System information Type 1 */
-struct gsm48_system_information_type_1 {
-	struct gsm48_system_information_type_header header;
-	uint8_t cell_channel_description[16];
-	struct gsm48_rach_control rach_control;
-	uint8_t rest_octets[0]; /* NCH position on the CCCH */
-} __attribute__ ((packed));
-
-/* Section 9.1.32 System information Type 2 */
-struct gsm48_system_information_type_2 {
-	struct gsm48_system_information_type_header header;
-	uint8_t bcch_frequency_list[16];
-	uint8_t ncc_permitted;
-	struct gsm48_rach_control rach_control;
-} __attribute__ ((packed));
-
-/* Section 9.1.35 System information Type 3 */
-struct gsm48_system_information_type_3 {
-	struct gsm48_system_information_type_header header;
-	uint16_t cell_identity;
-	struct gsm48_loc_area_id lai;
-	struct gsm48_control_channel_descr control_channel_desc;
-	struct gsm48_cell_options cell_options;
-	struct gsm48_cell_sel_par cell_sel_par;
-	struct gsm48_rach_control rach_control;
-	uint8_t rest_octets[0];
-} __attribute__ ((packed));
-
-/* Section 9.1.36 System information Type 4 */
-struct gsm48_system_information_type_4 {
-	struct gsm48_system_information_type_header header;
-	struct gsm48_loc_area_id lai;
-	struct gsm48_cell_sel_par cell_sel_par;
-	struct gsm48_rach_control rach_control;
-	/*	optional CBCH conditional CBCH... followed by
-		mandantory SI 4 Reset Octets
-	 */
-	uint8_t data[0];
-} __attribute__ ((packed));
-
-/* Section 9.1.37 System information Type 5 */
-struct gsm48_system_information_type_5 {
-	uint8_t rr_protocol_discriminator :4,
-		skip_indicator:4; 
-	uint8_t system_information;
-	uint8_t bcch_frequency_list[16];
-} __attribute__ ((packed));
-
-/* Section 9.1.40 System information Type 6 */
-struct gsm48_system_information_type_6 {
-	uint8_t rr_protocol_discriminator :4,
-		skip_indicator:4; 
-	uint8_t system_information;
-	uint16_t cell_identity;
-	struct gsm48_loc_area_id lai;
-	struct gsm48_cell_options cell_options;
-	uint8_t ncc_permitted;
-	uint8_t rest_octets[0];
-} __attribute__ ((packed));
-
-/* Section 9.1.43a System Information type 13 */
-struct gsm48_system_information_type_13 {
-	struct gsm48_system_information_type_header header;
-	uint8_t rest_octets[0];
-} __attribute__ ((packed));
-
-/* Section 9.2.12 IMSI Detach Indication */
-struct gsm48_imsi_detach_ind {
-	struct gsm48_classmark1 classmark1;
-	uint8_t mi_len;
-	uint8_t mi[0];
-} __attribute__ ((packed));
-
-/* Section 10.2 + GSM 04.07 12.2.3.1.1 */
-#define GSM48_PDISC_GROUP_CC	0x00
-#define GSM48_PDISC_BCAST_CC	0x01
-#define GSM48_PDISC_PDSS1	0x02
-#define GSM48_PDISC_CC		0x03
-#define GSM48_PDISC_PDSS2	0x04
-#define GSM48_PDISC_MM		0x05
-#define GSM48_PDISC_RR		0x06
-#define GSM48_PDISC_MM_GPRS	0x08
-#define GSM48_PDISC_SMS		0x09
-#define GSM48_PDISC_SM_GPRS	0x0a
-#define GSM48_PDISC_NC_SS	0x0b
-#define GSM48_PDISC_LOC		0x0c
-#define GSM48_PDISC_MASK	0x0f
-#define GSM48_PDISC_USSD	0x11
-
-/* Section 10.4 */
-#define GSM48_MT_RR_INIT_REQ		0x3c
-#define GSM48_MT_RR_ADD_ASS		0x3b
-#define GSM48_MT_RR_IMM_ASS		0x3f
-#define GSM48_MT_RR_IMM_ASS_EXT		0x39
-#define GSM48_MT_RR_IMM_ASS_REJ		0x3a
-
-#define GSM48_MT_RR_CIPH_M_CMD		0x35
-#define GSM48_MT_RR_CIPH_M_COMPL	0x32
-
-#define GSM48_MT_RR_CFG_CHG_CMD		0x30
-#define GSM48_MT_RR_CFG_CHG_ACK		0x31
-#define GSM48_MT_RR_CFG_CHG_REJ		0x33
-
-#define GSM48_MT_RR_ASS_CMD		0x2e
-#define GSM48_MT_RR_ASS_COMPL		0x29
-#define GSM48_MT_RR_ASS_FAIL		0x2f
-#define GSM48_MT_RR_HANDO_CMD		0x2b
-#define GSM48_MT_RR_HANDO_COMPL		0x2c
-#define GSM48_MT_RR_HANDO_FAIL		0x28
-#define GSM48_MT_RR_HANDO_INFO		0x2d
-
-#define GSM48_MT_RR_CELL_CHG_ORDER	0x08
-#define GSM48_MT_RR_PDCH_ASS_CMD	0x23
-
-#define GSM48_MT_RR_CHAN_REL		0x0d
-#define GSM48_MT_RR_PART_REL		0x0a
-#define GSM48_MT_RR_PART_REL_COMP	0x0f
-
-#define GSM48_MT_RR_PAG_REQ_1		0x21
-#define GSM48_MT_RR_PAG_REQ_2		0x22
-#define GSM48_MT_RR_PAG_REQ_3		0x24
-#define GSM48_MT_RR_PAG_RESP		0x27
-#define GSM48_MT_RR_NOTIF_NCH		0x20
-#define GSM48_MT_RR_NOTIF_FACCH		0x25
-#define GSM48_MT_RR_NOTIF_RESP		0x26
-
-#define GSM48_MT_RR_SYSINFO_8		0x18
-#define GSM48_MT_RR_SYSINFO_1		0x19
-#define GSM48_MT_RR_SYSINFO_2		0x1a
-#define GSM48_MT_RR_SYSINFO_3		0x1b
-#define GSM48_MT_RR_SYSINFO_4		0x1c
-#define GSM48_MT_RR_SYSINFO_5		0x1d
-#define GSM48_MT_RR_SYSINFO_6		0x1e
-#define GSM48_MT_RR_SYSINFO_7		0x1f
-
-#define GSM48_MT_RR_SYSINFO_2bis	0x02
-#define GSM48_MT_RR_SYSINFO_2ter	0x03
-#define GSM48_MT_RR_SYSINFO_5bis	0x05
-#define GSM48_MT_RR_SYSINFO_5ter	0x06
-#define GSM48_MT_RR_SYSINFO_9		0x04
-#define GSM48_MT_RR_SYSINFO_13		0x00
-
-#define GSM48_MT_RR_SYSINFO_16		0x3d
-#define GSM48_MT_RR_SYSINFO_17		0x3e
-
-#define GSM48_MT_RR_CHAN_MODE_MODIF	0x10
-#define GSM48_MT_RR_STATUS		0x12
-#define GSM48_MT_RR_CHAN_MODE_MODIF_ACK	0x17
-#define GSM48_MT_RR_FREQ_REDEF		0x14
-#define GSM48_MT_RR_MEAS_REP		0x15
-#define GSM48_MT_RR_CLSM_CHG		0x16
-#define GSM48_MT_RR_CLSM_ENQ		0x13
-#define GSM48_MT_RR_EXT_MEAS_REP	0x36
-#define GSM48_MT_RR_EXT_MEAS_REP_ORD	0x37
-#define GSM48_MT_RR_GPRS_SUSP_REQ	0x34
-
-#define GSM48_MT_RR_VGCS_UPL_GRANT	0x08
-#define GSM48_MT_RR_UPLINK_RELEASE	0x0e
-#define GSM48_MT_RR_UPLINK_FREE		0x0c
-#define GSM48_MT_RR_UPLINK_BUSY		0x2a
-#define GSM48_MT_RR_TALKER_IND		0x11
-
-#define GSM48_MT_RR_APP_INFO		0x38
-
-/* Table 10.2/3GPP TS 04.08 */
-#define GSM48_MT_MM_IMSI_DETACH_IND	0x01
-#define GSM48_MT_MM_LOC_UPD_ACCEPT	0x02
-#define GSM48_MT_MM_LOC_UPD_REJECT	0x04
-#define GSM48_MT_MM_LOC_UPD_REQUEST	0x08
-
-#define GSM48_MT_MM_AUTH_REJ		0x11
-#define GSM48_MT_MM_AUTH_REQ		0x12
-#define GSM48_MT_MM_AUTH_RESP		0x14
-#define GSM48_MT_MM_ID_REQ		0x18
-#define GSM48_MT_MM_ID_RESP		0x19
-#define GSM48_MT_MM_TMSI_REALL_CMD	0x1a
-#define GSM48_MT_MM_TMSI_REALL_COMPL	0x1b
-
-#define GSM48_MT_MM_CM_SERV_ACC		0x21
-#define GSM48_MT_MM_CM_SERV_REJ		0x22
-#define GSM48_MT_MM_CM_SERV_ABORT	0x23
-#define GSM48_MT_MM_CM_SERV_REQ		0x24
-#define GSM48_MT_MM_CM_SERV_PROMPT	0x25
-#define GSM48_MT_MM_CM_REEST_REQ	0x28
-#define GSM48_MT_MM_ABORT		0x29
-
-#define GSM48_MT_MM_NULL		0x30
-#define GSM48_MT_MM_STATUS		0x31
-#define GSM48_MT_MM_INFO		0x32
-
-/* Table 10.3/3GPP TS 04.08 */
-#define GSM48_MT_CC_ALERTING		0x01
-#define GSM48_MT_CC_CALL_CONF		0x08
-#define GSM48_MT_CC_CALL_PROC		0x02
-#define GSM48_MT_CC_CONNECT		0x07
-#define GSM48_MT_CC_CONNECT_ACK		0x0f
-#define GSM48_MT_CC_EMERG_SETUP		0x0e
-#define GSM48_MT_CC_PROGRESS		0x03
-#define GSM48_MT_CC_ESTAB		0x04
-#define GSM48_MT_CC_ESTAB_CONF		0x06
-#define GSM48_MT_CC_RECALL		0x0b
-#define GSM48_MT_CC_START_CC		0x09
-#define GSM48_MT_CC_SETUP		0x05
-
-#define GSM48_MT_CC_MODIFY		0x17
-#define GSM48_MT_CC_MODIFY_COMPL	0x1f
-#define GSM48_MT_CC_MODIFY_REJECT	0x13
-#define GSM48_MT_CC_USER_INFO		0x10
-#define GSM48_MT_CC_HOLD		0x18
-#define GSM48_MT_CC_HOLD_ACK		0x19
-#define GSM48_MT_CC_HOLD_REJ		0x1a
-#define GSM48_MT_CC_RETR		0x1c
-#define GSM48_MT_CC_RETR_ACK		0x1d
-#define GSM48_MT_CC_RETR_REJ		0x1e
-
-#define GSM48_MT_CC_DISCONNECT		0x25
-#define GSM48_MT_CC_RELEASE		0x2d
-#define GSM48_MT_CC_RELEASE_COMPL	0x2a
-
-#define GSM48_MT_CC_CONG_CTRL		0x39
-#define GSM48_MT_CC_NOTIFY		0x3e
-#define GSM48_MT_CC_STATUS		0x3d
-#define GSM48_MT_CC_STATUS_ENQ		0x34
-#define GSM48_MT_CC_START_DTMF		0x35
-#define GSM48_MT_CC_STOP_DTMF		0x31
-#define GSM48_MT_CC_STOP_DTMF_ACK	0x32
-#define GSM48_MT_CC_START_DTMF_ACK	0x36
-#define GSM48_MT_CC_START_DTMF_REJ	0x37
-#define GSM48_MT_CC_FACILITY		0x3a
-
-/* FIXME: Table 10.4 / 10.4a (GPRS) */
-
-/* Section 10.5.2.26, Table 10.5.64 */
-#define GSM48_PM_MASK		0x03
-#define GSM48_PM_NORMAL		0x00
-#define GSM48_PM_EXTENDED	0x01
-#define GSM48_PM_REORG		0x02
-#define GSM48_PM_SAME		0x03
-
-/* Chapter 10.5.3.5 / Table 10.5.93 */
-#define GSM48_LUPD_NORMAL	0x0
-#define GSM48_LUPD_PERIODIC	0x1
-#define GSM48_LUPD_IMSI_ATT	0x2
-#define GSM48_LUPD_RESERVED	0x3
-
-/* Table 10.5.4 */
-#define GSM_MI_TYPE_MASK	0x07
-#define GSM_MI_TYPE_NONE	0x00
-#define GSM_MI_TYPE_IMSI	0x01
-#define GSM_MI_TYPE_IMEI	0x02
-#define GSM_MI_TYPE_IMEISV	0x03
-#define GSM_MI_TYPE_TMSI	0x04
-#define GSM_MI_ODD		0x08
-
-#define GSM48_IE_MUL_RATE_CFG	0x03	/* 10.5.2.21aa */
-#define GSM48_IE_MOBILE_ID	0x17
-#define GSM48_IE_NAME_LONG	0x43	/* 10.5.3.5a */
-#define GSM48_IE_NAME_SHORT	0x45	/* 10.5.3.5a */
-#define GSM48_IE_UTC		0x46	/* 10.5.3.8 */
-#define GSM48_IE_NET_TIME_TZ	0x47	/* 10.5.3.9 */
-#define GSM48_IE_LSA_IDENT	0x48	/* 10.5.3.11 */
-
-#define GSM48_IE_BEARER_CAP	0x04	/* 10.5.4.5 */
-#define GSM48_IE_CAUSE		0x08	/* 10.5.4.11 */
-#define GSM48_IE_CC_CAP		0x15	/* 10.5.4.5a */
-#define GSM48_IE_ALERT		0x19	/* 10.5.4.26 */
-#define GSM48_IE_FACILITY	0x1c	/* 10.5.4.15 */
-#define GSM48_IE_PROGR_IND	0x1e	/* 10.5.4.21 */
-#define GSM48_IE_AUX_STATUS	0x24	/* 10.5.4.4 */
-#define GSM48_IE_NOTIFY		0x27	/* 10.5.4.20 */
-#define GSM48_IE_KPD_FACILITY	0x2c	/* 10.5.4.17 */
-#define GSM48_IE_SIGNAL		0x34	/* 10.5.4.23 */
-#define GSM48_IE_CONN_BCD	0x4c	/* 10.5.4.13 */
-#define GSM48_IE_CONN_SUB	0x4d	/* 10.5.4.14 */
-#define GSM48_IE_CALLING_BCD	0x5c	/* 10.5.4.9 */
-#define GSM48_IE_CALLING_SUB	0x5d	/* 10.5.4.10 */
-#define GSM48_IE_CALLED_BCD	0x5e	/* 10.5.4.7 */
-#define GSM48_IE_CALLED_SUB	0x6d	/* 10.5.4.8 */
-#define GSM48_IE_REDIR_BCD	0x74	/* 10.5.4.21a */
-#define GSM48_IE_REDIR_SUB	0x75	/* 10.5.4.21b */
-#define GSM48_IE_LOWL_COMPAT	0x7c	/* 10.5.4.18 */
-#define GSM48_IE_HIGHL_COMPAT	0x7d	/* 10.5.4.16 */
-#define GSM48_IE_USER_USER	0x7e	/* 10.5.4.25 */
-#define GSM48_IE_SS_VERS	0x7f	/* 10.5.4.24 */
-#define GSM48_IE_MORE_DATA	0xa0	/* 10.5.4.19 */
-#define GSM48_IE_CLIR_SUPP	0xa1	/* 10.5.4.11a */
-#define GSM48_IE_CLIR_INVOC	0xa2	/* 10.5.4.11b */
-#define GSM48_IE_REV_C_SETUP	0xa3	/* 10.5.4.22a */
-#define GSM48_IE_REPEAT_CIR	0xd1	/* 10.5.4.22 */
-#define GSM48_IE_REPEAT_SEQ	0xd3	/* 10.5.4.22 */
-
-/* Section 10.5.4.11 / Table 10.5.122 */
-#define GSM48_CAUSE_CS_GSM	0x60
-
-/* Section 9.1.2 / Table 9.3 */
-#define GSM48_IE_FRQLIST_AFTER	0x05
-#define GSM48_IE_CELL_CH_DESC	0x62
-#define GSM48_IE_MSLOT_DESC	0x10
-#define GSM48_IE_CHANMODE_1	0x63
-#define GSM48_IE_CHANMODE_2	0x11
-#define GSM48_IE_CHANMODE_3	0x13
-#define GSM48_IE_CHANMODE_4	0x14
-#define GSM48_IE_CHANMODE_5	0x15
-#define GSM48_IE_CHANMODE_6	0x16
-#define GSM48_IE_CHANMODE_7	0x17
-#define GSM48_IE_CHANMODE_8	0x18
-#define GSM48_IE_CHANDESC_2	0x64
-/* FIXME */
-
-/* Section 10.5.4.23 / Table 10.5.130 */
-enum gsm48_signal_val {
-	GSM48_SIGNAL_DIALTONE	= 0x00,
-	GSM48_SIGNAL_RINGBACK	= 0x01,
-	GSM48_SIGNAL_INTERCEPT	= 0x02,
-	GSM48_SIGNAL_NET_CONG	= 0x03,
-	GSM48_SIGNAL_BUSY	= 0x04,
-	GSM48_SIGNAL_CONFIRM	= 0x05,
-	GSM48_SIGNAL_ANSWER	= 0x06,
-	GSM48_SIGNAL_CALL_WAIT	= 0x07,
-	GSM48_SIGNAL_OFF_HOOK	= 0x08,
-	GSM48_SIGNAL_OFF	= 0x3f,
-	GSM48_SIGNAL_ALERT_OFF	= 0x4f,
-};
-
-enum gsm48_cause_loc {
-	GSM48_CAUSE_LOC_USER		= 0x00,
-	GSM48_CAUSE_LOC_PRN_S_LU	= 0x01,
-	GSM48_CAUSE_LOC_PUN_S_LU	= 0x02,
-	GSM48_CAUSE_LOC_TRANS_NET	= 0x03,
-	GSM48_CAUSE_LOC_PUN_S_RU	= 0x04,
-	GSM48_CAUSE_LOC_PRN_S_RU	= 0x05,
-	/* not defined */
-	GSM48_CAUSE_LOC_INN_NET		= 0x07,
-	GSM48_CAUSE_LOC_NET_BEYOND	= 0x0a,
-};
-
-/* Section 10.5.2.31 RR Cause / Table 10.5.70 */
-enum gsm48_rr_cause {
-	GSM48_RR_CAUSE_NORMAL		= 0x00,
-	GSM48_RR_CAUSE_ABNORMAL_UNSPEC	= 0x01,
-	GSM48_RR_CAUSE_ABNORMAL_UNACCT	= 0x02,
-	GSM48_RR_CAUSE_ABNORMAL_TIMER	= 0x03,
-	GSM48_RR_CAUSE_ABNORMAL_NOACT	= 0x04,
-	GSM48_RR_CAUSE_PREMPTIVE_REL	= 0x05,
-	GSM48_RR_CAUSE_HNDOVER_IMP	= 0x06,
-	GSM48_RR_CAUSE_CHAN_MODE_UNACCT	= 0x07,
-	GSM48_RR_CAUSE_FREQ_NOT_IMPL	= 0x08,
-	GSM48_RR_CAUSE_CALL_CLEARED	= 0x41,
-	GSM48_RR_CAUSE_SEMANT_INCORR	= 0x5f,
-	GSM48_RR_CAUSE_INVALID_MAND_INF = 0x60,
-	GSM48_RR_CAUSE_MSG_TYPE_N	= 0x61,
-	GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT= 0x62,
-	GSM48_RR_CAUSE_COND_IE_ERROR	= 0x64,
-	GSM48_RR_CAUSE_NO_CELL_ALLOC_A	= 0x65,
-	GSM48_RR_CAUSE_PROT_ERROR_UNSPC = 0x6f,
-};
-
-/* Section 10.5.4.11 CC Cause / Table 10.5.123 */
-enum gsm48_cc_cause {
-	GSM48_CC_CAUSE_UNASSIGNED_NR	= 1,
-	GSM48_CC_CAUSE_NO_ROUTE		= 3,
-	GSM48_CC_CAUSE_CHAN_UNACCEPT	= 6,
-	GSM48_CC_CAUSE_OP_DET_BARRING	= 8,
-	GSM48_CC_CAUSE_NORM_CALL_CLEAR	= 16,
-	GSM48_CC_CAUSE_USER_BUSY	= 17,
-	GSM48_CC_CAUSE_USER_NOTRESPOND	= 18,
-	GSM48_CC_CAUSE_USER_ALERTING_NA	= 19,
-	GSM48_CC_CAUSE_CALL_REJECTED	= 21,
-	GSM48_CC_CAUSE_NUMBER_CHANGED	= 22,
-	GSM48_CC_CAUSE_PRE_EMPTION	= 25,
-	GSM48_CC_CAUSE_NONSE_USER_CLR	= 26,
-	GSM48_CC_CAUSE_DEST_OOO		= 27,
-	GSM48_CC_CAUSE_INV_NR_FORMAT	= 28,
-	GSM48_CC_CAUSE_FACILITY_REJ	= 29,
-	GSM48_CC_CAUSE_RESP_STATUS_INQ	= 30,
-	GSM48_CC_CAUSE_NORMAL_UNSPEC	= 31,
-	GSM48_CC_CAUSE_NO_CIRCUIT_CHAN	= 34,
-	GSM48_CC_CAUSE_NETWORK_OOO	= 38,
-	GSM48_CC_CAUSE_TEMP_FAILURE	= 41,
-	GSM48_CC_CAUSE_SWITCH_CONG	= 42,
-	GSM48_CC_CAUSE_ACC_INF_DISCARD	= 43,
-	GSM48_CC_CAUSE_REQ_CHAN_UNAVAIL	= 44,
-	GSM48_CC_CAUSE_RESOURCE_UNAVAIL	= 47,
-	GSM48_CC_CAUSE_QOS_UNAVAIL	= 49,
-	GSM48_CC_CAUSE_REQ_FAC_NOT_SUBSC= 50,
-	GSM48_CC_CAUSE_INC_BARRED_CUG	= 55,
-	GSM48_CC_CAUSE_BEARER_CAP_UNAUTH= 57,
-	GSM48_CC_CAUSE_BEARER_CA_UNAVAIL= 58,
-	GSM48_CC_CAUSE_SERV_OPT_UNAVAIL	= 63,
-	GSM48_CC_CAUSE_BEARERSERV_UNIMPL= 65,
-	GSM48_CC_CAUSE_ACM_GE_ACM_MAX	= 68,
-	GSM48_CC_CAUSE_REQ_FAC_NOTIMPL	= 69,
-	GSM48_CC_CAUSE_RESTR_BCAP_AVAIL	= 70,
-	GSM48_CC_CAUSE_SERV_OPT_UNIMPL	= 79,
-	GSM48_CC_CAUSE_INVAL_TRANS_ID	= 81,
-	GSM48_CC_CAUSE_USER_NOT_IN_CUG	= 87,
-	GSM48_CC_CAUSE_INCOMPAT_DEST	= 88,
-	GSM48_CC_CAUSE_INVAL_TRANS_NET	= 91,
-	GSM48_CC_CAUSE_SEMANTIC_INCORR	= 95,
-	GSM48_CC_CAUSE_INVAL_MAND_INF	= 96,
-	GSM48_CC_CAUSE_MSGTYPE_NOTEXIST	= 97,
-	GSM48_CC_CAUSE_MSGTYPE_INCOMPAT	= 98,
-	GSM48_CC_CAUSE_IE_NOTEXIST	= 99,
-	GSM48_CC_CAUSE_COND_IE_ERR	= 100,
-	GSM48_CC_CAUSE_MSG_INCOMP_STATE	= 101,
-	GSM48_CC_CAUSE_RECOVERY_TIMER	= 102,
-	GSM48_CC_CAUSE_PROTO_ERR	= 111,
-	GSM48_CC_CAUSE_INTERWORKING	= 127,
-};
-
-/* Annex G, GSM specific cause values for mobility management */
-enum gsm48_reject_value {
-	GSM48_REJECT_IMSI_UNKNOWN_IN_HLR	= 2,
-	GSM48_REJECT_ILLEGAL_MS			= 3,
-	GSM48_REJECT_IMSI_UNKNOWN_IN_VLR	= 4,
-	GSM48_REJECT_IMEI_NOT_ACCEPTED		= 5,
-	GSM48_REJECT_ILLEGAL_ME			= 6,
-	GSM48_REJECT_PLMN_NOT_ALLOWED		= 11,
-	GSM48_REJECT_LOC_NOT_ALLOWED		= 12,
-	GSM48_REJECT_ROAMING_NOT_ALLOWED	= 13,
-	GSM48_REJECT_NETWORK_FAILURE		= 17,
-	GSM48_REJECT_CONGESTION			= 22,
-	GSM48_REJECT_SRV_OPT_NOT_SUPPORTED	= 32,
-	GSM48_REJECT_RQD_SRV_OPT_NOT_SUPPORTED	= 33,
-	GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER	= 34,
-	GSM48_REJECT_CALL_CAN_NOT_BE_IDENTIFIED	= 38,
-	GSM48_REJECT_INCORRECT_MESSAGE		= 95,
-	GSM48_REJECT_INVALID_MANDANTORY_INF	= 96,
-	GSM48_REJECT_MSG_TYPE_NOT_IMPLEMENTED	= 97,
-	GSM48_REJECT_MSG_TYPE_NOT_COMPATIBLE	= 98,
-	GSM48_REJECT_INF_ELEME_NOT_IMPLEMENTED	= 99,
-	GSM48_REJECT_CONDTIONAL_IE_ERROR	= 100,
-	GSM48_REJECT_MSG_NOT_COMPATIBLE		= 101,
-	GSM48_REJECT_PROTOCOL_ERROR		= 111,
-
-	/* according to G.6 Additional cause codes for GMM */
-	GSM48_REJECT_GPRS_NOT_ALLOWED		= 7,
-	GSM48_REJECT_SERVICES_NOT_ALLOWED	= 8,
-	GSM48_REJECT_MS_IDENTITY_NOT_DERVIVABLE = 9,
-	GSM48_REJECT_IMPLICITLY_DETACHED	= 10,
-	GSM48_REJECT_GPRS_NOT_ALLOWED_IN_PLMN	= 14,
-	GSM48_REJECT_MSC_TMP_NOT_REACHABLE	= 16,
-};
-
-enum chreq_type {
-	CHREQ_T_EMERG_CALL,
-	CHREQ_T_CALL_REEST_TCH_F,
-	CHREQ_T_CALL_REEST_TCH_H,
-	CHREQ_T_CALL_REEST_TCH_H_DBL,
-	CHREQ_T_SDCCH,
-	CHREQ_T_TCH_F,
-	CHREQ_T_VOICE_CALL_TCH_H,
-	CHREQ_T_DATA_CALL_TCH_H,
-	CHREQ_T_LOCATION_UPD,
-	CHREQ_T_PAG_R_ANY_NECI0,
-	CHREQ_T_PAG_R_ANY_NECI1,
-	CHREQ_T_PAG_R_TCH_F,
-	CHREQ_T_PAG_R_TCH_FH,
-	CHREQ_T_LMU,
-	CHREQ_T_RESERVED_SDCCH,
-	CHREQ_T_RESERVED_IGNORE,
-};
-
-/* Chapter 11.3 */
-#define GSM48_T301	180, 0
-#define GSM48_T303	30, 0
-#define GSM48_T305	30, 0
-#define GSM48_T306	30, 0
-#define GSM48_T308	10, 0
-#define GSM48_T310	180, 0
-#define GSM48_T313	30, 0
-#define GSM48_T323	30, 0
-#define GSM48_T331	30, 0
-#define GSM48_T333	30, 0
-#define GSM48_T334	25, 0 /* min 15 */
-#define GSM48_T338	30, 0
-
-/* Chapter 5.1.2.2 */
-#define	GSM_CSTATE_NULL			0
-#define	GSM_CSTATE_INITIATED		1
-#define	GSM_CSTATE_MO_CALL_PROC		3
-#define	GSM_CSTATE_CALL_DELIVERED	4
-#define	GSM_CSTATE_CALL_PRESENT		6
-#define	GSM_CSTATE_CALL_RECEIVED	7
-#define	GSM_CSTATE_CONNECT_REQUEST	8
-#define	GSM_CSTATE_MO_TERM_CALL_CONF	9
-#define	GSM_CSTATE_ACTIVE		10
-#define	GSM_CSTATE_DISCONNECT_REQ	12
-#define	GSM_CSTATE_DISCONNECT_IND	12
-#define	GSM_CSTATE_RELEASE_REQ		19
-#define	GSM_CSTATE_MO_ORIG_MODIFY	26
-#define	GSM_CSTATE_MO_TERM_MODIFY	27
-#define	GSM_CSTATE_CONNECT_IND		28
-
-#define SBIT(a) (1 << a)
-#define ALL_STATES 0xffffffff
-
-/* Table 10.5.3/3GPP TS 04.08: Location Area Identification information element */
-#define GSM_LAC_RESERVED_DETACHED       0x0
-#define GSM_LAC_RESERVED_ALL_BTS        0xfffe
-
-/* GSM 04.08 Bearer Capability: Information Transfer Capability */
-enum gsm48_bcap_itcap {
-	GSM48_BCAP_ITCAP_SPEECH		= 0,
-	GSM48_BCAP_ITCAP_UNR_DIG_INF	= 1,
-	GSM48_BCAP_ITCAP_3k1_AUDIO	= 2,
-	GSM48_BCAP_ITCAP_FAX_G3		= 3,
-	GSM48_BCAP_ITCAP_OTHER		= 5,
-	GSM48_BCAP_ITCAP_RESERVED	= 7,
-};
-
-/* GSM 04.08 Bearer Capability: Transfer Mode */
-enum gsm48_bcap_tmod {
-	GSM48_BCAP_TMOD_CIRCUIT		= 0,
-	GSM48_BCAP_TMOD_PACKET		= 1,
-};
-
-/* GSM 04.08 Bearer Capability: Coding Standard */
-enum gsm48_bcap_coding {
-	GSM48_BCAP_CODING_GSM_STD	= 0,
-};
-
-/* GSM 04.08 Bearer Capability: Radio Channel Requirements */
-enum gsm48_bcap_rrq {
-	GSM48_BCAP_RRQ_FR_ONLY	= 1,
-	GSM48_BCAP_RRQ_DUAL_HR	= 2,
-	GSM48_BCAP_RRQ_DUAL_FR	= 3,
-};
-
-
-#define GSM48_TMSI_LEN	5
-#define GSM48_MID_TMSI_LEN	(GSM48_TMSI_LEN + 2)
-#define GSM48_MI_SIZE 32
-
-
-#endif /* PROTO_GSM_04_08_H */
diff --git a/libosmocore/include/osmocore/protocol/gsm_04_11.h b/libosmocore/include/osmocore/protocol/gsm_04_11.h
deleted file mode 100644
index c6a2b19..0000000
--- a/libosmocore/include/osmocore/protocol/gsm_04_11.h
+++ /dev/null
@@ -1,188 +0,0 @@
-#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 */
diff --git a/libosmocore/include/osmocore/protocol/gsm_04_80.h b/libosmocore/include/osmocore/protocol/gsm_04_80.h
deleted file mode 100644
index fa5c945..0000000
--- a/libosmocore/include/osmocore/protocol/gsm_04_80.h
+++ /dev/null
@@ -1,126 +0,0 @@
-#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 */
diff --git a/libosmocore/include/osmocore/protocol/gsm_08_58.h b/libosmocore/include/osmocore/protocol/gsm_08_58.h
deleted file mode 100644
index ca9398f..0000000
--- a/libosmocore/include/osmocore/protocol/gsm_08_58.h
+++ /dev/null
@@ -1,512 +0,0 @@
-#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 */
-
-	/* 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 */
diff --git a/libosmocore/include/osmocore/protocol/gsm_12_21.h b/libosmocore/include/osmocore/protocol/gsm_12_21.h
deleted file mode 100644
index 9cae45d..0000000
--- a/libosmocore/include/osmocore/protocol/gsm_12_21.h
+++ /dev/null
@@ -1,713 +0,0 @@
-#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 */
diff --git a/libosmocore/include/osmocore/rsl.h b/libosmocore/include/osmocore/rsl.h
deleted file mode 100644
index 99b90d6..0000000
--- a/libosmocore/include/osmocore/rsl.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#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 */
diff --git a/libosmocore/include/osmocore/rxlev_stat.h b/libosmocore/include/osmocore/rxlev_stat.h
deleted file mode 100644
index 415509d..0000000
--- a/libosmocore/include/osmocore/rxlev_stat.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#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 */
diff --git a/libosmocore/include/osmocore/select.h b/libosmocore/include/osmocore/select.h
deleted file mode 100644
index 2d8b3ec..0000000
--- a/libosmocore/include/osmocore/select.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#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 */
diff --git a/libosmocore/include/osmocore/signal.h b/libosmocore/include/osmocore/signal.h
deleted file mode 100644
index 02d83d2..0000000
--- a/libosmocore/include/osmocore/signal.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#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 */
diff --git a/libosmocore/include/osmocore/statistics.h b/libosmocore/include/osmocore/statistics.h
deleted file mode 100644
index 1d56054..0000000
--- a/libosmocore/include/osmocore/statistics.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#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 */
diff --git a/libosmocore/include/osmocore/talloc.h b/libosmocore/include/osmocore/talloc.h
deleted file mode 100644
index f7f7643..0000000
--- a/libosmocore/include/osmocore/talloc.h
+++ /dev/null
@@ -1,192 +0,0 @@
-#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
diff --git a/libosmocore/include/osmocore/timer.h b/libosmocore/include/osmocore/timer.h
deleted file mode 100644
index fee888b..0000000
--- a/libosmocore/include/osmocore/timer.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * (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
diff --git a/libosmocore/include/osmocore/tlv.h b/libosmocore/include/osmocore/tlv.h
deleted file mode 100644
index c733dbc..0000000
--- a/libosmocore/include/osmocore/tlv.h
+++ /dev/null
@@ -1,244 +0,0 @@
-#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,
-};
-
-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 */
diff --git a/libosmocore/include/osmocore/utils.h b/libosmocore/include/osmocore/utils.h
deleted file mode 100644
index 51c6f03..0000000
--- a/libosmocore/include/osmocore/utils.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#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
diff --git a/libosmocore/include/osmocore/write_queue.h b/libosmocore/include/osmocore/write_queue.h
deleted file mode 100644
index c84000c..0000000
--- a/libosmocore/include/osmocore/write_queue.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* 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);
-};
-
-void write_queue_init(struct write_queue *queue, int max_length);
-int write_queue_enqueue(struct write_queue *queue, struct msgb *data);
-int write_queue_bfd_cb(struct bsc_fd *fd, unsigned int what);
-
-#endif
diff --git a/libosmocore/libosmocore.pc.in b/libosmocore/libosmocore.pc.in
deleted file mode 100644
index 7c29869..0000000
--- a/libosmocore/libosmocore.pc.in
+++ /dev/null
@@ -1,11 +0,0 @@
-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}/
-
diff --git a/libosmocore/m4/DUMMY b/libosmocore/m4/DUMMY
deleted file mode 100644
index fda557a..0000000
--- a/libosmocore/m4/DUMMY
+++ /dev/null
@@ -1 +0,0 @@
-Dummply placeholder.
diff --git a/libosmocore/src/Makefile.am b/libosmocore/src/Makefile.am
deleted file mode 100644
index f0effa2..0000000
--- a/libosmocore/src/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-# 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
-
-if ENABLE_TALLOC
-libosmocore_la_SOURCES += talloc.c
-endif
diff --git a/libosmocore/src/bitvec.c b/libosmocore/src/bitvec.c
deleted file mode 100644
index eb83ac6..0000000
--- a/libosmocore/src/bitvec.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/* 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;
-}
-
-/* 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;
-}
-
-/* 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;
-}
-
-/* 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;
-}
diff --git a/libosmocore/src/comp128.c b/libosmocore/src/comp128.c
deleted file mode 100644
index 5d5680c..0000000
--- a/libosmocore/src/comp128.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * 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;
-}
-
diff --git a/libosmocore/src/gsm48.c b/libosmocore/src/gsm48.c
deleted file mode 100644
index 5761c67..0000000
--- a/libosmocore/src/gsm48.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/* 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 */
-	},
-};
-
-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",
-	"illegal state 2",
-	"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 0
-	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);
-#endif
-
-	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];
-}
diff --git a/libosmocore/src/gsm48_ie.c b/libosmocore/src/gsm48_ie.c
deleted file mode 100644
index 4ca5fb8..0000000
--- a/libosmocore/src/gsm48_ie.c
+++ /dev/null
@@ -1,659 +0,0 @@
-/* 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) 2008-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;
-}
-
diff --git a/libosmocore/src/gsm_utils.c b/libosmocore/src/gsm_utils.c
deleted file mode 100644
index 593dd5c..0000000
--- a/libosmocore/src/gsm_utils.c
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * (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 "GSM450";
-	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));
-}
diff --git a/libosmocore/src/msgb.c b/libosmocore/src/msgb.c
deleted file mode 100644
index 60af373..0000000
--- a/libosmocore/src/msgb.c
+++ /dev/null
@@ -1,89 +0,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 <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->bts_link = NULL;
-	msg->trx = NULL;
-	msg->lchan = NULL;
-	msg->l2h = NULL;
-	msg->l3h = NULL;
-	msg->smsh = NULL;
-}
diff --git a/libosmocore/src/rsl.c b/libosmocore/src/rsl.c
deleted file mode 100644
index c002d33..0000000
--- a/libosmocore/src/rsl.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/* 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;
-}
diff --git a/libosmocore/src/rxlev_stat.c b/libosmocore/src/rxlev_stat.c
deleted file mode 100644
index 1bfd679..0000000
--- a/libosmocore/src/rxlev_stat.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/* 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");
-	}
-}
diff --git a/libosmocore/src/select.c b/libosmocore/src/select.c
deleted file mode 100644
index 9517778..0000000
--- a/libosmocore/src/select.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/* 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 */
-		if (unregistered_count > 1)
-			goto restart;
-	}
-	return work;
-}
-
-#endif /* _HAVE_SYS_SELECT_H */
diff --git a/libosmocore/src/signal.c b/libosmocore/src/signal.c
deleted file mode 100644
index c7ca86c..0000000
--- a/libosmocore/src/signal.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/* 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);
-	}
-}
diff --git a/libosmocore/src/statistics.c b/libosmocore/src/statistics.c
deleted file mode 100644
index 34e6a40..0000000
--- a/libosmocore/src/statistics.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/* 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;
-}
-
diff --git a/libosmocore/src/talloc.c b/libosmocore/src/talloc.c
deleted file mode 100644
index 98c2ee0..0000000
--- a/libosmocore/src/talloc.c
+++ /dev/null
@@ -1,1805 +0,0 @@
-/* 
-   Samba Unix SMB/CIFS implementation.
-
-   Samba trivial allocation library - new interface
-
-   NOTE: Please read talloc_guide.txt for full documentation
-
-   Copyright (C) Andrew Tridgell 2004
-   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/>.
-*/
-
-/*
-  inspired by http://swapped.cc/halloc/
-*/
-
-#ifdef _SAMBA_BUILD_
-#include "version.h"
-#if (SAMBA_VERSION_MAJOR<4)
-#include "includes.h"
-/* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file
- * we trust ourselves... */
-#ifdef malloc
-#undef malloc
-#endif
-#ifdef realloc
-#undef realloc
-#endif
-#define _TALLOC_SAMBA3
-#endif /* (SAMBA_VERSION_MAJOR<4) */
-#endif /* _SAMBA_BUILD_ */
-
-#ifndef _TALLOC_SAMBA3
-//#include "replace.h"
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdbool.h>
-#define __USE_GNU
-#include <string.h>
-#undef __USE_GNU
-#include <osmocore/talloc.h>
-#define MIN(x,y) ((x) < (y) ? (x) : (y))
-#endif /* not _TALLOC_SAMBA3 */
-
-/* use this to force every realloc to change the pointer, to stress test
-   code that might not cope */
-#define ALWAYS_REALLOC 0
-
-
-#define MAX_TALLOC_SIZE 0x10000000
-#define TALLOC_MAGIC 0xe814ec70
-#define TALLOC_FLAG_FREE 0x01
-#define TALLOC_FLAG_LOOP 0x02
-#define TALLOC_FLAG_POOL 0x04		/* This is a talloc pool */
-#define TALLOC_FLAG_POOLMEM 0x08	/* This is allocated in a pool */
-#define TALLOC_MAGIC_REFERENCE ((const char *)1)
-
-/* by default we abort when given a bad pointer (such as when talloc_free() is called 
-   on a pointer that came from malloc() */
-#ifndef TALLOC_ABORT
-#define TALLOC_ABORT(reason) abort()
-#endif
-
-#ifndef discard_const_p
-#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
-# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
-#else
-# define discard_const_p(type, ptr) ((type *)(ptr))
-#endif
-#endif
-
-/* these macros gain us a few percent of speed on gcc */
-#if (__GNUC__ >= 3)
-/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
-   as its first argument */
-#ifndef likely
-#define likely(x)   __builtin_expect(!!(x), 1)
-#endif
-#ifndef unlikely
-#define unlikely(x) __builtin_expect(!!(x), 0)
-#endif
-#else
-#ifndef likely
-#define likely(x) (x)
-#endif
-#ifndef unlikely
-#define unlikely(x) (x)
-#endif
-#endif
-
-#ifdef __APPLE__
-/* taken from http://insanecoding.blogspot.com/2007/03/methods-for-safe-string-handling.html */
-size_t strnlen(const char *s, size_t n)
-{
-  const char *p = (const char *)memchr(s, 0, n);
-  return(p ? p-s : n);
-}
-#endif
-
-/* this null_context is only used if talloc_enable_leak_report() or
-   talloc_enable_leak_report_full() is called, otherwise it remains
-   NULL
-*/
-static void *null_context;
-static void *autofree_context;
-
-struct talloc_reference_handle {
-	struct talloc_reference_handle *next, *prev;
-	void *ptr;
-};
-
-typedef int (*talloc_destructor_t)(void *);
-
-struct talloc_chunk {
-	struct talloc_chunk *next, *prev;
-	struct talloc_chunk *parent, *child;
-	struct talloc_reference_handle *refs;
-	talloc_destructor_t destructor;
-	const char *name;
-	size_t size;
-	unsigned flags;
-
-	/*
-	 * "pool" has dual use:
-	 *
-	 * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool"
-	 * marks the end of the currently allocated area.
-	 *
-	 * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool"
-	 * is a pointer to the struct talloc_chunk of the pool that it was
-	 * allocated from. This way children can quickly find the pool to chew
-	 * from.
-	 */
-	void *pool;
-};
-
-/* 16 byte alignment seems to keep everyone happy */
-#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
-#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
-
-static void (*talloc_abort_fn)(const char *reason);
-
-void talloc_set_abort_fn(void (*abort_fn)(const char *reason))
-{
-	talloc_abort_fn = abort_fn;
-}
-
-static void talloc_abort(const char *reason)
-{
-	if (!talloc_abort_fn) {
-		TALLOC_ABORT(reason);
-	}
-
-	talloc_abort_fn(reason);
-}
-
-static void talloc_abort_double_free(void)
-{
-	talloc_abort("Bad talloc magic value - double free");
-}
-
-static void talloc_abort_unknown_value(void)
-{
-	talloc_abort("Bad talloc magic value - unknown value");
-}
-
-/* panic if we get a bad magic value */
-static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
-{
-	const char *pp = (const char *)ptr;
-	struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
-	if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) { 
-		if (tc->flags & TALLOC_FLAG_FREE) {
-			talloc_abort_double_free();
-		} else {
-			talloc_abort_unknown_value();
-		}
-	}
-	return tc;
-}
-
-/* hook into the front of the list */
-#define _TLIST_ADD(list, p) \
-do { \
-        if (!(list)) { \
-		(list) = (p); \
-		(p)->next = (p)->prev = NULL; \
-	} else { \
-		(list)->prev = (p); \
-		(p)->next = (list); \
-		(p)->prev = NULL; \
-		(list) = (p); \
-	}\
-} while (0)
-
-/* remove an element from a list - element doesn't have to be in list. */
-#define _TLIST_REMOVE(list, p) \
-do { \
-	if ((p) == (list)) { \
-		(list) = (p)->next; \
-		if (list) (list)->prev = NULL; \
-	} else { \
-		if ((p)->prev) (p)->prev->next = (p)->next; \
-		if ((p)->next) (p)->next->prev = (p)->prev; \
-	} \
-	if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
-} while (0)
-
-
-/*
-  return the parent chunk of a pointer
-*/
-static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
-{
-	struct talloc_chunk *tc;
-
-	if (unlikely(ptr == NULL)) {
-		return NULL;
-	}
-
-	tc = talloc_chunk_from_ptr(ptr);
-	while (tc->prev) tc=tc->prev;
-
-	return tc->parent;
-}
-
-void *talloc_parent(const void *ptr)
-{
-	struct talloc_chunk *tc = talloc_parent_chunk(ptr);
-	return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
-}
-
-/*
-  find parents name
-*/
-const char *talloc_parent_name(const void *ptr)
-{
-	struct talloc_chunk *tc = talloc_parent_chunk(ptr);
-	return tc? tc->name : NULL;
-}
-
-/*
-  A pool carries an in-pool object count count in the first 16 bytes.
-  bytes. This is done to support talloc_steal() to a parent outside of the
-  pool. The count includes the pool itself, so a talloc_free() on a pool will
-  only destroy the pool if the count has dropped to zero. A talloc_free() of a
-  pool member will reduce the count, and eventually also call free(3) on the
-  pool memory.
-
-  The object count is not put into "struct talloc_chunk" because it is only
-  relevant for talloc pools and the alignment to 16 bytes would increase the
-  memory footprint of each talloc chunk by those 16 bytes.
-*/
-
-#define TALLOC_POOL_HDR_SIZE 16
-
-static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc)
-{
-	return (unsigned int *)((char *)tc + sizeof(struct talloc_chunk));
-}
-
-/*
-  Allocate from a pool
-*/
-
-static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
-					      size_t size)
-{
-	struct talloc_chunk *pool_ctx = NULL;
-	size_t space_left;
-	struct talloc_chunk *result;
-	size_t chunk_size;
-
-	if (parent == NULL) {
-		return NULL;
-	}
-
-	if (parent->flags & TALLOC_FLAG_POOL) {
-		pool_ctx = parent;
-	}
-	else if (parent->flags & TALLOC_FLAG_POOLMEM) {
-		pool_ctx = (struct talloc_chunk *)parent->pool;
-	}
-
-	if (pool_ctx == NULL) {
-		return NULL;
-	}
-
-	space_left = ((char *)pool_ctx + TC_HDR_SIZE + pool_ctx->size)
-		- ((char *)pool_ctx->pool);
-
-	/*
-	 * Align size to 16 bytes
-	 */
-	chunk_size = ((size + 15) & ~15);
-
-	if (space_left < chunk_size) {
-		return NULL;
-	}
-
-	result = (struct talloc_chunk *)pool_ctx->pool;
-
-#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
-	VALGRIND_MAKE_MEM_UNDEFINED(result, size);
-#endif
-
-	pool_ctx->pool = (void *)((char *)result + chunk_size);
-
-	result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM;
-	result->pool = pool_ctx;
-
-	*talloc_pool_objectcount(pool_ctx) += 1;
-
-	return result;
-}
-
-/* 
-   Allocate a bit of memory as a child of an existing pointer
-*/
-static inline void *__talloc(const void *context, size_t size)
-{
-	struct talloc_chunk *tc = NULL;
-
-	if (unlikely(context == NULL)) {
-		context = null_context;
-	}
-
-	if (unlikely(size >= MAX_TALLOC_SIZE)) {
-		return NULL;
-	}
-
-	if (context != NULL) {
-		tc = talloc_alloc_pool(talloc_chunk_from_ptr(context),
-				       TC_HDR_SIZE+size);
-	}
-
-	if (tc == NULL) {
-		tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
-		if (unlikely(tc == NULL)) return NULL;
-		tc->flags = TALLOC_MAGIC;
-		tc->pool  = NULL;
-	}
-
-	tc->size = size;
-	tc->destructor = NULL;
-	tc->child = NULL;
-	tc->name = NULL;
-	tc->refs = NULL;
-
-	if (likely(context)) {
-		struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
-
-		if (parent->child) {
-			parent->child->parent = NULL;
-			tc->next = parent->child;
-			tc->next->prev = tc;
-		} else {
-			tc->next = NULL;
-		}
-		tc->parent = parent;
-		tc->prev = NULL;
-		parent->child = tc;
-	} else {
-		tc->next = tc->prev = tc->parent = NULL;
-	}
-
-	return TC_PTR_FROM_CHUNK(tc);
-}
-
-/*
- * Create a talloc pool
- */
-
-void *talloc_pool(const void *context, size_t size)
-{
-	void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE);
-	struct talloc_chunk *tc;
-
-	if (unlikely(result == NULL)) {
-		return NULL;
-	}
-
-	tc = talloc_chunk_from_ptr(result);
-
-	tc->flags |= TALLOC_FLAG_POOL;
-	tc->pool = (char *)result + TALLOC_POOL_HDR_SIZE;
-
-	*talloc_pool_objectcount(tc) = 1;
-
-#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
-	VALGRIND_MAKE_MEM_NOACCESS(tc->pool, size);
-#endif
-
-	return result;
-}
-
-/*
-  setup a destructor to be called on free of a pointer
-  the destructor should return 0 on success, or -1 on failure.
-  if the destructor fails then the free is failed, and the memory can
-  be continued to be used
-*/
-void _talloc_set_destructor(const void *ptr, int (*destructor)(void *))
-{
-	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
-	tc->destructor = destructor;
-}
-
-/*
-  increase the reference count on a piece of memory. 
-*/
-int talloc_increase_ref_count(const void *ptr)
-{
-	if (unlikely(!talloc_reference(null_context, ptr))) {
-		return -1;
-	}
-	return 0;
-}
-
-/*
-  helper for talloc_reference()
-
-  this is referenced by a function pointer and should not be inline
-*/
-static int talloc_reference_destructor(struct talloc_reference_handle *handle)
-{
-	struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
-	_TLIST_REMOVE(ptr_tc->refs, handle);
-	return 0;
-}
-
-/*
-   more efficient way to add a name to a pointer - the name must point to a 
-   true string constant
-*/
-static inline void _talloc_set_name_const(const void *ptr, const char *name)
-{
-	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
-	tc->name = name;
-}
-
-/*
-  internal talloc_named_const()
-*/
-static inline void *_talloc_named_const(const void *context, size_t size, const char *name)
-{
-	void *ptr;
-
-	ptr = __talloc(context, size);
-	if (unlikely(ptr == NULL)) {
-		return NULL;
-	}
-
-	_talloc_set_name_const(ptr, name);
-
-	return ptr;
-}
-
-/*
-  make a secondary reference to a pointer, hanging off the given context.
-  the pointer remains valid until both the original caller and this given
-  context are freed.
-  
-  the major use for this is when two different structures need to reference the 
-  same underlying data, and you want to be able to free the two instances separately,
-  and in either order
-*/
-void *_talloc_reference(const void *context, const void *ptr)
-{
-	struct talloc_chunk *tc;
-	struct talloc_reference_handle *handle;
-	if (unlikely(ptr == NULL)) return NULL;
-
-	tc = talloc_chunk_from_ptr(ptr);
-	handle = (struct talloc_reference_handle *)_talloc_named_const(context,
-						   sizeof(struct talloc_reference_handle),
-						   TALLOC_MAGIC_REFERENCE);
-	if (unlikely(handle == NULL)) return NULL;
-
-	/* note that we hang the destructor off the handle, not the
-	   main context as that allows the caller to still setup their
-	   own destructor on the context if they want to */
-	talloc_set_destructor(handle, talloc_reference_destructor);
-	handle->ptr = discard_const_p(void, ptr);
-	_TLIST_ADD(tc->refs, handle);
-	return handle->ptr;
-}
-
-
-/* 
-   internal talloc_free call
-*/
-static inline int _talloc_free(void *ptr)
-{
-	struct talloc_chunk *tc;
-
-	if (unlikely(ptr == NULL)) {
-		return -1;
-	}
-
-	tc = talloc_chunk_from_ptr(ptr);
-
-	if (unlikely(tc->refs)) {
-		int is_child;
-		/* check this is a reference from a child or grantchild
-		 * back to it's parent or grantparent
-		 *
-		 * in that case we need to remove the reference and
-		 * call another instance of talloc_free() on the current
-		 * pointer.
-		 */
-		is_child = talloc_is_parent(tc->refs, ptr);
-		_talloc_free(tc->refs);
-		if (is_child) {
-			return _talloc_free(ptr);
-		}
-		return -1;
-	}
-
-	if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) {
-		/* we have a free loop - stop looping */
-		return 0;
-	}
-
-	if (unlikely(tc->destructor)) {
-		talloc_destructor_t d = tc->destructor;
-		if (d == (talloc_destructor_t)-1) {
-			return -1;
-		}
-		tc->destructor = (talloc_destructor_t)-1;
-		if (d(ptr) == -1) {
-			tc->destructor = d;
-			return -1;
-		}
-		tc->destructor = NULL;
-	}
-
-	if (tc->parent) {
-		_TLIST_REMOVE(tc->parent->child, tc);
-		if (tc->parent->child) {
-			tc->parent->child->parent = tc->parent;
-		}
-	} else {
-		if (tc->prev) tc->prev->next = tc->next;
-		if (tc->next) tc->next->prev = tc->prev;
-	}
-
-	tc->flags |= TALLOC_FLAG_LOOP;
-
-	while (tc->child) {
-		/* we need to work out who will own an abandoned child
-		   if it cannot be freed. In priority order, the first
-		   choice is owner of any remaining reference to this
-		   pointer, the second choice is our parent, and the
-		   final choice is the null context. */
-		void *child = TC_PTR_FROM_CHUNK(tc->child);
-		const void *new_parent = null_context;
-		if (unlikely(tc->child->refs)) {
-			struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
-			if (p) new_parent = TC_PTR_FROM_CHUNK(p);
-		}
-		if (unlikely(_talloc_free(child) == -1)) {
-			if (new_parent == null_context) {
-				struct talloc_chunk *p = talloc_parent_chunk(ptr);
-				if (p) new_parent = TC_PTR_FROM_CHUNK(p);
-			}
-			talloc_steal(new_parent, child);
-		}
-	}
-
-	tc->flags |= TALLOC_FLAG_FREE;
-
-	if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) {
-		struct talloc_chunk *pool;
-		unsigned int *pool_object_count;
-
-		pool = (tc->flags & TALLOC_FLAG_POOL)
-			? tc : (struct talloc_chunk *)tc->pool;
-
-		pool_object_count = talloc_pool_objectcount(pool);
-
-		if (*pool_object_count == 0) {
-			talloc_abort("Pool object count zero!");
-		}
-
-		*pool_object_count -= 1;
-
-		if (*pool_object_count == 0) {
-			free(pool);
-		}
-	}
-	else {
-		free(tc);
-	}
-	return 0;
-}
-
-/* 
-   move a lump of memory from one talloc context to another return the
-   ptr on success, or NULL if it could not be transferred.
-   passing NULL as ptr will always return NULL with no side effects.
-*/
-void *_talloc_steal(const void *new_ctx, const void *ptr)
-{
-	struct talloc_chunk *tc, *new_tc;
-
-	if (unlikely(!ptr)) {
-		return NULL;
-	}
-
-	if (unlikely(new_ctx == NULL)) {
-		new_ctx = null_context;
-	}
-
-	tc = talloc_chunk_from_ptr(ptr);
-
-	if (unlikely(new_ctx == NULL)) {
-		if (tc->parent) {
-			_TLIST_REMOVE(tc->parent->child, tc);
-			if (tc->parent->child) {
-				tc->parent->child->parent = tc->parent;
-			}
-		} else {
-			if (tc->prev) tc->prev->next = tc->next;
-			if (tc->next) tc->next->prev = tc->prev;
-		}
-		
-		tc->parent = tc->next = tc->prev = NULL;
-		return discard_const_p(void, ptr);
-	}
-
-	new_tc = talloc_chunk_from_ptr(new_ctx);
-
-	if (unlikely(tc == new_tc || tc->parent == new_tc)) {
-		return discard_const_p(void, ptr);
-	}
-
-	if (tc->parent) {
-		_TLIST_REMOVE(tc->parent->child, tc);
-		if (tc->parent->child) {
-			tc->parent->child->parent = tc->parent;
-		}
-	} else {
-		if (tc->prev) tc->prev->next = tc->next;
-		if (tc->next) tc->next->prev = tc->prev;
-	}
-
-	tc->parent = new_tc;
-	if (new_tc->child) new_tc->child->parent = NULL;
-	_TLIST_ADD(new_tc->child, tc);
-
-	return discard_const_p(void, ptr);
-}
-
-
-
-/*
-  remove a secondary reference to a pointer. This undo's what
-  talloc_reference() has done. The context and pointer arguments
-  must match those given to a talloc_reference()
-*/
-static inline int talloc_unreference(const void *context, const void *ptr)
-{
-	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
-	struct talloc_reference_handle *h;
-
-	if (unlikely(context == NULL)) {
-		context = null_context;
-	}
-
-	for (h=tc->refs;h;h=h->next) {
-		struct talloc_chunk *p = talloc_parent_chunk(h);
-		if (p == NULL) {
-			if (context == NULL) break;
-		} else if (TC_PTR_FROM_CHUNK(p) == context) {
-			break;
-		}
-	}
-	if (h == NULL) {
-		return -1;
-	}
-
-	return _talloc_free(h);
-}
-
-/*
-  remove a specific parent context from a pointer. This is a more
-  controlled varient of talloc_free()
-*/
-int talloc_unlink(const void *context, void *ptr)
-{
-	struct talloc_chunk *tc_p, *new_p;
-	void *new_parent;
-
-	if (ptr == NULL) {
-		return -1;
-	}
-
-	if (context == NULL) {
-		context = null_context;
-	}
-
-	if (talloc_unreference(context, ptr) == 0) {
-		return 0;
-	}
-
-	if (context == NULL) {
-		if (talloc_parent_chunk(ptr) != NULL) {
-			return -1;
-		}
-	} else {
-		if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
-			return -1;
-		}
-	}
-	
-	tc_p = talloc_chunk_from_ptr(ptr);
-
-	if (tc_p->refs == NULL) {
-		return _talloc_free(ptr);
-	}
-
-	new_p = talloc_parent_chunk(tc_p->refs);
-	if (new_p) {
-		new_parent = TC_PTR_FROM_CHUNK(new_p);
-	} else {
-		new_parent = NULL;
-	}
-
-	if (talloc_unreference(new_parent, ptr) != 0) {
-		return -1;
-	}
-
-	talloc_steal(new_parent, ptr);
-
-	return 0;
-}
-
-/*
-  add a name to an existing pointer - va_list version
-*/
-static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
-
-static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
-{
-	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
-	tc->name = talloc_vasprintf(ptr, fmt, ap);
-	if (likely(tc->name)) {
-		_talloc_set_name_const(tc->name, ".name");
-	}
-	return tc->name;
-}
-
-/*
-  add a name to an existing pointer
-*/
-const char *talloc_set_name(const void *ptr, const char *fmt, ...)
-{
-	const char *name;
-	va_list ap;
-	va_start(ap, fmt);
-	name = talloc_set_name_v(ptr, fmt, ap);
-	va_end(ap);
-	return name;
-}
-
-
-/*
-  create a named talloc pointer. Any talloc pointer can be named, and
-  talloc_named() operates just like talloc() except that it allows you
-  to name the pointer.
-*/
-void *talloc_named(const void *context, size_t size, const char *fmt, ...)
-{
-	va_list ap;
-	void *ptr;
-	const char *name;
-
-	ptr = __talloc(context, size);
-	if (unlikely(ptr == NULL)) return NULL;
-
-	va_start(ap, fmt);
-	name = talloc_set_name_v(ptr, fmt, ap);
-	va_end(ap);
-
-	if (unlikely(name == NULL)) {
-		_talloc_free(ptr);
-		return NULL;
-	}
-
-	return ptr;
-}
-
-/*
-  return the name of a talloc ptr, or "UNNAMED"
-*/
-const char *talloc_get_name(const void *ptr)
-{
-	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
-	if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) {
-		return ".reference";
-	}
-	if (likely(tc->name)) {
-		return tc->name;
-	}
-	return "UNNAMED";
-}
-
-
-/*
-  check if a pointer has the given name. If it does, return the pointer,
-  otherwise return NULL
-*/
-void *talloc_check_name(const void *ptr, const char *name)
-{
-	const char *pname;
-	if (unlikely(ptr == NULL)) return NULL;
-	pname = talloc_get_name(ptr);
-	if (likely(pname == name || strcmp(pname, name) == 0)) {
-		return discard_const_p(void, ptr);
-	}
-	return NULL;
-}
-
-static void talloc_abort_type_missmatch(const char *location,
-					const char *name,
-					const char *expected)
-{
-	const char *reason;
-
-	reason = talloc_asprintf(NULL,
-				 "%s: Type mismatch: name[%s] expected[%s]",
-				 location,
-				 name?name:"NULL",
-				 expected);
-	if (!reason) {
-		reason = "Type mismatch";
-	}
-
-	talloc_abort(reason);
-}
-
-void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location)
-{
-	const char *pname;
-
-	if (unlikely(ptr == NULL)) {
-		talloc_abort_type_missmatch(location, NULL, name);
-		return NULL;
-	}
-
-	pname = talloc_get_name(ptr);
-	if (likely(pname == name || strcmp(pname, name) == 0)) {
-		return discard_const_p(void, ptr);
-	}
-
-	talloc_abort_type_missmatch(location, pname, name);
-	return NULL;
-}
-
-/*
-  this is for compatibility with older versions of talloc
-*/
-void *talloc_init(const char *fmt, ...)
-{
-	va_list ap;
-	void *ptr;
-	const char *name;
-
-	/*
-	 * samba3 expects talloc_report_depth_cb(NULL, ...)
-	 * reports all talloc'ed memory, so we need to enable
-	 * null_tracking
-	 */
-	talloc_enable_null_tracking();
-
-	ptr = __talloc(NULL, 0);
-	if (unlikely(ptr == NULL)) return NULL;
-
-	va_start(ap, fmt);
-	name = talloc_set_name_v(ptr, fmt, ap);
-	va_end(ap);
-
-	if (unlikely(name == NULL)) {
-		_talloc_free(ptr);
-		return NULL;
-	}
-
-	return ptr;
-}
-
-/*
-  this is a replacement for the Samba3 talloc_destroy_pool functionality. It
-  should probably not be used in new code. It's in here to keep the talloc
-  code consistent across Samba 3 and 4.
-*/
-void talloc_free_children(void *ptr)
-{
-	struct talloc_chunk *tc;
-
-	if (unlikely(ptr == NULL)) {
-		return;
-	}
-
-	tc = talloc_chunk_from_ptr(ptr);
-
-	while (tc->child) {
-		/* we need to work out who will own an abandoned child
-		   if it cannot be freed. In priority order, the first
-		   choice is owner of any remaining reference to this
-		   pointer, the second choice is our parent, and the
-		   final choice is the null context. */
-		void *child = TC_PTR_FROM_CHUNK(tc->child);
-		const void *new_parent = null_context;
-		if (unlikely(tc->child->refs)) {
-			struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
-			if (p) new_parent = TC_PTR_FROM_CHUNK(p);
-		}
-		if (unlikely(_talloc_free(child) == -1)) {
-			if (new_parent == null_context) {
-				struct talloc_chunk *p = talloc_parent_chunk(ptr);
-				if (p) new_parent = TC_PTR_FROM_CHUNK(p);
-			}
-			talloc_steal(new_parent, child);
-		}
-	}
-
-	if ((tc->flags & TALLOC_FLAG_POOL)
-	    && (*talloc_pool_objectcount(tc) == 1)) {
-		tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE);
-#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
-		VALGRIND_MAKE_MEM_NOACCESS(
-			tc->pool, tc->size - TALLOC_POOL_HDR_SIZE);
-#endif
-	}
-}
-
-/* 
-   Allocate a bit of memory as a child of an existing pointer
-*/
-void *_talloc(const void *context, size_t size)
-{
-	return __talloc(context, size);
-}
-
-/*
-  externally callable talloc_set_name_const()
-*/
-void talloc_set_name_const(const void *ptr, const char *name)
-{
-	_talloc_set_name_const(ptr, name);
-}
-
-/*
-  create a named talloc pointer. Any talloc pointer can be named, and
-  talloc_named() operates just like talloc() except that it allows you
-  to name the pointer.
-*/
-void *talloc_named_const(const void *context, size_t size, const char *name)
-{
-	return _talloc_named_const(context, size, name);
-}
-
-/* 
-   free a talloc pointer. This also frees all child pointers of this 
-   pointer recursively
-
-   return 0 if the memory is actually freed, otherwise -1. The memory
-   will not be freed if the ref_count is > 1 or the destructor (if
-   any) returns non-zero
-*/
-int talloc_free(void *ptr)
-{
-	return _talloc_free(ptr);
-}
-
-
-
-/*
-  A talloc version of realloc. The context argument is only used if
-  ptr is NULL
-*/
-void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
-{
-	struct talloc_chunk *tc;
-	void *new_ptr;
-	bool malloced = false;
-
-	/* size zero is equivalent to free() */
-	if (unlikely(size == 0)) {
-		_talloc_free(ptr);
-		return NULL;
-	}
-
-	if (unlikely(size >= MAX_TALLOC_SIZE)) {
-		return NULL;
-	}
-
-	/* realloc(NULL) is equivalent to malloc() */
-	if (ptr == NULL) {
-		return _talloc_named_const(context, size, name);
-	}
-
-	tc = talloc_chunk_from_ptr(ptr);
-
-	/* don't allow realloc on referenced pointers */
-	if (unlikely(tc->refs)) {
-		return NULL;
-	}
-
-	/* don't let anybody try to realloc a talloc_pool */
-	if (unlikely(tc->flags & TALLOC_FLAG_POOL)) {
-		return NULL;
-	}
-
-	/* don't shrink if we have less than 1k to gain */
-	if ((size < tc->size) && ((tc->size - size) < 1024)) {
-		tc->size = size;
-		return ptr;
-	}
-
-	/* by resetting magic we catch users of the old memory */
-	tc->flags |= TALLOC_FLAG_FREE;
-
-#if ALWAYS_REALLOC
-	new_ptr = malloc(size + TC_HDR_SIZE);
-	if (new_ptr) {
-		memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
-		free(tc);
-	}
-#else
-	if (tc->flags & TALLOC_FLAG_POOLMEM) {
-
-		new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE);
-		*talloc_pool_objectcount((struct talloc_chunk *)
-					 (tc->pool)) -= 1;
-
-		if (new_ptr == NULL) {
-			new_ptr = malloc(TC_HDR_SIZE+size);
-			malloced = true;
-		}
-
-		if (new_ptr) {
-			memcpy(new_ptr, tc, MIN(tc->size,size) + TC_HDR_SIZE);
-		}
-	}
-	else {
-		new_ptr = realloc(tc, size + TC_HDR_SIZE);
-	}
-#endif
-	if (unlikely(!new_ptr)) {	
-		tc->flags &= ~TALLOC_FLAG_FREE; 
-		return NULL; 
-	}
-
-	tc = (struct talloc_chunk *)new_ptr;
-	tc->flags &= ~TALLOC_FLAG_FREE;
-	if (malloced) {
-		tc->flags &= ~TALLOC_FLAG_POOLMEM;
-	}
-	if (tc->parent) {
-		tc->parent->child = tc;
-	}
-	if (tc->child) {
-		tc->child->parent = tc;
-	}
-
-	if (tc->prev) {
-		tc->prev->next = tc;
-	}
-	if (tc->next) {
-		tc->next->prev = tc;
-	}
-
-	tc->size = size;
-	_talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
-
-	return TC_PTR_FROM_CHUNK(tc);
-}
-
-/*
-  a wrapper around talloc_steal() for situations where you are moving a pointer
-  between two structures, and want the old pointer to be set to NULL
-*/
-void *_talloc_move(const void *new_ctx, const void *_pptr)
-{
-	const void **pptr = discard_const_p(const void *,_pptr);
-	void *ret = _talloc_steal(new_ctx, *pptr);
-	(*pptr) = NULL;
-	return ret;
-}
-
-/*
-  return the total size of a talloc pool (subtree)
-*/
-size_t talloc_total_size(const void *ptr)
-{
-	size_t total = 0;
-	struct talloc_chunk *c, *tc;
-
-	if (ptr == NULL) {
-		ptr = null_context;
-	}
-	if (ptr == NULL) {
-		return 0;
-	}
-
-	tc = talloc_chunk_from_ptr(ptr);
-
-	if (tc->flags & TALLOC_FLAG_LOOP) {
-		return 0;
-	}
-
-	tc->flags |= TALLOC_FLAG_LOOP;
-
-	total = tc->size;
-	for (c=tc->child;c;c=c->next) {
-		total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
-	}
-
-	tc->flags &= ~TALLOC_FLAG_LOOP;
-
-	return total;
-}
-
-/*
-  return the total number of blocks in a talloc pool (subtree)
-*/
-size_t talloc_total_blocks(const void *ptr)
-{
-	size_t total = 0;
-	struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
-
-	if (tc->flags & TALLOC_FLAG_LOOP) {
-		return 0;
-	}
-
-	tc->flags |= TALLOC_FLAG_LOOP;
-
-	total++;
-	for (c=tc->child;c;c=c->next) {
-		total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
-	}
-
-	tc->flags &= ~TALLOC_FLAG_LOOP;
-
-	return total;
-}
-
-/*
-  return the number of external references to a pointer
-*/
-size_t talloc_reference_count(const void *ptr)
-{
-	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
-	struct talloc_reference_handle *h;
-	size_t ret = 0;
-
-	for (h=tc->refs;h;h=h->next) {
-		ret++;
-	}
-	return ret;
-}
-
-/*
-  report on memory usage by all children of a pointer, giving a full tree view
-*/
-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)
-{
-	struct talloc_chunk *c, *tc;
-
-	if (ptr == NULL) {
-		ptr = null_context;
-	}
-	if (ptr == NULL) return;
-
-	tc = talloc_chunk_from_ptr(ptr);
-
-	if (tc->flags & TALLOC_FLAG_LOOP) {
-		return;
-	}
-
-	callback(ptr, depth, max_depth, 0, private_data);
-
-	if (max_depth >= 0 && depth >= max_depth) {
-		return;
-	}
-
-	tc->flags |= TALLOC_FLAG_LOOP;
-	for (c=tc->child;c;c=c->next) {
-		if (c->name == TALLOC_MAGIC_REFERENCE) {
-			struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c);
-			callback(h->ptr, depth + 1, max_depth, 1, private_data);
-		} else {
-			talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data);
-		}
-	}
-	tc->flags &= ~TALLOC_FLAG_LOOP;
-}
-
-static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f)
-{
-	const char *name = talloc_get_name(ptr);
-	FILE *f = (FILE *)_f;
-
-	if (is_ref) {
-		fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
-		return;
-	}
-
-	if (depth == 0) {
-		fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n", 
-			(max_depth < 0 ? "full " :""), name,
-			(unsigned long)talloc_total_size(ptr),
-			(unsigned long)talloc_total_blocks(ptr));
-		return;
-	}
-
-	fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n", 
-		depth*4, "",
-		name,
-		(unsigned long)talloc_total_size(ptr),
-		(unsigned long)talloc_total_blocks(ptr),
-		(int)talloc_reference_count(ptr), ptr);
-
-#if 0
-	fprintf(f, "content: ");
-	if (talloc_total_size(ptr)) {
-		int tot = talloc_total_size(ptr);
-		int i;
-
-		for (i = 0; i < tot; i++) {
-			if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) {
-				fprintf(f, "%c", ((char *)ptr)[i]);
-			} else {
-				fprintf(f, "~%02x", ((char *)ptr)[i]);
-			}
-		}
-	}
-	fprintf(f, "\n");
-#endif
-}
-
-/*
-  report on memory usage by all children of a pointer, giving a full tree view
-*/
-void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f)
-{
-	talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f);
-	fflush(f);
-}
-
-/*
-  report on memory usage by all children of a pointer, giving a full tree view
-*/
-void talloc_report_full(const void *ptr, FILE *f)
-{
-	talloc_report_depth_file(ptr, 0, -1, f);
-}
-
-/*
-  report on memory usage by all children of a pointer
-*/
-void talloc_report(const void *ptr, FILE *f)
-{
-	talloc_report_depth_file(ptr, 0, 1, f);
-}
-
-/*
-  report on any memory hanging off the null context
-*/
-static void talloc_report_null(void)
-{
-	if (talloc_total_size(null_context) != 0) {
-		talloc_report(null_context, stderr);
-	}
-}
-
-/*
-  report on any memory hanging off the null context
-*/
-static void talloc_report_null_full(void)
-{
-	if (talloc_total_size(null_context) != 0) {
-		talloc_report_full(null_context, stderr);
-	}
-}
-
-/*
-  enable tracking of the NULL context
-*/
-void talloc_enable_null_tracking(void)
-{
-	if (null_context == NULL) {
-		null_context = _talloc_named_const(NULL, 0, "null_context");
-	}
-}
-
-/*
-  disable tracking of the NULL context
-*/
-void talloc_disable_null_tracking(void)
-{
-	_talloc_free(null_context);
-	null_context = NULL;
-}
-
-/*
-  enable leak reporting on exit
-*/
-void talloc_enable_leak_report(void)
-{
-	talloc_enable_null_tracking();
-	atexit(talloc_report_null);
-}
-
-/*
-  enable full leak reporting on exit
-*/
-void talloc_enable_leak_report_full(void)
-{
-	talloc_enable_null_tracking();
-	atexit(talloc_report_null_full);
-}
-
-/* 
-   talloc and zero memory. 
-*/
-void *_talloc_zero(const void *ctx, size_t size, const char *name)
-{
-	void *p = _talloc_named_const(ctx, size, name);
-
-	if (p) {
-		memset(p, '\0', size);
-	}
-
-	return p;
-}
-
-/*
-  memdup with a talloc. 
-*/
-void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
-{
-	void *newp = _talloc_named_const(t, size, name);
-
-	if (likely(newp)) {
-		memcpy(newp, p, size);
-	}
-
-	return newp;
-}
-
-static inline char *__talloc_strlendup(const void *t, const char *p, size_t len)
-{
-	char *ret;
-
-	ret = (char *)__talloc(t, len + 1);
-	if (unlikely(!ret)) return NULL;
-
-	memcpy(ret, p, len);
-	ret[len] = 0;
-
-	_talloc_set_name_const(ret, ret);
-	return ret;
-}
-
-/*
-  strdup with a talloc
-*/
-char *talloc_strdup(const void *t, const char *p)
-{
-	if (unlikely(!p)) return NULL;
-	return __talloc_strlendup(t, p, strlen(p));
-}
-
-/*
-  strndup with a talloc
-*/
-char *talloc_strndup(const void *t, const char *p, size_t n)
-{
-	if (unlikely(!p)) return NULL;
-	return __talloc_strlendup(t, p, strnlen(p, n));
-}
-
-static inline char *__talloc_strlendup_append(char *s, size_t slen,
-					      const char *a, size_t alen)
-{
-	char *ret;
-
-	ret = talloc_realloc(NULL, s, char, slen + alen + 1);
-	if (unlikely(!ret)) return NULL;
-
-	/* append the string and the trailing \0 */
-	memcpy(&ret[slen], a, alen);
-	ret[slen+alen] = 0;
-
-	_talloc_set_name_const(ret, ret);
-	return ret;
-}
-
-/*
- * Appends at the end of the string.
- */
-char *talloc_strdup_append(char *s, const char *a)
-{
-	if (unlikely(!s)) {
-		return talloc_strdup(NULL, a);
-	}
-
-	if (unlikely(!a)) {
-		return s;
-	}
-
-	return __talloc_strlendup_append(s, strlen(s), a, strlen(a));
-}
-
-/*
- * Appends at the end of the talloc'ed buffer,
- * not the end of the string.
- */
-char *talloc_strdup_append_buffer(char *s, const char *a)
-{
-	size_t slen;
-
-	if (unlikely(!s)) {
-		return talloc_strdup(NULL, a);
-	}
-
-	if (unlikely(!a)) {
-		return s;
-	}
-
-	slen = talloc_get_size(s);
-	if (likely(slen > 0)) {
-		slen--;
-	}
-
-	return __talloc_strlendup_append(s, slen, a, strlen(a));
-}
-
-/*
- * Appends at the end of the string.
- */
-char *talloc_strndup_append(char *s, const char *a, size_t n)
-{
-	if (unlikely(!s)) {
-		return talloc_strdup(NULL, a);
-	}
-
-	if (unlikely(!a)) {
-		return s;
-	}
-
-	return __talloc_strlendup_append(s, strlen(s), a, strnlen(a, n));
-}
-
-/*
- * Appends at the end of the talloc'ed buffer,
- * not the end of the string.
- */
-char *talloc_strndup_append_buffer(char *s, const char *a, size_t n)
-{
-	size_t slen;
-
-	if (unlikely(!s)) {
-		return talloc_strdup(NULL, a);
-	}
-
-	if (unlikely(!a)) {
-		return s;
-	}
-
-	slen = talloc_get_size(s);
-	if (likely(slen > 0)) {
-		slen--;
-	}
-
-	return __talloc_strlendup_append(s, slen, a, strnlen(a, n));
-}
-
-#ifndef HAVE_VA_COPY
-#ifdef HAVE___VA_COPY
-#define va_copy(dest, src) __va_copy(dest, src)
-#else
-#define va_copy(dest, src) (dest) = (src)
-#endif
-#endif
-
-char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
-{
-	int len;
-	char *ret;
-	va_list ap2;
-	char c;
-
-	/* this call looks strange, but it makes it work on older solaris boxes */
-	va_copy(ap2, ap);
-	len = vsnprintf(&c, 1, fmt, ap2);
-	va_end(ap2);
-	if (unlikely(len < 0)) {
-		return NULL;
-	}
-
-	ret = (char *)__talloc(t, len+1);
-	if (unlikely(!ret)) return NULL;
-
-	va_copy(ap2, ap);
-	vsnprintf(ret, len+1, fmt, ap2);
-	va_end(ap2);
-
-	_talloc_set_name_const(ret, ret);
-	return ret;
-}
-
-
-/*
-  Perform string formatting, and return a pointer to newly allocated
-  memory holding the result, inside a memory pool.
- */
-char *talloc_asprintf(const void *t, const char *fmt, ...)
-{
-	va_list ap;
-	char *ret;
-
-	va_start(ap, fmt);
-	ret = talloc_vasprintf(t, fmt, ap);
-	va_end(ap);
-	return ret;
-}
-
-static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
-						 const char *fmt, va_list ap)
-						 PRINTF_ATTRIBUTE(3,0);
-
-static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
-						 const char *fmt, va_list ap)
-{
-	ssize_t alen;
-	va_list ap2;
-	char c;
-
-	va_copy(ap2, ap);
-	alen = vsnprintf(&c, 1, fmt, ap2);
-	va_end(ap2);
-
-	if (alen <= 0) {
-		/* Either the vsnprintf failed or the format resulted in
-		 * no characters being formatted. In the former case, we
-		 * ought to return NULL, in the latter we ought to return
-		 * the original string. Most current callers of this
-		 * function expect it to never return NULL.
-		 */
-		return s;
-	}
-
-	s = talloc_realloc(NULL, s, char, slen + alen + 1);
-	if (!s) return NULL;
-
-	va_copy(ap2, ap);
-	vsnprintf(s + slen, alen + 1, fmt, ap2);
-	va_end(ap2);
-
-	_talloc_set_name_const(s, s);
-	return s;
-}
-
-/**
- * Realloc @p s to append the formatted result of @p fmt and @p ap,
- * and return @p s, which may have moved.  Good for gradually
- * accumulating output into a string buffer. Appends at the end
- * of the string.
- **/
-char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
-{
-	if (unlikely(!s)) {
-		return talloc_vasprintf(NULL, fmt, ap);
-	}
-
-	return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap);
-}
-
-/**
- * Realloc @p s to append the formatted result of @p fmt and @p ap,
- * and return @p s, which may have moved. Always appends at the
- * end of the talloc'ed buffer, not the end of the string.
- **/
-char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap)
-{
-	size_t slen;
-
-	if (unlikely(!s)) {
-		return talloc_vasprintf(NULL, fmt, ap);
-	}
-
-	slen = talloc_get_size(s);
-	if (likely(slen > 0)) {
-		slen--;
-	}
-
-	return __talloc_vaslenprintf_append(s, slen, fmt, ap);
-}
-
-/*
-  Realloc @p s to append the formatted result of @p fmt and return @p
-  s, which may have moved.  Good for gradually accumulating output
-  into a string buffer.
- */
-char *talloc_asprintf_append(char *s, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	s = talloc_vasprintf_append(s, fmt, ap);
-	va_end(ap);
-	return s;
-}
-
-/*
-  Realloc @p s to append the formatted result of @p fmt and return @p
-  s, which may have moved.  Good for gradually accumulating output
-  into a buffer.
- */
-char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	s = talloc_vasprintf_append_buffer(s, fmt, ap);
-	va_end(ap);
-	return s;
-}
-
-/*
-  alloc an array, checking for integer overflow in the array size
-*/
-void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
-{
-	if (count >= MAX_TALLOC_SIZE/el_size) {
-		return NULL;
-	}
-	return _talloc_named_const(ctx, el_size * count, name);
-}
-
-/*
-  alloc an zero array, checking for integer overflow in the array size
-*/
-void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
-{
-	if (count >= MAX_TALLOC_SIZE/el_size) {
-		return NULL;
-	}
-	return _talloc_zero(ctx, el_size * count, name);
-}
-
-/*
-  realloc an array, checking for integer overflow in the array size
-*/
-void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
-{
-	if (count >= MAX_TALLOC_SIZE/el_size) {
-		return NULL;
-	}
-	return _talloc_realloc(ctx, ptr, el_size * count, name);
-}
-
-/*
-  a function version of talloc_realloc(), so it can be passed as a function pointer
-  to libraries that want a realloc function (a realloc function encapsulates
-  all the basic capabilities of an allocation library, which is why this is useful)
-*/
-void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
-{
-	return _talloc_realloc(context, ptr, size, NULL);
-}
-
-
-static int talloc_autofree_destructor(void *ptr)
-{
-	autofree_context = NULL;
-	return 0;
-}
-
-static void talloc_autofree(void)
-{
-	_talloc_free(autofree_context);
-}
-
-/*
-  return a context which will be auto-freed on exit
-  this is useful for reducing the noise in leak reports
-*/
-void *talloc_autofree_context(void)
-{
-	if (autofree_context == NULL) {
-		autofree_context = _talloc_named_const(NULL, 0, "autofree_context");
-		talloc_set_destructor(autofree_context, talloc_autofree_destructor);
-		atexit(talloc_autofree);
-	}
-	return autofree_context;
-}
-
-size_t talloc_get_size(const void *context)
-{
-	struct talloc_chunk *tc;
-
-	if (context == NULL)
-		return 0;
-
-	tc = talloc_chunk_from_ptr(context);
-
-	return tc->size;
-}
-
-/*
-  find a parent of this context that has the given name, if any
-*/
-void *talloc_find_parent_byname(const void *context, const char *name)
-{
-	struct talloc_chunk *tc;
-
-	if (context == NULL) {
-		return NULL;
-	}
-
-	tc = talloc_chunk_from_ptr(context);
-	while (tc) {
-		if (tc->name && strcmp(tc->name, name) == 0) {
-			return TC_PTR_FROM_CHUNK(tc);
-		}
-		while (tc && tc->prev) tc = tc->prev;
-		if (tc) {
-			tc = tc->parent;
-		}
-	}
-	return NULL;
-}
-
-/*
-  show the parentage of a context
-*/
-void talloc_show_parents(const void *context, FILE *file)
-{
-	struct talloc_chunk *tc;
-
-	if (context == NULL) {
-		fprintf(file, "talloc no parents for NULL\n");
-		return;
-	}
-
-	tc = talloc_chunk_from_ptr(context);
-	fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
-	while (tc) {
-		fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
-		while (tc && tc->prev) tc = tc->prev;
-		if (tc) {
-			tc = tc->parent;
-		}
-	}
-	fflush(file);
-}
-
-/*
-  return 1 if ptr is a parent of context
-*/
-int talloc_is_parent(const void *context, const void *ptr)
-{
-	struct talloc_chunk *tc;
-
-	if (context == NULL) {
-		return 0;
-	}
-
-	tc = talloc_chunk_from_ptr(context);
-	while (tc) {
-		if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1;
-		while (tc && tc->prev) tc = tc->prev;
-		if (tc) {
-			tc = tc->parent;
-		}
-	}
-	return 0;
-}
diff --git a/libosmocore/src/timer.c b/libosmocore/src/timer.c
deleted file mode 100644
index 37d7d16..0000000
--- a/libosmocore/src/timer.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * (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;
-}
diff --git a/libosmocore/src/tlv_parser.c b/libosmocore/src/tlv_parser.c
deleted file mode 100644
index 407e57a..0000000
--- a/libosmocore/src/tlv_parser.c
+++ /dev/null
@@ -1,171 +0,0 @@
-#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;
-
-	/* 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;
-}
diff --git a/libosmocore/src/utils.c b/libosmocore/src/utils.c
deleted file mode 100644
index 4dab064..0000000
--- a/libosmocore/src/utils.c
+++ /dev/null
@@ -1,50 +0,0 @@
-
-#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;
-}
diff --git a/libosmocore/src/write_queue.c b/libosmocore/src/write_queue.c
deleted file mode 100644
index 7d908b4..0000000
--- a/libosmocore/src/write_queue.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* 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_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;
-}
diff --git a/libosmocore/tests/Makefile.am b/libosmocore/tests/Makefile.am
deleted file mode 100644
index 0119a02..0000000
--- a/libosmocore/tests/Makefile.am
+++ /dev/null
@@ -1,3 +0,0 @@
-if ENABLE_TESTS
-SUBDIRS = timer sms
-endif
diff --git a/libosmocore/tests/sms/Makefile.am b/libosmocore/tests/sms/Makefile.am
deleted file mode 100644
index a8f1ff6..0000000
--- a/libosmocore/tests/sms/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-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
diff --git a/libosmocore/tests/sms/sms_test.c b/libosmocore/tests/sms/sms_test.c
deleted file mode 100644
index f5183d5..0000000
--- a/libosmocore/tests/sms/sms_test.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * (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);
-	}
-}
diff --git a/libosmocore/tests/timer/Makefile.am b/libosmocore/tests/timer/Makefile.am
deleted file mode 100644
index d3decf5..0000000
--- a/libosmocore/tests/timer/Makefile.am
+++ /dev/null
@@ -1,6 +0,0 @@
-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
-
diff --git a/libosmocore/tests/timer/timer_test.c b/libosmocore/tests/timer/timer_test.c
deleted file mode 100644
index 1b458d8..0000000
--- a/libosmocore/tests/timer/timer_test.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * (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
-}
diff --git a/openbsc/README b/openbsc/README
index 51807bb..fa01ff4 100644
--- a/openbsc/README
+++ b/openbsc/README
@@ -14,6 +14,8 @@
 
  * A-bis over IP as used by the ip.access nanoBTS product family
 
+You can find the project documentation at http://openbsc.gnumonks.org/
+
 This project is still in its early days, and there are lots of areas where it
 doesn't behave as per GSM spec.
 
diff --git a/openbsc/configure.in b/openbsc/configure.in
index 27fb0ed..d2fd67a 100644
--- a/openbsc/configure.in
+++ b/openbsc/configure.in
@@ -17,8 +17,13 @@
 dnl checks for libraries
 AC_SEARCH_LIBS(crypt, crypt,
     [LIBCRYPT="-lcrypt"; AC_DEFINE([VTY_CRYPT_PW], [], [Use crypt functionality of vty.])])
+AC_SEARCH_LIBS(gtp_new, gtp,
+    [LIBCRYPT="-lgtp"; AC_SUBST([GPRS_LIBGTP], [1])])
 
-PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.1)
+AM_CONDITIONAL(HAVE_LIBGTP, test "x$GPRS_LIBGTP" != "x")
+
+PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.11)
+PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.1.9)
 
 dnl checks for header files
 AC_HEADER_STDC
@@ -44,10 +49,11 @@
     openbsc.pc
     libsccp.pc
     include/openbsc/Makefile
-    include/vty/Makefile
     include/sccp/Makefile
     include/Makefile
     src/Makefile
+    src/ipaccess/Makefile
+    src/gprs/Makefile
     tests/Makefile
     tests/debug/Makefile
     tests/gsm0408/Makefile
diff --git a/openbsc/contrib/gprs/gb-proxy-unblock-bug.py b/openbsc/contrib/gprs/gb-proxy-unblock-bug.py
new file mode 100755
index 0000000..0cd4b87
--- /dev/null
+++ b/openbsc/contrib/gprs/gb-proxy-unblock-bug.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+"""
+demonstrate a unblock bug on the GB Proxy..
+"""
+
+bts_ns_reset = "\x02\x00\x81\x01\x01\x82\x1f\xe7\x04\x82\x1f\xe7"
+ns_reset_ack = "\x03\x01\x82\x1f\xe7\x04\x82\x1f\xe7"
+
+bts_ns_unblock = "\x06"
+ns_unblock_ack = "\x07"
+
+bts_bvc_reset_0 = "\x00\x00\x00\x00\x22\x04\x82\x00\x00\x07\x81\x03\x3b\x81\x02"
+ns_bvc_reset_0_ack = "\x00\x00\x00\x00\x23\x04\x82\x00\x00"
+
+bts_bvc_reset_8167 = "\x00\x00\x00\x00\x22\x04\x82\x1f\xe7\x07\x81\x08\x08\x88\x72\xf4\x80\x10\x1c\x00\x9c\x40"
+
+
+import socket
+socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+socket.bind(("0.0.0.0", 0))
+socket.setblocking(1)
+
+
+import sys
+port = int(sys.argv[1])
+print "Sending data to port: %d" % port
+
+def send_and_receive(packet):
+    socket.sendto(packet, ("127.0.0.1", port))
+
+    try:
+        data, addr = socket.recvfrom(4096)
+    except socket.error, e:
+        print "ERROR", e
+        import sys
+        sys.exit(0)
+    return data
+
+#send stuff once
+
+to_send = [
+    (bts_ns_reset, ns_reset_ack, "reset ack"),
+    (bts_ns_unblock, ns_unblock_ack, "unblock ack"),
+    (bts_bvc_reset_0, ns_bvc_reset_0_ack, "BVCI=0 reset ack"),
+]
+
+
+for (out, inp, type) in to_send:
+    res = send_and_receive(out)
+    if res != inp:
+        print "Failed to get the %s" % type
+        sys.exit(-1)
+
+import time
+time.sleep(3)
+res = send_and_receive(bts_bvc_reset_8167)
+print "Sent all messages... check wireshark for the last response"
diff --git a/openbsc/contrib/gprs/gprs-bssgp-histogram.lua b/openbsc/contrib/gprs/gprs-bssgp-histogram.lua
new file mode 100644
index 0000000..b1ab5df
--- /dev/null
+++ b/openbsc/contrib/gprs/gprs-bssgp-histogram.lua
@@ -0,0 +1,78 @@
+-- Simple LUA script to print the size of BSSGP messages over their type...
+
+do
+	local ip_bucket = {}
+
+	local pdu_types = {}
+	pdu_types[ 6] = "PAGING"
+	pdu_types[11] = "SUSPEND"
+	pdu_types[12] = "SUSPEND-ACK"
+	pdu_types[32] = "BVC-BLOCK"
+	pdu_types[33] = "BVC-BLOCK-ACK"
+	pdu_types[34] = "BVC-RESET"
+	pdu_types[35] = "BVC-RESET-ACK"
+	pdu_types[36] = "UNBLOCK"
+	pdu_types[37] = "UNBLOCK-ACK"
+	pdu_types[38] = "FLOW-CONTROL-BVC"
+	pdu_types[39] = "FLOW-CONTROL-BVC-ACK"
+	pdu_types[40] = "FLOW-CONTROL-MS"
+	pdu_types[41] = "FLOW-CONTROL-MS-ACK"
+	pdu_types[44] = "LLC-DISCARDED"
+
+	local function init_listener()
+		-- handle the port as NS over IP
+		local udp_port_table = DissectorTable.get("udp.port")
+		local gprs_ns_dis = Dissector.get("gprs_ns")
+		udp_port_table:add(23000,gprs_ns_dis)
+
+		-- bssgp filters
+		local bssgp_pdu_get = Field.new("bssgp.pdu_type")
+		local udp_length_get = Field.new("udp.length")
+
+		local tap = Listener.new("ip", "udp.port == 23000")
+		function tap.packet(pinfo,tvb,ip)
+			local pdu = bssgp_pdu_get()
+			local len = udp_length_get()
+
+			-- only handle bssgp, but we also want the IP frame
+			if not pdu then
+				return
+			end
+
+			pdu = tostring(pdu)
+			if tonumber(pdu) == 0 or tonumber(pdu) == 1 then
+				return
+			end
+
+			local ip_src = tostring(ip.ip_src)
+			local bssgp_histo = ip_bucket[ip_src]
+			if not bssgp_histo then
+				bssgp_histo = {}
+				ip_bucket[ip_src] = bssgp_histo
+			end
+
+			local key = pdu
+			local bucket = bssgp_histo[key]
+			if not bucket then
+				bucket = {}
+				bssgp_histo[key] = bucket
+			end
+
+			table.insert(bucket, tostring(len))
+			print("IP: " .. ip_src .. " PDU: " .. pdu_types[tonumber(pdu)] .. " Length: " .. tostring(len))
+		end
+
+		function tap.draw()
+			-- well... this will not be called...
+--			for ip,bssgp_histo in pairs(dumpers) do
+--				print("IP " .. ip)
+--			end
+		end
+
+		function tap.reset()
+			-- well... this will not be called...
+		end
+	end
+
+	init_listener()
+end
diff --git a/openbsc/contrib/gprs/gprs-split-trace-by-tlli.lua b/openbsc/contrib/gprs/gprs-split-trace-by-tlli.lua
new file mode 100644
index 0000000..018c377
--- /dev/null
+++ b/openbsc/contrib/gprs/gprs-split-trace-by-tlli.lua
@@ -0,0 +1,46 @@
+-- Create a file named by_ip/''ip_addess''.cap with all ip traffic of each ip host. (works for tshark only)
+-- Dump files are created for both source and destination hosts
+do
+	local dir = "by_tlli"
+	local dumpers = {}
+	local function init_listener()
+		local udp_port_table = DissectorTable.get("udp.port")
+		local gprs_ns_dis = Dissector.get("gprs_ns")
+		udp_port_table:add(23000,gprs_ns_dis)
+
+		local field_tlli = Field.new("bssgp.tlli")
+		local tap = Listener.new("ip", "udp.port == 23000")
+
+		-- we will be called once for every IP Header.
+		-- If there's more than one IP header in a given packet we'll dump the packet once per every header
+		function tap.packet(pinfo,tvb,ip)
+			local tlli = field_tlli()
+			if not tlli then
+				return
+			end
+
+			local tlli_str = tostring(tlli)
+			tlli_dmp = dumpers[tlli_str]
+			if not tlli_dmp then
+				local tlli_hex = string.format("0x%x", tonumber(tlli_str))
+				print("Creating dump for TLLI " .. tlli_hex)
+				tlli_dmp = Dumper.new_for_current(dir .. "/" .. tlli_hex .. ".pcap")
+				dumpers[tlli_str] = tlli_dmp
+			end
+			tlli_dmp:dump_current()
+			tlli_dmp:flush()
+		end
+		function tap.draw()
+			for tlli,dumper in pairs(dumpers) do
+				 dumper:flush()
+			end
+		end
+		function tap.reset()
+			for tlli,dumper in pairs(dumpers) do
+				 dumper:close()
+			end
+			dumpers = {}
+		end
+	end
+	init_listener()
+end
diff --git a/openbsc/contrib/gprs/gprs-verify-nu.lua b/openbsc/contrib/gprs/gprs-verify-nu.lua
new file mode 100644
index 0000000..e44fdd1
--- /dev/null
+++ b/openbsc/contrib/gprs/gprs-verify-nu.lua
@@ -0,0 +1,59 @@
+-- This script verifies that the N(U) is increasing...
+--
+do
+	local nu_state_src = {}
+
+	local function init_listener()
+		-- handle the port as NS over IP
+		local udp_port_table = DissectorTable.get("udp.port")
+		local gprs_ns_dis = Dissector.get("gprs_ns")
+		udp_port_table:add(23000,gprs_ns_dis)
+
+		-- we want to look here...
+		local llc_sapi_get = Field.new("llcgprs.sapib")
+		local llc_nu_get = Field.new("llcgprs.nu")
+		local bssgp_tlli_get = Field.new("bssgp.tlli")
+
+		local tap = Listener.new("ip", "udp.port == 23000")
+		function tap.packet(pinfo,tvb,ip)
+			local llc_sapi = llc_sapi_get()
+			local llc_nu = llc_nu_get()
+			local bssgp_tlli = bssgp_tlli_get()
+
+			if not llc_sapi or not llc_nu or not bssgp_tlli then
+				return
+			end
+
+			local ip_src = tostring(ip.ip_src)
+			local bssgp_tlli = tostring(bssgp_tlli)
+			local llc_nu = tostring(llc_nu)
+			local llc_sapi = tostring(llc_sapi)
+
+			local src_key = ip_src .. "-" .. bssgp_tlli .. "-" .. llc_sapi
+			local last_nu = nu_state_src[src_key]
+			if not last_nu then
+				-- print("Establishing mapping for " .. src_key)
+				nu_state_src[src_key] = llc_nu
+				return
+			end
+
+			local function tohex(number)
+				return string.format("0x%x", tonumber(number))
+			end
+
+			nu_state_src[src_key] = llc_nu
+			if tonumber(last_nu) + 1 ~= tonumber(llc_nu) then
+				print("JUMP in N(U) on TLLI " .. tohex(bssgp_tlli) .. " and SAPI: " .. llc_sapi .. " src: " .. ip_src)
+				print("\t last: " .. last_nu .. " now: " .. llc_nu)
+			end
+		end
+
+		function tap.draw()
+		end
+
+		function tap.reset()
+		end
+	end
+	init_listener()
+end
+
diff --git a/openbsc/contrib/mgcp_server.py b/openbsc/contrib/mgcp_server.py
index cf3ef38..05c489d 100755
--- a/openbsc/contrib/mgcp_server.py
+++ b/openbsc/contrib/mgcp_server.py
@@ -10,7 +10,7 @@
 audit_packet = """AUEP %d 13@mgw MGCP 1.0\r\n"""
 crcx_packet = """CRCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n"""
 dlcx_packet = """DLCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\n"""
-mdcx_packet = """MDCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 258696477 0 IN IP4 172.16.1.107\r\ns=-\r\nc=IN IP4 172.16.1.107\r\nt=0 0\r\nm=audio 4400 RTP/AVP 127\r\na=rtpmap:127 GSM-EFR/8000/1\r\na=ptime:20\r\na=recvonly\r\nm=image 4402 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n"""
+mdcx_packet = """MDCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 258696477 0 IN IP4 172.16.1.107\r\ns=-\r\nc=IN IP4 172.16.1.107\r\nt=0 0\r\nm=audio 6666 RTP/AVP 127\r\na=rtpmap:127 GSM-EFR/8000/1\r\na=ptime:20\r\na=recvonly\r\nm=image 4402 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n"""
 
 def hexdump(src, length=8):
     """Recipe is from http://code.activestate.com/recipes/142812/"""
@@ -25,15 +25,24 @@
 
 server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 server_socket.bind(("127.0.0.1", MGCP_CALLAGENT_PORT))
-server_socket.setblocking(0)
+server_socket.setblocking(1)
 
-
-def send_receive(packet):
+last_ci = 1
+def send_and_receive(packet):
+    global last_ci
     server_socket.sendto(packet, ("127.0.0.1", MGCP_GATEWAY_PORT))
     try:
         data, addr = server_socket.recvfrom(4096)
+
+        # attempt to store the CI of the response
+        list = data.split("\n")
+        for item in list:
+           if item.startswith("I: "):
+               last_ci = int(item[3:])
+
         print hexdump(data), addr
-    except socket.error:
+    except socket.error, e:
+        print e
         pass
 
 def generate_tid():
@@ -42,13 +51,10 @@
 
 
 
-i = 1
 while True:
-    send_receive(rsip_resp)
-    send_receive(audit_packet)
-    send_receive(crcx_packet % generate_tid() )
-    send_receive(mdcx_packet % (generate_tid(), i))
-    send_receive(dlcx_packet % (generate_tid(), i))
-    i = i + 1
+    send_and_receive(audit_packet % generate_tid())
+    send_and_receive(crcx_packet % generate_tid() )
+    send_and_receive(mdcx_packet % (generate_tid(), last_ci))
+    send_and_receive(dlcx_packet % (generate_tid(), last_ci))
 
     time.sleep(3)
diff --git a/openbsc/include/Makefile.am b/openbsc/include/Makefile.am
index 56b2a33..a4acc23 100644
--- a/openbsc/include/Makefile.am
+++ b/openbsc/include/Makefile.am
@@ -1,3 +1,3 @@
-SUBDIRS = openbsc vty sccp
+SUBDIRS = openbsc sccp
 
 noinst_HEADERS = mISDNif.h compat_af_isdn.h
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index 483997a..5957d71 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -1,11 +1,15 @@
 noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
 		 gsm_subscriber.h gsm_04_11.h debug.h signal.h \
-		 misdn.h chan_alloc.h telnet_interface.h paging.h \
+		 misdn.h chan_alloc.h paging.h \
 		 subchan_demux.h trau_frame.h e1_input.h trau_mux.h \
 		 ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \
 		 bsc_rll.h mncc.h transaction.h ussd.h gsm_04_80.h \
 		 silent_call.h mgcp.h meas_rep.h rest_octets.h \
-		 system_information.h handover.h mgcp_internal.h
+		 system_information.h handover.h mgcp_internal.h \
+		 vty.h socket.h \
+		crc24.h gprs_bssgp.h gprs_llc.h gprs_ns.h gprs_gmm.h \
+		gb_proxy.h gprs_sgsn.h gsm_04_08_gprs.h sgsn.h \
+		gprs_ns_frgre.h auth.h osmo_msc.h
 
-openbsc_HEADERS = gsm_04_08.h meas_rep.h
+openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
 openbscdir = $(includedir)/openbsc
diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h
index 45307e3..b3bf27e 100644
--- a/openbsc/include/openbsc/abis_nm.h
+++ b/openbsc/include/openbsc/abis_nm.h
@@ -55,6 +55,8 @@
 	u_int8_t ca_list_si1[16];
 };
 
+extern const struct value_string abis_nm_adm_state_names[];
+extern const struct value_string abis_nm_obj_class_names[];
 extern const struct tlv_definition nm_att_tlvdef;
 
 /* PUBLIC */
@@ -92,7 +94,7 @@
 int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *msg);
 int abis_nm_event_reports(struct gsm_bts *bts, int on);
 int abis_nm_reset_resource(struct gsm_bts *bts);
-int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
+int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
 			  u_int8_t win_size, int forced,
 			  gsm_cbfn *cbfn, void *cb_data);
 int abis_nm_software_load_status(struct gsm_bts *bts);
@@ -148,7 +150,7 @@
 			 u_int8_t *attr, int attr_len);
 int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
 				int attr_len);
-int abis_nm_ipaccess_restart(struct gsm_bts *bts);
+int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx);
 int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
 				u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
 				u_int8_t *attr, u_int8_t attr_len);
@@ -164,9 +166,13 @@
 	EVT_STATECHG_ADM,
 };
 int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
-		   struct gsm_nm_state *old_state, struct gsm_nm_state *new_state); 
+		   struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
+		   struct abis_om_obj_inst *obj_inst);
 
 const char *nm_opstate_name(u_int8_t os);
 const char *nm_avail_name(u_int8_t avail);
 int nm_is_running(struct gsm_nm_state *s);
+
+int abis_nm_vty_init(void);
+
 #endif /* _NM_H */
diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h
index b280184..e87f430 100644
--- a/openbsc/include/openbsc/abis_rsl.h
+++ b/openbsc/include/openbsc/abis_rsl.h
@@ -59,7 +59,7 @@
 int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip,
 		   u_int16_t port, u_int8_t rtp_payload2);
 int rsl_ipacc_mdcx_to_rtpsock(struct gsm_lchan *lchan);
-int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan);
+int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan, int act);
 
 int abis_rsl_rcvmsg(struct msgb *msg);
 
@@ -68,12 +68,13 @@
 unsigned int n_pag_blocks(int bs_ccch_sdcch_comb, unsigned int bs_ag_blks_res);
 u_int64_t str_to_imsi(const char *imsi_str);
 u_int8_t lchan2chan_nr(const struct gsm_lchan *lchan);
-int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id);
+int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id, u_int8_t reason);
+
+int rsl_lchan_set_state(struct gsm_lchan *lchan, int);
 
 /* to be provided by external code */
 int abis_rsl_sendmsg(struct msgb *msg);
 int rsl_deact_sacch(struct gsm_lchan *lchan);
-int rsl_chan_release(struct gsm_lchan *lchan);
 
 /* BCCH related code */
 int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf);
diff --git a/openbsc/include/openbsc/auth.h b/openbsc/include/openbsc/auth.h
new file mode 100644
index 0000000..0e5cad6
--- /dev/null
+++ b/openbsc/include/openbsc/auth.h
@@ -0,0 +1,10 @@
+#ifndef _AUTH_H
+#define _AUTH_H
+
+struct gsm_auth_tuple;
+struct gsm_subscriber;
+
+int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
+                              struct gsm_subscriber *subscr, int key_seq);
+
+#endif /* _AUTH_H */
diff --git a/openbsc/include/openbsc/bsc_api.h b/openbsc/include/openbsc/bsc_api.h
new file mode 100644
index 0000000..05a5e46
--- /dev/null
+++ b/openbsc/include/openbsc/bsc_api.h
@@ -0,0 +1,26 @@
+/* GSM 08.08 like API for OpenBSC */
+
+#ifndef OPENBSC_BSC_API_H
+#define OPENBSC_BSC_API_H
+
+#include "gsm_data.h"
+
+struct bsc_api {
+	void (*sapi_n_reject)(struct gsm_subscriber_connection *conn, int dlci);
+	void (*cipher_mode_compl)(struct gsm_subscriber_connection *conn,
+				  struct msgb *msg, uint16_t ind);
+	void (*compl_l3)(struct gsm_subscriber_connection *conn,
+			 struct msgb *msg, uint16_t chosen_channel); 
+	void (*ass_compl)(struct gsm_subscriber_connection *conn,
+			  uint16_t rr_cause);
+	void (*ass_fail)(struct gsm_subscriber_connection *conn,
+			 uint16_t rr_cause);
+	void (*clear_request)(struct gsm_subscriber_connection *conn,
+			      uint32_t cause);
+	void (*clear_compl)(struct gsm_subscriber_connection *conn);
+};
+
+int bsc_api_init(struct gsm_network *network, struct bsc_api *api);
+int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn, struct msgb *msg, int link_id);
+
+#endif
diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h
index f564e9e..d4f5858 100644
--- a/openbsc/include/openbsc/chan_alloc.h
+++ b/openbsc/include/openbsc/chan_alloc.h
@@ -45,6 +45,7 @@
 
 /* Free a logical channel (SDCCH, TCH, ...) */
 void lchan_free(struct gsm_lchan *lchan);
+void lchan_reset(struct gsm_lchan *lchan);
 
 /* Consider releasing the channel */
 int lchan_auto_release(struct gsm_lchan *lchan);
diff --git a/openbsc/include/openbsc/crc24.h b/openbsc/include/openbsc/crc24.h
new file mode 100644
index 0000000..358fcb5
--- /dev/null
+++ b/openbsc/include/openbsc/crc24.h
@@ -0,0 +1,8 @@
+#ifndef _CRC24_H
+#define _CRC24_H
+
+#define INIT_CRC24	0xffffff
+
+u_int32_t crc24_calc(u_int32_t fcs, u_int8_t *cp, unsigned int len);
+
+#endif
diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h
index df664db..2a521f0 100644
--- a/openbsc/include/openbsc/db.h
+++ b/openbsc/include/openbsc/db.h
@@ -44,19 +44,19 @@
 int db_sync_equipment(struct gsm_equipment *equip);
 
 /* auth info */
-int get_authinfo_by_subscr(struct gsm_auth_info *ainfo,
-                           struct gsm_subscriber *subscr);
-int set_authinfo_for_subscr(struct gsm_auth_info *ainfo,
-                            struct gsm_subscriber *subscr);
-int get_authtuple_by_subscr(struct gsm_auth_tuple *atuple,
-                            struct gsm_subscriber *subscr);
-int set_authtuple_for_subscr(struct gsm_auth_tuple *atuple,
-                             struct gsm_subscriber *subscr);
+int db_get_authinfo_for_subscr(struct gsm_auth_info *ainfo,
+                               struct gsm_subscriber *subscr);
+int db_sync_authinfo_for_subscr(struct gsm_auth_info *ainfo,
+                                struct gsm_subscriber *subscr);
+int db_get_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
+                                    struct gsm_subscriber *subscr);
+int db_sync_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
+                                     struct gsm_subscriber *subscr);
 
 /* SMS store-and-forward */
 int db_sms_store(struct gsm_sms *sms);
-struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id);
-struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, int min_subscr_id);
+struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, unsigned long long min_id);
+struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, unsigned long long min_subscr_id);
 struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr);
 int db_sms_mark_sent(struct gsm_sms *sms);
 
@@ -66,6 +66,9 @@
 			u_int8_t *apdu);
 
 /* Statistics counter storage */
+struct counter;
 int db_store_counter(struct counter *ctr);
+struct rate_ctr_group;
+int db_store_rate_ctr_group(struct rate_ctr_group *ctrg);
 
 #endif /* _DB_H */
diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h
index 4b67c61..203aedb 100644
--- a/openbsc/include/openbsc/debug.h
+++ b/openbsc/include/openbsc/debug.h
@@ -5,6 +5,7 @@
 #include <osmocore/linuxlist.h>
 
 #define DEBUG
+#include <osmocore/logging.h>
 
 /* Debug Areas of the code */
 enum {
@@ -28,104 +29,41 @@
 	DHO,
 	DDB,
 	DREF,
+	DGPRS,
+	DNS,
+	DBSSGP,
+	DLLC,
+	DSNDCP,
 	Debug_LastEntry,
 };
 
-#ifdef DEBUG
-#define DEBUGP(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 0, fmt, ## args)
-#define DEBUGPC(ss, fmt, args...) debugp(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 debugp(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...) debugp2(ss, level, __FILE__, __LINE__, 0, fmt, ##args)
-#define LOGPC(ss, level, fmt, args...) debugp2(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 */
-
 /* context */
 #define BSC_CTX_LCHAN	0
 #define BSC_CTX_SUBSCR	1
 #define BSC_CTX_BTS	2
 #define BSC_CTX_SCCP	3
+#define BSC_CTX_NSVC	4
+#define BSC_CTX_BVC	5
 
 /* target */
 
 enum {
-	DEBUG_FILTER_IMSI = 1 << 0,
-	DEBUG_FILTER_ALL = 1 << 1,
+	//DEBUG_FILTER_ALL = 1 << 0,
+	LOG_FILTER_IMSI = 1 << 1,
+	LOG_FILTER_NSVC = 1 << 2,
+	LOG_FILTER_BVC  = 1 << 3,
 };
 
-struct debug_category {
-	int enabled;
-	int loglevel;
-};
+/* we don't need a header dependency for this... */
+struct gprs_nsvc;
+struct bssgp_bvc_ctx;
 
-struct debug_target {
-	int filter_map;
-	char *imsi_filter;
+void log_set_imsi_filter(struct log_target *target, const char *imsi);
+void log_set_nsvc_filter(struct log_target *target,
+			 struct gprs_nsvc *nsvc);
+void log_set_bvc_filter(struct log_target *target,
+			struct bssgp_bvc_ctx *bctx);
 
+extern const struct log_info log_info;
 
-	struct debug_category categories[Debug_LastEntry];
-	int use_color;
-	int print_timestamp;
-	int loglevel;
-
-	union {
-		struct {
-			FILE *out;
-		} tgt_stdout;
-
-		struct {
-			int priority;
-		} tgt_syslog;
-
-		struct {
-			void *vty;
-		} tgt_vty;
-	};
-
-        void (*output) (struct debug_target *target, const char *string);
-
-        struct llist_head entry;
-};
-
-/* use the above macros */
-void debugp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 6, 7)));
-void debug_init(void);
-
-/* context management */
-void debug_reset_context(void);
-void debug_set_context(int ctx, void *value);
-
-/* filter on the targets */
-void debug_set_imsi_filter(struct debug_target *target, const char *imsi);
-void debug_set_all_filter(struct debug_target *target, int);
-void debug_set_use_color(struct debug_target *target, int);
-void debug_set_print_timestamp(struct debug_target *target, int);
-void debug_set_log_level(struct debug_target *target, int log_level);
-void debug_parse_category_mask(struct debug_target *target, const char* mask);
-int debug_parse_level(const char *lvl);
-int debug_parse_category(const char *category);
-void debug_set_category_filter(struct debug_target *target, int category, int enable, int level);
-
-
-/* management of the targets */
-struct debug_target *debug_target_create(void);
-struct debug_target *debug_target_create_stderr(void);
-void debug_add_target(struct debug_target *target);
-void debug_del_target(struct debug_target *target);
 #endif /* _DEBUG_H */
diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h
new file mode 100644
index 0000000..18ded22
--- /dev/null
+++ b/openbsc/include/openbsc/gb_proxy.h
@@ -0,0 +1,39 @@
+#ifndef _GB_PROXY_H
+#define _GB_PROXY_H
+
+#include <sys/types.h>
+
+#include <osmocore/msgb.h>
+
+#include <openbsc/gprs_ns.h>
+#include <osmocom/vty/command.h>
+
+struct gbproxy_config {
+	/* parsed from config file */
+	u_int16_t nsip_sgsn_nsei;
+
+	/* misc */
+	struct gprs_ns_inst *nsi;
+};
+
+extern struct gbproxy_config gbcfg;
+extern struct cmd_element show_gbproxy_cmd;
+
+/* gb_proxy_vty .c */
+
+int gbproxy_vty_init(void);
+int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg);
+
+
+/* gb_proxy.c */
+
+/* Main input function for Gb proxy */
+int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci);
+
+int gbprox_signal(unsigned int subsys, unsigned int signal,
+		  void *handler_data, void *signal_data);
+
+/* Reset all persistent NS-VC's */
+int gbprox_reset_persistent_nsvcs(struct gprs_ns_inst *nsi);
+
+#endif
diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h
new file mode 100644
index 0000000..e432cf7
--- /dev/null
+++ b/openbsc/include/openbsc/gprs_bssgp.h
@@ -0,0 +1,232 @@
+#ifndef _GPRS_BSSGP_H
+#define _GPRS_BSSGP_H
+
+#include <stdint.h>
+
+/* Section 5.4.1 */
+#define BVCI_SIGNALLING	0x0000
+#define BVCI_PTM	0x0001
+
+/* Section 11.3.26 / Table 11.27 */
+enum bssgp_pdu_type {
+	/* PDUs between RL and BSSGP SAPs */
+	BSSGP_PDUT_DL_UNITDATA		= 0x00,
+	BSSGP_PDUT_UL_UNITDATA		= 0x01,
+	BSSGP_PDUT_RA_CAPABILITY	= 0x02,
+	BSSGP_PDUT_PTM_UNITDATA		= 0x03,
+	/* PDUs between GMM SAPs */
+	BSSGP_PDUT_PAGING_PS		= 0x06,
+	BSSGP_PDUT_PAGING_CS		= 0x07,
+	BSSGP_PDUT_RA_CAPA_UDPATE	= 0x08,
+	BSSGP_PDUT_RA_CAPA_UPDATE_ACK	= 0x09,
+	BSSGP_PDUT_RADIO_STATUS		= 0x0a,
+	BSSGP_PDUT_SUSPEND		= 0x0b,
+	BSSGP_PDUT_SUSPEND_ACK		= 0x0c,
+	BSSGP_PDUT_SUSPEND_NACK		= 0x0d,
+	BSSGP_PDUT_RESUME		= 0x0e,
+	BSSGP_PDUT_RESUME_ACK		= 0x0f,
+	BSSGP_PDUT_RESUME_NACK		= 0x10,
+	/* PDus between NM SAPs */
+	BSSGP_PDUT_BVC_BLOCK		= 0x20,
+	BSSGP_PDUT_BVC_BLOCK_ACK	= 0x21,
+	BSSGP_PDUT_BVC_RESET		= 0x22,
+	BSSGP_PDUT_BVC_RESET_ACK	= 0x23,
+	BSSGP_PDUT_BVC_UNBLOCK		= 0x24,
+	BSSGP_PDUT_BVC_UNBLOCK_ACK	= 0x25,
+	BSSGP_PDUT_FLOW_CONTROL_BVC	= 0x26,
+	BSSGP_PDUT_FLOW_CONTROL_BVC_ACK	= 0x27,
+	BSSGP_PDUT_FLOW_CONTROL_MS	= 0x28,
+	BSSGP_PDUT_FLOW_CONTROL_MS_ACK	= 0x29,
+	BSSGP_PDUT_FLUSH_LL		= 0x2a,
+	BSSGP_PDUT_FLUSH_LL_ACK		= 0x2b,
+	BSSGP_PDUT_LLC_DISCARD		= 0x2c,
+	BSSGP_PDUT_SGSN_INVOKE_TRACE	= 0x40,
+	BSSGP_PDUT_STATUS		= 0x41,
+	/* PDUs between PFM SAP's */
+	BSSGP_PDUT_DOWNLOAD_BSS_PFC	= 0x50,
+	BSSGP_PDUT_CREATE_BSS_PFC	= 0x51,
+	BSSGP_PDUT_CREATE_BSS_PFC_ACK	= 0x52,
+	BSSGP_PDUT_CREATE_BSS_PFC_NACK	= 0x53,
+	BSSGP_PDUT_MODIFY_BSS_PFC	= 0x54,
+	BSSGP_PDUT_MODIFY_BSS_PFC_ACK	= 0x55,
+	BSSGP_PDUT_DELETE_BSS_PFC	= 0x56,
+	BSSGP_PDUT_DELETE_BSS_PFC_ACK	= 0x57,
+};
+
+/* Section 10.2.1 and 10.2.2 */
+struct bssgp_ud_hdr {
+	uint8_t pdu_type;
+	uint32_t tlli;
+	uint8_t qos_profile[3];
+	uint8_t data[0];	/* TLV's */
+} __attribute__((packed));
+
+struct bssgp_normal_hdr {
+	uint8_t pdu_type;
+	uint8_t data[0];	/* TLV's */
+};
+
+enum bssgp_iei_type {
+	BSSGP_IE_ALIGNMENT		= 0x00,
+	BSSGP_IE_BMAX_DEFAULT_MS	= 0x01,
+	BSSGP_IE_BSS_AREA_ID		= 0x02,
+	BSSGP_IE_BUCKET_LEAK_RATE	= 0x03,
+	BSSGP_IE_BVCI			= 0x04,
+	BSSGP_IE_BVC_BUCKET_SIZE	= 0x05,
+	BSSGP_IE_BVC_MEASUREMENT	= 0x06,
+	BSSGP_IE_CAUSE			= 0x07,
+	BSSGP_IE_CELL_ID		= 0x08,
+	BSSGP_IE_CHAN_NEEDED		= 0x09,
+	BSSGP_IE_DRX_PARAMS		= 0x0a,
+	BSSGP_IE_EMLPP_PRIO		= 0x0b,
+	BSSGP_IE_FLUSH_ACTION		= 0x0c,
+	BSSGP_IE_IMSI			= 0x0d,
+	BSSGP_IE_LLC_PDU		= 0x0e,
+	BSSGP_IE_LLC_FRAMES_DISCARDED	= 0x0f,
+	BSSGP_IE_LOCATION_AREA		= 0x10,
+	BSSGP_IE_MOBILE_ID		= 0x11,
+	BSSGP_IE_MS_BUCKET_SIZE		= 0x12,
+	BSSGP_IE_MS_RADIO_ACCESS_CAP	= 0x13,
+	BSSGP_IE_OMC_ID			= 0x14,
+	BSSGP_IE_PDU_IN_ERROR		= 0x15,
+	BSSGP_IE_PDU_LIFETIME		= 0x16,
+	BSSGP_IE_PRIORITY		= 0x17,
+	BSSGP_IE_QOS_PROFILE		= 0x18,
+	BSSGP_IE_RADIO_CAUSE		= 0x19,
+	BSSGP_IE_RA_CAP_UPD_CAUSE	= 0x1a,
+	BSSGP_IE_ROUTEING_AREA		= 0x1b,
+	BSSGP_IE_R_DEFAULT_MS		= 0x1c,
+	BSSGP_IE_SUSPEND_REF_NR		= 0x1d,
+	BSSGP_IE_TAG			= 0x1e,
+	BSSGP_IE_TLLI			= 0x1f,
+	BSSGP_IE_TMSI			= 0x20,
+	BSSGP_IE_TRACE_REFERENC		= 0x21,
+	BSSGP_IE_TRACE_TYPE		= 0x22,
+	BSSGP_IE_TRANSACTION_ID		= 0x23,
+	BSSGP_IE_TRIGGER_ID		= 0x24,
+	BSSGP_IE_NUM_OCT_AFF		= 0x25,
+	BSSGP_IE_LSA_ID_LIST		= 0x26,
+	BSSGP_IE_LSA_INFORMATION	= 0x27,
+	BSSGP_IE_PACKET_FLOW_ID		= 0x28,
+	BSSGP_IE_PACKET_FLOW_TIMER	= 0x29,
+	BSSGP_IE_AGG_BSS_QOS_PROFILE	= 0x3a,
+	BSSGP_IE_FEATURE_BITMAP		= 0x3b,
+	BSSGP_IE_BUCKET_FULL_RATIO	= 0x3c,
+	BSSGP_IE_SERVICE_UTRAN_CCO	= 0x3d,
+};
+
+/* Section 11.3.8 / Table 11.10: Cause coding */
+enum gprs_bssgp_cause {
+	BSSGP_CAUSE_PROC_OVERLOAD	= 0x00,
+	BSSGP_CAUSE_EQUIP_FAIL		= 0x01,
+	BSSGP_CAUSE_TRASIT_NET_FAIL	= 0x02,
+	BSSGP_CAUSE_CAPA_GREATER_0KPBS	= 0x03,
+	BSSGP_CAUSE_UNKNOWN_MS		= 0x04,
+	BSSGP_CAUSE_UNKNOWN_BVCI	= 0x05,
+	BSSGP_CAUSE_CELL_TRAF_CONG	= 0x06,
+	BSSGP_CAUSE_SGSN_CONG		= 0x07,
+	BSSGP_CAUSE_OML_INTERV		= 0x08,
+	BSSGP_CAUSE_BVCI_BLOCKED	= 0x09,
+	BSSGP_CAUSE_PFC_CREATE_FAIL	= 0x0a,
+	BSSGP_CAUSE_SEM_INCORR_PDU	= 0x20,
+	BSSGP_CAUSE_INV_MAND_INF	= 0x21,
+	BSSGP_CAUSE_MISSING_MAND_IE	= 0x22,
+	BSSGP_CAUSE_MISSING_COND_IE	= 0x23,
+	BSSGP_CAUSE_UNEXP_COND_IE	= 0x24,
+	BSSGP_CAUSE_COND_IE_ERR		= 0x25,
+	BSSGP_CAUSE_PDU_INCOMP_STATE	= 0x26,
+	BSSGP_CAUSE_PROTO_ERR_UNSPEC	= 0x27,
+	BSSGP_CAUSE_PDU_INCOMP_FEAT	= 0x28,
+};
+
+/* Our implementation */
+
+/* gprs_bssgp_util.c */
+extern struct gprs_ns_inst *bssgp_nsi;
+struct msgb *bssgp_msgb_alloc(void);
+const char *bssgp_cause_str(enum gprs_bssgp_cause cause);
+/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */
+int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei,
+			 uint16_t bvci, uint16_t ns_bvci);
+/* Chapter 10.4.14: Status */
+int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg);
+
+/* gprs_bssgp.c */
+
+#define BVC_S_BLOCKED	0x0001
+
+/* The per-BTS context that we keep on the SGSN side of the BSSGP link */
+struct bssgp_bvc_ctx {
+	struct llist_head list;
+
+	/* parsed RA ID and Cell ID of the remote BTS */
+	struct gprs_ra_id ra_id;
+	uint16_t cell_id;
+
+	/* NSEI and BVCI of underlying Gb link.  Together they
+	 * uniquely identify a link to a BTS (5.4.4) */
+	uint16_t bvci;
+	uint16_t nsei;
+
+	uint32_t state;
+
+	struct rate_ctr_group *ctrg;
+
+	/* we might want to add this as a shortcut later, avoiding the NSVC
+	 * lookup for every packet, similar to a routing cache */
+	//struct gprs_nsvc *nsvc;
+};
+extern struct llist_head bssgp_bvc_ctxts;
+/* Find a BTS Context based on parsed RA ID and Cell ID */
+struct bssgp_bvc_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid);
+/* Find a BTS context based on BVCI+NSEI tuple */
+struct bssgp_bvc_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei);
+
+#include <osmocore/tlv.h>
+
+/* BSSGP-UL-UNITDATA.ind */
+int gprs_bssgp_rcvmsg(struct msgb *msg);
+
+/* BSSGP-DL-UNITDATA.req */
+struct sgsn_mm_ctx;
+int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx);
+
+uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf);
+
+/* Wrapper around TLV parser to parse BSSGP IEs */
+static inline int bssgp_tlv_parse(struct tlv_parsed *tp, uint8_t *buf, int len)
+{
+	return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0);
+}
+
+enum bssgp_paging_mode {
+	BSSGP_PAGING_PS,
+	BSSGP_PAGING_CS,
+};
+
+enum bssgp_paging_scope {
+	BSSGP_PAGING_BSS_AREA,		/* all cells in BSS */
+	BSSGP_PAGING_LOCATION_AREA,	/* all cells in LA */
+	BSSGP_PAGING_ROUTEING_AREA,	/* all cells in RA */
+	BSSGP_PAGING_BVCI,		/* one cell */
+};
+
+struct bssgp_paging_info {
+	enum bssgp_paging_mode mode;
+	enum bssgp_paging_scope scope;
+	struct gprs_ra_id raid;
+	uint16_t bvci;
+	const char *imsi;
+	uint32_t *ptmsi;
+	uint16_t drx_params;
+	uint8_t qos[3];
+};
+
+/* Send a single GMM-PAGING.req to a given NSEI/NS-BVCI */
+int gprs_bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci,
+			 struct bssgp_paging_info *pinfo);
+
+/* gprs_bssgp_vty.c */
+int gprs_bssgp_vty_init(void);
+
+#endif /* _GPRS_BSSGP_H */
diff --git a/openbsc/include/openbsc/gprs_gmm.h b/openbsc/include/openbsc/gprs_gmm.h
new file mode 100644
index 0000000..b91b489
--- /dev/null
+++ b/openbsc/include/openbsc/gprs_gmm.h
@@ -0,0 +1,18 @@
+#ifndef _GPRS_GMM_H
+#define _GPRS_GMM_H
+
+#include <osmocore/msgb.h>
+#include <openbsc/gprs_sgsn.h>
+
+int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
+			     uint8_t cause, uint8_t pco_len, uint8_t *pco_v);
+int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp);
+int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp);
+
+int gsm0408_gprs_rcvmsg(struct msgb *msg, struct gprs_llc_llme *llme);
+
+int gprs_gmm_rx_suspend(struct gprs_ra_id *raid, uint32_t tlli);
+int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli,
+		       uint8_t suspend_ref);
+
+#endif /* _GPRS_GMM_H */
diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h
new file mode 100644
index 0000000..0ddb518
--- /dev/null
+++ b/openbsc/include/openbsc/gprs_llc.h
@@ -0,0 +1,149 @@
+#ifndef _GPRS_LLC_H
+#define _GPRS_LLC_H
+
+#include <stdint.h>
+#include <openbsc/gprs_sgsn.h>
+
+/* Section 4.7 LLC Layer Structure */
+enum gprs_llc_sapi {
+	GPRS_SAPI_GMM		= 1,
+	GPRS_SAPI_TOM2		= 2,
+	GPRS_SAPI_SNDCP3	= 3,
+	GPRS_SAPI_SNDCP5	= 5,
+	GPRS_SAPI_SMS		= 7,
+	GPRS_SAPI_TOM8		= 8,
+	GPRS_SAPI_SNDCP9	= 9,
+	GPRS_SAPI_SNDCP11	= 11,
+};
+
+/* Section 6.4 Commands and Responses */
+enum gprs_llc_u_cmd {
+	GPRS_LLC_U_DM_RESP		= 0x01,
+	GPRS_LLC_U_DISC_CMD		= 0x04,
+	GPRS_LLC_U_UA_RESP		= 0x06,
+	GPRS_LLC_U_SABM_CMD		= 0x07,
+	GPRS_LLC_U_FRMR_RESP		= 0x08,
+	GPRS_LLC_U_XID			= 0x0b,
+	GPRS_LLC_U_NULL_CMD		= 0x00,
+};
+
+/* TS 04.64 Section 7.1.2 Table 7: LLC layer primitives (GMM/SNDCP/SMS/TOM) */
+/* TS 04.65 Section 5.1.2 Table 2: Service primitives used by SNDCP */
+enum gprs_llc_primitive {
+	/* GMM <-> LLME */
+	LLGMM_ASSIGN_REQ,	/* GMM tells us new TLLI: TLLI old, TLLI new, Kc, CiphAlg */
+	LLGMM_RESET_REQ,	/* GMM tells us to perform XID negotiation: TLLI */
+	LLGMM_RESET_CNF,	/* LLC informs GMM that XID has completed: TLLI */
+	LLGMM_SUSPEND_REQ,	/* GMM tells us MS has suspended: TLLI, Page */
+	LLGMM_RESUME_REQ,	/* GMM tells us MS has resumed: TLLI */
+	LLGMM_PAGE_IND,		/* LLC asks GMM to page MS: TLLI */
+	LLGMM_IOV_REQ,		/* GMM tells us to perform XID: TLLI */
+	LLGMM_STATUS_IND,	/* LLC informs GMM about error: TLLI, Cause */
+	/* LLE <-> (GMM/SNDCP/SMS/TOM) */
+	LL_RESET_IND,		/* TLLI */
+	LL_ESTABLISH_REQ,	/* TLLI, XID Req */
+	LL_ESTABLISH_IND,	/* TLLI, XID Req, N201-I, N201-U */
+	LL_ESTABLISH_RESP,	/* TLLI, XID Negotiated */
+	LL_ESTABLISH_CONF,	/* TLLI, XID Neg, N201-i, N201-U */
+	LL_RELEASE_REQ,		/* TLLI, Local */
+	LL_RELEASE_IND,		/* TLLI, Cause */
+	LL_RELEASE_CONF,	/* TLLI */
+	LL_XID_REQ,		/* TLLI, XID Requested */
+	LL_XID_IND,		/* TLLI, XID Req, N201-I, N201-U */
+	LL_XID_RESP,		/* TLLI, XID Negotiated */
+	LL_XID_CONF,		/* TLLI, XID Neg, N201-I, N201-U */
+	LL_DATA_REQ,		/* TLLI, SN-PDU, Ref, QoS, Radio Prio, Ciph */
+	LL_DATA_IND,		/* TLLI, SN-PDU */
+	LL_DATA_CONF,		/* TLLI, Ref */
+	LL_UNITDATA_REQ,	/* TLLI, SN-PDU, Ref, QoS, Radio Prio, Ciph */
+	LL_UNITDATA_IND,	/* TLLI, SN-PDU */
+	LL_STATUS_IND,		/* TLLI, Cause */
+};
+
+/* Section 4.5.2 Logical Link States + Annex C.2 */
+enum gprs_llc_lle_state {
+	GPRS_LLES_UNASSIGNED	= 1,	/* No TLLI yet */
+	GPRS_LLES_ASSIGNED_ADM	= 2,	/* TLLI assigned */
+	GPRS_LLES_LOCAL_EST	= 3,	/* Local Establishment */
+	GPRS_LLES_REMOTE_EST	= 4,	/* Remote Establishment */
+	GPRS_LLES_ABM		= 5,
+	GPRS_LLES_LOCAL_REL	= 6,	/* Local Release */
+	GPRS_LLES_TIMER_REC 	= 7,	/* Timer Recovery */
+};
+
+enum gprs_llc_llme_state {
+	GPRS_LLMS_UNASSIGNED	= 1,	/* No TLLI yet */
+	GPRS_LLMS_ASSIGNED	= 2,	/* TLLI assigned */
+};
+
+/* Section 8.9.9 LLC layer parameter default values */
+struct gprs_llc_params {
+	uint16_t iov_i_exp;
+	uint16_t t200_201;
+	uint16_t n200;
+	uint16_t n201_u;
+	uint16_t n201_i;
+	uint16_t mD;
+	uint16_t mU;
+	uint16_t kD;
+	uint16_t kU;
+};
+
+/* Section 4.7.1: Logical Link Entity: One per DLCI (TLLI + SAPI) */
+struct gprs_llc_lle {
+	struct llist_head list;
+
+	uint32_t sapi;
+
+	struct gprs_llc_llme *llme;
+
+	enum gprs_llc_lle_state state;
+
+	struct timer_list t200;
+	struct timer_list t201;	/* wait for acknowledgement */
+
+	uint16_t v_sent;
+	uint16_t v_ack;
+	uint16_t v_recv;
+
+	uint16_t vu_send;
+	uint16_t vu_recv;
+
+	unsigned int retrans_ctr;
+
+	struct gprs_llc_params params;
+};
+
+#define NUM_SAPIS	16
+
+struct gprs_llc_llme {
+	struct llist_head list;
+
+	enum gprs_llc_llme_state state;
+
+	uint32_t tlli;
+	uint32_t old_tlli;
+
+	/* over which BSSGP BTS ctx do we need to transmit */
+	uint16_t bvci;
+	uint16_t nsei;
+	struct gprs_llc_lle lle[NUM_SAPIS];
+};
+
+extern struct llist_head gprs_llc_llmes;
+
+/* BSSGP-UL-UNITDATA.ind */
+int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv);
+
+/* LL-UNITDATA.req */
+int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
+		   void *mmctx);
+
+/* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */
+int gprs_llgmm_assign(struct gprs_llc_llme *llme,
+		      uint32_t old_tlli, uint32_t new_tlli,
+		      enum gprs_ciph_algo alg, const uint8_t *kc);
+
+int gprs_llc_vty_init(void);
+
+#endif
diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h
new file mode 100644
index 0000000..953c364
--- /dev/null
+++ b/openbsc/include/openbsc/gprs_ns.h
@@ -0,0 +1,232 @@
+#ifndef _GPRS_NS_H
+#define _GPRS_NS_H
+
+#include <stdint.h>
+
+/* GPRS Networks Service (NS) messages on the Gb interface
+ * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05)
+ * 3GPP TS 48.016 version 6.5.0 Release 6 / ETSI TS 148 016 V6.5.0 (2005-11) */
+
+struct gprs_ns_hdr {
+	uint8_t pdu_type;
+	uint8_t data[0];
+} __attribute__((packed));
+
+/* TS 08.16, Section 10.3.7, Table 14 */
+enum ns_pdu_type {
+	NS_PDUT_UNITDATA	= 0x00,
+	NS_PDUT_RESET		= 0x02,
+	NS_PDUT_RESET_ACK	= 0x03,
+	NS_PDUT_BLOCK		= 0x04,
+	NS_PDUT_BLOCK_ACK	= 0x05,
+	NS_PDUT_UNBLOCK		= 0x06,
+	NS_PDUT_UNBLOCK_ACK	= 0x07,
+	NS_PDUT_STATUS		= 0x08,
+	NS_PDUT_ALIVE		= 0x0a,
+	NS_PDUT_ALIVE_ACK	= 0x0b,
+	/* TS 48.016 Section 10.3.7, Table 10.3.7.1 */
+	SNS_PDUT_ACK		= 0x0c,
+	SNS_PDUT_ADD		= 0x0d,
+	SNS_PDUT_CHANGE_WEIGHT	= 0x0e,
+	SNS_PDUT_CONFIG		= 0x0f,
+	SNS_PDUT_CONFIG_ACK	= 0x10,
+	SNS_PDUT_DELETE		= 0x11,
+	SNS_PDUT_SIZE		= 0x12,
+	SNS_PDUT_SIZE_ACK	= 0x13,
+};
+
+/* TS 08.16, Section 10.3, Table 12 */
+enum ns_ctrl_ie {
+	NS_IE_CAUSE		= 0x00,
+	NS_IE_VCI		= 0x01,
+	NS_IE_PDU		= 0x02,
+	NS_IE_BVCI		= 0x03,
+	NS_IE_NSEI		= 0x04,
+	/* TS 48.016 Section 10.3, Table 10.3.1 */
+	NS_IE_IPv4_LIST		= 0x05,
+	NS_IE_IPv6_LIST		= 0x06,
+	NS_IE_MAX_NR_NSVC	= 0x07,
+	NS_IE_IPv4_EP_NR	= 0x08,
+	NS_IE_IPv6_EP_NR	= 0x09,
+	NS_IE_RESET_FLAG	= 0x0a,
+	NS_IE_IP_ADDR		= 0x0b,
+};
+
+/* TS 08.16, Section 10.3.2, Table 13 */
+enum ns_cause {
+	NS_CAUSE_TRANSIT_FAIL		= 0x00,
+	NS_CAUSE_OM_INTERVENTION	= 0x01,
+	NS_CAUSE_EQUIP_FAIL		= 0x02,
+	NS_CAUSE_NSVC_BLOCKED		= 0x03,
+	NS_CAUSE_NSVC_UNKNOWN		= 0x04,
+	NS_CAUSE_BVCI_UNKNOWN		= 0x05,
+	NS_CAUSE_SEM_INCORR_PDU		= 0x08,
+	NS_CAUSE_PDU_INCOMP_PSTATE	= 0x0a,
+	NS_CAUSE_PROTO_ERR_UNSPEC	= 0x0b,
+	NS_CAUSE_INVAL_ESSENT_IE	= 0x0c,
+	NS_CAUSE_MISSING_ESSENT_IE	= 0x0d,
+	/* TS 48.016 Section 10.3.2, Table 10.3.2.1 */
+	NS_CAUSE_INVAL_NR_IPv4_EP	= 0x0e,
+	NS_CAUSE_INVAL_NR_IPv6_EP	= 0x0f,
+	NS_CAUSE_INVAL_NR_NS_VC		= 0x10,
+	NS_CAUSE_INVAL_WEIGH		= 0x11,
+	NS_CAUSE_UNKN_IP_EP		= 0x12,
+	NS_CAUSE_UNKN_IP_ADDR		= 0x13,
+	NS_CAUSE_UNKN_IP_TEST_FAILED	= 0x14,
+};
+
+/* Our Implementation */
+#include <netinet/in.h>
+#include <osmocore/linuxlist.h>
+#include <osmocore/msgb.h>
+#include <osmocore/timer.h>
+#include <osmocore/select.h>
+
+#define NS_TIMERS_COUNT 7
+#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries)"
+#define NS_TIMERS_HELP	\
+	"(un)blocking Timer (Tns-block) timeout\n"		\
+	"(un)blocking Timer (Tns-block) number of retries\n"	\
+	"Reset Timer (Tns-reset) timeout\n"			\
+	"Reset Timer (Tns-reset) number of retries\n"		\
+	"Test Timer (Tns-test) timeout\n"			\
+
+enum ns_timeout {
+	NS_TOUT_TNS_BLOCK,
+	NS_TOUT_TNS_BLOCK_RETRIES,
+	NS_TOUT_TNS_RESET,
+	NS_TOUT_TNS_RESET_RETRIES,
+	NS_TOUT_TNS_TEST,
+	NS_TOUT_TNS_ALIVE,
+	NS_TOUT_TNS_ALIVE_RETRIES,
+};
+
+#define NSE_S_BLOCKED	0x0001
+#define NSE_S_ALIVE	0x0002
+
+enum gprs_ns_ll {
+	GPRS_NS_LL_UDP,
+	GPRS_NS_LL_E1,
+	GPRS_NS_LL_FR_GRE,
+};
+
+enum gprs_ns_evt {
+	GPRS_NS_EVT_UNIT_DATA,
+};
+
+struct gprs_nsvc;
+typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
+			 struct msgb *msg, uint16_t bvci);
+
+/* An instance of the NS protocol stack */
+struct gprs_ns_inst {
+	/* callback to the user for incoming UNIT DATA IND */
+	gprs_ns_cb_t *cb;
+
+	/* linked lists of all NSVC in this instance */
+	struct llist_head gprs_nsvcs;
+
+	/* a NSVC object that's needed to deal with packets for unknown NSVC */
+	struct gprs_nsvc *unknown_nsvc;
+
+	uint16_t timeout[NS_TIMERS_COUNT];
+
+	/* NS-over-IP specific bits */
+	struct {
+		struct bsc_fd fd;
+		uint32_t local_ip;
+		uint16_t local_port;
+	} nsip;
+	/* NS-over-FR-over-GRE-over-IP specific bits */
+	struct {
+		struct bsc_fd fd;
+		uint32_t local_ip;
+		int enabled:1;
+	} frgre;
+};
+
+enum nsvc_timer_mode {
+	/* standard timers */
+	NSVC_TIMER_TNS_TEST,
+	NSVC_TIMER_TNS_ALIVE,
+	NSVC_TIMER_TNS_RESET,
+	_NSVC_TIMER_NR,
+};
+
+struct gprs_nsvc {
+	struct llist_head list;
+	struct gprs_ns_inst *nsi;
+
+	uint16_t nsei;		/* end-to-end significance */
+	uint16_t nsvci;	/* uniquely identifies NS-VC at SGSN */
+
+	uint32_t state;
+	uint32_t remote_state;
+
+	struct timer_list timer;
+	enum nsvc_timer_mode timer_mode;
+	int alive_retries;
+
+	unsigned int remote_end_is_sgsn:1;
+	unsigned int persistent:1;
+
+	struct rate_ctr_group *ctrg;
+
+	/* which link-layer are we based on? */
+	enum gprs_ns_ll ll;
+
+	union {
+		struct {
+			struct sockaddr_in bts_addr;
+		} ip;
+		struct {
+			struct sockaddr_in bts_addr;
+		} frgre;
+	};
+};
+
+/* Create a new NS protocol instance */
+struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb);
+
+/* Destroy a NS protocol instance */
+void gprs_ns_destroy(struct gprs_ns_inst *nsi);
+
+/* Listen for incoming GPRS packets via NS/UDP */
+int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi);
+
+struct sockaddr_in;
+
+/* main function for higher layers (BSSGP) to send NS messages */
+int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg);
+
+int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause);
+int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause);
+int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc);
+
+/* Listen for incoming GPRS packets via NS/FR/GRE */
+int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi);
+
+/* Establish a connection (from the BSS) to the SGSN */
+struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi,
+				struct sockaddr_in *dest, uint16_t nsei,
+				uint16_t nsvci);
+
+struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci);
+void nsvc_delete(struct gprs_nsvc *nsvc);
+struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei);
+struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci);
+
+/* Initiate a RESET procedure (including timer start, ...)*/
+void gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause);
+
+/* Add NS-specific VTY stuff */
+int gprs_ns_vty_init(struct gprs_ns_inst *nsi);
+
+#define NS_ALLOC_SIZE	2048
+#define NS_ALLOC_HEADROOM 20
+static inline struct msgb *gprs_ns_msgb_alloc(void)
+{
+	return msgb_alloc_headroom(NS_ALLOC_SIZE, NS_ALLOC_HEADROOM, "GPRS/NS");
+}
+
+#endif
diff --git a/openbsc/include/openbsc/gprs_ns_frgre.h b/openbsc/include/openbsc/gprs_ns_frgre.h
new file mode 100644
index 0000000..abcd43f
--- /dev/null
+++ b/openbsc/include/openbsc/gprs_ns_frgre.h
@@ -0,0 +1,6 @@
+#ifndef _GPRS_NS_FRGRE_H
+#define _GPRS_NS_FRGRE_H
+
+int gprs_ns_frgre_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg);
+
+#endif
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
new file mode 100644
index 0000000..0801150
--- /dev/null
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -0,0 +1,210 @@
+#ifndef _GPRS_SGSN_H
+#define _GPRS_SGSN_H
+
+#include <stdint.h>
+#include <netinet/in.h>
+
+#include <osmocore/gsm48.h>
+
+#define GSM_IMSI_LENGTH 17
+#define GSM_IMEI_LENGTH 17
+#define GSM_EXTENSION_LENGTH 15
+
+struct gprs_llc_lle;
+
+/* TS 04.08 4.1.3.3 GMM mobility management states on the network side */
+enum gprs_mm_state {
+	GMM_DEREGISTERED,		/* 4.1.3.3.1.1 */
+	GMM_COMMON_PROC_INIT,		/* 4.1.3.3.1.2 */
+	GMM_REGISTERED_NORMAL,		/* 4.1.3.3.2.1 */
+	GMM_REGISTERED_SUSPENDED,	/* 4.1.3.3.2.2 */
+	GMM_DEREGISTERED_INIT,		/* 4.1.3.3.1.4 */
+};
+
+enum gprs_ciph_algo {
+	GPRS_ALGO_GEA0,
+	GPRS_ALGO_GEA1,
+	GPRS_ALGO_GEA2,
+	GPRS_ALGO_GEA3,
+};
+
+enum gprs_mm_ctr {
+	GMM_CTR_PKTS_SIG_IN,
+	GMM_CTR_PKTS_SIG_OUT,
+	GMM_CTR_PKTS_UDATA_IN,
+	GMM_CTR_PKTS_UDATA_OUT,
+	GMM_CTR_BYTES_UDATA_IN,
+	GMM_CTR_BYTES_UDATA_OUT,
+	GMM_CTR_PDP_CTX_ACT,
+	GMM_CTR_SUSPEND,
+	GMM_CTR_PAGING_PS,
+	GMM_CTR_PAGING_CS,
+	GMM_CTR_RA_UPDATE,
+};
+
+enum gprs_pdp_ctx {
+	PDP_CTR_PKTS_UDATA_IN,
+	PDP_CTR_PKTS_UDATA_OUT,
+	PDP_CTR_BYTES_UDATA_IN,
+	PDP_CTR_BYTES_UDATA_OUT,
+};
+
+enum gprs_t3350_mode {
+	GMM_T3350_MODE_ATT,
+	GMM_T3350_MODE_RAU,
+	GMM_T3350_MODE_PTMSI_REALL,
+};
+
+#define MS_RADIO_ACCESS_CAPA
+
+/* According to TS 03.60, Table 5: SGSN MM and PDP Contexts */
+/* Extended by 3GPP TS 23.060, Table 6: SGSN MM and PDP Contexts */
+struct sgsn_mm_ctx {
+	struct llist_head	list;
+
+	char 			imsi[GSM_IMSI_LENGTH];
+	enum gprs_mm_state	mm_state;
+	uint32_t 		p_tmsi;
+	uint32_t 		p_tmsi_old;	/* old P-TMSI before new is confirmed */
+	uint32_t 		p_tmsi_sig;
+	char 			imei[GSM_IMEI_LENGTH];
+	/* Opt: Software Version Numbber / TS 23.195 */
+	char 			msisdn[GSM_EXTENSION_LENGTH];
+	struct gprs_ra_id	ra;
+	uint16_t		cell_id;
+	uint32_t		cell_id_age;
+	uint16_t		sac;	/* Iu: Service Area Code */
+	uint32_t		sac_age;/* Iu: Service Area Code age */
+	/* VLR number */
+	uint32_t		new_sgsn_addr;
+	/* Authentication Triplets */
+	/* Kc */
+	/* Iu: CK, IK, KSI */
+	/* CKSN */
+	enum gprs_ciph_algo	ciph_algo;
+	struct {
+		uint8_t	buf[14];	/* 10.5.5.12a */
+		uint8_t	len;
+	} ms_radio_access_capa;
+	struct {
+		uint8_t	buf[4];		/* 10.5.5.12 */
+		uint8_t	len;
+	} ms_network_capa;
+	uint16_t		drx_parms;
+	int			mnrg;	/* MS reported to HLR? */
+	int			ngaf;	/* MS reported to MSC/VLR? */
+	int			ppf;	/* paging for GPRS + non-GPRS? */
+	/* SMS Parameters */
+	int			recovery;
+	uint8_t			radio_prio_sms;
+
+	struct llist_head	pdp_list;
+
+	/* Additional bits not present in the GSM TS */
+	struct gprs_llc_llme	*llme;
+	uint32_t		tlli;
+	uint32_t		tlli_new;
+	uint16_t		nsei;
+	uint16_t		bvci;
+	struct rate_ctr_group	*ctrg;
+	struct timer_list	timer;
+	unsigned int		T;		/* Txxxx number */
+	unsigned int		num_T_exp;	/* number of consecutive T expirations */
+
+	enum gprs_t3350_mode	t3350_mode;
+	uint8_t			t3370_id_type;
+};
+
+/* look-up a SGSN MM context based on TLLI + RAI */
+struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
+					const struct gprs_ra_id *raid);
+struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t tmsi);
+struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi);
+
+/* Allocate a new SGSN MM context */
+struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
+					const struct gprs_ra_id *raid);
+
+
+enum pdp_ctx_state {
+	PDP_STATE_NONE,
+	PDP_STATE_CR_REQ,
+	PDP_STATE_CR_CONF,
+};
+
+enum pdp_type {
+	PDP_TYPE_NONE,
+	PDP_TYPE_ETSI_PPP,
+	PDP_TYPE_IANA_IPv4,
+	PDP_TYPE_IANA_IPv6,
+};
+
+struct sgsn_pdp_ctx {
+	struct llist_head	list;	/* list_head for mmctx->pdp_list */
+	struct llist_head	g_list;	/* list_head for global list */
+	struct sgsn_mm_ctx	*mm;	/* back pointer to MM CTX */
+	struct sgsn_ggsn_ctx	*ggsn;	/* which GGSN serves this PDP */
+	struct rate_ctr_group	*ctrg;
+
+	//unsigned int		id;
+	struct pdp_t		*lib;	/* pointer to libgtp PDP ctx */
+	enum pdp_ctx_state	state;
+	enum pdp_type		type;
+	uint32_t		address;
+	char 			*apn_subscribed;
+	//char 			*apn_used;
+	uint16_t		nsapi;	/* SNDCP */
+	uint16_t		sapi;	/* LLC */
+	uint8_t			ti;	/* transaction identifier */
+	int			vplmn_allowed;
+	uint32_t		qos_profile_subscr;
+	//uint32_t		qos_profile_req;
+	//uint32_t		qos_profile_neg;
+	uint8_t			radio_prio;
+	uint32_t		tx_npdu_nr;
+	uint32_t		rx_npdu_nr;
+	uint32_t		tx_gtp_snd;
+	uint32_t		rx_gtp_snu;
+	//uint32_t		charging_id;
+	int			reordering_reqd;
+};
+
+
+/* look up PDP context by MM context and NSAPI */
+struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm,
+					   uint8_t nsapi);
+/* look up PDP context by MM context and transaction ID */
+struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm,
+					 uint8_t tid);
+
+struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
+					uint8_t nsapi);
+void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp);
+
+
+struct sgsn_ggsn_ctx {
+	struct llist_head list;
+	uint32_t id;
+	unsigned int gtp_version;
+	struct in_addr remote_addr;
+	struct gsn_t *gsn;
+};
+struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id);
+struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id);
+struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id);
+
+struct apn_ctx {
+	struct llist_head list;
+	struct sgsn_ggsn_ctx *ggsn;
+	char *name;
+	char *description;
+};
+
+extern struct llist_head sgsn_mm_ctxts;
+extern struct llist_head sgsn_ggsn_ctxts;
+extern struct llist_head sgsn_apn_ctxts;
+extern struct llist_head sgsn_pdp_ctxts;
+
+uint32_t sgsn_alloc_ptmsi(void);
+
+#endif /* _GPRS_SGSN_H */
diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index c4018cd..1e5ffce 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -11,21 +11,28 @@
 struct gsm_subscriber;
 struct gsm_network;
 struct gsm_trans;
+struct gsm_subscriber_connection;
+
+#define GSM48_ALLOC_SIZE	1024
+#define GSM48_ALLOC_HEADROOM	128
+
+static inline struct msgb *gsm48_msgb_alloc(void)
+{
+	return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM,
+				   "GSM 04.08");
+}
 
 /* config options controlling the behaviour of the lower leves */
 void gsm0408_allow_everyone(int allow);
+void gsm0408_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause);
 
 int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id);
 enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci);
 enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci);
 
-int gsm48_tx_mm_info(struct gsm_lchan *lchan);
+int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn);
 int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand, int key_seq);
 int gsm48_tx_mm_auth_rej(struct gsm_lchan *lchan);
-struct msgb *gsm48_msgb_alloc(void);
-int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans);
-int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len);
-
 int gsm48_send_rr_release(struct gsm_lchan *lchan);
 int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv);
 int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id,
@@ -45,7 +52,8 @@
 		      int h_len);
 
 int send_siemens_mrpci(struct gsm_lchan *lchan, u_int8_t *classmark2_lv);
-int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type);
+int gsm48_extract_mi(uint8_t *classmark2, int length, char *mi_string, uint8_t *mi_type);
+int gsm48_paging_extract_mi(struct gsm48_pag_resp *pag, int length, char *mi_string, u_int8_t *mi_type);
 int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr);
 
 int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode);
diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h
new file mode 100644
index 0000000..baa513b
--- /dev/null
+++ b/openbsc/include/openbsc/gsm_04_08_gprs.h
@@ -0,0 +1,366 @@
+#ifndef _GSM48_GPRS_H
+#define _GSM48_GPRS_H
+
+#include <stdint.h>
+#include <osmocore/protocol/gsm_04_08.h>
+
+/* Table 10.4 / 10.4a, GPRS Mobility Management (GMM) */
+#define GSM48_MT_GMM_ATTACH_REQ		0x01
+#define GSM48_MT_GMM_ATTACH_ACK		0x02
+#define GSM48_MT_GMM_ATTACH_COMPL	0x03
+#define GSM48_MT_GMM_ATTACH_REJ		0x04
+#define GSM48_MT_GMM_DETACH_REQ		0x05
+#define GSM48_MT_GMM_DETACH_ACK		0x06
+
+#define GSM48_MT_GMM_RA_UPD_REQ		0x08
+#define GSM48_MT_GMM_RA_UPD_ACK		0x09
+#define GSM48_MT_GMM_RA_UPD_COMPL	0x0a
+#define GSM48_MT_GMM_RA_UPD_REJ		0x0b
+
+#define GSM48_MT_GMM_PTMSI_REALL_CMD	0x10
+#define GSM48_MT_GMM_PTMSI_REALL_COMPL	0x11
+#define GSM48_MT_GMM_AUTH_CIPH_REQ	0x12
+#define GSM48_MT_GMM_AUTH_CIPH_RESP	0x13
+#define GSM48_MT_GMM_AUTH_CIPH_REJ	0x14
+#define GSM48_MT_GMM_ID_REQ		0x15
+#define GSM48_MT_GMM_ID_RESP		0x16
+#define GSM48_MT_GMM_STATUS		0x20
+#define GSM48_MT_GMM_INFO		0x21
+
+/* Table 10.4a, GPRS Session Management (GSM) */
+#define GSM48_MT_GSM_ACT_PDP_REQ	0x41
+#define GSM48_MT_GSM_ACT_PDP_ACK	0x42
+#define GSM48_MT_GSM_ACT_PDP_REJ	0x43
+#define GSM48_MT_GSM_REQ_PDP_ACT	0x44
+#define GSM48_MT_GSM_REQ_PDP_ACT_REJ	0x45
+#define GSM48_MT_GSM_DEACT_PDP_REQ	0x46
+#define GSM48_MT_GSM_DEACT_PDP_ACK	0x47
+#define GSM48_MT_GSM_ACT_AA_PDP_REQ	0x50
+#define GSM48_MT_GSM_ACT_AA_PDP_ACK	0x51
+#define GSM48_MT_GSM_ACT_AA_PDP_REJ	0x52
+#define GSM48_MT_GSM_DEACT_AA_PDP_REQ	0x53
+#define GSM48_MT_GSM_DEACT_AA_PDP_ACK	0x54
+#define GSM48_MT_GSM_STATUS		0x55
+
+/* Chapter 10.5.5.2 / Table 10.5.135 */
+#define GPRS_ATT_T_ATTACH		1
+#define GPRS_ATT_T_ATT_WHILE_IMSI	2
+#define GPRS_ATT_T_COMBINED		3
+
+/* Chapter 10.5.5.5 / Table 10.5.138 */
+#define GPRS_DET_T_MO_GPRS		1
+#define GPRS_DET_T_MO_IMSI		2
+#define GPRS_DET_T_MO_COMBINED		3
+/* Network to MS direction */
+#define GPRS_DET_T_MT_REATT_REQ		1
+#define GPRS_DET_T_MT_REATT_NOTREQ	2
+#define GPRS_DET_T_MT_IMSI		3
+
+/* Chapter 10.5.5.18 / Table 105.150 */
+#define GPRS_UPD_T_RA			0
+#define GPRS_UPD_T_RA_LA		1
+#define GPRS_UPD_T_RA_LA_IMSI_ATT	2
+#define GPRS_UPD_T_PERIODIC		3
+
+enum gsm48_gprs_ie_mm {
+	GSM48_IE_GMM_TIMER_READY	= 0x17,	/* 10.5.7.3 */
+	GSM48_IE_GMM_ALLOC_PTMSI	= 0x18,	/* 10.5.1.4 */
+	GSM48_IE_GMM_PTMSI_SIG		= 0x19,	/* 10.5.5.8 */
+	GSM48_IE_GMM_AUTH_RAND		= 0x21,	/* 10.5.3.1 */
+	GSM48_IE_GMM_AUTH_SRES		= 0x22,	/* 10.5.3.2 */
+	GSM48_IE_GMM_IMEISV		= 0x23,	/* 10.5.1.4 */
+	GSM48_IE_GMM_DRX_PARAM		= 0x27,	/* 10.5.5.6 */
+	GSM48_IE_GMM_MS_NET_CAPA	= 0x31,	/* 10.5.5.12 */
+	GSM48_IE_GMM_PDP_CTX_STATUS	= 0x32,	/* 10.5.7.1 */
+	GSM48_IE_GMM_PS_LCS_CAPA	= 0x33,	/* 10.5.5.22 */
+	GSM48_IE_GMM_GMM_MBMS_CTX_ST	= 0x35,	/* 10.5.7.6 */
+};
+
+enum gsm48_gprs_ie_sm {
+	GSM48_IE_GSM_APN		= 0x28,	/* 10.5.6.1 */
+	GSM48_IE_GSM_PROTO_CONF_OPT	= 0x27,	/* 10.5.6.3 */
+	GSM48_IE_GSM_PDP_ADDR		= 0x2b, /* 10.5.6.4 */
+	GSM48_IE_GSM_AA_TMR		= 0x29,	/* 10.5.7.3 */
+	GSM48_IE_GSM_NAME_FULL		= 0x43, /* 10.5.3.5a */
+	GSM48_IE_GSM_NAME_SHORT		= 0x45, /* 10.5.3.5a */
+	GSM48_IE_GSM_TIMEZONE		= 0x46, /* 10.5.3.8 */
+	GSM48_IE_GSM_UTC_AND_TZ		= 0x47, /* 10.5.3.9 */
+	GSM48_IE_GSM_LSA_ID		= 0x48, /* 10.5.3.11 */
+
+	/* Fake IEs that are not present on the Layer3 air interface,
+	 * but which we use to simplify internal APIs */
+	OSMO_IE_GSM_REQ_QOS		= 0xfd,
+	OSMO_IE_GSM_REQ_PDP_ADDR	= 0xfe,
+};
+
+/* Chapter 9.4.15 / Table 9.4.15 */
+struct gsm48_ra_upd_ack {
+	uint8_t force_stby:4,	/* 10.5.5.7 */
+		 upd_result:4;	/* 10.5.5.17 */
+	uint8_t ra_upd_timer;	/* 10.5.7.3 */
+	struct gsm48_ra_id ra_id; /* 10.5.5.15 */
+	uint8_t data[0];
+} __attribute__((packed));
+
+/* Chapter 10.5.7.3 */
+enum gsm48_gprs_tmr_unit {
+	GPRS_TMR_2SECONDS	= 0 << 5,
+	GPRS_TMR_MINUTE		= 1 << 5,
+	GPRS_TMR_6MINUTE	= 2 << 5,
+	GPRS_TMR_DEACTIVATED	= 3 << 5,
+};
+
+/* Chapter 9.4.2 / Table 9.4.2 */
+struct gsm48_attach_ack {
+	uint8_t att_result:4,	/* 10.5.5.7 */
+		 force_stby:4;	/* 10.5.5.1 */
+	uint8_t ra_upd_timer;	/* 10.5.7.3 */
+	uint8_t radio_prio;	/* 10.5.7.2 */
+	struct gsm48_ra_id ra_id; /* 10.5.5.15 */
+	uint8_t data[0];
+} __attribute__((packed));
+
+/* Chapter 9.5.1 / Table 9.5.1 */
+struct gsm48_act_pdp_ctx_req {
+	uint8_t req_nsapi;
+	uint8_t req_llc_sapi;
+	uint8_t data[0];
+} __attribute__((packed));
+
+/* Chapter 10.5.5.14 / Table 10.5.147 */
+enum gsm48_gmm_cause {
+	GMM_CAUSE_IMSI_UNKNOWN		= 0x02,
+	GMM_CAUSE_ILLEGAL_MS		= 0x03,
+	GMM_CAUSE_ILLEGAL_ME		= 0x06,
+	GMM_CAUSE_GPRS_NOTALLOWED	= 0x07,
+	GMM_CAUSE_GPRS_OTHER_NOTALLOWED	= 0x08,
+	GMM_CAUSE_MS_ID_NOT_DERIVED	= 0x09,
+	GMM_CAUSE_IMPL_DETACHED		= 0x0a,
+	GMM_CAUSE_PLMN_NOTALLOWED	= 0x0b,
+	GMM_CAUSE_LA_NOTALLOWED		= 0x0c,
+	GMM_CAUSE_ROAMING_NOTALLOWED	= 0x0d,
+	GMM_CAUSE_NO_GPRS_PLMN		= 0x0e,
+	GMM_CAUSE_MSC_TEMP_NOTREACH	= 0x10,
+	GMM_CAUSE_NET_FAIL		= 0x11,
+	GMM_CAUSE_CONGESTION		= 0x16,
+	GMM_CAUSE_SEM_INCORR_MSG	= 0x5f,
+	GMM_CAUSE_INV_MAND_INFO		= 0x60,
+	GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL	= 0x61,
+	GMM_CAUSE_MSGT_INCOMP_P_STATE	= 0x62,
+	GMM_CAUSE_IE_NOTEXIST_NOTIMPL	= 0x63,
+	GMM_CAUSE_COND_IE_ERR		= 0x64,
+	GMM_CAUSE_MSG_INCOMP_P_STATE	= 0x65,
+	GMM_CAUSE_PROTO_ERR_UNSPEC	= 0x6f,
+};
+
+/* Chapter 10.4.6.6 / Table 10.5.157 */
+enum gsm48_gsm_cause {
+	GSM_CAUSE_INSUFF_RSRC		= 0x1a,
+	GSM_CAUSE_MISSING_APN		= 0x1b,
+	GSM_CAUSE_UNKNOWN_PDP		= 0x1c,
+	GSM_CAUSE_AUTH_FAILED		= 0x1d,
+	GSM_CAUSE_ACT_REJ_GGSN		= 0x1e,
+	GSM_CAUSE_ACT_REJ_UNSPEC	= 0x1f,
+	GSM_CAUSE_SERV_OPT_NOTSUPP	= 0x20,
+	GSM_CAUSE_REQ_SERV_OPT_NOTSUB	= 0x21,
+	GSM_CAUSE_SERV_OPT_TEMP_OOO	= 0x22,
+	GSM_CAUSE_NSAPI_IN_USE		= 0x23,
+	GSM_CAUSE_DEACT_REGULAR		= 0x24,
+	GSM_CAUSE_QOS_NOT_ACCEPTED	= 0x25,
+	GSM_CAUSE_NET_FAIL		= 0x26,
+	GSM_CAUSE_REACT_RQD		= 0x27,
+	GSM_CAUSE_FEATURE_NOTSUPP	= 0x28,
+	GSM_CAUSE_INVALID_TRANS_ID	= 0x51,
+	GSM_CAUSE_SEM_INCORR_MSG	= 0x5f,
+	GSM_CAUSE_INV_MAND_INFO		= 0x60,
+	GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL	= 0x61,
+	GSM_CAUSE_MSGT_INCOMP_P_STATE	= 0x62,
+	GSM_CAUSE_IE_NOTEXIST_NOTIMPL	= 0x63,
+	GSM_CAUSE_COND_IE_ERR		= 0x64,
+	GSM_CAUSE_MSG_INCOMP_P_STATE	= 0x65,
+	GSM_CAUSE_PROTO_ERR_UNSPEC	= 0x6f,
+};
+
+/* Section 6.1.2.2: Session management states on the network side */
+enum gsm48_pdp_state {
+	PDP_S_INACTIVE,
+	PDP_S_ACTIVE_PENDING,
+	PDP_S_ACTIVE,
+	PDP_S_INACTIVE_PENDING,
+	PDP_S_MODIFY_PENDING,
+};
+
+/* Table 10.5.155/3GPP TS 24.008 */
+enum gsm48_pdp_type_org {
+	PDP_TYPE_ORG_ETSI		= 0x00,
+	PDP_TYPE_ORG_IETF		= 0x01,
+};
+enum gsm48_pdp_type_nr {
+	PDP_TYPE_N_ETSI_RESERVED	= 0x00,
+	PDP_TYPE_N_ETSI_PPP		= 0x01,
+	PDP_TYPE_N_IETF_IPv4		= 0x21,
+	PDP_TYPE_N_IETF_IPv6		= 0x57,
+};
+
+/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */
+enum gsm48_qos_reliab_class {
+	GSM48_QOS_RC_LLC_ACK_RLC_ACK_DATA_PROT	= 2,
+	GSM48_QOS_RC_LLC_UN_RLC_ACK_DATA_PROT	= 3,
+	GSM48_QOS_RC_LLC_UN_RLC_UN_PROT_DATA	= 4,
+	GSM48_QOS_RC_LLC_UN_RLC_UN_DATA_UN	= 5,
+};
+
+/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */
+enum gsm48_qos_preced_class {
+	GSM48_QOS_PC_HIGH	= 1,
+	GSM48_QOS_PC_NORMAL	= 2,
+	GSM48_QOS_PC_LOW	= 3,
+};
+
+/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */
+enum gsm48_qos_peak_tput {
+	GSM48_QOS_PEAK_TPUT_1000bps	= 1,
+	GSM48_QOS_PEAK_TPUT_2000bps	= 2,
+	GSM48_QOS_PEAK_TPUT_4000bps	= 3,
+	GSM48_QOS_PEAK_TPUT_8000bps	= 4,
+	GSM48_QOS_PEAK_TPUT_16000bps	= 5,
+	GSM48_QOS_PEAK_TPUT_32000bps	= 6,
+	GSM48_QOS_PEAK_TPUT_64000bps	= 7,
+	GSM48_QOS_PEAK_TPUT_128000bps	= 8,
+	GSM48_QOS_PEAK_TPUT_256000bps	= 9,
+};
+
+/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */
+enum gsm48_qos_mean_tput {
+	GSM48_QOS_MEAN_TPUT_100bph	= 1,
+	GSM48_QOS_MEAN_TPUT_200bph	= 2,
+	GSM48_QOS_MEAN_TPUT_500bph	= 3,
+	GSM48_QOS_MEAN_TPUT_1000bph	= 4,
+	GSM48_QOS_MEAN_TPUT_2000bph	= 5,
+	GSM48_QOS_MEAN_TPUT_5000bph	= 6,
+	GSM48_QOS_MEAN_TPUT_10000bph	= 7,
+	GSM48_QOS_MEAN_TPUT_20000bph	= 8,
+	GSM48_QOS_MEAN_TPUT_50000bph	= 9,
+	GSM48_QOS_MEAN_TPUT_100kbph	= 10,
+	GSM48_QOS_MEAN_TPUT_200kbph	= 11,
+	GSM48_QOS_MEAN_TPUT_500kbph	= 0xc,
+	GSM48_QOS_MEAN_TPUT_1Mbph	= 0xd,
+	GSM48_QOS_MEAN_TPUT_2Mbph	= 0xe,
+	GSM48_QOS_MEAN_TPUT_5Mbph	= 0xf,
+	GSM48_QOS_MEAN_TPUT_10Mbph	= 0x10,
+	GSM48_QOS_MEAN_TPUT_20Mbph	= 0x11,
+	GSM48_QOS_MEAN_TPUT_50Mbph	= 0x12,
+	GSM48_QOS_MEAN_TPUT_BEST_EFFORT	= 0x1f,
+};
+
+/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */
+enum gsm48_qos_err_sdu {
+	GSM48_QOS_ERRSDU_NODETECT	= 1,
+	GSM48_QOS_ERRSDU_YES		= 2,
+	GSM48_QOS_ERRSDU_NO		= 3,
+};
+
+/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */
+enum gsm48_qos_deliv_order {
+	GSM48_QOS_DO_ORDERED		= 1,
+	GSM48_QOS_DO_UNORDERED		= 2,
+};
+
+/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */
+enum gsm48_qos_traf_class {
+	GSM48_QOS_TC_CONVERSATIONAL	= 1,
+	GSM48_QOS_TC_STREAMING		= 2,
+	GSM48_QOS_TC_INTERACTIVE	= 3,
+	GSM48_QOS_TC_BACKGROUND		= 4,
+};
+
+/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */
+enum gsm48_qos_max_sdu_size {
+	/* values below in 10 octet granularity */
+	GSM48_QOS_MAXSDU_1502		= 0x97,
+	GSM48_QOS_MAXSDU_1510		= 0x98,
+	GSM48_QOS_MAXSDU_1520		= 0x99,
+};
+
+/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */
+enum gsm48_qos_max_bitrate {
+	GSM48_QOS_MBRATE_1k		= 0x01,
+	GSM48_QOS_MBRATE_63k		= 0x3f,
+	GSM48_QOS_MBRATE_64k		= 0x40,
+	GSM48_QOS_MBRATE_568k		= 0x7f,
+	GSM48_QOS_MBRATE_576k		= 0x80,
+	GSM48_QOS_MBRATE_8640k		= 0xfe,
+	GSM48_QOS_MBRATE_0k		= 0xff,
+};
+
+/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */
+enum gsm48_qos_resid_ber {
+	GSM48_QOS_RBER_5e_2		= 0x01,
+	GSM48_QOS_RBER_1e_2		= 0x02,
+	GSM48_QOS_RBER_5e_3		= 0x03,
+	GSM48_QOS_RBER_4e_3		= 0x04,
+	GSM48_QOS_RBER_1e_3		= 0x05,
+	GSM48_QOS_RBER_1e_4		= 0x06,
+	GSM48_QOS_RBER_1e_5		= 0x07,
+	GSM48_QOS_RBER_1e_6		= 0x08,
+	GSM48_QOS_RBER_6e_8		= 0x09,
+};
+
+/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */
+enum gsm48_qos_sdu_err {
+	GSM48_QOS_SERR_1e_2		= 0x01,
+	GSM48_QOS_SERR_7e_2		= 0x02,
+	GSM48_QOS_SERR_1e_3		= 0x03,
+	GSM48_QOS_SERR_1e_4		= 0x04,
+	GSM48_QOS_SERR_1e_5		= 0x05,
+	GSM48_QOS_SERR_1e_6		= 0x06,
+	GSM48_QOS_SERR_1e_1		= 0x07,
+};
+
+/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */
+struct gsm48_qos {
+	/* octet 3 */
+	uint8_t reliab_class:3;
+	uint8_t delay_class:3;
+	uint8_t spare:2;
+	/* octet 4 */
+	uint8_t preced_class:3;
+	uint8_t spare2:1;
+	uint8_t peak_tput:4;
+	/* octet 5 */
+	uint8_t mean_tput:5;
+	uint8_t spare3:3;
+	/* octet 6 */
+	uint8_t deliv_err_sdu:3;
+	uint8_t deliv_order:2;
+	uint8_t traf_class:3;
+	/* octet 7 */
+	uint8_t max_sdu_size;
+	/* octet 8 */
+	uint8_t max_bitrate_up;
+	/* octet 9 */
+	uint8_t max_bitrate_down;
+	/* octet 10 */
+	uint8_t sdu_err_ratio:4;
+	uint8_t resid_ber:4;
+	/* octet 11 */
+	uint8_t handling_prio:2;
+	uint8_t xfer_delay:6;
+	/* octet 12 */
+	uint8_t guar_bitrate_up;
+	/* octet 13 */
+	uint8_t guar_bitrate_down;
+	/* octet 14 */
+	uint8_t src_stats_desc:4;
+	uint8_t sig_ind:1;
+	uint8_t spare5:3;
+	/* octet 15 */
+	uint8_t max_bitrate_down_ext;
+	/* octet 16 */
+	uint8_t guar_bitrate_down_ext;
+};
+
+
+int gprs_tlli_type(uint32_t tlli);
+
+#endif /* _GSM48_GPRS_H */
diff --git a/openbsc/include/openbsc/gsm_04_11.h b/openbsc/include/openbsc/gsm_04_11.h
index 9badd36..95ff5ef 100644
--- a/openbsc/include/openbsc/gsm_04_11.h
+++ b/openbsc/include/openbsc/gsm_04_11.h
@@ -3,6 +3,8 @@
 
 #include <osmocore/protocol/gsm_04_11.h>
 
+#define UM_SAPI_SMS 3	/* See GSM 04.05/04.06 */
+
 /* SMS deliver PDU */
 struct sms_deliver {
 	u_int8_t mti:2;		/* message type indicator */
@@ -25,7 +27,7 @@
 
 int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id);
 
-int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms);
+int gsm411_send_sms_lchan(struct gsm_subscriber_connection *conn, struct gsm_sms *sms);
 
 struct gsm_sms *sms_alloc(void);
 void sms_free(struct gsm_sms *sms);
@@ -33,4 +35,5 @@
 void _gsm411_sms_trans_free(struct gsm_trans *trans);
 int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
 			   struct gsm_sms *sms);
+void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn);
 #endif
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 88e7f16..4292bb1 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -65,6 +65,7 @@
 enum gsm_hooks {
 	GSM_HOOK_NM_SWLOAD,
 	GSM_HOOK_RR_PAGING,
+	GSM_HOOK_RR_SECURITY,
 };
 
 enum gsm_paging_event {
@@ -73,6 +74,45 @@
 	GSM_PAGING_OOM,
 };
 
+enum bts_gprs_mode {
+	BTS_GPRS_NONE = 0,
+	BTS_GPRS_GPRS = 1,
+	BTS_GPRS_EGPRS = 2,
+};
+
+/* the data structure stored in msgb->cb for openbsc apps */
+struct openbsc_msgb_cb {
+	unsigned char *bssgph;
+	unsigned char *llch;
+
+	/* Cell Identifier */
+	unsigned char *bssgp_cell_id;
+
+	/* Identifiers of a BTS, equal to 'struct bssgp_bts_ctx' */
+	u_int16_t nsei;
+	u_int16_t bvci;
+
+	/* Identifier of a MS (inside BTS), equal to 'struct sgsn_mm_ctx' */
+	u_int32_t tlli;
+} __attribute__((packed));
+#define OBSC_MSGB_CB(__msgb)	((struct openbsc_msgb_cb *)&((__msgb)->cb[0]))
+#define msgb_tlli(__x)		OBSC_MSGB_CB(__x)->tlli
+#define msgb_nsei(__x)		OBSC_MSGB_CB(__x)->nsei
+#define msgb_bvci(__x)		OBSC_MSGB_CB(__x)->bvci
+#define msgb_gmmh(__x)		(__x)->l3h
+#define msgb_bssgph(__x)	OBSC_MSGB_CB(__x)->bssgph
+#define msgb_bssgp_len(__x)	((__x)->tail - (uint8_t *)msgb_bssgph(__x))
+#define msgb_bcid(__x)		OBSC_MSGB_CB(__x)->bssgp_cell_id
+#define msgb_llch(__x)		OBSC_MSGB_CB(__x)->llch
+
+#define OBSC_LINKID_CB(__msgb)	(__msgb)->cb[3]
+
+enum gsm_security_event {
+	GSM_SECURITY_NOAVAIL,
+	GSM_SECURITY_AUTH_FAILED,
+	GSM_SECURITY_SUCCEEDED,
+};
+
 struct msgb;
 typedef int gsm_cbfn(unsigned int hooknum,
 		     unsigned int event,
@@ -84,26 +124,21 @@
  * will be started.
  */
 #define LCHAN_RELEASE_TIMEOUT 20, 0
-#define use_lchan(lchan) \
-	do {	lchan->use_count++; \
+#define use_subscr_con(con) \
+	do {	(con)->use_count++; \
 		DEBUGP(DREF, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) increases usage to: %d\n", \
-			lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \
-			lchan->nr, lchan->use_count); \
-		bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT); } while(0);
+			(con)->lchan->ts->trx->bts->nr, (con)->lchan->ts->trx->nr, (con)->lchan->ts->nr, \
+			(con)->lchan->nr, (con)->use_count); \
+		bsc_schedule_timer(&(con)->release_timer, LCHAN_RELEASE_TIMEOUT); } while(0);
 
-#define put_lchan(lchan) \
-	do { lchan->use_count--; \
+#define put_subscr_con(con) \
+	do { (con)->use_count--; \
 		DEBUGP(DREF, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) decreases usage to: %d\n", \
-			lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \
-			lchan->nr, lchan->use_count); \
+			(con)->lchan->ts->trx->bts->nr, (con)->lchan->ts->trx->nr, (con)->lchan->ts->nr, \
+			(con)->lchan->nr, (con)->use_count); \
 	} while(0);
 
 
-/* communications link with a BTS */
-struct gsm_bts_link {
-	struct gsm_bts *bts;
-};
-
 /* Real authentication information containing Ki */
 enum gsm_auth_algo {
 	AUTH_ALGO_NONE,
@@ -124,12 +159,14 @@
 	u_int8_t sres[4];
 	u_int8_t kc[8];
 };
+#define GSM_KEY_SEQ_INVAL	7	/* GSM 04.08 - 10.5.1.2 */
 
 
 struct gsm_lchan;
 struct gsm_subscriber;
 struct gsm_mncc;
 struct rtp_socket;
+struct bsc_api;
 
 /* Network Management State */
 struct gsm_nm_state {
@@ -149,6 +186,16 @@
         struct timer_list updating_timer;
 	unsigned int waiting_for_imsi : 1;
 	unsigned int waiting_for_imei : 1;
+	unsigned int key_seq : 4;
+};
+
+/*
+ * AUTHENTICATION/CIPHERING state
+ */
+struct gsm_security_operation {
+	struct gsm_auth_tuple atuple;
+	gsm_cbfn *cb;
+	void *cb_data;
 };
 
 /* Maximum number of neighbor cells whose average we track */
@@ -166,6 +213,9 @@
 };
 
 #define MAX_A5_KEY_LEN	(128/8)
+#define A38_XOR_MIN_KEY_LEN	12
+#define A38_XOR_MAX_KEY_LEN	16
+#define A38_COMP128_KEY_LEN	16
 #define RSL_ENC_ALG_A5(x)	(x+1)
 
 /* is the data link established? who established it? */
@@ -179,9 +229,35 @@
 	LCHAN_S_ACT_REQ,	/* channel activatin requested */
 	LCHAN_S_ACTIVE,		/* channel is active and operational */
 	LCHAN_S_REL_REQ,	/* channel release has been requested */
+	LCHAN_S_REL_ERR,	/* channel is in an error state */
 	LCHAN_S_INACTIVE,	/* channel is set inactive */
 };
 
+/* the per subscriber data for lchan */
+struct gsm_subscriber_connection {
+	/* To whom we are allocated at the moment */
+	struct gsm_subscriber *subscr;
+
+	/* Timer started to release the channel */
+	struct timer_list release_timer;
+
+	/*
+	 * Operations that have a state and might be pending
+	 */
+	struct gsm_loc_updating_operation *loc_operation;
+	struct gsm_security_operation *sec_operation;
+
+	/* use count. how many users use this channel */
+	unsigned int use_count;
+
+	/* Are we part of a special "silent" call */
+	int silent_call;
+
+	/* back pointers */
+	struct gsm_lchan *lchan;
+	struct gsm_bts *bts;
+};
+
 struct gsm_lchan {
 	/* The TS that we're part of */
 	struct gsm_bts_trx_ts *ts;
@@ -204,31 +280,17 @@
 		u_int8_t key_len;
 		u_int8_t key[MAX_A5_KEY_LEN];
 	} encr;
-	/* Are we part of a special "silent" call */
-	int silent_call;
+
+	struct timer_list T3101;
+	struct timer_list T3111;
+	struct timer_list error_timer;
 
 	/* AMR bits */
 	struct gsm48_multi_rate_conf mr_conf;
 	
-	/* To whom we are allocated at the moment */
-	struct gsm_subscriber *subscr;
-
-	/* Timer started to release the channel */
-	struct timer_list release_timer;
-
-	struct timer_list T3101;
-
 	/* Established data link layer services */
 	u_int8_t sapis[8];
 
-	/*
-	 * Operations that have a state and might be pending
-	 */
-	struct gsm_loc_updating_operation *loc_operation;
-
-	/* use count. how many users use this channel */
-	unsigned int use_count;
-
 	/* cache of last measurement reports on this lchan */
 	struct gsm_meas_rep meas_rep[6];
 	int meas_rep_idx;
@@ -242,10 +304,13 @@
 		u_int16_t bound_port;
 		u_int16_t connect_port;
 		u_int16_t conn_id;
+		u_int8_t rtp_payload;
 		u_int8_t rtp_payload2;
 		u_int8_t speech_mode;
 		struct rtp_socket *rtp_socket;
 	} abis_ip;
+
+	struct gsm_subscriber_connection conn;
 };
 
 struct gsm_e1_subslot {
@@ -257,7 +322,7 @@
 	u_int8_t	e1_ts_ss;
 };
 
-#define BTS_TRX_F_ACTIVATED	0x0001
+#define TS_F_PDCH_MODE	0x1000
 /* One Timeslot in a TRX */
 struct gsm_bts_trx_ts {
 	struct gsm_bts_trx *trx;
@@ -285,6 +350,8 @@
 	struct gsm_bts *bts;
 	/* number of this TRX in the BTS */
 	u_int8_t nr;
+	/* human readable name / description */
+	char *description;
 	/* how do we talk RSL with this TRX? */
 	struct gsm_e1_subslot rsl_e1_link;
 	u_int8_t rsl_tei;
@@ -358,7 +425,6 @@
 struct gsm_bts_paging_state {
 	/* pending requests */
 	struct llist_head pending_requests;
-	struct gsm_paging_request *last_request;
 	struct gsm_bts *bts;
 
 	struct timer_list work_timer;
@@ -373,11 +439,14 @@
 
 struct gsm_bts_gprs_nsvc {
 	struct gsm_bts *bts;
+	/* data read via VTY config file, to configure the BTS
+	 * via OML from BSC */
 	int id;
 	u_int16_t nsvci;
-	u_int16_t local_port;
-	u_int16_t remote_port;
-	u_int32_t remote_ip;
+	u_int16_t local_port;	/* on the BTS */
+	u_int16_t remote_port;	/* on the SGSN */
+	u_int32_t remote_ip;	/* on the SGSN */
+
 	struct gsm_nm_state nm_state;
 };
 
@@ -389,6 +458,8 @@
 	struct gsm_network *network;
 	/* number of ths BTS in network */
 	u_int8_t nr;
+	/* human readable name / description */
+	char *description;
 	/* Cell Identity */
 	u_int16_t cell_identity;
 	/* location area code of this BTS */
@@ -466,18 +537,24 @@
 
 	/* Not entirely sure how ip.access specific this is */
 	struct {
-		int enabled;
+		enum bts_gprs_mode mode;
 		struct {
 			struct gsm_nm_state nm_state;
 			u_int16_t nsei;
+			uint8_t timer[7];
 		} nse;
 		struct {
 			struct gsm_nm_state nm_state;
 			u_int16_t bvci;
+			uint8_t timer[11];
 		} cell;
 		struct gsm_bts_gprs_nsvc nsvc[2];
 		u_int8_t rac;
 	} gprs;
+
+	/* RACH NM values */
+	int rach_b_thresh;
+	int rach_ldavg_slots;
 	
 	/* transceivers */
 	int num_trx;
@@ -525,6 +602,14 @@
 		struct counter *alerted;	/* we alerted the other end */
 		struct counter *connected;/* how many calls were accepted */
 	} call;
+	struct {
+		struct counter *rf_fail;
+		struct counter *rll_err;
+	} chan;
+	struct {
+		struct counter *oml_fail;
+		struct counter *rsl_fail;
+	} bts;
 };
 
 enum gsm_auth_policy {
@@ -570,6 +655,7 @@
 	int (*mncc_recv) (struct gsm_network *net, int msg_type, void *arg);
 	struct llist_head upqueue;
 	struct llist_head trans_list;
+	struct bsc_api *bsc_api;
 
 	unsigned int num_bts;
 	struct llist_head bts_list;
@@ -687,15 +773,10 @@
 enum rrlp_mode rrlp_mode_parse(const char *arg);
 const char *rrlp_mode_name(enum rrlp_mode mode);
 
-void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked);
+enum bts_gprs_mode bts_gprs_mode_parse(const char *arg);
+const char *bts_gprs_mode_name(enum bts_gprs_mode mode);
 
-/* A parsed GPRS routing area */
-struct gprs_ra_id {
-	u_int16_t	mnc;
-	u_int16_t	mcc;
-	u_int16_t	lac;
-	u_int8_t	rac;
-};
+void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked);
 
 int gsm48_ra_id_by_bts(u_int8_t *buf, struct gsm_bts *bts);
 void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts);
diff --git a/openbsc/include/openbsc/ipaccess.h b/openbsc/include/openbsc/ipaccess.h
index 86248aa..f8ddfd4 100644
--- a/openbsc/include/openbsc/ipaccess.h
+++ b/openbsc/include/openbsc/ipaccess.h
@@ -53,6 +53,8 @@
 
 int ipaccess_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len);
 
+int ipaccess_drop_oml(struct gsm_bts *bts);
+int ipaccess_drop_rsl(struct gsm_bts_trx *trx);
 
 /*
  * Firmware specific header
diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h
index f7e800b..71b7fc1 100644
--- a/openbsc/include/openbsc/mgcp.h
+++ b/openbsc/include/openbsc/mgcp.h
@@ -77,6 +77,7 @@
 
 typedef int (*mgcp_change)(struct mgcp_config *cfg, int endpoint, int state, int local_rtp);
 typedef int (*mgcp_policy)(struct mgcp_config *cfg, int endpoint, int state, const char *transactio_id);
+typedef int (*mgcp_reset)(struct mgcp_config *cfg);
 
 struct mgcp_config {
 	int source_port;
@@ -84,6 +85,7 @@
 	char *source_addr;
 	unsigned int number_endpoints;
 	char *bts_ip;
+	char *call_agent_addr;
 
 	struct in_addr bts_in;
 	char *audio_name;
@@ -95,8 +97,12 @@
 	char *forward_ip;
 	int forward_port;
 
+	/* spec handling */
+	int force_realloc;
+
 	mgcp_change change_cb;
 	mgcp_policy policy_cb;
+	mgcp_reset reset_cb;
 	void *data;
 
 	struct mgcp_endpoint *endpoints;
@@ -115,8 +121,15 @@
  * format helper functions
  */
 struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg);
-struct msgb *mgcp_create_rsip(void);
 struct msgb *mgcp_create_response_with_data(int code, const char *msg, const char *trans, const char *data);
 
+/* adc helper */
+static inline int mgcp_timeslot_to_endpoint(int multiplex, int timeslot)
+{
+	if (timeslot == 0)
+		timeslot = 1;
+	return timeslot + (31 * multiplex);
+}
+
 
 #endif
diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h
index 10d0ca6..d5aec30 100644
--- a/openbsc/include/openbsc/mgcp_internal.h
+++ b/openbsc/include/openbsc/mgcp_internal.h
@@ -57,8 +57,22 @@
 
 	/* backpointer */
 	struct mgcp_config *cfg;
+
+	/* statistics */
+	unsigned int in_bts;
+	unsigned int in_remote;
 };
 
 #define ENDPOINT_NUMBER(endp) abs(endp - endp->cfg->endpoints)
 
+struct mgcp_msg_ptr {
+	unsigned int start;
+	unsigned int length;
+};
+
+int mgcp_analyze_header(struct mgcp_config *cfg, struct msgb *msg,
+			struct mgcp_msg_ptr *ptr, int size,
+			const char **transaction_id, struct mgcp_endpoint **endp);
+int mgcp_send_dummy(struct mgcp_endpoint *endp);
+
 #endif
diff --git a/openbsc/include/openbsc/osmo_msc.h b/openbsc/include/openbsc/osmo_msc.h
new file mode 100644
index 0000000..d5d8917
--- /dev/null
+++ b/openbsc/include/openbsc/osmo_msc.h
@@ -0,0 +1,10 @@
+/* Routines for the MSC handling */
+
+#ifndef OSMO_MSC_H
+#define OSMO_MSC_H
+
+#include "bsc_api.h"
+
+struct bsc_api *msc_bsc_api();
+
+#endif
diff --git a/openbsc/include/openbsc/rest_octets.h b/openbsc/include/openbsc/rest_octets.h
index 4e72c0f..6d90119 100644
--- a/openbsc/include/openbsc/rest_octets.h
+++ b/openbsc/include/openbsc/rest_octets.h
@@ -71,6 +71,7 @@
 	GPRS_NMO_III	= 2,	/* no paging coordination */
 };
 
+/* TS 04.60 12.24 */
 struct gprs_cell_options {
 	enum gprs_nmo nmo;
 	/* T3168: wait for packet uplink assignment message */
@@ -79,6 +80,16 @@
 	u_int32_t t3192;	/* in milliseconds */
 	u_int32_t drx_timer_max;/* in seconds */
 	u_int32_t bs_cv_max;
+
+	u_int8_t ext_info_present;
+	struct {
+		u_int8_t egprs_supported;
+			u_int8_t use_egprs_p_ch_req;
+			u_int8_t bep_period;
+		u_int8_t pfc_supported;
+		u_int8_t dtm_supported;
+		u_int8_t bss_paging_coordination;
+	} ext_info;
 };
 
 /* TS 04.60 Table 12.9.2 */
diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h
index f82711a..65b1a5f 100644
--- a/openbsc/include/openbsc/rtp_proxy.h
+++ b/openbsc/include/openbsc/rtp_proxy.h
@@ -28,6 +28,12 @@
 #include <osmocore/linuxlist.h>
 #include <osmocore/select.h>
 
+#define RTP_PT_GSM_FULL 3
+#define RTP_PT_GSM_HALF 96
+#define RTP_PT_GSM_EFR 97
+#define RTP_PT_AMR_FULL 98
+#define RTP_PT_AMR_HALF 99
+
 enum rtp_rx_action {
 	RTP_NONE,
 	RTP_PROXY,
diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h
new file mode 100644
index 0000000..eccfdea
--- /dev/null
+++ b/openbsc/include/openbsc/sgsn.h
@@ -0,0 +1,65 @@
+#ifndef _SGSN_H
+#define _SGSN_H
+
+#include <sys/types.h>
+
+#include <osmocore/msgb.h>
+
+#include <openbsc/gprs_ns.h>
+#include <openbsc/gprs_sgsn.h>
+
+struct sgsn_config {
+	/* parsed from config file */
+
+	char *gtp_statedir;
+	struct sockaddr_in gtp_listenaddr;
+
+	/* misc */
+	struct gprs_ns_inst *nsi;
+};
+
+struct sgsn_instance {
+	char *config_file;
+	struct sgsn_config cfg;
+	/* File descriptor wrappers for LibGTP */
+	struct bsc_fd gtp_fd0;
+	struct bsc_fd gtp_fd1c;
+	struct bsc_fd gtp_fd1u;
+	/* Timer for libGTP */
+	struct timer_list gtp_timer;
+	/* GSN instance for libgtp */
+	struct gsn_t *gsn;
+};
+
+extern struct sgsn_instance *sgsn;
+
+/* sgsn_vty.c */
+
+int sgsn_vty_init(void);
+int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg);
+
+/* sgsn.c */
+
+/* Main input function for Gb proxy */
+int sgsn_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci);
+
+
+struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
+					 struct sgsn_mm_ctx *mmctx,
+					 uint16_t nsapi,
+					 struct tlv_parsed *tp);
+int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx);
+
+/* gprs_sndcp.c */
+
+/* Entry point for the SNSM-ACTIVATE.indication */
+int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi);
+/* Entry point for the SNSM-DEACTIVATE.indication */
+int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi);
+/* Called by SNDCP when it has received/re-assembled a N-PDU */
+int sgsn_rx_sndcp_ud_ind(uint32_t tlli, uint8_t nsapi, struct msgb *msg,
+			 uint32_t npdu_len, uint8_t *npdu);
+int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
+			void *mmcontext);
+
+#endif
diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h
index 0c22869..48f7946 100644
--- a/openbsc/include/openbsc/signal.h
+++ b/openbsc/include/openbsc/signal.h
@@ -26,7 +26,6 @@
 #include <errno.h>
 
 #include <openbsc/gsm_data.h>
-#include <openbsc/gsm_subscriber.h>
 
 #include <osmocore/signal.h>
 
@@ -42,6 +41,8 @@
 	SS_SUBSCR,
 	SS_SCALL,
 	SS_GLOBAL,
+	SS_CHALLOC,
+	SS_NS,
 };
 
 /* SS_PAGING signals */
@@ -93,6 +94,12 @@
 	S_LCHAN_MEAS_REP,		/* 08.58 Measurement Report */
 };
 
+/* SS_CHALLOC signals */
+enum signal_challoc {
+	S_CHALLOC_ALLOC_FAIL,	/* allocation of lchan has failed */
+	S_CHALLOC_FREED,	/* lchan has been successfully freed */
+};
+
 /* SS_SUBSCR signals */
 enum signal_subscr {
 	S_SUBSCR_ATTACHED,
@@ -111,6 +118,8 @@
 	S_GLOBAL_SHUTDOWN,
 };
 
+struct gsm_subscriber;
+
 struct paging_signal_data {
 	struct gsm_subscriber *subscr;
 	struct gsm_bts *bts;
@@ -126,8 +135,26 @@
 };
 
 struct ipacc_ack_signal_data {
-	struct gsm_bts *bts;
+	struct gsm_bts_trx *trx;
 	u_int8_t msg_type;	
 };
 
+struct challoc_signal_data {
+	struct gsm_bts *bts;
+	struct gsm_lchan *lchan;
+	enum gsm_chan_t type;
+};
+
+enum signal_ns {
+	S_NS_RESET,
+	S_NS_BLOCK,
+	S_NS_UNBLOCK,
+	S_NS_ALIVE_EXP,	/* Tns-alive expired more than N times */
+};
+
+struct ns_signal_data {
+	struct gprs_nsvc *nsvc;
+	uint8_t cause;
+};
+
 #endif
diff --git a/openbsc/include/openbsc/socket.h b/openbsc/include/openbsc/socket.h
new file mode 100644
index 0000000..4d31611
--- /dev/null
+++ b/openbsc/include/openbsc/socket.h
@@ -0,0 +1,14 @@
+#ifndef _BSC_SOCKET_H
+#define _BSC_SOCKET_H
+
+#include <sys/types.h>
+#include <osmocore/select.h>
+
+#ifndef IPPROTO_GRE
+#define IPPROTO_GRE 47
+#endif
+
+int make_sock(struct bsc_fd *bfd, int proto, u_int32_t ip, u_int16_t port,
+	      int (*cb)(struct bsc_fd *fd, unsigned int what));
+
+#endif /* _BSC_SOCKET_H */
diff --git a/openbsc/include/openbsc/telnet_interface.h b/openbsc/include/openbsc/telnet_interface.h
deleted file mode 100644
index 20e794b..0000000
--- a/openbsc/include/openbsc/telnet_interface.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* 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 "gsm_data.h"
-#include "debug.h"
-#include <osmocore/select.h>
-
-#include <vty/vty.h>
-
-struct telnet_connection {
-	struct llist_head entry;
-	struct gsm_network *network;
-	struct bsc_fd fd;
-	struct vty *vty;
-	struct debug_target *dbg;
-};
-
-
-void telnet_init(struct gsm_network *network, int port);
-
-int bsc_vty_init(struct gsm_network *net);
-
-#endif
diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h
index 50c3cc5..90a008b 100644
--- a/openbsc/include/openbsc/transaction.h
+++ b/openbsc/include/openbsc/transaction.h
@@ -20,8 +20,8 @@
 	/* To whom we belong, unique identifier of remote MM entity */
 	struct gsm_subscriber *subscr;
 
-	/* The LCHAN that we're currently using to transmit messages */
-	struct gsm_lchan *lchan;
+	/* The associated connection we are using to transmit messages */
+	struct gsm_subscriber_connection *conn;
 
 	/* reference from MNCC or other application */
 	u_int32_t callref;
@@ -71,6 +71,6 @@
 
 /* update all transactions to use a different LCHAN, e.g.
  * after handover has succeeded */
-int trans_lchan_change(struct gsm_lchan *lchan_old,
-		       struct gsm_lchan *lchan_new);
+int trans_lchan_change(struct gsm_subscriber_connection *conn_old,
+		       struct gsm_subscriber_connection *conn_new);
 #endif
diff --git a/openbsc/include/openbsc/vty.h b/openbsc/include/openbsc/vty.h
new file mode 100644
index 0000000..ed21e88
--- /dev/null
+++ b/openbsc/include/openbsc/vty.h
@@ -0,0 +1,35 @@
+#ifndef OPENBSC_VTY_H
+#define OPENBSC_VTY_H
+
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/buffer.h>
+#include <osmocom/vty/command.h>
+
+struct gsm_network;
+struct vty;
+
+void logging_vty_add_cmds(void);
+void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *);
+
+struct buffer *vty_argv_to_buffer(int argc, const char *argv[], int base);
+
+extern struct cmd_element cfg_description_cmd;
+extern struct cmd_element cfg_no_description_cmd;
+extern struct cmd_element ournode_exit_cmd;
+extern struct cmd_element ournode_end_cmd;
+
+enum bsc_vty_node {
+	GSMNET_NODE = _LAST_OSMOVTY_NODE + 1,
+	BTS_NODE,
+	TRX_NODE,
+	TS_NODE,
+	SUBSCR_NODE,
+	MGCP_NODE,
+	GBPROXY_NODE,
+	SGSN_NODE,
+	NS_NODE,
+	BSSGP_NODE,
+	OML_NODE,
+};
+
+#endif
diff --git a/openbsc/include/vty/Makefile.am b/openbsc/include/vty/Makefile.am
deleted file mode 100644
index 1674766..0000000
--- a/openbsc/include/vty/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-noinst_HEADERS = buffer.h command.h  vector.h vty.h
diff --git a/openbsc/include/vty/buffer.h b/openbsc/include/vty/buffer.h
deleted file mode 100644
index 3151940..0000000
--- a/openbsc/include/vty/buffer.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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(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 */
diff --git a/openbsc/include/vty/command.h b/openbsc/include/vty/command.h
deleted file mode 100644
index 03b071f..0000000
--- a/openbsc/include/vty/command.h
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * 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;
-};
-
-/* 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. */
-#if 0
-	AAA_NODE,		/* AAA node. */
-	KEYCHAIN_NODE,		/* Key-chain node. */
-	KEYCHAIN_KEY_NODE,	/* Key-chain key node. */
-	INTERFACE_NODE,		/* Interface mode node. */
-	ZEBRA_NODE,		/* zebra connection node. */
-	TABLE_NODE,		/* rtm_table selection node. */
-	RIP_NODE,		/* RIP protocol mode node. */
-	RIPNG_NODE,		/* RIPng protocol mode node. */
-	BGP_NODE,		/* BGP protocol mode which includes BGP4+ */
-	BGP_VPNV4_NODE,		/* BGP MPLS-VPN PE exchange. */
-	BGP_IPV4_NODE,		/* BGP IPv4 unicast address family.  */
-	BGP_IPV4M_NODE,		/* BGP IPv4 multicast address family.  */
-	BGP_IPV6_NODE,		/* BGP IPv6 address family */
-	OSPF_NODE,		/* OSPF protocol mode */
-	OSPF6_NODE,		/* OSPF protocol for IPv6 mode */
-	ISIS_NODE,		/* ISIS protocol mode */
-	MASC_NODE,		/* MASC for multicast.  */
-	IRDP_NODE,		/* ICMP Router Discovery Protocol mode. */
-	IP_NODE,		/* Static ip route node. */
-	ACCESS_NODE,		/* Access list node. */
-	PREFIX_NODE,		/* Prefix list node. */
-	ACCESS_IPV6_NODE,	/* Access list node. */
-	PREFIX_IPV6_NODE,	/* Prefix list node. */
-	AS_LIST_NODE,		/* AS list node. */
-	COMMUNITY_LIST_NODE,	/* Community list node. */
-	RMAP_NODE,		/* Route map node. */
-	SMUX_NODE,		/* SNMP configuration node. */
-	DUMP_NODE,		/* Packet dump node. */
-	FORWARDING_NODE,	/* IP forwarding node. */
-#endif
-	VTY_NODE,		/* Vty node. */
-
-	GSMNET_NODE,
-	BTS_NODE,
-	TRX_NODE,
-	TS_NODE,
-	SUBSCR_NODE,
-	MGCP_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) \
-  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)
-
-#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)
-
-#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 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_end_cmd;
-extern struct cmd_element config_exit_cmd;
-extern struct cmd_element config_quit_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 *);
-
-void print_version(const char *);
-
-extern void *tall_vty_cmd_ctx;
-
-#endif				/* _ZEBRA_COMMAND_H */
diff --git a/openbsc/include/vty/vector.h b/openbsc/include/vty/vector.h
deleted file mode 100644
index 22a184d..0000000
--- a/openbsc/include/vty/vector.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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 */
diff --git a/openbsc/include/vty/vty.h b/openbsc/include/vty/vty.h
deleted file mode 100644
index 0441fc5..0000000
--- a/openbsc/include/vty/vty.h
+++ /dev/null
@@ -1,151 +0,0 @@
-#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;
-}
-
-/* Prototypes. */
-void vty_init (void);
-int vty_read_config_file(const char *file_name);
-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
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index 1d18475..87cd0ea 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -1,48 +1,44 @@
 INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
-AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS)
+AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS)
 AM_LDFLAGS = $(LIBOSMOCORE_LIBS)
 
-sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \
-                isdnsync bsc_mgcp ipaccess-proxy
-noinst_LIBRARIES = libbsc.a libmsc.a libvty.a
-noinst_HEADERS = vty/cardshell.h
+# build current directory before building gprs
+SUBDIRS = . ipaccess gprs
+
+sbin_PROGRAMS = bsc_hack bs11_config isdnsync bsc_mgcp
+noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a
 
 bscdir = $(libdir)
 bsc_LIBRARIES = libsccp.a
 
 libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \
-		chan_alloc.c debug.c \
+		chan_alloc.c debug.c socket.c abis_nm_vty.c \
 		gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \
 		trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c \
 		input/misdn.c input/ipaccess.c \
 		talloc_ctx.c system_information.c rest_octets.c \
 		rtp_proxy.c bts_siemens_bs11.c bts_ipaccess_nanobts.c \
-		bts_unknown.c bsc_version.c
+		bts_unknown.c bsc_version.c bsc_api.c bsc_vty.c
 
-libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \
+libmsc_a_SOURCES = gsm_subscriber.c db.c \
 		mncc.c gsm_04_08.c gsm_04_11.c transaction.c \
 		token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c \
-		handover_logic.c handover_decision.c meas_rep.c
+		handover_logic.c handover_decision.c meas_rep.c auth.c \
+		osmo_msc.c
 
-libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c
+libvty_a_SOURCES = common_vty.c
 
 libsccp_a_SOURCES = sccp/sccp.c
 
-bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c
-bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT)
+bsc_hack_SOURCES = bsc_hack.c bsc_init.c bsc_vty.c vty_interface_layer3.c
+bsc_hack_LDADD = libmsc.a libbsc.a libvty.a libmsc.a \
+		-ldl -ldbi $(LIBCRYPT) $(LIBOSMOVTY_LIBS)
 
 bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c debug.c \
 		      rs232.c bts_siemens_bs11.c
 
-ipaccess_find_SOURCES = ipaccess/ipaccess-find.c
-
-ipaccess_config_SOURCES = ipaccess/ipaccess-config.c ipaccess/ipaccess-firmware.c
-ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYPT)
-
 isdnsync_SOURCES = isdnsync.c
 
 bsc_mgcp_SOURCES = mgcp/mgcp_main.c mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgcp/mgcp_vty.c \
-		   debug.c telnet_interface.c
-bsc_mgcp_LDADD = libvty.a
-
-ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c debug.c
+		   debug.c
+bsc_mgcp_LDADD = libvty.a $(LIBOSMOVTY_LIBS)
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c
index c9852bf..6837305 100644
--- a/openbsc/src/abis_nm.c
+++ b/openbsc/src/abis_nm.c
@@ -1,4 +1,4 @@
-/* GSM Network Management (OML) messages on the A-bis interface 
+/* GSM Network Management (OML) 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>
@@ -419,30 +419,30 @@
 
 static int abis_nm_rcvmsg_sw(struct msgb *mb);
 
-static struct value_string obj_class_names[] = {
-	{ NM_OC_SITE_MANAGER,	"SITE MANAGER" },
+const struct value_string abis_nm_obj_class_names[] = {
+	{ NM_OC_SITE_MANAGER,	"SITE-MANAGER" },
 	{ NM_OC_BTS,		"BTS" },
-	{ NM_OC_RADIO_CARRIER,	"RADIO CARRIER" },
-	{ NM_OC_BASEB_TRANSC,	"BASEBAND TRANSCEIVER" },
+	{ NM_OC_RADIO_CARRIER,	"RADIO-CARRIER" },
+	{ NM_OC_BASEB_TRANSC,	"BASEBAND-TRANSCEIVER" },
 	{ NM_OC_CHANNEL,	"CHANNEL" },
 	{ NM_OC_BS11_ADJC,	"ADJC" },
 	{ NM_OC_BS11_HANDOVER,	"HANDOVER" },
-	{ NM_OC_BS11_PWR_CTRL,	"POWER CONTROL" },
+	{ NM_OC_BS11_PWR_CTRL,	"POWER-CONTROL" },
 	{ NM_OC_BS11_BTSE,	"BTSE" },
 	{ NM_OC_BS11_RACK,	"RACK" },
 	{ NM_OC_BS11_TEST,	"TEST" },
 	{ NM_OC_BS11_ENVABTSE,	"ENVABTSE" },
 	{ NM_OC_BS11_BPORT,	"BPORT" },
-	{ NM_OC_GPRS_NSE,	"GPRS NSE" },
-	{ NM_OC_GPRS_CELL,	"GPRS CELL" },
-	{ NM_OC_GPRS_NSVC,	"GPRS NSVC" },
+	{ NM_OC_GPRS_NSE,	"GPRS-NSE" },
+	{ NM_OC_GPRS_CELL,	"GPRS-CELL" },
+	{ NM_OC_GPRS_NSVC,	"GPRS-NSVC" },
 	{ NM_OC_BS11,		"SIEMENSHW" },
 	{ 0,			NULL }
 };
 
 static const char *obj_class_name(u_int8_t oc)
 {
-	return get_value_string(obj_class_names, oc);
+	return get_value_string(abis_nm_obj_class_names, oc);
 }
 
 const char *nm_opstate_name(u_int8_t os)
@@ -490,18 +490,17 @@
 	{ 0, NULL }
 };
 
+const struct value_string abis_nm_adm_state_names[] = {
+	{ NM_STATE_LOCKED,	"Locked" },
+	{ NM_STATE_UNLOCKED,	"Unlocked" },
+	{ NM_STATE_SHUTDOWN,	"Shutdown" },
+	{ NM_STATE_NULL,	"NULL" },
+	{ 0, NULL }
+};
+
 const char *nm_adm_name(u_int8_t adm)
 {
-	switch (adm) {
-	case 1:
-		return "Locked";
-	case 2:
-		return "Unlocked";
-	case 3:
-		return "Shutdown";
-	default:
-		return "<not used>";
-	}
+	return get_value_string(abis_nm_adm_state_names, adm);
 }
 
 int nm_is_running(struct gsm_nm_state *s) {
@@ -514,7 +513,7 @@
 static void debugp_foh(struct abis_om_fom_hdr *foh)
 {
 	DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
-		obj_class_name(foh->obj_class), foh->obj_class, 
+		obj_class_name(foh->obj_class), foh->obj_class,
 		foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
 		foh->obj_inst.ts_nr);
 }
@@ -678,7 +677,7 @@
 	new_state = *nm_state;
 	new_state.administrative = adm_state;
 
-	rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
+	rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state, obj_inst);
 
 	nm_state->administrative = adm_state;
 
@@ -732,7 +731,7 @@
 		/* Update the operational state of a given object in our in-memory data
  		* structures and send an event to the higher layer */
 		void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
-		rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
+		rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state, &foh->obj_inst);
 		nm_state->operational = new_state.operational;
 		nm_state->availability = new_state.availability;
 		if (nm_state->administrative == 0)
@@ -822,15 +821,56 @@
 	return abis_nm_sendmsg(bts, msg);
 }
 
+static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
+{
+	static const struct tlv_definition sw_descr_def = {
+		.def = {
+			[NM_ATT_FILE_ID] =		{ TLV_TYPE_TL16V, },
+			[NM_ATT_FILE_VERSION] =		{ TLV_TYPE_TL16V, },
+		},
+	};
+
+	u_int8_t tag;
+	u_int16_t tag_len;
+	const u_int8_t *val;
+	int ofs = 0, len;
+
+	/* Classic TLV parsing doesn't work well with SW_DESCR because of it's
+	 * nested nature and the fact you have to assume it contains only two sub
+	 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
+
+	if (sw_descr[0] != NM_ATT_SW_DESCR) {
+		DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
+		return -1;
+	}
+	ofs += 1;
+
+	len = tlv_parse_one(&tag, &tag_len, &val,
+		&sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
+	if (len < 0 || (tag != NM_ATT_FILE_ID)) {
+		DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
+		return -2;
+	}
+	ofs += len;
+
+	len = tlv_parse_one(&tag, &tag_len, &val,
+		&sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
+	if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
+		DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
+		return -3;
+	}
+	ofs += len;
+
+	return ofs;
+}
+
 static int abis_nm_rx_sw_act_req(struct msgb *mb)
 {
 	struct abis_om_hdr *oh = msgb_l2(mb);
 	struct abis_om_fom_hdr *foh = msgb_l3(mb);
 	struct tlv_parsed tp;
 	const u_int8_t *sw_config;
-	int sw_config_len;
-	int file_id_len;
-	int ret;
+	int ret, sw_config_len, sw_descr_len;
 
 	debugp_foh(foh);
 
@@ -854,20 +894,16 @@
 		DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
 	}
 
-	if (sw_config[0] != NM_ATT_SW_DESCR)
-		DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
-	if (sw_config[1] != NM_ATT_FILE_ID)
-		DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
-	file_id_len = sw_config[2] * 256 + sw_config[3];
+		/* Use the first SW_DESCR present in SW config */
+	sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
+	if (sw_descr_len < 0)
+		return -EINVAL;
 
-	/* Assumes first SW file in list is the one to be activated */
-	/* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
 	return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
 				 foh->obj_inst.bts_nr,
 				 foh->obj_inst.trx_nr,
 				 foh->obj_inst.ts_nr,
-				 sw_config + 4,
-				 file_id_len);
+				 sw_config, sw_descr_len);
 }
 
 /* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
@@ -938,7 +974,7 @@
 
 		abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
 		if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
-			DEBUGPC(DNM, "CAUSE=%s\n", 
+			DEBUGPC(DNM, "CAUSE=%s\n",
 				nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
 		else
 			DEBUGPC(DNM, "\n");
@@ -1102,6 +1138,7 @@
 
 struct abis_nm_sw {
 	struct gsm_bts *bts;
+	int trx_nr;
 	gsm_cbfn *cbfn;
 	void *cb_data;
 	int forced;
@@ -1349,7 +1386,7 @@
 			return -1;
 		}
 		/* read first line and parse file ID and VERSION */
-		rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n", 
+		rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
 			    file_id, file_version);
 		if (rc != 2) {
 			perror("parsing header line of software file");
@@ -1555,7 +1592,7 @@
 }
 
 /* Load the specified software into the BTS */
-int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
+int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
 			  u_int8_t win_size, int forced,
 			  gsm_cbfn *cbfn, void *cb_data)
 {
@@ -1569,6 +1606,7 @@
 		return -EBUSY;
 
 	sw->bts = bts;
+	sw->trx_nr = trx_nr;
 
 	switch (bts->type) {
 	case GSM_BTS_TYPE_BS11:
@@ -1579,8 +1617,8 @@
 		break;
 	case GSM_BTS_TYPE_NANOBTS:
 		sw->obj_class = NM_OC_BASEB_TRANSC;
-		sw->obj_instance[0] = 0x00;
-		sw->obj_instance[1] = 0x00;
+		sw->obj_instance[0] = sw->bts->nr;
+		sw->obj_instance[1] = sw->trx_nr;
 		sw->obj_instance[2] = 0xff;
 		break;
 	case GSM_BTS_TYPE_UNKNOWN:
@@ -2233,7 +2271,7 @@
 }
 
 /* like abis_nm_conn_terr_traf + set_tei */
-int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port, 
+int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
 			  u_int8_t e1_timeslot, u_int8_t e1_subslot,
 			  u_int8_t tei)
 {
@@ -2514,7 +2552,7 @@
 		fle = fl_dequeue(&bs11_sw->file_list);
 		if (fle) {
 			/* start download the next file of our file list */
-			rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
+			rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
 						   bs11_sw->win_size,
 						   bs11_sw->forced,
 						   &bs11_swload_cbfn, bs11_sw);
@@ -2570,7 +2608,7 @@
 		return -EINVAL;
 
 	/* start download the next file of our file list */
-	rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
+	rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
 				   bs11_swload_cbfn, bs11_sw);
 	talloc_free(fle);
 	return rc;
@@ -2595,7 +2633,7 @@
 	NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
 #endif
 	
-static u_int8_t req_attr[] = { 
+static u_int8_t req_attr[] = {
 	NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
 	0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
 	0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
@@ -2674,11 +2712,11 @@
 		DEBUGPC(DNM, "RSL CONNECT ACK ");
 		if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
 			DEBUGPC(DNM, "IP=%s ",
-				inet_ntoa(*((struct in_addr *) 
+				inet_ntoa(*((struct in_addr *)
 					TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
 		if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
 			DEBUGPC(DNM, "PORT=%u ",
-				ntohs(*((u_int16_t *) 
+				ntohs(*((u_int16_t *)
 					TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
 		if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
 			DEBUGPC(DNM, "STREAM=0x%02x ",
@@ -2688,7 +2726,7 @@
 	case NM_MT_IPACC_RSL_CONNECT_NACK:
 		LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
 		if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
-			DEBUGPC(DNM, " CAUSE=%s\n", 
+			DEBUGPC(DNM, " CAUSE=%s\n",
 				nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
 		else
 			DEBUGPC(DNM, "\n");
@@ -2700,7 +2738,7 @@
 	case NM_MT_IPACC_SET_NVATTR_NACK:
 		LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
 		if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
-			LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", 
+			LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
 				nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
 		else
 			LOGPC(DNM, LOGL_ERROR, "\n");
@@ -2712,7 +2750,7 @@
 	case NM_MT_IPACC_GET_NVATTR_NACK:
 		LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
 		if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
-			LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", 
+			LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
 				nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
 		else
 			LOGPC(DNM, LOGL_ERROR, "\n");
@@ -2723,7 +2761,7 @@
 	case NM_MT_IPACC_SET_ATTR_NACK:
 		LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
 		if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
-			LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", 
+			LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
 				nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
 		else
 			LOGPC(DNM, LOGL_ERROR, "\n");
@@ -2738,12 +2776,12 @@
 	case NM_MT_IPACC_RSL_CONNECT_NACK:
 	case NM_MT_IPACC_SET_NVATTR_NACK:
 	case NM_MT_IPACC_GET_NVATTR_NACK:
-		signal.bts = msg->trx->bts;
+		signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
 		signal.msg_type = foh->msg_type;
 		dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
 		break;
 	case NM_MT_IPACC_SET_NVATTR_ACK:
-		signal.bts = msg->trx->bts;
+		signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
 		signal.msg_type = foh->msg_type;
 		dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
 		break;
@@ -2800,7 +2838,7 @@
 				    attr_len);
 }
 
-int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx, 
+int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
 				 u_int32_t ip, u_int16_t port, u_int8_t stream)
 {
 	struct in_addr ia;
@@ -2829,9 +2867,16 @@
 }
 
 /* restart / reboot an ip.access nanoBTS */
-int abis_nm_ipaccess_restart(struct gsm_bts *bts)
+int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
 {
-	return __simple_cmd(bts, NM_MT_IPACC_RESTART);
+	struct abis_om_hdr *oh;
+	struct msgb *msg = nm_msgb_alloc();
+
+	oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
+	fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
+			trx->bts->nr, trx->nr, 0xff);
+
+	return abis_nm_sendmsg(trx->bts, msg);
 }
 
 int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
diff --git a/openbsc/src/abis_nm_vty.c b/openbsc/src/abis_nm_vty.c
new file mode 100644
index 0000000..b6eca3b
--- /dev/null
+++ b/openbsc/src/abis_nm_vty.c
@@ -0,0 +1,198 @@
+/* VTY interface for A-bis OML (Netowrk Management) */
+
+/* (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 <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <arpa/inet.h>
+
+#include <openbsc/gsm_data.h>
+#include <osmocore/msgb.h>
+#include <osmocore/tlv.h>
+#include <osmocore/talloc.h>
+#include <openbsc/debug.h>
+#include <openbsc/signal.h>
+#include <openbsc/abis_nm.h>
+#include <openbsc/vty.h>
+
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/logging.h>
+#include <osmocom/vty/telnet_interface.h>
+
+extern struct gsm_network *bsc_gsmnet;
+
+static struct cmd_node oml_node = {
+	OML_NODE,
+	"%s(oml)# ",
+	1,
+};
+
+struct oml_node_state {
+	struct gsm_bts *bts;
+	uint8_t obj_class;
+	uint8_t obj_inst[3];
+};
+
+static int dummy_config_write(struct vty *v)
+{
+	return CMD_SUCCESS;
+}
+
+/* FIXME: auto-generate those strings from the value_string lists */
+#define NM_OBJCLASS_VTY "(site-manager|bts|radio-carrier|baseband-transceiver|channel|adjc|handover|power-contorl|btse|rack|test|envabtse|bport|gprs-nse|gprs-cell|gprs-nsvc|siemenshw)"
+#define NM_OBJCLASS_VTY_HELP "FIXME"
+
+DEFUN(oml_class_inst, oml_class_inst_cmd,
+	"bts <0-255> oml class " NM_OBJCLASS_VTY
+					" instance <0-255> <0-255> <0-255>",
+	"BTS related commands\n" "BTS Number\n"
+	"Manipulate the OML managed objects\n"
+	"Object Class\n" 	NM_OBJCLASS_VTY_HELP
+	"Object Instance\n" "BTS Number\n" "TRX Number\n" "TS Number\n")
+{
+	struct gsm_bts *bts;
+	struct oml_node_state *oms;
+	int bts_nr = atoi(argv[0]);
+
+	bts = gsm_bts_num(bsc_gsmnet, bts_nr);
+	if (!bts) {
+		vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	oms = talloc_zero(tall_bsc_ctx, struct oml_node_state);
+	if (!oms)
+		return CMD_WARNING;
+
+	oms->bts = bts;
+	oms->obj_class = get_string_value(abis_nm_obj_class_names, argv[1]);
+	oms->obj_inst[0] = atoi(argv[2]);
+	oms->obj_inst[1] = atoi(argv[3]);
+	oms->obj_inst[2] = atoi(argv[4]);
+
+	vty->index = oms;
+	vty->node = OML_NODE;
+
+	return CMD_SUCCESS;
+
+}
+
+DEFUN(oml_classnum_inst, oml_classnum_inst_cmd,
+	"bts <0-255> oml class <0-255> instance <0-255> <0-255> <0-255>",
+	"BTS related commands\n" "BTS Number\n"
+	"Manipulate the OML managed objects\n"
+	"Object Class\n" "Object Class\n"
+	"Object Instance\n" "BTS Number\n" "TRX Number\n" "TS Number\n")
+{
+	struct gsm_bts *bts;
+	struct oml_node_state *oms;
+	int bts_nr = atoi(argv[0]);
+
+	bts = gsm_bts_num(bsc_gsmnet, bts_nr);
+	if (!bts) {
+		vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	oms = talloc_zero(tall_bsc_ctx, struct oml_node_state);
+	if (!oms)
+		return CMD_WARNING;
+
+	oms->bts = bts;
+	oms->obj_class = atoi(argv[1]);
+	oms->obj_inst[0] = atoi(argv[2]);
+	oms->obj_inst[1] = atoi(argv[3]);
+	oms->obj_inst[2] = atoi(argv[4]);
+
+	vty->index = oms;
+	vty->node = OML_NODE;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(oml_attrib_get, oml_attrib_get_cmd,
+	"attribute get <0-255>",
+	"OML Attribute Actions\n" "Get a single OML Attribute\n"
+	"OML Attribute Number\n")
+{
+	struct oml_node_state *oms = vty->index;
+
+	/* FIXME */
+	return CMD_SUCCESS;
+}
+
+DEFUN(oml_attrib_set, oml_attrib_set_cmd,
+	"attribute set <0-255> .HEX",
+	"OML Attribute Actions\n" "Set a single OML Attribute\n"
+	"OML Attribute Number\n")
+{
+	struct oml_node_state *oms = vty->index;
+
+	/* FIXME */
+	return CMD_SUCCESS;
+}
+
+DEFUN(oml_chg_adm_state, oml_chg_adm_state_cmd,
+	"change-adm-state (locked|unlocked|shutdown|null)",
+	"Change the Administrative State\n"
+	"Locked\n" "Unlocked\n" "Shutdown\n" "NULL\n")
+{
+	struct oml_node_state *oms = vty->index;
+	enum abis_nm_adm_state state;
+
+	state = get_string_value(abis_nm_adm_state_names, argv[0]);
+
+	abis_nm_chg_adm_state(oms->bts, oms->obj_class, oms->obj_inst[0],
+			      oms->obj_inst[1], oms->obj_inst[2], state);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(oml_opstart, oml_opstart_cmd,
+	"opstart", "Send an OPSTART message to the object")
+{
+	struct oml_node_state *oms = vty->index;
+
+	abis_nm_opstart(oms->bts, oms->obj_class, oms->obj_inst[0],
+			oms->obj_inst[1], oms->obj_inst[2]);
+
+	return CMD_SUCCESS;
+}
+
+int abis_nm_vty_init(void)
+{
+	install_element(ENABLE_NODE, &oml_class_inst_cmd);
+	install_element(ENABLE_NODE, &oml_classnum_inst_cmd);
+	install_node(&oml_node, dummy_config_write);
+
+	install_default(OML_NODE);
+	install_element(OML_NODE, &ournode_exit_cmd);
+	install_element(OML_NODE, &oml_attrib_get_cmd);
+	install_element(OML_NODE, &oml_attrib_set_cmd);
+	install_element(OML_NODE, &oml_chg_adm_state_cmd);
+	install_element(OML_NODE, &oml_opstart_cmd);
+
+	return 0;
+}
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index e7844af..451c80d 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -1,4 +1,4 @@
-/* GSM Radio Signalling Link messages on the A-bis interface 
+/* 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>
@@ -118,8 +118,8 @@
 	}
 
 	lchan = &ts->lchan[lch_idx];
-	debug_set_context(BSC_CTX_LCHAN, lchan);
-	debug_set_context(BSC_CTX_SUBSCR, lchan->subscr);
+	log_set_context(BSC_CTX_LCHAN, lchan);
+	log_set_context(BSC_CTX_SUBSCR, lchan->conn.subscr);
 
 	return lchan;
 }
@@ -222,7 +222,7 @@
 
 	LOGPC(DRSL, lvl, "CAUSE=0x%02x(%s) ",
 		cause_v[0], rsl_err_name(cause_v[0]));
-	for (i = 1; i < cause_len-1; i++) 
+	for (i = 1; i < cause_len-1; i++)
 		LOGPC(DRSL, lvl, "%02x ", cause_v[i]);
 }
 
@@ -245,7 +245,7 @@
 	return abis_rsl_sendmsg(msg);
 }
 
-int rsl_sacch_filling(struct gsm_bts_trx *trx, u_int8_t type, 
+int rsl_sacch_filling(struct gsm_bts_trx *trx, u_int8_t type,
 		      const u_int8_t *data, int len)
 {
 	struct abis_rsl_common_hdr *ch;
@@ -416,7 +416,7 @@
 }
 #endif
 
-int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, 
+int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
 			    u_int8_t ta, u_int8_t ho_ref)
 {
 	struct abis_rsl_dchan_hdr *dh;
@@ -568,12 +568,33 @@
 	return abis_rsl_sendmsg(msg);
 }
 
+static void error_timeout_cb(void *data)
+{
+	struct gsm_lchan *lchan = data;
+	if (lchan->state != LCHAN_S_REL_ERR) {
+		LOGP(DRSL, LOGL_ERROR, "%s error timeout but not in error state: %d\n",
+		     gsm_lchan_name(lchan), lchan->state);
+		return;
+	}
+
+	/* go back to the none state */
+	LOGP(DRSL, LOGL_NOTICE, "%s is back in operation.\n", gsm_lchan_name(lchan));
+	rsl_lchan_set_state(lchan, LCHAN_S_NONE);
+}
+
 /* Chapter 8.4.14 / 4.7: Tell BTS to release the radio channel */
-int rsl_rf_chan_release(struct gsm_lchan *lchan)
+static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error)
 {
 	struct abis_rsl_dchan_hdr *dh;
-	struct msgb *msg = rsl_msgb_alloc();
+	struct msgb *msg;
 
+	if (lchan->state == LCHAN_S_REL_ERR) {
+		LOGP(DRSL, LOGL_NOTICE, "%s is in error state not sending release.\n",
+		     gsm_lchan_name(lchan));
+		return -1;
+	}
+
+	msg = rsl_msgb_alloc();
 	dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
 	init_dchan_hdr(dh, RSL_MT_RF_CHAN_REL);
 	dh->chan_nr = lchan2chan_nr(lchan);
@@ -581,7 +602,20 @@
 	msg->lchan = lchan;
 	msg->trx = lchan->ts->trx;
 
-	DEBUGP(DRSL, "%s RF Channel Release CMD\n", gsm_lchan_name(lchan));
+	DEBUGP(DRSL, "%s RF Channel Release CMD due error %d\n", gsm_lchan_name(lchan), error);
+
+	if (error) {
+		/*
+		 * the nanoBTS sends RLL release indications after the channel release. This can
+		 * be a problem when we have reassigned the channel to someone else and then can
+		 * not figure out who used this channel.
+		 */
+		rsl_lchan_set_state(lchan, LCHAN_S_REL_ERR);
+		lchan->error_timer.data = lchan;
+		lchan->error_timer.cb = error_timeout_cb;
+		bsc_schedule_timer(&lchan->error_timer,
+				   msg->trx->bts->network->T3111 + 2, 0);
+	}
 
 	/* BTS will respond by RF CHAN REL ACK */
 	return abis_rsl_sendmsg(msg);
@@ -718,16 +752,16 @@
    RELEASE CONFIRM, which we in turn use to trigger RSL CHANNEL RELEASE,
    which in turn is acknowledged by RSL CHANNEL RELEASE ACK, which calls
    lchan_free() */
-int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id)
+int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id, u_int8_t reason)
 {
 
 	struct msgb *msg;
 
 	msg = rsl_rll_simple(RSL_MT_REL_REQ, lchan2chan_nr(lchan),
 			     link_id, 0);
-	msgb_tv_put(msg, RSL_IE_RELEASE_MODE, 0);	/* normal release */
+	/* 0 is normal release, 1 is local end */
+	msgb_tv_put(msg, RSL_IE_RELEASE_MODE, reason);
 
-	lchan->state = LCHAN_S_REL_REQ;
 	/* FIXME: start some timer in case we don't receive a REL ACK ? */
 
 	msg->trx = lchan->ts->trx;
@@ -735,6 +769,12 @@
 	return abis_rsl_sendmsg(msg);
 }
 
+int rsl_lchan_set_state(struct gsm_lchan *lchan, int state)
+{
+	lchan->state = state;
+	return 0;
+}
+
 /* Chapter 8.4.2: Channel Activate Acknowledge */
 static int rsl_rx_chan_act_ack(struct msgb *msg)
 {
@@ -749,7 +789,7 @@
 		LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK, but state %s\n",
 			gsm_lchan_name(msg->lchan),
 			gsm_lchans_name(msg->lchan->state));
-	msg->lchan->state = LCHAN_S_ACTIVE;
+	rsl_lchan_set_state(msg->lchan, LCHAN_S_ACTIVE);
 
 	dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_ACK, msg->lchan);
 
@@ -775,10 +815,10 @@
 		print_rsl_cause(LOGL_ERROR, cause,
 				TLVP_LEN(&tp, RSL_IE_CAUSE));
 		if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC)
-			msg->lchan->state = LCHAN_S_NONE;
+			rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
 	} else
-		msg->lchan->state = LCHAN_S_NONE;
- 
+		rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
+
 	LOGPC(DRSL, LOGL_ERROR, "\n");
 
 	dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_NACK, msg->lchan);
@@ -805,7 +845,8 @@
 
 	LOGPC(DRSL, LOGL_NOTICE, "\n");
 	/* FIXME: only free it after channel release ACK */
-	return rsl_rf_chan_release(msg->lchan);
+	counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rf_fail);
+	return rsl_rf_chan_release(msg->lchan, 1);
 }
 
 static void print_meas_rep_uni(struct gsm_meas_rep_unidir *mru,
@@ -977,11 +1018,14 @@
 		break;
 	case RSL_MT_RF_CHAN_REL_ACK:
 		DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", ts_name);
-		if (msg->lchan->state != LCHAN_S_REL_REQ)
+		if (msg->lchan->state != LCHAN_S_REL_REQ && msg->lchan->state != LCHAN_S_REL_ERR)
 			LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state %s\n",
 				gsm_lchan_name(msg->lchan),
 				gsm_lchans_name(msg->lchan->state));
-		msg->lchan->state = LCHAN_S_NONE;
+		bsc_del_timer(&msg->lchan->T3111);
+		/* we have an error timer pending to release that */
+		if (msg->lchan->state != LCHAN_S_REL_ERR)
+			rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
 		lchan_free(msg->lchan);
 		break;
 	case RSL_MT_MODE_MODIFY_ACK:
@@ -992,12 +1036,14 @@
 		break;
 	case RSL_MT_IPAC_PDCH_ACT_ACK:
 		DEBUGPC(DRSL, "%s IPAC PDCH ACT ACK\n", ts_name);
+		msg->lchan->ts->flags |= TS_F_PDCH_MODE;
 		break;
 	case RSL_MT_IPAC_PDCH_ACT_NACK:
 		LOGP(DRSL, LOGL_ERROR, "%s IPAC PDCH ACT NACK\n", ts_name);
 		break;
 	case RSL_MT_IPAC_PDCH_DEACT_ACK:
 		DEBUGP(DRSL, "%s IPAC PDCH DEACT ACK\n", ts_name);
+		msg->lchan->ts->flags &= ~TS_F_PDCH_MODE;
 		break;
 	case RSL_MT_IPAC_PDCH_DEACT_NACK:
 		LOGP(DRSL, LOGL_ERROR, "%s IPAC PDCH DEACT NACK\n", ts_name);
@@ -1054,7 +1100,7 @@
 		//DEBUGP(DRSL, "%s RF Resource Indication\n", gsm_trx_name(msg->trx));
 		break;
 	case RSL_MT_OVERLOAD:
-		/* indicate CCCH / ACCH / processor overload */ 
+		/* indicate CCCH / ACCH / processor overload */
 		LOGP(DRSL, LOGL_ERROR, "%s CCCH/ACCH/CPU Overload\n",
 		     gsm_trx_name(msg->trx));
 		break;
@@ -1071,7 +1117,15 @@
 {
 	struct gsm_lchan *lchan = data;
 
-	rsl_rf_chan_release(lchan);
+	rsl_rf_chan_release(lchan, 1);
+}
+
+/* If T3111 expires, we will send the RF Channel Request */
+static void t3111_expired(void *data)
+{
+	struct gsm_lchan *lchan = data;
+
+	rsl_rf_chan_release(lchan, 0);
 }
 
 /* MS has requested a channel on the RACH */
@@ -1122,7 +1176,7 @@
 		LOGP(DRSL, LOGL_NOTICE, "%s lchan_alloc() returned channel "
 		     "in state %s\n", gsm_lchan_name(lchan),
 		     gsm_lchans_name(lchan->state));
-	lchan->state = LCHAN_S_ACT_REQ;
+	rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ);
 
 	ts_number = lchan->ts->nr;
 	arfcn = lchan->ts->trx->arfcn;
@@ -1179,6 +1233,10 @@
 	switch (rslh->data[0]) {
 	case RSL_IE_PAGING_LOAD:
 		pg_buf_space = rslh->data[1] << 8 | rslh->data[2];
+		if (is_ipaccess_bts(msg->trx->bts) && pg_buf_space == 0xffff) {
+			/* paging load below configured threshold, use 50 as default */
+			pg_buf_space = 50;
+		}
 		paging_update_buffer_space(msg->trx->bts, pg_buf_space);
 		break;
 	case RSL_IE_RACH_LOAD:
@@ -1238,13 +1296,31 @@
 
 	rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND);
 
-	if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED)
-		return rsl_rf_chan_release(msg->lchan);
+	if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED) {
+		counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rll_err);
+		return rsl_rf_chan_release(msg->lchan, 1);
+	}
 
 	return 0;
 }
 
-/*	ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST 
+static void rsl_handle_release(struct gsm_lchan *lchan)
+{
+	struct gsm_bts *bts;
+	if (lchan->state != LCHAN_S_REL_REQ)
+		LOGP(DRSL, LOGL_ERROR, "RF release on %s but state %s\n",
+			gsm_lchan_name(lchan),
+			gsm_lchans_name(lchan->state));
+
+
+	/* wait a bit to send the RF Channel Release */
+	lchan->T3111.cb = t3111_expired;
+	lchan->T3111.data = lchan;
+	bts = lchan->ts->trx->bts;
+	bsc_schedule_timer(&lchan->T3111, bts->network->T3111, 0);
+}
+
+/*	ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST
 	0x02, 0x06,
 	0x01, 0x20,
 	0x02, 0x00,
@@ -1264,7 +1340,7 @@
 	switch (rllh->c.msg_type) {
 	case RSL_MT_DATA_IND:
 		DEBUGPC(DRLL, "DATA INDICATION\n");
-		if (msgb_l2len(msg) > 
+		if (msgb_l2len(msg) >
 		    sizeof(struct abis_rsl_common_hdr) + sizeof(*rllh) &&
 		    rllh->data[0] == RSL_IE_L3_INFO) {
 			msg->l3h = &rllh->data[3];
@@ -1276,7 +1352,7 @@
 		/* lchan is established, stop T3101 */
 		msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_MS;
 		bsc_del_timer(&msg->lchan->T3101);
-		if (msgb_l2len(msg) > 
+		if (msgb_l2len(msg) >
 		    sizeof(struct abis_rsl_common_hdr) + sizeof(*rllh) &&
 		    rllh->data[0] == RSL_IE_L3_INFO) {
 			msg->l3h = &rllh->data[3];
@@ -1295,20 +1371,14 @@
 		msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED;
 		rll_indication(msg->lchan, rllh->link_id,
 				  BSC_RLLR_IND_REL_IND);
-		/* we can now releae the channel on the BTS/Abis side */
-		/* FIXME: officially we need to start T3111 and wait for
-		 * some grace period */
-		rsl_rf_chan_release(msg->lchan);
+		rsl_handle_release(msg->lchan);
 		break;
 	case RSL_MT_REL_CONF:
 		/* BTS informs us of having received UA from MS,
 		 * in response to DISC that we've sent earlier */
 		DEBUGPC(DRLL, "RELEASE CONFIRMATION\n");
 		msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED;
-		/* we can now releae the channel on the BTS/Abis side */
-		/* FIXME: officially we need to start T3111 and wait for
-		 * some grace period */
-		rsl_rf_chan_release(msg->lchan);
+		rsl_handle_release(msg->lchan);
 		break;
 	case RSL_MT_ERROR_IND:
 		rc = rsl_rx_rll_err_ind(msg);
@@ -1361,6 +1431,44 @@
 	return 0;
 }
 
+static u_int8_t ipa_rtp_pt_for_lchan(struct gsm_lchan *lchan)
+{
+	switch (lchan->tch_mode) {
+	case GSM48_CMODE_SPEECH_V1:
+		switch (lchan->type) {
+		case GSM_LCHAN_TCH_F:
+			return RTP_PT_GSM_FULL;
+		case GSM_LCHAN_TCH_H:
+			return RTP_PT_GSM_HALF;
+		default:
+			break;
+		}
+	case GSM48_CMODE_SPEECH_EFR:
+		switch (lchan->type) {
+		case GSM_LCHAN_TCH_F:
+			return RTP_PT_GSM_EFR;
+		/* there's no half-rate EFR */
+		default:
+			break;
+		}
+	case GSM48_CMODE_SPEECH_AMR:
+		switch (lchan->type) {
+		case GSM_LCHAN_TCH_F:
+			return RTP_PT_AMR_FULL;
+		case GSM_LCHAN_TCH_H:
+			return RTP_PT_AMR_HALF;
+		default:
+			break;
+		}
+	default:
+		break;
+	}
+	LOGP(DRSL, LOGL_ERROR, "Cannot determine ip.access rtp payload type for "
+		"tch_mode == 0x%02x\n & lchan_type == %d",
+		lchan->tch_mode, lchan->type);
+	return 0;
+}
+
 /* ip.access specific RSL extensions */
 static void ipac_parse_rtp(struct gsm_lchan *lchan, struct tlv_parsed *tv)
 {
@@ -1427,10 +1535,13 @@
 
 	/* 0x1- == receive-only, 0x-1 == EFR codec */
 	lchan->abis_ip.speech_mode = 0x10 | ipa_smod_s_for_lchan(lchan);
+	lchan->abis_ip.rtp_payload = ipa_rtp_pt_for_lchan(lchan);
 	msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode);
+	msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload);
 
-	DEBUGP(DRSL, "%s IPAC_BIND speech_mode=0x%02x\n",
-		gsm_lchan_name(lchan), lchan->abis_ip.speech_mode);
+	DEBUGP(DRSL, "%s IPAC_BIND speech_mode=0x%02x RTP_PAYLOAD=%d\n",
+		gsm_lchan_name(lchan), lchan->abis_ip.speech_mode,
+		lchan->abis_ip.rtp_payload);
 
 	msg->trx = lchan->ts->trx;
 
@@ -1457,11 +1568,13 @@
 
 	/* 0x0- == both directions, 0x-1 == EFR codec */
 	lchan->abis_ip.speech_mode = 0x00 | ipa_smod_s_for_lchan(lchan);
+	lchan->abis_ip.rtp_payload = ipa_rtp_pt_for_lchan(lchan);
 
 	ia.s_addr = htonl(ip);
-	DEBUGP(DRSL, "%s IPAC_MDCX IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d "
-		"speech_mode=0x%02x\n", gsm_lchan_name(lchan), inet_ntoa(ia), port,
-		rtp_payload2, lchan->abis_ip.conn_id, lchan->abis_ip.speech_mode);
+	DEBUGP(DRSL, "%s IPAC_MDCX IP=%s PORT=%d RTP_PAYLOAD=%d RTP_PAYLOAD2=%d "
+		"CONN_ID=%d speech_mode=0x%02x\n", gsm_lchan_name(lchan),
+		inet_ntoa(ia), port, lchan->abis_ip.rtp_payload, rtp_payload2,
+		lchan->abis_ip.conn_id, lchan->abis_ip.speech_mode);
 
 	msgb_tv16_put(msg, RSL_IE_IPAC_CONN_ID, lchan->abis_ip.conn_id);
 	msgb_v_put(msg, RSL_IE_IPAC_REMOTE_IP);
@@ -1469,6 +1582,7 @@
 	*att_ip = ia.s_addr;
 	msgb_tv16_put(msg, RSL_IE_IPAC_REMOTE_PORT, port);
 	msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode);
+	msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload);
 	if (rtp_payload2)
 		msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, rtp_payload2);
 	
@@ -1491,17 +1605,24 @@
 	return rc;
 }
 
-int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan)
+int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan, int act)
 {
 	struct msgb *msg = rsl_msgb_alloc();
 	struct abis_rsl_dchan_hdr *dh;
+	u_int8_t msg_type;
+
+	if (act)
+		msg_type = RSL_MT_IPAC_PDCH_ACT;
+	else
+		msg_type = RSL_MT_IPAC_PDCH_DEACT;
 
 	dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
-	init_dchan_hdr(dh, RSL_MT_IPAC_PDCH_ACT);
+	init_dchan_hdr(dh, msg_type);
 	dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN;
 	dh->chan_nr = lchan2chan_nr(lchan);
 
-	DEBUGP(DRSL, "%s IPAC_PDCH_ACT\n", gsm_lchan_name(lchan));
+	DEBUGP(DRSL, "%s IPAC_PDCH_%sACT\n", gsm_lchan_name(lchan),
+		act ? "" : "DE");
 
 	msg->trx = lchan->ts->trx;
 
@@ -1643,9 +1764,21 @@
 /* Entry-point where L2 RSL from BTS enters */
 int abis_rsl_rcvmsg(struct msgb *msg)
 {
-	struct abis_rsl_common_hdr *rslh = msgb_l2(msg)	;
+	struct abis_rsl_common_hdr *rslh;
 	int rc = 0;
 
+	if (!msg) {
+		DEBUGP(DRSL, "Empty RSL msg?..\n");
+		return -1;
+	}
+
+	if (msgb_l2len(msg) < sizeof(*rslh)) {
+		DEBUGP(DRSL, "Truncated RSL message with l2len: %u\n", msgb_l2len(msg));
+		return -1;
+	}
+
+	rslh = msgb_l2(msg);
+
 	switch (rslh->msg_discr & 0xfe) {
 	case ABIS_RSL_MDISC_RLL:
 		rc = abis_rsl_rx_rll(msg);
diff --git a/openbsc/src/auth.c b/openbsc/src/auth.c
new file mode 100644
index 0000000..f57b668
--- /dev/null
+++ b/openbsc/src/auth.c
@@ -0,0 +1,128 @@
+/* Authentication related functions */
+
+/*
+ * (C) 2010 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.
+ *
+ */
+
+#include <openbsc/db.h>
+#include <openbsc/debug.h>
+#include <openbsc/gsm_data.h>
+
+#include <osmocore/comp128.h>
+
+#include <stdlib.h>
+
+
+static int
+_use_xor(struct gsm_auth_info *ainfo, struct gsm_auth_tuple *atuple)
+{
+	int i, l = ainfo->a3a8_ki_len;
+
+	if ((l > A38_XOR_MAX_KEY_LEN) || (l < A38_XOR_MIN_KEY_LEN)) {
+		DEBUGP(DMM, "Invalid XOR key (len=%d) %s",
+			ainfo->a3a8_ki_len,
+			hexdump(ainfo->a3a8_ki, ainfo->a3a8_ki_len));
+		return -1;
+	}
+
+	for (i=0; i<4; i++)
+		atuple->sres[i] = atuple->rand[i] ^ ainfo->a3a8_ki[i];
+	for (i=8; i<12; i++)
+		atuple->kc[i-4] = atuple->rand[i] ^ ainfo->a3a8_ki[i];
+
+	return 0;
+}
+
+static int
+_use_comp128_v1(struct gsm_auth_info *ainfo, struct gsm_auth_tuple *atuple)
+{
+	if (ainfo->a3a8_ki_len != A38_COMP128_KEY_LEN) {
+		DEBUGP(DMM, "Invalid COMP128v1 key (len=%d) %s",
+			ainfo->a3a8_ki_len,
+			hexdump(ainfo->a3a8_ki, ainfo->a3a8_ki_len));
+		return -1;
+	}
+
+	comp128(ainfo->a3a8_ki, atuple->rand, atuple->sres, atuple->kc);
+
+	return 0;
+}
+
+/* Return values 
+ *  -1 -> Internal error
+ *   0 -> Not available
+ *   1 -> Tuple returned, need to do auth, then enable cipher
+ *   2 -> Tuple returned, need to enable cipher
+ */
+int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
+                              struct gsm_subscriber *subscr, int key_seq)
+{
+	struct gsm_auth_info ainfo;
+	int i, rc;
+
+	/* Get subscriber info (if any) */
+	rc = db_get_authinfo_for_subscr(&ainfo, subscr);
+	if (rc < 0) {
+		DEBUGP(DMM, "No retrievable Ki for subscriber, skipping auth");
+		return rc == -ENOENT ? 0 : -1;
+	}
+
+	/* If possible, re-use the last tuple and skip auth */
+	rc = db_get_lastauthtuple_for_subscr(atuple, subscr);
+	if ((rc == 0) &&
+	    (atuple->key_seq != GSM_KEY_SEQ_INVAL) &&
+	    (atuple->use_count < 3))
+	{
+		atuple->use_count++;
+		db_sync_lastauthtuple_for_subscr(atuple, subscr);
+		return 2;
+	}
+
+	/* Generate a new one */
+	atuple->use_count = 1;
+	atuple->key_seq = (atuple->key_seq + 1) % 7;
+        for (i=0; i<sizeof(atuple->rand); i++)
+                atuple->rand[i] = random() & 0xff;
+
+	switch (ainfo.auth_algo) {
+		case AUTH_ALGO_NONE:
+			return 0;
+
+		case AUTH_ALGO_XOR:
+			if (_use_xor(&ainfo, atuple))
+				return 0;
+			break;
+
+		case AUTH_ALGO_COMP128v1:
+			if (_use_comp128_v1(&ainfo, atuple))
+				return 0;
+			break;
+
+		default:
+			DEBUGP(DMM, "Unsupported auth type algo_id=%d\n",
+				ainfo.auth_algo);
+			return 0;
+	}
+
+        db_sync_lastauthtuple_for_subscr(atuple, subscr);
+
+	return 1;
+}
+
diff --git a/openbsc/src/bs11_config.c b/openbsc/src/bs11_config.c
index 80f9ba9..44cef0a 100644
--- a/openbsc/src/bs11_config.c
+++ b/openbsc/src/bs11_config.c
@@ -3,7 +3,7 @@
 /* (C) 2009 by Harald Welte <laforge@gnumonks.org>
  * All Rights Reserved
  *
- * This software is based on ideas (but not code) of BS11Config 
+ * This software is based on ideas (but not code) of BS11Config
  * (C) 2009 by Dieter Spaar <spaar@mirider.augusta.de>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -54,9 +54,9 @@
 static char *command, *value;
 struct timer_list status_timer;
 
-static const u_int8_t obj_li_attr[] = { 
+static const u_int8_t obj_li_attr[] = {
 	NM_ATT_BS11_BIT_ERR_THESH, 0x09, 0x00,
-	NM_ATT_BS11_L1_PROT_TYPE, 0x00, 
+	NM_ATT_BS11_L1_PROT_TYPE, 0x00,
 	NM_ATT_BS11_LINE_CFG, 0x00,
 };
 static const u_int8_t obj_bbsig0_attr[] = {
@@ -71,7 +71,7 @@
 
 static const u_int8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 };
 
-static struct debug_target *stderr_target;
+static struct log_target *stderr_target;
 
 /* dummy function to keep gsm_data.c happy */
 struct counter *counter_alloc(const char *name)
@@ -481,7 +481,7 @@
 		 * argument, so our swload_cbfn can distinguish
 		 * a safety load from a regular software */
 		if (file_is_readable(fname_safety))
-			rc = abis_nm_software_load(g_bts, fname_safety,
+			rc = abis_nm_software_load(g_bts, 0xff, fname_safety,
 						   win_size, param_forced,
 						   swload_cbfn, g_bts);
 		else
@@ -697,7 +697,8 @@
 }
 
 int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
-		   struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
+		   struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
+		   struct abis_om_obj_inst *obj_ins)
 {
 	return 0;
 }
@@ -778,7 +779,7 @@
 			serial_port = optarg;
 			break;
 		case 'b':
-			debug_parse_category_mask(stderr_target, optarg);
+			log_parse_category_mask(stderr_target, optarg);
 			break;
 		case 's':
 			fname_software = optarg;
@@ -829,15 +830,16 @@
 	}
 }
 
+extern int bts_model_bs11_init(void);
 int main(int argc, char **argv)
 {
 	struct gsm_network *gsmnet;
 	int rc;
 
-	debug_init();
-	stderr_target = debug_target_create_stderr();
-	debug_add_target(stderr_target);
-	debug_set_all_filter(stderr_target, 1);
+	log_init(&log_info);
+	stderr_target = log_target_create_stderr();
+	log_add_target(stderr_target);
+	log_set_all_filter(stderr_target, 1);
 	handle_options(argc, argv);
 	bts_model_bs11_init();
 
diff --git a/openbsc/src/bsc_api.c b/openbsc/src/bsc_api.c
new file mode 100644
index 0000000..25b8b66
--- /dev/null
+++ b/openbsc/src/bsc_api.c
@@ -0,0 +1,134 @@
+/* GSM 08.08 like API for OpenBSC. The bridge from MSC to BSC */
+
+/* (C) 2010 by Holger Hans Peter Freyther
+ * (C) 2010 by On Waves
+ * (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 <openbsc/bsc_api.h>
+#include <openbsc/bsc_rll.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/signal.h>
+#include <openbsc/abis_rsl.h>
+
+#include <osmocore/talloc.h>
+
+static void rll_ind_cb(struct gsm_lchan *, uint8_t, void *, enum bsc_rllr_ind);
+static void send_sapi_reject(struct gsm_subscriber_connection *conn, int link_id);
+
+int bsc_api_init(struct gsm_network *network, struct bsc_api *api)
+{
+	network->bsc_api = api;
+	return 0;
+}
+
+int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn,
+			struct msgb *msg, int link_id)
+{
+	uint8_t sapi = link_id & 0x7;
+	msg->lchan = conn->lchan;
+	msg->trx = msg->lchan->ts->trx;
+
+	if (conn->lchan->sapis[sapi] == LCHAN_SAPI_UNUSED) {
+		OBSC_LINKID_CB(msg) = link_id;
+		if (rll_establish(msg->lchan, sapi, rll_ind_cb, msg) != 0) {
+			msgb_free(msg);
+			send_sapi_reject(conn, link_id);
+			return -1;
+		}
+		return 0;
+	} else {
+		return rsl_data_request(msg, link_id);
+	}
+}
+
+/* dequeue messages to layer 4 */
+int bsc_upqueue(struct gsm_network *net)
+{
+	struct gsm_mncc *mncc;
+	struct msgb *msg;
+	int work = 0;
+
+	if (net)
+		while ((msg = msgb_dequeue(&net->upqueue))) {
+			mncc = (struct gsm_mncc *)msg->data;
+			if (net->mncc_recv)
+				net->mncc_recv(net, mncc->msg_type, mncc);
+			work = 1; /* work done */
+			talloc_free(msg);
+		}
+
+	return work;
+}
+
+static void send_sapi_reject(struct gsm_subscriber_connection *conn, int link_id)
+{
+	struct bsc_api *api;
+
+	api = conn->bts->network->bsc_api;
+	if (!api || !api->sapi_n_reject)
+		return;
+
+	api->sapi_n_reject(conn, link_id);
+}
+
+static void rll_ind_cb(struct gsm_lchan *lchan, uint8_t link_id, void *_data, enum bsc_rllr_ind rllr_ind)
+{
+	struct msgb *msg = _data;
+
+	switch (rllr_ind) {
+	case BSC_RLLR_IND_EST_CONF:
+		rsl_data_request(msg, OBSC_LINKID_CB(msg));
+		break;
+	case BSC_RLLR_IND_REL_IND:
+	case BSC_RLLR_IND_ERR_IND:
+	case BSC_RLLR_IND_TIMEOUT:
+		send_sapi_reject(&lchan->conn, OBSC_LINKID_CB(msg));
+		msgb_free(msg);
+		break;
+	}
+}
+
+static int bsc_handle_lchan_signal(unsigned int subsys, unsigned int signal,
+				   void *handler_data, void *signal_data)
+{
+	struct bsc_api *bsc;
+	struct gsm_lchan *lchan;
+
+	if (subsys != SS_LCHAN || signal != S_LCHAN_UNEXPECTED_RELEASE)
+		return 0;
+
+	lchan = (struct gsm_lchan *)signal_data;
+	if (!lchan)
+		return 0;
+
+
+	bsc = lchan->ts->trx->bts->network->bsc_api;
+	if (!bsc || !bsc->clear_request)
+		return 0;
+
+	bsc->clear_request(&lchan->conn, 0);
+	return 0;
+}
+
+static __attribute__((constructor)) void on_dso_load_bsc(void)
+{
+	register_signal_handler(SS_LCHAN, bsc_handle_lchan_signal, NULL);
+}
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index 4cde4dd..7be0360 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -37,12 +37,15 @@
 #include <osmocore/talloc.h>
 #include <openbsc/signal.h>
 
+#include <osmocom/vty/command.h>
+
+#include "../bscconfig.h"
+
 /* MCC and MNC for the Location Area Identifier */
-static struct debug_target *stderr_target;
+static struct log_target *stderr_target;
 struct gsm_network *bsc_gsmnet = 0;
 static const char *database_name = "hlr.sqlite3";
 static const char *config_file = "openbsc.cfg";
-extern const char *openbsc_version;
 extern const char *openbsc_copyright;
 
 /* timer to store statistics */
@@ -87,16 +90,6 @@
 	printf("  -e --log-level number. Set a global loglevel.\n");
 }
 
-static void print_version()
-{
-	printf("%s\n", openbsc_version);
-}
-
-static void print_copyright()
-{
-	puts(openbsc_copyright);
-}
-
 static void handle_options(int argc, char** argv)
 {
 	while (1) {
@@ -127,10 +120,10 @@
 			print_help();
 			exit(0);
 		case 's':
-			debug_set_use_color(stderr_target, 0);
+			log_set_use_color(stderr_target, 0);
 			break;
 		case 'd':
-			debug_parse_category_mask(stderr_target, optarg);
+			log_parse_category_mask(stderr_target, optarg);
 			break;
 		case 'l':
 			database_name = strdup(optarg);
@@ -142,18 +135,16 @@
 			create_pcap_file(optarg);
 			break;
 		case 'T':
-			debug_set_print_timestamp(stderr_target, 1);
+			log_set_print_timestamp(stderr_target, 1);
 			break;
 		case 'P':
 			ipacc_rtp_direct = 0;
 			break;
 		case 'e':
-			debug_set_log_level(stderr_target, atoi(optarg));
+			log_set_log_level(stderr_target, atoi(optarg));
 			break;
 		case 'V':
-			print_version();
-			printf("\n");
-			print_copyright();
+			print_version(1);
 			exit(0);
 			break;
 		default:
@@ -207,29 +198,47 @@
 extern int bts_model_bs11_init(void);
 extern int bts_model_nanobts_init(void);
 
+extern enum node_type bsc_vty_go_parent(struct vty *vty);
+
+static struct vty_app_info vty_info = {
+	.name 		= "OpenBSC",
+	.version	= PACKAGE_VERSION,
+	.go_parent_cb	= bsc_vty_go_parent,
+};
+
 int main(int argc, char **argv)
 {
 	int rc;
 
-	debug_init();
+	vty_info.copyright = openbsc_copyright;
+
+	log_init(&log_info);
 	tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
 	talloc_ctx_init();
 	on_dso_load_token();
 	on_dso_load_rrlp();
 	on_dso_load_ho_dec();
-	stderr_target = debug_target_create_stderr();
-	debug_add_target(stderr_target);
+	stderr_target = log_target_create_stderr();
+	log_add_target(stderr_target);
 
 	bts_model_unknown_init();
 	bts_model_bs11_init();
 	bts_model_nanobts_init();
 
 	/* enable filters */
-	debug_set_all_filter(stderr_target, 1);
+	log_set_all_filter(stderr_target, 1);
+
+	/* This needs to precede handle_options() */
+	vty_init(&vty_info);
+	bsc_vty_init();
 
 	/* parse options */
 	handle_options(argc, argv);
 
+	rc = bsc_bootstrap_network(mncc_recv, config_file);
+	if (rc < 0)
+		exit(1);
+
 	/* seed the PRNG */
 	srand(time(NULL));
 
@@ -250,10 +259,6 @@
 	db_sync_timer.data = NULL;
 	bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL);
 
-	rc = bsc_bootstrap_network(mncc_recv, config_file);
-	if (rc < 0)
-		exit(1);
-
 	signal(SIGINT, &signal_handler);
 	signal(SIGABRT, &signal_handler);
 	signal(SIGUSR1, &signal_handler);
@@ -262,7 +267,7 @@
 
 	while (1) {
 		bsc_upqueue(bsc_gsmnet);
-		debug_reset_context();
+		log_reset_context();
 		bsc_select_main(0);
 	}
 }
diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c
index f343662..ddb53ba 100644
--- a/openbsc/src/bsc_init.c
+++ b/openbsc/src/bsc_init.c
@@ -1,6 +1,6 @@
 /* A hackish minimal BSC (+MSC +HLR) implementation */
 
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
+/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
  * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
  * All Rights Reserved
  *
@@ -27,10 +27,12 @@
 #include <openbsc/abis_nm.h>
 #include <openbsc/debug.h>
 #include <openbsc/misdn.h>
-#include <openbsc/telnet_interface.h>
+#include <openbsc/osmo_msc.h>
+#include <osmocom/vty/telnet_interface.h>
 #include <openbsc/system_information.h>
 #include <openbsc/paging.h>
 #include <openbsc/signal.h>
+#include <openbsc/chan_alloc.h>
 #include <osmocore/talloc.h>
 
 /* global pointer to the gsm network data structure */
@@ -377,11 +379,11 @@
 		4,	/* N3103 */
 		8,	/* N3105 */
 		15,	/* RLC CV countdown */
-	NM_ATT_IPACC_CODING_SCHEMES, 0, 2,  0x0f, 0x00,
+	NM_ATT_IPACC_CODING_SCHEMES, 0, 2,  0x0f, 0x00,	/* CS1..CS4 */
 	NM_ATT_IPACC_RLC_CFG_2, 0, 5,
-		0x00, 250,
-		0x00, 250,
-		2,	/* MCS2 */
+		0x00, 250,	/* T downlink TBF extension (0..500) */
+		0x00, 250,	/* T uplink TBF extension (0..500) */
+		2,	/* CS2 */
 #if 0
 	/* EDGE model only, breaks older models.
 	 * Should inquire the BTS capabilities */
@@ -400,7 +402,8 @@
 
 /* Callback function to be called whenever we get a GSM 12.21 state change event */
 int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
-		   struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
+		   struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
+		   struct abis_om_obj_inst *obj_inst)
 {
 	struct gsm_bts *bts;
 	struct gsm_bts_trx *trx;
@@ -417,9 +420,9 @@
 	switch (obj_class) {
 	case NM_OC_SITE_MANAGER:
 		bts = container_of(obj, struct gsm_bts, site_mgr);
-		if ((new_state->operational == 2 &&
+		if ((new_state->operational == NM_OPSTATE_ENABLED &&
 		     new_state->availability == NM_AVSTATE_OK) ||
-		    (new_state->operational == 1 &&
+		    (new_state->operational == NM_OPSTATE_DISABLED &&
 		     new_state->availability == NM_AVSTATE_OFF_LINE))
 			abis_nm_opstart(bts, obj_class, 0xff, 0xff, 0xff);
 		break;
@@ -439,7 +442,7 @@
 	case NM_OC_CHANNEL:
 		ts = obj;
 		trx = ts->trx;
-		if (new_state->operational == 1 &&
+		if (new_state->operational == NM_OPSTATE_DISABLED &&
 		    new_state->availability == NM_AVSTATE_DEPENDENCY) {
 			patch_nm_tables(trx->bts);
 			enum abis_nm_chan_comb ccomb =
@@ -454,16 +457,16 @@
 		break;
 	case NM_OC_RADIO_CARRIER:
 		trx = obj;
-		if (new_state->operational == 1 &&
+		if (new_state->operational == NM_OPSTATE_DISABLED &&
 		    new_state->availability == NM_AVSTATE_OK)
 			abis_nm_opstart(trx->bts, obj_class, trx->bts->bts_nr,
 					trx->nr, 0xff);
 		break;
 	case NM_OC_GPRS_NSE:
 		bts = container_of(obj, struct gsm_bts, gprs.nse);
-		if (!bts->gprs.enabled)
+		if (bts->gprs.mode == BTS_GPRS_NONE)
 			break;
-		if (new_state->availability == 5) {
+		if (new_state->availability == NM_AVSTATE_DEPENDENCY) {
 			abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
 						  0xff, 0xff, nanobts_attr_nse,
 						  sizeof(nanobts_attr_nse));
@@ -475,9 +478,9 @@
 		break;
 	case NM_OC_GPRS_CELL:
 		bts = container_of(obj, struct gsm_bts, gprs.cell);
-		if (!bts->gprs.enabled)
+		if (bts->gprs.mode == BTS_GPRS_NONE)
 			break;
-		if (new_state->availability == 5) {
+		if (new_state->availability == NM_AVSTATE_DEPENDENCY) {
 			abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
 						  0, 0xff, nanobts_attr_cell,
 						  sizeof(nanobts_attr_cell));
@@ -490,9 +493,9 @@
 	case NM_OC_GPRS_NSVC:
 		nsvc = obj;
 		bts = nsvc->bts;
-		if (!bts->gprs.enabled)
+		if (bts->gprs.mode == BTS_GPRS_NONE)
 			break;
-	        /* We skip NSVC1 since we only use NSVC0 */
+		/* We skip NSVC1 since we only use NSVC0 */
 		if (nsvc->id == 1)
 			break;
 		if (new_state->availability == NM_AVSTATE_OFF_LINE) {
@@ -798,7 +801,7 @@
 			DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc));
 			rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp));
 		}
-		if (bts->gprs.enabled) {
+		if (bts->gprs.mode != BTS_GPRS_NONE) {
 			i = 13;
 			rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13);
 			if (rc < 0)
@@ -852,6 +855,22 @@
 	bs11_attr_radio[2] |= arfcn_high;
 	bs11_attr_radio[3] = arfcn_low;
 
+	/* patch the RACH attributes */
+	if (bts->rach_b_thresh != -1) {
+		nanobts_attr_bts[33] = bts->rach_b_thresh & 0xff;
+		bs11_attr_bts[33] = bts->rach_b_thresh & 0xff;
+	}
+
+	if (bts->rach_ldavg_slots != -1) {
+		u_int8_t avg_high = bts->rach_ldavg_slots & 0xff;
+		u_int8_t avg_low = (bts->rach_ldavg_slots >> 8) & 0x0f;
+
+		nanobts_attr_bts[35] = avg_high;
+		nanobts_attr_bts[36] = avg_low;
+		bs11_attr_bts[35] = avg_high;
+		bs11_attr_bts[36] = avg_low;
+	}
+
 	/* patch BSIC */
 	bs11_attr_bts[1] = bts->bsic;
 	nanobts_attr_bts[sizeof(nanobts_attr_bts)-11] = bts->bsic;
@@ -866,6 +885,10 @@
 	/* patch NSEI */
 	nanobts_attr_nse[3] = bts->gprs.nse.nsei >> 8;
 	nanobts_attr_nse[4] = bts->gprs.nse.nsei & 0xff;
+	memcpy(nanobts_attr_nse+8, bts->gprs.nse.timer,
+		ARRAY_SIZE(bts->gprs.nse.timer));
+	memcpy(nanobts_attr_nse+18, bts->gprs.cell.timer,
+		ARRAY_SIZE(bts->gprs.cell.timer));
 
 	/* patch NSVCI */
 	nanobts_attr_nsvc0[3] = bts->gprs.nsvc[0].nsvci >> 8;
@@ -885,6 +908,11 @@
 	/* patch RAC */
 	nanobts_attr_cell[3] = bts->gprs.rac;
 
+	if (bts->gprs.mode == BTS_GPRS_EGPRS) {
+		/* patch EGPRS coding schemes MCS 1..9 */
+		nanobts_attr_cell[29] = 0x8f;
+		nanobts_attr_cell[30] = 0xff;
+	}
 }
 
 static void bootstrap_rsl(struct gsm_bts_trx *trx)
@@ -899,6 +927,8 @@
 
 void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
 {
+	int ts_no, lchan_no;
+
 	switch (event) {
 	case EVT_E1_TEI_UP:
 		switch (type) {
@@ -913,8 +943,35 @@
 		}
 		break;
 	case EVT_E1_TEI_DN:
-		LOGP(DMI, LOGL_NOTICE, "Lost some E1 TEI link\n");
-		/* FIXME: deal with TEI or L1 link loss */
+		LOGP(DMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", type, trx);
+
+		if (type == E1INP_SIGN_OML)
+			counter_inc(trx->bts->network->stats.bts.oml_fail);
+		else if (type == E1INP_SIGN_RSL)
+			counter_inc(trx->bts->network->stats.bts.rsl_fail);
+
+		/*
+		 * free all allocated channels. change the nm_state so the
+		 * trx and trx_ts becomes unusable and chan_alloc.c can not
+		 * allocate from it.
+		 */
+		for (ts_no = 0; ts_no < ARRAY_SIZE(trx->ts); ++ts_no) {
+			struct gsm_bts_trx_ts *ts = &trx->ts[ts_no];
+
+			for (lchan_no = 0; lchan_no < ARRAY_SIZE(ts->lchan); ++lchan_no) {
+				if (ts->lchan[lchan_no].state != GSM_LCHAN_NONE)
+					lchan_free(&ts->lchan[lchan_no]);
+				lchan_reset(&ts->lchan[lchan_no]);
+			}
+
+			ts->nm_state.operational = 0;
+			ts->nm_state.availability = 0;
+		}
+
+		trx->nm_state.operational = 0;
+		trx->nm_state.availability = 0;
+		trx->bb_transc.nm_state.operational = 0;
+		trx->bb_transc.nm_state.availability = 0;
 		break;
 	default:
 		break;
@@ -923,6 +980,10 @@
 
 static int bootstrap_bts(struct gsm_bts *bts)
 {
+	int i, n;
+
+	/* FIXME: What about secondary TRX of a BTS?  What about a BTS that has TRX
+	 * in different bands? Why is 'band' a parameter of the BTS and not of the TRX? */
 	switch (bts->band) {
 	case GSM_BAND_1800:
 		if (bts->c0->arfcn < 512 || bts->c0->arfcn > 885) {
@@ -944,6 +1005,12 @@
 			return -EINVAL;
 		}
 		break;
+	case GSM_BAND_850:
+		if (bts->c0->arfcn < 128 || bts->c0->arfcn > 251) {
+			LOGP(DNM, LOGL_ERROR, "GSM850 channel must be between 128-251.\n");
+			return -EINVAL;
+		}
+		break;
 	default:
 		LOGP(DNM, LOGL_ERROR, "Unsupported frequency band.\n");
 		return -EINVAL;
@@ -959,10 +1026,34 @@
 
 	/* Control Channel Description */
 	bts->si_common.chan_desc.att = 1;
-	bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
 	bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5;
 	/* T3212 is set from vty/config */
 
+	/* Set ccch config by looking at ts config */
+	for (n=0, i=0; i<8; i++)
+		n += bts->c0->ts[i].pchan == GSM_PCHAN_CCCH ? 1 : 0;
+
+	switch (n) {
+	case 0:
+		bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
+		break;
+	case 1:
+		bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_NC;
+		break;
+	case 2:
+		bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_2_NC;
+		break;
+	case 3:
+		bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_3_NC;
+		break;
+	case 4:
+		bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_4_NC;
+		break;
+	default:
+		LOGP(DNM, LOGL_ERROR, "Unsupported CCCH timeslot configuration\n");
+		return -EINVAL;
+	}
+
 	/* some defaults for our system information */
 	bts->si_common.cell_options.radio_link_timeout = 2; /* 12 */
 	bts->si_common.cell_options.dtx = 2; /* MS shall not use upplink DTX */
@@ -980,6 +1071,7 @@
 int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, int, void *),
 			  const char *config_file)
 {
+	struct telnet_connection dummy_conn;
 	struct gsm_bts *bts;
 	int rc;
 
@@ -990,14 +1082,20 @@
 
 	bsc_gsmnet->name_long = talloc_strdup(bsc_gsmnet, "OpenBSC");
 	bsc_gsmnet->name_short = talloc_strdup(bsc_gsmnet, "OpenBSC");
+	bsc_api_init(bsc_gsmnet, msc_bsc_api());
 
-	telnet_init(bsc_gsmnet, 4242);
-	rc = vty_read_config_file(config_file);
+	/* our vty command code expects vty->priv to point to a telnet_connection */
+	dummy_conn.priv = bsc_gsmnet;
+	rc = vty_read_config_file(config_file, &dummy_conn);
 	if (rc < 0) {
 		LOGP(DNM, LOGL_FATAL, "Failed to parse the config file: '%s'\n", config_file);
 		return rc;
 	}
 
+	rc = telnet_init(tall_bsc_ctx, bsc_gsmnet, 4242);
+	if (rc < 0)
+		return rc;
+
 	register_signal_handler(SS_NM, nm_sig_cb, NULL);
 
 	llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) {
diff --git a/openbsc/src/bsc_rll.c b/openbsc/src/bsc_rll.c
index 1551d94..a8e642f 100644
--- a/openbsc/src/bsc_rll.c
+++ b/openbsc/src/bsc_rll.c
@@ -31,6 +31,7 @@
 #include <openbsc/gsm_data.h>
 #include <openbsc/chan_alloc.h>
 #include <openbsc/abis_rsl.h>
+#include <openbsc/signal.h>
 
 struct bsc_rll_req {
 	struct llist_head list;
@@ -51,8 +52,10 @@
 
 static void complete_rllr(struct bsc_rll_req *rllr, enum bsc_rllr_ind type)
 {
+	struct gsm_subscriber_connection *conn;
+
+	conn = &rllr->lchan->conn;
 	llist_del(&rllr->list);
-	put_lchan(rllr->lchan);
 	rllr->cb(rllr->lchan, rllr->link_id, rllr->data, type);
 	talloc_free(rllr);
 }
@@ -70,6 +73,7 @@
 			     enum bsc_rllr_ind),
 		  void *data)
 {
+	struct gsm_subscriber_connection *conn;
 	struct bsc_rll_req *rllr = talloc_zero(tall_bsc_ctx, struct bsc_rll_req);
 	u_int8_t link_id;
 	if (!rllr)
@@ -83,7 +87,7 @@
 	     lchan->type == GSM_LCHAN_TCH_H) && sapi != 0)
 		link_id |= 0x40;
 
-	use_lchan(lchan);
+	conn = &lchan->conn;
 	rllr->lchan = lchan;
 	rllr->link_id = link_id;
 	rllr->cb = cb;
@@ -115,3 +119,29 @@
 		}
 	}
 }
+
+static int rll_lchan_signal(unsigned int subsys, unsigned int signal,
+			    void *handler_data, void *signal_data)
+{
+	struct challoc_signal_data *challoc;
+	struct bsc_rll_req *rllr, *rllr2;
+
+	if (subsys != SS_CHALLOC || signal != S_CHALLOC_FREED)
+		return 0;
+
+	challoc = (struct challoc_signal_data *) signal_data;
+
+	llist_for_each_entry_safe(rllr, rllr2, &bsc_rll_reqs, list) {
+		if (rllr->lchan == challoc->lchan) {
+			bsc_del_timer(&rllr->timer);
+			complete_rllr(rllr, BSC_RLLR_IND_ERR_IND);
+		}
+	}
+
+	return 0;
+}
+
+static __attribute__((constructor)) void on_dso_load_rll(void)
+{
+	register_signal_handler(SS_CHALLOC, rll_lchan_signal, NULL);
+}
diff --git a/openbsc/src/bsc_version.c b/openbsc/src/bsc_version.c
index 0266194..432e63b 100644
--- a/openbsc/src/bsc_version.c
+++ b/openbsc/src/bsc_version.c
@@ -20,7 +20,6 @@
 
 #include "bscconfig.h"
 
-const char *openbsc_version = "OpenBSC " PACKAGE_VERSION;
 const char *openbsc_copyright =
 	"Copyright (C) 2008-2010 Harald Welte, Holger Freyther\n"
 	"Contributions by Daniel Willmann, Jan Lübbe,Stefan Schmidt\n"
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/bsc_vty.c
similarity index 76%
rename from openbsc/src/vty_interface.c
rename to openbsc/src/bsc_vty.c
index e894869..a17064d 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/bsc_vty.c
@@ -22,9 +22,11 @@
 #include <unistd.h>
 #include <sys/types.h>
 
-#include <vty/command.h>
-#include <vty/buffer.h>
-#include <vty/vty.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/buffer.h>
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/logging.h>
+#include <osmocom/vty/telnet_interface.h>
 
 #include <arpa/inet.h>
 
@@ -37,9 +39,38 @@
 #include <openbsc/meas_rep.h>
 #include <openbsc/db.h>
 #include <osmocore/talloc.h>
-#include <openbsc/telnet_interface.h>
+#include <openbsc/vty.h>
+#include <openbsc/gprs_ns.h>
+#include <openbsc/debug.h>
 
-static struct gsm_network *gsmnet;
+#include "../bscconfig.h"
+
+/* FIXME: this should go to some common file */
+static const struct value_string gprs_ns_timer_strs[] = {
+	{ 0, "tns-block" },
+	{ 1, "tns-block-retries" },
+	{ 2, "tns-reset" },
+	{ 3, "tns-reset-retries" },
+	{ 4, "tns-test" },
+	{ 5, "tns-alive" },
+	{ 6, "tns-alive-retries" },
+	{ 0, NULL }
+};
+
+static const struct value_string gprs_bssgp_cfg_strs[] = {
+	{ 0,	"blocking-timer" },
+	{ 1,	"blocking-retries" },
+	{ 2,	"unblocking-retries" },
+	{ 3,	"reset-timer" },
+	{ 4,	"reset-retries" },
+	{ 5,	"suspend-timer" },
+	{ 6,	"suspend-retries" },
+	{ 7,	"resume-timer" },
+	{ 8,	"resume-retries" },
+	{ 9,	"capability-update-timer" },
+	{ 10,	"capability-update-retries" },
+	{ 0,	NULL }
+};
 
 struct cmd_node net_node = {
 	GSMNET_NODE,
@@ -65,6 +96,21 @@
 	1,
 };
 
+extern struct gsm_network *bsc_gsmnet;
+
+struct gsm_network *gsmnet_from_vty(struct vty *v)
+{
+	/* In case we read from the config file, the vty->priv cannot
+	 * point to a struct telnet_connection, and thus conn->priv
+	 * will not point to the gsm_network structure */
+#if 0
+	struct telnet_connection *conn = v->priv;
+	return (struct gsm_network *) conn->priv;
+#else
+	return bsc_gsmnet;
+#endif
+}
+
 static int dummy_config_write(struct vty *v)
 {
 	return CMD_SUCCESS;
@@ -130,7 +176,7 @@
 DEFUN(show_net, show_net_cmd, "show network",
 	SHOW_STR "Display information about a GSM NETWORK\n")
 {
-	struct gsm_network *net = gsmnet;
+	struct gsm_network *net = gsmnet_from_vty(vty);
 	net_dump_vty(vty, net);
 
 	return CMD_SUCCESS;
@@ -162,8 +208,10 @@
 		"BSIC %u, TSC %u and %u TRX%s",
 		bts->nr, btstype2str(bts->type), gsm_band_name(bts->band),
 		bts->cell_identity,
-		bts->location_area_code, bts->bsic, bts->tsc, 
+		bts->location_area_code, bts->bsic, bts->tsc,
 		bts->num_trx, VTY_NEWLINE);
+	vty_out(vty, "Description: %s%s",
+		bts->description ? bts->description : "(null)", VTY_NEWLINE);
 	vty_out(vty, "MS Max power: %u dBm%s", bts->ms_max_power, VTY_NEWLINE);
 	vty_out(vty, "Minimum Rx Level for Access: %i dBm%s",
 		rxlev2dbm(bts->si_common.cell_sel_par.rxlev_acc_min),
@@ -202,7 +250,7 @@
 	SHOW_STR "Display information about a BTS\n"
 		"BTS number")
 {
-	struct gsm_network *net = gsmnet;
+	struct gsm_network *net = gsmnet_from_vty(vty);
 	int bts_nr;
 
 	if (argc != 0) {
@@ -265,6 +313,12 @@
 	int i;
 
 	vty_out(vty, "  trx %u%s", trx->nr, VTY_NEWLINE);
+	if (trx->description)
+		vty_out(vty, "   description %s%s", trx->description,
+			VTY_NEWLINE);
+	vty_out(vty, "   rf_locked %u%s",
+		trx->nm_state.administrative == NM_STATE_LOCKED ? 1 : 0,
+		VTY_NEWLINE);
 	vty_out(vty, "   arfcn %u%s", trx->arfcn, VTY_NEWLINE);
 	vty_out(vty, "   nominal power %u%s", trx->nominal_power, VTY_NEWLINE);
 	vty_out(vty, "   max_power_red %u%s", trx->max_power_red, VTY_NEWLINE);
@@ -275,13 +329,53 @@
 		config_write_ts_single(vty, &trx->ts[i]);
 }
 
+static void config_write_bts_gprs(struct vty *vty, struct gsm_bts *bts)
+{
+	unsigned int i;
+	vty_out(vty, "  gprs mode %s%s", bts_gprs_mode_name(bts->gprs.mode),
+		VTY_NEWLINE);
+	if (bts->gprs.mode == BTS_GPRS_NONE)
+		return;
+
+	vty_out(vty, "  gprs routing area %u%s", bts->gprs.rac,
+		VTY_NEWLINE);
+	vty_out(vty, "  gprs cell bvci %u%s", bts->gprs.cell.bvci,
+		VTY_NEWLINE);
+	for (i = 0; i < ARRAY_SIZE(bts->gprs.cell.timer); i++)
+		vty_out(vty, "  gprs cell timer %s %u%s",
+			get_value_string(gprs_bssgp_cfg_strs, i),
+			bts->gprs.cell.timer[i], VTY_NEWLINE);
+	vty_out(vty, "  gprs nsei %u%s", bts->gprs.nse.nsei,
+		VTY_NEWLINE);
+	for (i = 0; i < ARRAY_SIZE(bts->gprs.nse.timer); i++)
+		vty_out(vty, "  gprs ns timer %s %u%s",
+			get_value_string(gprs_ns_timer_strs, i),
+			bts->gprs.nse.timer[i], VTY_NEWLINE);
+	for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
+		struct gsm_bts_gprs_nsvc *nsvc =
+					&bts->gprs.nsvc[i];
+		struct in_addr ia;
+
+		ia.s_addr = htonl(nsvc->remote_ip);
+		vty_out(vty, "  gprs nsvc %u nsvci %u%s", i,
+			nsvc->nsvci, VTY_NEWLINE);
+		vty_out(vty, "  gprs nsvc %u local udp port %u%s", i,
+			nsvc->local_port, VTY_NEWLINE);
+		vty_out(vty, "  gprs nsvc %u remote udp port %u%s", i,
+			nsvc->remote_port, VTY_NEWLINE);
+		vty_out(vty, "  gprs nsvc %u remote ip %s%s", i,
+			inet_ntoa(ia), VTY_NEWLINE);
+	}
+}
+
 static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
 {
 	struct gsm_bts_trx *trx;
-	int i;
 
 	vty_out(vty, " bts %u%s", bts->nr, VTY_NEWLINE);
 	vty_out(vty, "  type %s%s", btstype2str(bts->type), VTY_NEWLINE);
+	if (bts->description)
+		vty_out(vty, "  description %s%s", bts->description, VTY_NEWLINE);
 	vty_out(vty, "  band %s%s", gsm_band_name(bts->band), VTY_NEWLINE);
 	vty_out(vty, "  cell_identity %u%s", bts->cell_identity, VTY_NEWLINE);
 	vty_out(vty, "  location_area_code %u%s", bts->location_area_code,
@@ -304,8 +398,17 @@
 	vty_out(vty, "  rach max transmission %u%s",
 		rach_max_trans_raw2val(bts->si_common.rach_control.max_trans),
 		VTY_NEWLINE);
+
+	if (bts->rach_b_thresh != -1)
+		vty_out(vty, "  rach nm busy threshold %u%s",
+			bts->rach_b_thresh, VTY_NEWLINE);
+	if (bts->rach_ldavg_slots != -1)
+		vty_out(vty, "  rach nm load average %u%s",
+			bts->rach_ldavg_slots, VTY_NEWLINE);
 	if (bts->si_common.rach_control.cell_bar)
 		vty_out(vty, "  cell barred 1%s", VTY_NEWLINE);
+	if ((bts->si_common.rach_control.t2 & 0x4) == 0)
+		vty_out(vty, "  rach emergency call allowed 1%s", VTY_NEWLINE);
 	if (is_ipaccess_bts(bts)) {
 		vty_out(vty, "  ip.access unit_id %u %u%s",
 			bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE);
@@ -314,30 +417,7 @@
 		config_write_e1_link(vty, &bts->oml_e1_link, "  oml ");
 		vty_out(vty, "  oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE);
 	}
-	vty_out(vty, "  gprs enabled %u%s", bts->gprs.enabled, VTY_NEWLINE);
-	if (bts->gprs.enabled) {
-		vty_out(vty, "  gprs routing area %u%s", bts->gprs.rac,
-			VTY_NEWLINE);
-		vty_out(vty, "  gprs cell bvci %u%s", bts->gprs.cell.bvci,
-			VTY_NEWLINE);
-		vty_out(vty, "  gprs nsei %u%s", bts->gprs.nse.nsei,
-			VTY_NEWLINE);
-		for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
-			struct gsm_bts_gprs_nsvc *nsvc =
-						&bts->gprs.nsvc[i];
-			struct in_addr ia;
-
-			ia.s_addr = htonl(nsvc->remote_ip);
-			vty_out(vty, "  gprs nsvc %u nsvci %u%s", i,
-				nsvc->nsvci, VTY_NEWLINE);
-			vty_out(vty, "  gprs nsvc %u local udp port %u%s", i,
-				nsvc->local_port, VTY_NEWLINE);
-			vty_out(vty, "  gprs nsvc %u remote udp port %u%s", i,
-				nsvc->remote_port, VTY_NEWLINE);
-			vty_out(vty, "  gprs nsvc %u remote ip %s%s", i,
-				inet_ntoa(ia), VTY_NEWLINE);
-		}
-	}
+	config_write_bts_gprs(vty, bts);
 
 	llist_for_each_entry(trx, &bts->trx_list, list)
 		config_write_trx_single(vty, trx);
@@ -345,6 +425,7 @@
 
 static int config_write_bts(struct vty *v)
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(v);
 	struct gsm_bts *bts;
 
 	llist_for_each_entry(bts, &gsmnet->bts_list, list)
@@ -355,6 +436,8 @@
 
 static int config_write_net(struct vty *vty)
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	vty_out(vty, "network%s", VTY_NEWLINE);
 	vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE);
 	vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE);
@@ -400,6 +483,8 @@
 {
 	vty_out(vty, "TRX %u of BTS %u is on ARFCN %u%s",
 		trx->nr, trx->bts->nr, trx->arfcn, VTY_NEWLINE);
+	vty_out(vty, "Description: %s%s",
+		trx->description ? trx->description : "(null)", VTY_NEWLINE);
 	vty_out(vty, "  RF Nominal Power: %d dBm, reduced by %u dB, "
 		"resulting BS power: %d dBm%s",
 		trx->nominal_power, trx->max_power_red,
@@ -420,9 +505,11 @@
 DEFUN(show_trx,
       show_trx_cmd,
       "show trx [bts_nr] [trx_nr]",
-	SHOW_STR "Display information about a TRX\n")
+	SHOW_STR "Display information about a TRX\n"
+	"BTS Number\n"
+	"TRX Number\n")
 {
-	struct gsm_network *net = gsmnet;
+	struct gsm_network *net = gsmnet_from_vty(vty);
 	struct gsm_bts *bts = NULL;
 	struct gsm_bts_trx *trx;
 	int bts_nr, trx_nr;
@@ -485,9 +572,10 @@
 DEFUN(show_ts,
       show_ts_cmd,
       "show timeslot [bts_nr] [trx_nr] [ts_nr]",
-	SHOW_STR "Display information about a TS\n")
+	SHOW_STR "Display information about a TS\n"
+	"BTS Number\n" "TRX Number\n" "Timeslot Number\n")
 {
-	struct gsm_network *net = gsmnet;
+	struct gsm_network *net = gsmnet_from_vty(vty);
 	struct gsm_bts *bts;
 	struct gsm_bts_trx *trx;
 	struct gsm_bts_trx_ts *ts;
@@ -539,10 +627,6 @@
 
 static void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr)
 {
-	int rc;
-	struct gsm_auth_info ainfo;
-	struct gsm_auth_tuple atuple;
-
 	vty_out(vty, "    ID: %llu, Authorized: %d%s", subscr->id,
 		subscr->authorized, VTY_NEWLINE);
 	if (subscr->name)
@@ -593,29 +677,29 @@
 	meas_rep_dump_uni_vty(vty, &mr->ul, prefix, "ul");
 }
 
-static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan)
+static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan)
 {
 	int idx;
 
 	vty_out(vty, "Lchan %u in Timeslot %u of TRX %u in BTS %u, Type %s%s",
-		lchan->nr, lchan->ts->nr, lchan->ts->trx->nr, 
+		lchan->nr, lchan->ts->nr, lchan->ts->trx->nr,
 		lchan->ts->trx->bts->nr, gsm_lchant_name(lchan->type),
 		VTY_NEWLINE);
-	vty_out(vty, "  Use Count: %u, State: %s%s", lchan->use_count,
+	vty_out(vty, "  Use Count: %u, State: %s%s", lchan->conn.use_count,
 		gsm_lchans_name(lchan->state), VTY_NEWLINE);
 	vty_out(vty, "  BS Power: %u dBm, MS Power: %u dBm%s",
 		lchan->ts->trx->nominal_power - lchan->ts->trx->max_power_red
 		- lchan->bs_power*2,
 		ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power),
 		VTY_NEWLINE);
-	if (lchan->subscr) {
+	if (lchan->conn.subscr) {
 		vty_out(vty, "  Subscriber:%s", VTY_NEWLINE);
-		subscr_dump_vty(vty, lchan->subscr);
+		subscr_dump_vty(vty, lchan->conn.subscr);
 	} else
 		vty_out(vty, "  No Subscriber%s", VTY_NEWLINE);
 	if (is_ipaccess_bts(lchan->ts->trx->bts)) {
 		struct in_addr ia;
-		ia.s_addr = lchan->abis_ip.bound_ip;
+		ia.s_addr = htonl(lchan->abis_ip.bound_ip);
 		vty_out(vty, "  Bound IP: %s Port %u RTP_TYPE2=%u CONN_ID=%u%s",
 			inet_ntoa(ia), lchan->abis_ip.bound_port,
 			lchan->abis_ip.rtp_payload2, lchan->abis_ip.conn_id,
@@ -628,39 +712,30 @@
 	meas_rep_dump_vty(vty, &lchan->meas_rep[idx], "  ");
 }
 
-#if 0
-TODO: callref and remote callref of call must be resolved to get gsm_trans object
-static void call_dump_vty(struct vty *vty, struct gsm_call *call)
+static void lchan_dump_short_vty(struct vty *vty, struct gsm_lchan *lchan)
 {
-	vty_out(vty, "Call Type %u, State %u, Transaction ID %u%s",
-		call->type, call->state, call->transaction_id, VTY_NEWLINE);
+	struct gsm_meas_rep *mr;
+	int idx;
 
-	if (call->local_lchan) {
-		vty_out(vty, "Call Local Channel:%s", VTY_NEWLINE);
-		lchan_dump_vty(vty, call->local_lchan);
-	} else
-		vty_out(vty, "Call has no Local Channel%s", VTY_NEWLINE);
+	/* we want to report the last measurement report */
+	idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
+			       lchan->meas_rep_idx, 1);
+	mr =  &lchan->meas_rep[idx];
 
-	if (call->remote_lchan) {
-		vty_out(vty, "Call Remote Channel:%s", VTY_NEWLINE);
-		lchan_dump_vty(vty, call->remote_lchan);
-	} else
-		vty_out(vty, "Call has no Remote Channel%s", VTY_NEWLINE);
-
-	if (call->called_subscr) {
-		vty_out(vty, "Called Subscriber:%s", VTY_NEWLINE);
-		subscr_dump_vty(vty, call->called_subscr);
-	} else
-		vty_out(vty, "Call has no Called Subscriber%s", VTY_NEWLINE);
+	vty_out(vty, "Lchan: %u Timeslot: %u TRX: %u BTS: %u Type: %s - L1 MS Power: %u dBm "
+		     "RXL-FULL-dl: %4d dBm RXL-FULL-ul: %4d dBm%s",
+		lchan->nr, lchan->ts->nr, lchan->ts->trx->nr,
+		lchan->ts->trx->bts->nr, gsm_lchant_name(lchan->type),
+		mr->ms_l1.pwr,
+		rxlev2dbm(mr->dl.full.rx_lev),
+		rxlev2dbm(mr->ul.full.rx_lev),
+		VTY_NEWLINE);
 }
-#endif
 
-DEFUN(show_lchan,
-      show_lchan_cmd,
-      "show lchan [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
-	SHOW_STR "Display information about a logical channel\n")
+static int lchan_summary(struct vty *vty, int argc, const char **argv,
+			 void (*dump_cb)(struct vty *, struct gsm_lchan *))
 {
-	struct gsm_network *net = gsmnet;
+	struct gsm_network *net = gsmnet_from_vty(vty);
 	struct gsm_bts *bts;
 	struct gsm_bts_trx *trx;
 	struct gsm_bts_trx_ts *ts;
@@ -703,7 +778,7 @@
 			return CMD_WARNING;
 		}
 		lchan = &ts->lchan[lchan_nr];
-		lchan_dump_vty(vty, lchan);
+		dump_cb(vty, lchan);
 		return CMD_SUCCESS;
 	}
 	for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
@@ -717,7 +792,7 @@
 					lchan = &ts->lchan[lchan_nr];
 					if (lchan->type == GSM_LCHAN_NONE)
 						continue;
-					lchan_dump_vty(vty, lchan);
+					dump_cb(vty, lchan);
 				}
 			}
 		}
@@ -726,6 +801,28 @@
 	return CMD_SUCCESS;
 }
 
+
+DEFUN(show_lchan,
+      show_lchan_cmd,
+      "show lchan [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
+	SHOW_STR "Display information about a logical channel\n"
+	"BTS Number\n" "TRX Number\n" "Timeslot Number\n"
+	"Logical Channel Number\n")
+
+{
+	return lchan_summary(vty, argc, argv, lchan_dump_full_vty);
+}
+
+DEFUN(show_lchan_summary,
+      show_lchan_summary_cmd,
+      "show lchan summary [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
+	SHOW_STR "Display information about a logical channel\n"
+	"BTS Number\n" "TRX Number\n" "Timeslot Number\n"
+	"Logical Channel Number\n")
+{
+	return lchan_summary(vty, argc, argv, lchan_dump_short_vty);
+}
+
 static void e1drv_dump_vty(struct vty *vty, struct e1inp_driver *drv)
 {
 	vty_out(vty, "E1 Input Driver %s%s", drv->name, VTY_NEWLINE);
@@ -754,7 +851,8 @@
 DEFUN(show_e1line,
       show_e1line_cmd,
       "show e1_line [line_nr]",
-	SHOW_STR "Display information about a E1 line\n")
+	SHOW_STR "Display information about a E1 line\n"
+	"E1 Line Number\n")
 {
 	struct e1inp_line *line;
 
@@ -787,7 +885,8 @@
 DEFUN(show_e1ts,
       show_e1ts_cmd,
       "show e1_timeslot [line_nr] [ts_nr]",
-	SHOW_STR "Display information about a E1 timeslot\n")
+	SHOW_STR "Display information about a E1 timeslot\n"
+	"E1 Line Number\n" "E1 Timeslot Number\n")
 {
 	struct e1inp_line *line = NULL;
 	struct e1inp_ts *ts;
@@ -851,9 +950,10 @@
 DEFUN(show_paging,
       show_paging_cmd,
       "show paging [bts_nr]",
-	SHOW_STR "Display information about paging reuqests of a BTS\n")
+	SHOW_STR "Display information about paging reuqests of a BTS\n"
+	"BTS Number\n")
 {
-	struct gsm_network *net = gsmnet;
+	struct gsm_network *net = gsmnet_from_vty(vty);
 	struct gsm_bts *bts;
 	int bts_nr;
 
@@ -878,250 +978,13 @@
 	return CMD_SUCCESS;
 }
 
-static void _vty_output(struct debug_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 debug_target *debug_target_create_vty(struct vty *vty)
-{
-	struct debug_target *target;
-
-	target = debug_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",
-      "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 = debug_target_create_vty(vty);
-	if (!conn->dbg)
-		return CMD_WARNING;
-
-	debug_add_target(conn->dbg);
-	return CMD_SUCCESS;
-}
-
-DEFUN(logging_fltr_imsi,
-      logging_fltr_imsi_cmd,
-      "logging filter imsi IMSI",
-      "Print all messages related to a IMSI\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;
-	}
-
-	debug_set_imsi_filter(conn->dbg, argv[0]);
-	return CMD_SUCCESS;
-}
-
-DEFUN(logging_fltr_all,
-      logging_fltr_all_cmd,
-      "logging filter all <0-1>",
-      "Print all messages to the console\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;
-	}
-
-	debug_set_all_filter(conn->dbg, atoi(argv[0]));
-	return CMD_SUCCESS;
-}
-
-DEFUN(logging_use_clr,
-      logging_use_clr_cmd,
-      "logging color <0-1>",
-      "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;
-	}
-
-	debug_set_use_color(conn->dbg, atoi(argv[0]));
-	return CMD_SUCCESS;
-}
-
-DEFUN(logging_prnt_timestamp,
-      logging_prnt_timestamp_cmd,
-      "logging timestamp <0-1>",
-      "Print the timestamp of each message\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;
-	}
-
-	debug_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)"
-#define VTY_DEBUG_LEVELS "(everything|debug|info|notice|error|fatal)"
-DEFUN(logging_level,
-      logging_level_cmd,
-      "logging level " VTY_DEBUG_CATEGORIES " " VTY_DEBUG_LEVELS,
-      "Set the log level for a specified category\n")
-{
-	struct telnet_connection *conn;
-	int category = debug_parse_category(argv[0]);
-	int level = debug_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 (category < 0) {
-		vty_out(vty, "Invalid category `%s'%s", argv[0], VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	if (level < 0) {
-		vty_out(vty, "Invalid level `%s'%s", argv[1], 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 debug mask MASK",
-      "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;
-	}
-
-	debug_parse_category_mask(conn->dbg, argv[0]);
-	return CMD_SUCCESS;
-}
-
-DEFUN(logging_set_log_level,
-      logging_set_log_level_cmd,
-      "logging set log level <0-8>",
-      "Set the global log level. The value 0 implies no filtering.\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;
-	}
-
-	debug_set_log_level(conn->dbg, atoi(argv[0]));
-	return CMD_SUCCESS;
-}
-
-DEFUN(diable_logging,
-      disable_logging_cmd,
-      "logging disable",
-      "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;
-	}
-
-	debug_del_target(conn->dbg);
-	talloc_free(conn->dbg);
-	conn->dbg = NULL;
-	return CMD_SUCCESS;
-}
-
-DEFUN(show_stats,
-      show_stats_cmd,
-      "show statistics",
-	SHOW_STR "Display network statistics\n")
-{
-	struct gsm_network *net = gsmnet;
-
-	vty_out(vty, "Channel Requests        : %lu total, %lu no channel%s",
-		counter_get(net->stats.chreq.total),
-		counter_get(net->stats.chreq.no_channel), VTY_NEWLINE);
-	vty_out(vty, "Location Update         : %lu attach, %lu normal, %lu periodic%s",
-		counter_get(net->stats.loc_upd_type.attach),
-		counter_get(net->stats.loc_upd_type.normal),
-		counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE);
-	vty_out(vty, "IMSI Detach Indications : %lu%s",
-		counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE);
-	vty_out(vty, "Location Update Response: %lu accept, %lu reject%s",
-		counter_get(net->stats.loc_upd_resp.accept),
-		counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE);
-	vty_out(vty, "Paging                  : %lu attempted, %lu complete, %lu expired%s",
-		counter_get(net->stats.paging.attempted),
-		counter_get(net->stats.paging.completed),
-		counter_get(net->stats.paging.expired), VTY_NEWLINE);
-	vty_out(vty, "Handover                : %lu attempted, %lu no_channel, %lu timeout, "
-		"%lu completed, %lu failed%s",
-		counter_get(net->stats.handover.attempted),
-		counter_get(net->stats.handover.no_channel),
-		counter_get(net->stats.handover.timeout),
-		counter_get(net->stats.handover.completed),
-		counter_get(net->stats.handover.failed), VTY_NEWLINE);
-	vty_out(vty, "SMS MO                  : %lu submitted, %lu no receiver%s",
-		counter_get(net->stats.sms.submitted),
-		counter_get(net->stats.sms.no_receiver), VTY_NEWLINE);
-	vty_out(vty, "SMS MT                  : %lu delivered, %lu no memory, %lu other error%s",
-		counter_get(net->stats.sms.delivered),
-		counter_get(net->stats.sms.rp_err_mem),
-		counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE);
-	return CMD_SUCCESS;
-}
+#define NETWORK_STR "Configure the GSM network\n"
 
 DEFUN(cfg_net,
       cfg_net_cmd,
-      "network",
-      "Configure the GSM network")
+      "network", NETWORK_STR)
 {
-	vty->index = gsmnet;
+	vty->index = gsmnet_from_vty(vty);
 	vty->node = GSMNET_NODE;
 
 	return CMD_SUCCESS;
@@ -1133,6 +996,8 @@
       "network country code <1-999>",
       "Set the GSM network country code")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	gsmnet->country_code = atoi(argv[0]);
 
 	return CMD_SUCCESS;
@@ -1143,6 +1008,8 @@
       "mobile network code <1-999>",
       "Set the GSM mobile network code")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	gsmnet->network_code = atoi(argv[0]);
 
 	return CMD_SUCCESS;
@@ -1153,6 +1020,8 @@
       "short name NAME",
       "Set the short GSM network name")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	if (gsmnet->name_short)
 		talloc_free(gsmnet->name_short);
 
@@ -1166,6 +1035,8 @@
       "long name NAME",
       "Set the long GSM network name")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	if (gsmnet->name_long)
 		talloc_free(gsmnet->name_long);
 
@@ -1177,9 +1048,14 @@
 DEFUN(cfg_net_auth_policy,
       cfg_net_auth_policy_cmd,
       "auth policy (closed|accept-all|token)",
-      "Set the GSM network authentication policy\n")
+	"Authentication (not cryptographic)\n"
+	"Set the GSM network authentication policy\n"
+	"Require the MS to be activated in HLR\n"
+	"Accept all MS, whether in HLR or not\n"
+	"Use SMS-token based authentication\n")
 {
 	enum gsm_auth_policy policy = gsm_auth_policy_parse(argv[0]);
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 
 	gsmnet->auth_policy = policy;
 
@@ -1191,6 +1067,8 @@
       "location updating reject cause <2-111>",
       "Set the reject cause of location updating reject\n")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	gsmnet->reject_cause = atoi(argv[0]);
 
 	return CMD_SUCCESS;
@@ -1199,8 +1077,12 @@
 DEFUN(cfg_net_encryption,
       cfg_net_encryption_cmd,
       "encryption a5 (0|1|2)",
-      "Enable or disable encryption (A5) for this network\n")
+	"Encryption options\n"
+	"A5 encryption\n" "A5/0: No encryption\n"
+	"A5/1: Encryption\n" "A5/2: Export-grade Encryption\n")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	gsmnet->a5_encryption= atoi(argv[0]);
 
 	return CMD_SUCCESS;
@@ -1209,16 +1091,26 @@
 DEFUN(cfg_net_neci,
       cfg_net_neci_cmd,
       "neci (0|1)",
-      "Set if NECI of cell selection is to be set")
+	"New Establish Cause Indication\n"
+	"Don't set the NECI bit\n" "Set the NECI bit\n")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	gsmnet->neci = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
 
 DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd,
       "rrlp mode (none|ms-based|ms-preferred|ass-preferred)",
-	"Set the Radio Resource Location Protocol Mode")
+	"Radio Resource Location Protocol\n"
+	"Set the Radio Resource Location Protocol Mode\n"
+	"Don't send RRLP request\n"
+	"Request MS-based location\n"
+	"Request any location, prefer MS-based\n"
+	"Request any location, prefer MS-assisted\n")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	gsmnet->rrlp.mode = rrlp_mode_parse(argv[0]);
 
 	return CMD_SUCCESS;
@@ -1228,16 +1120,23 @@
       "mm info (0|1)",
 	"Whether to send MM INFO after LOC UPD ACCEPT")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	gsmnet->send_mm_info = atoi(argv[0]);
 
 	return CMD_SUCCESS;
 }
 
+#define HANDOVER_STR	"Handover Options\n"
+
 DEFUN(cfg_net_handover, cfg_net_handover_cmd,
       "handover (0|1)",
-	"Whether or not to use in-call handover")
+	HANDOVER_STR
+	"Don't perform in-call handover\n"
+	"Perform in-call handover\n")
 {
 	int enable = atoi(argv[0]);
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 
 	if (enable && ipacc_rtp_direct) {
 		vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode "
@@ -1250,50 +1149,67 @@
 	return CMD_SUCCESS;
 }
 
+#define HO_WIN_STR HANDOVER_STR "Measurement Window\n"
+#define HO_WIN_RXLEV_STR HO_WIN_STR "Received Level Averaging\n"
+#define HO_WIN_RXQUAL_STR HO_WIN_STR "Received Quality Averaging\n"
+#define HO_PBUDGET_STR HANDOVER_STR "Power Budget\n"
+
 DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd,
       "handover window rxlev averaging <1-10>",
+	HO_WIN_RXLEV_STR
 	"How many RxLev measurements are used for averaging")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	gsmnet->handover.win_rxlev_avg = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
 
 DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd,
       "handover window rxqual averaging <1-10>",
+	HO_WIN_RXQUAL_STR
 	"How many RxQual measurements are used for averaging")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	gsmnet->handover.win_rxqual_avg = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
 
 DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd,
       "handover window rxlev neighbor averaging <1-10>",
+	HO_WIN_RXLEV_STR
 	"How many RxQual measurements are used for averaging")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
 
 DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd,
       "handover power budget interval <1-99>",
+	HO_PBUDGET_STR
 	"How often to check if we have a better cell (SACCH frames)")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	gsmnet->handover.pwr_interval = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
 
 DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd,
       "handover power budget hysteresis <0-999>",
+	HO_PBUDGET_STR
 	"How many dB does a neighbor to be stronger to become a HO candidate")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	gsmnet->handover.pwr_hysteresis = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
 
 DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd,
       "handover maximum distance <0-9999>",
+	HANDOVER_STR
 	"How big is the maximum timing advance before HO is forced")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	gsmnet->handover.max_distance = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
@@ -1302,8 +1218,10 @@
     DEFUN(cfg_net_T##number,					\
       cfg_net_T##number##_cmd,					\
       "timer t" #number  " <0-65535>",				\
+      "Configure GSM Timers\n"					\
       doc)							\
 {								\
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);	\
 	int value = atoi(argv[0]);				\
 								\
 	if (value < 0 || value > 65535) {			\
@@ -1321,7 +1239,7 @@
 DECLARE_TIMER(3105, "Currently not used.")
 DECLARE_TIMER(3107, "Currently not used.")
 DECLARE_TIMER(3109, "Currently not used.")
-DECLARE_TIMER(3111, "Currently not used.")
+DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.")
 DECLARE_TIMER(3113, "Set the time to try paging a subscriber.")
 DECLARE_TIMER(3115, "Currently not used.")
 DECLARE_TIMER(3117, "Currently not used.")
@@ -1333,8 +1251,10 @@
 DEFUN(cfg_bts,
       cfg_bts_cmd,
       "bts BTS_NR",
-      "Select a BTS to configure\n")
+      "Select a BTS to configure\n"
+	"BTS Number\n")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	int bts_nr = atoi(argv[0]);
 	struct gsm_bts *bts;
 
@@ -1346,7 +1266,7 @@
 		/* allocate a new one */
 		bts = gsm_bts_alloc(gsmnet, GSM_BTS_TYPE_UNKNOWN,
 				    HARDCODED_TSC, HARDCODED_BSIC);
-	} else 
+	} else
 		bts = gsm_bts_num(gsmnet, bts_nr);
 
 	if (!bts) {
@@ -1356,6 +1276,7 @@
 	}
 
 	vty->index = bts;
+	vty->index_sub = &bts->description;
 	vty->node = BTS_NODE;
 
 	return CMD_SUCCESS;
@@ -1496,9 +1417,13 @@
 	return CMD_SUCCESS;
 }
 
+#define OML_STR	"Organization & Maintenance Link\n"
+#define IPA_STR "ip.access Specific Options\n"
+
 DEFUN(cfg_bts_stream_id,
       cfg_bts_stream_id_cmd,
       "oml ip.access stream_id <0-255>",
+	OML_STR IPA_STR
       "Set the ip.access Stream ID of the OML link of this BTS\n")
 {
 	struct gsm_bts *bts = vty->index;
@@ -1514,10 +1439,12 @@
 	return CMD_SUCCESS;
 }
 
+#define OML_E1_STR OML_STR "E1 Line\n"
 
 DEFUN(cfg_bts_oml_e1,
       cfg_bts_oml_e1_cmd,
       "oml e1 line E1_LINE timeslot <1-31> sub-slot (0|1|2|3|full)",
+	OML_E1_STR
       "E1 interface to be used for OML\n")
 {
 	struct gsm_bts *bts = vty->index;
@@ -1531,6 +1458,7 @@
 DEFUN(cfg_bts_oml_e1_tei,
       cfg_bts_oml_e1_tei_cmd,
       "oml e1 tei <0-63>",
+	OML_E1_STR
       "Set the TEI to be used for OML")
 {
 	struct gsm_bts *bts = vty->index;
@@ -1542,7 +1470,9 @@
 
 DEFUN(cfg_bts_challoc, cfg_bts_challoc_cmd,
       "channel allocator (ascending|descending)",
-      "Should the channel allocator allocate in reverse TRX order?")
+	"Channnel Allocator\n" "Channel Allocator\n"
+	"Allocate Timeslots and Transceivers in ascending order\n"
+	"Allocate Timeslots and Transceivers in descending order\n")
 {
 	struct gsm_bts *bts = vty->index;
 
@@ -1554,9 +1484,12 @@
 	return CMD_SUCCESS;
 }
 
+#define RACH_STR "Random Access Control Channel\n"
+
 DEFUN(cfg_bts_rach_tx_integer,
       cfg_bts_rach_tx_integer_cmd,
       "rach tx integer <0-15>",
+	RACH_STR
       "Set the raw tx integer value in RACH Control parameters IE")
 {
 	struct gsm_bts *bts = vty->index;
@@ -1567,6 +1500,7 @@
 DEFUN(cfg_bts_rach_max_trans,
       cfg_bts_rach_max_trans_cmd,
       "rach max transmission (1|2|4|7)",
+	RACH_STR
       "Set the maximum number of RACH burst transmissions")
 {
 	struct gsm_bts *bts = vty->index;
@@ -1574,6 +1508,30 @@
 	return CMD_SUCCESS;
 }
 
+#define NM_STR "Network Management\n"
+
+DEFUN(cfg_bts_rach_nm_b_thresh,
+      cfg_bts_rach_nm_b_thresh_cmd,
+      "rach nm busy threshold <0-255>",
+	RACH_STR NM_STR
+      "Set the NM Busy Threshold in dB")
+{
+	struct gsm_bts *bts = vty->index;
+	bts->rach_b_thresh = atoi(argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_rach_nm_ldavg,
+      cfg_bts_rach_nm_ldavg_cmd,
+      "rach nm load average <0-65535>",
+	RACH_STR NM_STR
+      "Set the NM Loadaverage Slots value")
+{
+	struct gsm_bts *bts = vty->index;
+	bts->rach_ldavg_slots = atoi(argv[0]);
+	return CMD_SUCCESS;
+}
+
 DEFUN(cfg_bts_cell_barred, cfg_bts_cell_barred_cmd,
       "cell barred (0|1)",
       "Should this cell be barred from access?")
@@ -1585,6 +1543,20 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_bts_rach_ec_allowed, cfg_bts_rach_ec_allowed_cmd,
+      "rach emergency call allowed (0|1)",
+      "Should this cell allow emergency calls?")
+{
+	struct gsm_bts *bts = vty->index;
+
+	if (atoi(argv[0]) == 0)
+		bts->si_common.rach_control.t2 |= 0x4;
+	else
+		bts->si_common.rach_control.t2 &= ~0x4;
+
+	return CMD_SUCCESS;
+}
+
 DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd,
       "ms max power <0-40>",
       "Maximum transmit power of the MS")
@@ -1629,13 +1601,17 @@
 	return CMD_SUCCESS;
 }
 
+#define GPRS_TEXT	"GPRS Packet Network\n"
+
 DEFUN(cfg_bts_prs_bvci, cfg_bts_gprs_bvci_cmd,
-	"gprs cell bvci <0-65535>",
+	"gprs cell bvci <2-65535>",
+	GPRS_TEXT
+	"GPRS Cell Settings\n"
 	"GPRS BSSGP VC Identifier")
 {
 	struct gsm_bts *bts = vty->index;
 
-	if (!bts->gprs.enabled) {
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
 		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
 		return CMD_WARNING;
 	}
@@ -1647,11 +1623,12 @@
 
 DEFUN(cfg_bts_gprs_nsei, cfg_bts_gprs_nsei_cmd,
 	"gprs nsei <0-65535>",
+	GPRS_TEXT
 	"GPRS NS Entity Identifier")
 {
 	struct gsm_bts *bts = vty->index;
 
-	if (!bts->gprs.enabled) {
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
 		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
 		return CMD_WARNING;
 	}
@@ -1661,15 +1638,19 @@
 	return CMD_SUCCESS;
 }
 
+#define NSVC_TEXT "Network Service Virtual Connection (NS-VC)\n" \
+		"NSVC Logical Number\n"
 
 DEFUN(cfg_bts_gprs_nsvci, cfg_bts_gprs_nsvci_cmd,
 	"gprs nsvc <0-1> nsvci <0-65535>",
+	GPRS_TEXT NSVC_TEXT
+	"NS Virtual Connection Identifier\n"
 	"GPRS NS VC Identifier")
 {
 	struct gsm_bts *bts = vty->index;
 	int idx = atoi(argv[0]);
 
-	if (!bts->gprs.enabled) {
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
 		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
 		return CMD_WARNING;
 	}
@@ -1681,12 +1662,13 @@
 
 DEFUN(cfg_bts_gprs_nsvc_lport, cfg_bts_gprs_nsvc_lport_cmd,
 	"gprs nsvc <0-1> local udp port <0-65535>",
+	GPRS_TEXT NSVC_TEXT
 	"GPRS NS Local UDP Port")
 {
 	struct gsm_bts *bts = vty->index;
 	int idx = atoi(argv[0]);
 
-	if (!bts->gprs.enabled) {
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
 		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
 		return CMD_WARNING;
 	}
@@ -1698,12 +1680,13 @@
 
 DEFUN(cfg_bts_gprs_nsvc_rport, cfg_bts_gprs_nsvc_rport_cmd,
 	"gprs nsvc <0-1> remote udp port <0-65535>",
+	GPRS_TEXT NSVC_TEXT
 	"GPRS NS Remote UDP Port")
 {
 	struct gsm_bts *bts = vty->index;
 	int idx = atoi(argv[0]);
 
-	if (!bts->gprs.enabled) {
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
 		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
 		return CMD_WARNING;
 	}
@@ -1715,13 +1698,14 @@
 
 DEFUN(cfg_bts_gprs_nsvc_rip, cfg_bts_gprs_nsvc_rip_cmd,
 	"gprs nsvc <0-1> remote ip A.B.C.D",
+	GPRS_TEXT NSVC_TEXT
 	"GPRS NS Remote IP Address")
 {
 	struct gsm_bts *bts = vty->index;
 	int idx = atoi(argv[0]);
 	struct in_addr ia;
 
-	if (!bts->gprs.enabled) {
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
 		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
 		return CMD_WARNING;
 	}
@@ -1732,13 +1716,74 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_bts_gprs_ns_timer, cfg_bts_gprs_ns_timer_cmd,
+	"gprs ns timer " NS_TIMERS " <0-255>",
+	GPRS_TEXT "Network Service\n"
+	"Network Service Timer\n"
+	NS_TIMERS_HELP "Timer Value\n")
+{
+	struct gsm_bts *bts = vty->index;
+	int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
+	int val = atoi(argv[1]);
+
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
+		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (idx < 0 || idx >= ARRAY_SIZE(bts->gprs.nse.timer))
+		return CMD_WARNING;
+
+	bts->gprs.nse.timer[idx] = val;
+
+	return CMD_SUCCESS;
+}
+
+#define BSSGP_TIMERS "(blocking-timer|blocking-retries|unblocking-retries|reset-timer|reset-retries|suspend-timer|suspend-retries|resume-timer|resume-retries|capability-update-timer|capability-update-retries)"
+#define BSSGP_TIMERS_HELP	\
+	"Tbvc-block timeout\n"			\
+	"Tbvc-block retries\n"			\
+	"Tbvc-unblock retries\n"		\
+	"Tbvcc-reset timeout\n"			\
+	"Tbvc-reset retries\n"			\
+	"Tbvc-suspend timeout\n"		\
+	"Tbvc-suspend retries\n"		\
+	"Tbvc-resume timeout\n"			\
+	"Tbvc-resume retries\n"			\
+	"Tbvc-capa-update timeout\n"		\
+	"Tbvc-capa-update retries\n"
+
+DEFUN(cfg_bts_gprs_cell_timer, cfg_bts_gprs_cell_timer_cmd,
+	"gprs cell timer " BSSGP_TIMERS " <0-255>",
+	GPRS_TEXT "Cell / BSSGP\n"
+	"Cell/BSSGP Timer\n"
+	BSSGP_TIMERS_HELP "Timer Value\n")
+{
+	struct gsm_bts *bts = vty->index;
+	int idx = get_string_value(gprs_bssgp_cfg_strs, argv[0]);
+	int val = atoi(argv[1]);
+
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
+		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (idx < 0 || idx >= ARRAY_SIZE(bts->gprs.cell.timer))
+		return CMD_WARNING;
+
+	bts->gprs.cell.timer[idx] = val;
+
+	return CMD_SUCCESS;
+}
+
 DEFUN(cfg_bts_gprs_rac, cfg_bts_gprs_rac_cmd,
 	"gprs routing area <0-255>",
+	GPRS_TEXT
 	"GPRS Routing Area Code")
 {
 	struct gsm_bts *bts = vty->index;
 
-	if (!bts->gprs.enabled) {
+	if (bts->gprs.mode == BTS_GPRS_NONE) {
 		vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
 		return CMD_WARNING;
 	}
@@ -1748,22 +1793,28 @@
 	return CMD_SUCCESS;
 }
 
-DEFUN(cfg_bts_gprs_enabled, cfg_bts_gprs_enabled_cmd,
-	"gprs enabled <0-1>",
-	"GPRS Enabled on this BTS")
+DEFUN(cfg_bts_gprs_mode, cfg_bts_gprs_mode_cmd,
+	"gprs mode (none|gprs|egprs)",
+	GPRS_TEXT
+	"GPRS Mode for this BTS\n"
+	"GPRS Disabled on this BTS\n"
+	"GPRS Enabled on this BTS\n"
+	"EGPRS (EDGE) Enabled on this BTS\n")
 {
 	struct gsm_bts *bts = vty->index;
 
-	bts->gprs.enabled = atoi(argv[0]);
+	bts->gprs.mode = bts_gprs_mode_parse(argv[0]);
 
 	return CMD_SUCCESS;
 }
 
+#define TRX_TEXT "Radio Transceiver\n"
 
 /* per TRX configuration */
 DEFUN(cfg_trx,
       cfg_trx_cmd,
       "trx TRX_NR",
+	TRX_TEXT
       "Select a TRX to configure")
 {
 	int trx_nr = atoi(argv[0]);
@@ -1777,13 +1828,14 @@
 	} else if (trx_nr == bts->num_trx) {
 		/* we need to allocate a new one */
 		trx = gsm_bts_trx_alloc(bts);
-	} else 
+	} else
 		trx = gsm_bts_trx_num(bts, trx_nr);
-	
+
 	if (!trx)
 		return CMD_WARNING;
 
 	vty->index = trx;
+	vty->index_sub = &trx->description;
 	vty->node = TRX_NODE;
 
 	return CMD_SUCCESS;
@@ -1791,7 +1843,7 @@
 
 DEFUN(cfg_trx_arfcn,
       cfg_trx_arfcn_cmd,
-      "arfcn <1-1024>",
+      "arfcn <0-1024>",
       "Set the ARFCN for this TRX\n")
 {
 	int arfcn = atoi(argv[0]);
@@ -1937,39 +1989,67 @@
 	return CMD_SUCCESS;
 }
 
-int bsc_vty_init(struct gsm_network *net)
+void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net)
 {
-	gsmnet = net;
+	vty_out(vty, "Channel Requests        : %lu total, %lu no channel%s",
+		counter_get(net->stats.chreq.total),
+		counter_get(net->stats.chreq.no_channel), VTY_NEWLINE);
+	vty_out(vty, "Channel Failures        : %lu rf_failures, %lu rll failures%s",
+		counter_get(net->stats.chan.rf_fail),
+		counter_get(net->stats.chan.rll_err), VTY_NEWLINE);
+	vty_out(vty, "Paging                  : %lu attempted, %lu complete, %lu expired%s",
+		counter_get(net->stats.paging.attempted),
+		counter_get(net->stats.paging.completed),
+		counter_get(net->stats.paging.expired), VTY_NEWLINE);
+	vty_out(vty, "BTS failures            : %lu OML, %lu RSL%s",
+		counter_get(net->stats.bts.oml_fail),
+		counter_get(net->stats.bts.rsl_fail), VTY_NEWLINE);
+}
 
-	cmd_init(1);
-	vty_init();
+DEFUN(logging_fltr_imsi,
+      logging_fltr_imsi_cmd,
+      "logging filter imsi IMSI",
+	LOGGING_STR FILTER_STR
+      "Filter log messages by IMSI\n" "IMSI to be used as filter\n")
+{
+	struct telnet_connection *conn;
 
-	install_element(VIEW_NODE, &show_net_cmd);
-	install_element(VIEW_NODE, &show_bts_cmd);
-	install_element(VIEW_NODE, &show_trx_cmd);
-	install_element(VIEW_NODE, &show_ts_cmd);
-	install_element(VIEW_NODE, &show_lchan_cmd);
+	conn = (struct telnet_connection *) vty->priv;
+	if (!conn->dbg) {
+		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
 
-	install_element(VIEW_NODE, &show_e1drv_cmd);
-	install_element(VIEW_NODE, &show_e1line_cmd);
-	install_element(VIEW_NODE, &show_e1ts_cmd);
+	log_set_imsi_filter(conn->dbg, argv[0]);
+	return CMD_SUCCESS;
+}
 
-	install_element(VIEW_NODE, &show_paging_cmd);
-	install_element(VIEW_NODE, &show_stats_cmd);
+extern int bsc_vty_init_extra(void);
+extern const char *openbsc_copyright;
 
-	install_element(VIEW_NODE, &enable_logging_cmd);
-	install_element(VIEW_NODE, &disable_logging_cmd);
-	install_element(VIEW_NODE, &logging_fltr_imsi_cmd);
-	install_element(VIEW_NODE, &logging_fltr_all_cmd);
-	install_element(VIEW_NODE, &logging_use_clr_cmd);
-	install_element(VIEW_NODE, &logging_prnt_timestamp_cmd);
-	install_element(VIEW_NODE, &logging_set_category_mask_cmd);
-	install_element(VIEW_NODE, &logging_level_cmd);
-	install_element(VIEW_NODE, &logging_set_log_level_cmd);
+int bsc_vty_init(void)
+{
+	install_element_ve(&show_net_cmd);
+	install_element_ve(&show_bts_cmd);
+	install_element_ve(&show_trx_cmd);
+	install_element_ve(&show_ts_cmd);
+	install_element_ve(&show_lchan_cmd);
+	install_element_ve(&show_lchan_summary_cmd);
+	install_element_ve(&logging_fltr_imsi_cmd);
+
+	install_element_ve(&show_e1drv_cmd);
+	install_element_ve(&show_e1line_cmd);
+	install_element_ve(&show_e1ts_cmd);
+
+	install_element_ve(&show_paging_cmd);
+
+	logging_vty_add_cmds();
 
 	install_element(CONFIG_NODE, &cfg_net_cmd);
 	install_node(&net_node, config_write_net);
 	install_default(GSMNET_NODE);
+	install_element(GSMNET_NODE, &ournode_exit_cmd);
+	install_element(GSMNET_NODE, &ournode_end_cmd);
 	install_element(GSMNET_NODE, &cfg_net_ncc_cmd);
 	install_element(GSMNET_NODE, &cfg_net_mnc_cmd);
 	install_element(GSMNET_NODE, &cfg_net_name_short_cmd);
@@ -2002,7 +2082,11 @@
 	install_element(GSMNET_NODE, &cfg_bts_cmd);
 	install_node(&bts_node, config_write_bts);
 	install_default(BTS_NODE);
+	install_element(BTS_NODE, &ournode_exit_cmd);
+	install_element(BTS_NODE, &ournode_end_cmd);
 	install_element(BTS_NODE, &cfg_bts_type_cmd);
+	install_element(BTS_NODE, &cfg_description_cmd);
+	install_element(BTS_NODE, &cfg_no_description_cmd);
 	install_element(BTS_NODE, &cfg_bts_band_cmd);
 	install_element(BTS_NODE, &cfg_bts_ci_cmd);
 	install_element(BTS_NODE, &cfg_bts_lac_cmd);
@@ -2015,14 +2099,19 @@
 	install_element(BTS_NODE, &cfg_bts_challoc_cmd);
 	install_element(BTS_NODE, &cfg_bts_rach_tx_integer_cmd);
 	install_element(BTS_NODE, &cfg_bts_rach_max_trans_cmd);
+	install_element(BTS_NODE, &cfg_bts_rach_nm_b_thresh_cmd);
+	install_element(BTS_NODE, &cfg_bts_rach_nm_ldavg_cmd);
 	install_element(BTS_NODE, &cfg_bts_cell_barred_cmd);
+	install_element(BTS_NODE, &cfg_bts_rach_ec_allowed_cmd);
 	install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd);
 	install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd);
 	install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd);
 	install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd);
-	install_element(BTS_NODE, &cfg_bts_gprs_enabled_cmd);
+	install_element(BTS_NODE, &cfg_bts_gprs_mode_cmd);
+	install_element(BTS_NODE, &cfg_bts_gprs_ns_timer_cmd);
 	install_element(BTS_NODE, &cfg_bts_gprs_rac_cmd);
 	install_element(BTS_NODE, &cfg_bts_gprs_bvci_cmd);
+	install_element(BTS_NODE, &cfg_bts_gprs_cell_timer_cmd);
 	install_element(BTS_NODE, &cfg_bts_gprs_nsei_cmd);
 	install_element(BTS_NODE, &cfg_bts_gprs_nsvci_cmd);
 	install_element(BTS_NODE, &cfg_bts_gprs_nsvc_lport_cmd);
@@ -2032,7 +2121,11 @@
 	install_element(BTS_NODE, &cfg_trx_cmd);
 	install_node(&trx_node, dummy_config_write);
 	install_default(TRX_NODE);
+	install_element(TRX_NODE, &ournode_exit_cmd);
+	install_element(TRX_NODE, &ournode_end_cmd);
 	install_element(TRX_NODE, &cfg_trx_arfcn_cmd);
+	install_element(TRX_NODE, &cfg_description_cmd);
+	install_element(TRX_NODE, &cfg_no_description_cmd);
 	install_element(TRX_NODE, &cfg_trx_nominal_power_cmd);
 	install_element(TRX_NODE, &cfg_trx_max_power_red_cmd);
 	install_element(TRX_NODE, &cfg_trx_rsl_e1_cmd);
@@ -2042,10 +2135,14 @@
 	install_element(TRX_NODE, &cfg_ts_cmd);
 	install_node(&ts_node, dummy_config_write);
 	install_default(TS_NODE);
+	install_element(TS_NODE, &ournode_exit_cmd);
+	install_element(TS_NODE, &ournode_end_cmd);
 	install_element(TS_NODE, &cfg_ts_pchan_cmd);
 	install_element(TS_NODE, &cfg_ts_e1_subslot_cmd);
 
-	bsc_vty_init_extra(net);
+	abis_nm_vty_init();
+
+	bsc_vty_init_extra();
 
 	return 0;
 }
diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c
index 2e88524..9df449f 100644
--- a/openbsc/src/chan_alloc.c
+++ b/openbsc/src/chan_alloc.c
@@ -152,6 +152,7 @@
 	[GSM_PCHAN_TCH_H] = 2,
 	[GSM_PCHAN_SDCCH8_SACCH8C] = 8,
 	/* FIXME: what about dynamic TCH_F_TCH_H ? */
+	[GSM_PCHAN_TCH_F_PDCH] = 1,
 };
 
 static struct gsm_lchan *
@@ -167,7 +168,14 @@
 		ts = &trx->ts[j];
 		if (!ts_is_usable(ts))
 			continue;
-		if (ts->pchan != pchan)
+		/* ip.access dynamic TCH/F + PDCH combination */
+		if (ts->pchan == GSM_PCHAN_TCH_F_PDCH &&
+		    pchan == GSM_PCHAN_TCH_F) {
+			/* we can only consider such a dynamic channel
+			 * if the PDCH is currently inactive */
+			if (ts->flags & TS_F_PDCH_MODE)
+				continue;
+		} else if (ts->pchan != pchan)
 			continue;
 		/* check if all sub-slots are allocated yet */
 		for (ss = 0; ss < subslots_per_pchan[pchan]; ss++) {
@@ -177,6 +185,7 @@
 				return lc;
 		}
 	}
+
 	return NULL;
 }
 
@@ -252,7 +261,6 @@
 
 	if (lchan) {
 		lchan->type = type;
-		lchan->use_count = 0;
 
 		/* clear sapis */
 		memset(lchan->sapis, 0, ARRAY_SIZE(lchan->sapis));
@@ -260,10 +268,21 @@
 		/* clear multi rate config */
 		memset(&lchan->mr_conf, 0, sizeof(lchan->mr_conf));
 
+		/* clear per MSC/BSC data */
+		memset(&lchan->conn, 0, sizeof(lchan->conn));
+
 		/* Configure the time and start it so it will be closed */
-		lchan->release_timer.cb = auto_release_channel;
-		lchan->release_timer.data = lchan;
-		bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT);
+		lchan->conn.lchan = lchan;
+		lchan->conn.bts = lchan->ts->trx->bts;
+		lchan->conn.release_timer.cb = auto_release_channel;
+		lchan->conn.release_timer.data = lchan;
+		bsc_schedule_timer(&lchan->conn.release_timer, LCHAN_RELEASE_TIMEOUT);
+
+	} else {
+		struct challoc_signal_data sig;
+		sig.bts = bts;
+		sig.type = type;
+		dispatch_signal(SS_CHALLOC, S_CHALLOC_ALLOC_FAIL, &sig);
 	}
 
 	return lchan;
@@ -272,22 +291,24 @@
 /* Free a logical channel */
 void lchan_free(struct gsm_lchan *lchan)
 {
+	struct challoc_signal_data sig;
 	int i;
 
+	sig.type = lchan->type;
 	lchan->type = GSM_LCHAN_NONE;
-	if (lchan->subscr) {
-		subscr_put(lchan->subscr);
-		lchan->subscr = NULL;
+	if (lchan->conn.subscr) {
+		subscr_put(lchan->conn.subscr);
+		lchan->conn.subscr = NULL;
 	}
 
 	/* We might kill an active channel... */
-	if (lchan->use_count != 0) {
+	if (lchan->conn.use_count != 0) {
 		dispatch_signal(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, lchan);
-		lchan->use_count = 0;
+		lchan->conn.use_count = 0;
 	}
 
 	/* stop the timer */
-	bsc_del_timer(&lchan->release_timer);
+	bsc_del_timer(&lchan->conn.release_timer);
 	bsc_del_timer(&lchan->T3101);
 
 	/* clear cached measuement reports */
@@ -299,31 +320,52 @@
 	for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++)
 		lchan->neigh_meas[i].arfcn = 0;
 
-	lchan->silent_call = 0;
+	lchan->conn.silent_call = 0;
+
+	sig.lchan = lchan;
+	sig.bts = lchan->ts->trx->bts;
+	dispatch_signal(SS_CHALLOC, S_CHALLOC_FREED, &sig);
 
 	/* FIXME: ts_free() the timeslot, if we're the last logical
 	 * channel using it */
 }
 
+/*
+ * There was an error with the TRX and we need to forget
+ * any state so that a lchan can be allocated again after
+ * the trx is fully usable.
+ */
+void lchan_reset(struct gsm_lchan *lchan)
+{
+	bsc_del_timer(&lchan->T3101);
+	bsc_del_timer(&lchan->T3111);
+	bsc_del_timer(&lchan->error_timer);
+
+	lchan->type = GSM_LCHAN_NONE;
+	lchan->state = LCHAN_S_NONE;
+}
+
+
 /* Consider releasing the channel now */
 int lchan_auto_release(struct gsm_lchan *lchan)
 {
-	if (lchan->use_count > 0) {
+	if (lchan->conn.use_count > 0) {
 		return 0;
 	}
 
 	/* Assume we have GSM04.08 running and send a release */
-	if (lchan->subscr) {
+	if (lchan->conn.subscr) {
 		gsm48_send_rr_release(lchan);
 	}
 
 	/* spoofed? message */
-	if (lchan->use_count < 0)
+	if (lchan->conn.use_count < 0)
 		LOGP(DRLL, LOGL_ERROR, "Channel count is negative: %d\n",
-			lchan->use_count);
+			lchan->conn.use_count);
 
 	DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan));
-	rsl_release_request(lchan, 0);
+	rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
+	rsl_release_request(lchan, 0, 0);
 	return 1;
 }
 
@@ -333,19 +375,19 @@
 	struct gsm_lchan *lchan = _lchan;
 
 	if (!lchan_auto_release(lchan))
-		bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT);
+		bsc_schedule_timer(&lchan->conn.release_timer, LCHAN_RELEASE_TIMEOUT);
 }
 
 struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) {
 	struct gsm_bts_trx *trx;
-	int ts_no, lchan_no; 
+	int ts_no, lchan_no;
 
 	llist_for_each_entry(trx, &bts->trx_list, list) {
 		for (ts_no = 0; ts_no < 8; ++ts_no) {
 			for (lchan_no = 0; lchan_no < TS_MAX_LCHAN; ++lchan_no) {
 				struct gsm_lchan *lchan =
 					&trx->ts[ts_no].lchan[lchan_no];
-				if (subscr == lchan->subscr)
+				if (subscr == lchan->conn.subscr)
 					return lchan;
 			}
 		}
diff --git a/openbsc/src/common_vty.c b/openbsc/src/common_vty.c
new file mode 100644
index 0000000..16d6815
--- /dev/null
+++ b/openbsc/src/common_vty.c
@@ -0,0 +1,165 @@
+/* OpenBSC VTY common helpers */
+/* (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 <openbsc/vty.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/debug.h>
+#include <openbsc/gsm_subscriber.h>
+
+#include <osmocom/vty/telnet_interface.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/buffer.h>
+#include <osmocom/vty/vty.h>
+
+
+enum node_type bsc_vty_go_parent(struct vty *vty)
+{
+	switch (vty->node) {
+	case GSMNET_NODE:
+		vty->node = CONFIG_NODE;
+		vty->index = NULL;
+		break;
+	case BTS_NODE:
+		vty->node = GSMNET_NODE;
+		{
+			/* set vty->index correctly ! */
+			struct gsm_bts *bts = vty->index;
+			vty->index = bts->network;
+		}
+		break;
+	case TRX_NODE:
+		vty->node = BTS_NODE;
+		{
+			/* set vty->index correctly ! */
+			struct gsm_bts_trx *trx = vty->index;
+			vty->index = trx->bts;
+		}
+		break;
+	case TS_NODE:
+		vty->node = TRX_NODE;
+		{
+			/* set vty->index correctly ! */
+			struct gsm_bts_trx_ts *ts = vty->index;
+			vty->index = ts->trx;
+		}
+		break;
+	case OML_NODE:
+		vty->node = ENABLE_NODE;
+		talloc_free(vty->index);
+		vty->index = NULL;
+		break;
+	default:
+		vty->node = CONFIG_NODE;
+	}
+
+	return vty->node;
+}
+
+/* Down vty node level. */
+gDEFUN(ournode_exit,
+       ournode_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
+{
+	switch (vty->node) {
+	case GSMNET_NODE:
+		vty->node = CONFIG_NODE;
+		vty->index = NULL;
+		break;
+	case BTS_NODE:
+		vty->node = GSMNET_NODE;
+		{
+			/* set vty->index correctly ! */
+			struct gsm_bts *bts = vty->index;
+			vty->index = bts->network;
+			vty->index_sub = NULL;
+		}
+		break;
+	case TRX_NODE:
+		vty->node = BTS_NODE;
+		{
+			/* set vty->index correctly ! */
+			struct gsm_bts_trx *trx = vty->index;
+			vty->index = trx->bts;
+			vty->index_sub = &trx->bts->description;
+		}
+		break;
+	case TS_NODE:
+		vty->node = TRX_NODE;
+		{
+			/* set vty->index correctly ! */
+			struct gsm_bts_trx_ts *ts = vty->index;
+			vty->index = ts->trx;
+			vty->index_sub = &ts->trx->description;
+		}
+		break;
+	case MGCP_NODE:
+	case GBPROXY_NODE:
+	case SGSN_NODE:
+	case NS_NODE:
+	case BSSGP_NODE:
+		vty->node = CONFIG_NODE;
+		vty->index = NULL;
+		break;
+	case OML_NODE:
+		vty->node = ENABLE_NODE;
+		talloc_free(vty->index);
+		vty->index = NULL;
+		break;
+	default:
+		break;
+	}
+	return CMD_SUCCESS;
+}
+
+/* End of configuration. */
+gDEFUN(ournode_end,
+       ournode_end_cmd, "end", "End current mode and change to enable mode.")
+{
+	switch (vty->node) {
+	case VIEW_NODE:
+	case ENABLE_NODE:
+		/* Nothing to do. */
+		break;
+	case CONFIG_NODE:
+	case GSMNET_NODE:
+	case BTS_NODE:
+	case TRX_NODE:
+	case TS_NODE:
+	case MGCP_NODE:
+	case GBPROXY_NODE:
+	case SGSN_NODE:
+	case NS_NODE:
+	case VTY_NODE:
+		vty_config_unlock(vty);
+		vty->node = ENABLE_NODE;
+		vty->index = NULL;
+		vty->index_sub = NULL;
+		break;
+	default:
+		break;
+	}
+	return CMD_SUCCESS;
+}
+
diff --git a/openbsc/src/db.c b/openbsc/src/db.c
index 10c1d6d..72e6bd3 100644
--- a/openbsc/src/db.c
+++ b/openbsc/src/db.c
@@ -20,13 +20,8 @@
  *
  */
 
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_04_11.h>
-#include <openbsc/db.h>
-#include <osmocore/talloc.h>
-#include <openbsc/debug.h>
-#include <osmocore/statistics.h>
-
+#include <stdint.h>
+#include <inttypes.h>
 #include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -34,6 +29,14 @@
 #include <errno.h>
 #include <dbi/dbi.h>
 
+#include <openbsc/gsm_data.h>
+#include <openbsc/gsm_04_11.h>
+#include <openbsc/db.h>
+#include <osmocore/talloc.h>
+#include <openbsc/debug.h>
+#include <osmocore/statistics.h>
+#include <osmocore/rate_ctr.h>
+
 static char *db_basename = NULL;
 static char *db_dirname = NULL;
 static dbi_conn conn;
@@ -124,15 +127,20 @@
 		"value INTEGER NOT NULL, "
 		"name TEXT NOT NULL "
 		")",
-	"CREATE TABLE IF NOT EXISTS AuthKeys ("
+	"CREATE TABLE IF NOT EXISTS RateCounters ("
 		"id INTEGER PRIMARY KEY AUTOINCREMENT, "
-		"subscriber_id INTEGER UNIQUE NOT NULL, "
+		"timestamp TIMESTAMP NOT NULL, "
+		"value INTEGER NOT NULL, "
+		"name TEXT NOT NULL, "
+		"idx INTEGER NOT NULL "
+		")",
+	"CREATE TABLE IF NOT EXISTS AuthKeys ("
+		"subscriber_id INTEGER PRIMARY KEY, "
 		"algorithm_id INTEGER NOT NULL, "
 		"a3a8_ki BLOB "
 		")",
-	"CREATE TABLE IF NOT EXISTS AuthTuples ("
-		"id INTEGER PRIMARY KEY AUTOINCREMENT, "
-		"subscriber_id NUMERIC UNIQUE NOT NULL, "
+	"CREATE TABLE IF NOT EXISTS AuthLastTuples ("
+		"subscriber_id INTEGER PRIMARY KEY, "
 		"issued TIMESTAMP NOT NULL, "
 		"use_count INTEGER NOT NULL DEFAULT 0, "
 		"key_seq INTEGER NOT NULL, "
@@ -254,7 +262,7 @@
 	struct gsm_subscriber *subscr;
 
 	/* Is this subscriber known in the db? */
-	subscr = db_get_subscriber(net, GSM_SUBSCRIBER_IMSI, imsi); 
+	subscr = db_get_subscriber(net, GSM_SUBSCRIBER_IMSI, imsi);
 	if (subscr) {
 		result = dbi_conn_queryf(conn,
                          "UPDATE Subscriber set updated = datetime('now') "
@@ -288,6 +296,8 @@
 	return subscr;
 }
 
+static_assert(sizeof(unsigned char) == sizeof(struct gsm48_classmark1), classmark1_size);
+
 static int get_equipment_by_subscr(struct gsm_subscriber *subscr)
 {
 	dbi_result result;
@@ -316,9 +326,10 @@
 		strncpy(equip->imei, string, sizeof(equip->imei));
 
 	string = dbi_result_get_string(result, "classmark1");
-	if (string)
-		 cm1 = atoi(string) & 0xff;
-	equip->classmark1 = *((struct gsm48_classmark1 *) &cm1);
+	if (string) {
+		cm1 = atoi(string) & 0xff;
+		memcpy(&equip->classmark1, &cm1, sizeof(equip->classmark1));
+	}
 
 	equip->classmark2_len = dbi_result_get_field_length(result, "classmark2");
 	cm2 = dbi_result_get_binary(result, "classmark2");
@@ -337,8 +348,8 @@
 	return 0;
 }
 
-int get_authinfo_by_subscr(struct gsm_auth_info *ainfo,
-			   struct gsm_subscriber *subscr)
+int db_get_authinfo_for_subscr(struct gsm_auth_info *ainfo,
+                               struct gsm_subscriber *subscr)
 {
 	dbi_result result;
 	const unsigned char *a3a8_ki;
@@ -366,8 +377,8 @@
 	return 0;
 }
 
-int set_authinfo_for_subscr(struct gsm_auth_info *ainfo,
-			    struct gsm_subscriber *subscr)
+int db_sync_authinfo_for_subscr(struct gsm_auth_info *ainfo,
+                                struct gsm_subscriber *subscr)
 {
 	dbi_result result;
 	struct gsm_auth_info ainfo_old;
@@ -389,7 +400,7 @@
 	}
 
 	/* Check if already existing */
-	rc = get_authinfo_by_subscr(&ainfo_old, subscr);
+	rc = db_get_authinfo_for_subscr(&ainfo_old, subscr);
 	if (rc && rc != -ENOENT)
 		return rc;
 	upd = rc ? 0 : 1;
@@ -422,15 +433,15 @@
 	return 0;
 }
 
-int get_authtuple_by_subscr(struct gsm_auth_tuple *atuple,
-			    struct gsm_subscriber *subscr)
+int db_get_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
+                                    struct gsm_subscriber *subscr)
 {
 	dbi_result result;
 	int len;
 	const unsigned char *blob;
 
 	result = dbi_conn_queryf(conn,
-			"SELECT * FROM AuthTuples WHERE subscriber_id=%u",
+			"SELECT * FROM AuthLastTuples WHERE subscriber_id=%u",
 			subscr->id);
 	if (!result)
 		return -EIO;
@@ -475,8 +486,8 @@
 	return -EIO;
 }
 
-int set_authtuple_for_subscr(struct gsm_auth_tuple *atuple,
-			     struct gsm_subscriber *subscr)
+int db_sync_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
+                                     struct gsm_subscriber *subscr)
 {
 	dbi_result result;
 	int rc, upd;
@@ -486,7 +497,7 @@
 	/* Deletion ? */
 	if (atuple == NULL) {
 		result = dbi_conn_queryf(conn,
-			"DELETE FROM AuthTuples WHERE subscriber_id=%u",
+			"DELETE FROM AuthLastTuples WHERE subscriber_id=%u",
 			subscr->id);
 
 		if (!result)
@@ -498,7 +509,7 @@
 	}
 
 	/* Check if already existing */
-	rc = get_authtuple_by_subscr(&atuple_old, subscr);
+	rc = db_get_lastauthtuple_for_subscr(&atuple_old, subscr);
 	if (rc && rc != -ENOENT)
 		return rc;
 	upd = rc ? 0 : 1;
@@ -513,7 +524,7 @@
 
 	if (!upd) {
 		result = dbi_conn_queryf(conn,
-				"INSERT INTO AuthTuples "
+				"INSERT INTO AuthLastTuples "
 				"(subscriber_id, issued, use_count, "
 				 "key_seq, rand, sres, kc) "
 				"VALUES (%u, datetime('now'), %u, "
@@ -524,7 +535,7 @@
 		char *issued = atuple->key_seq == atuple_old.key_seq ?
 					"issued" : "datetime('now')";
 		result = dbi_conn_queryf(conn,
-				"UPDATE AuthKeys "
+				"UPDATE AuthLastTuples "
 				"SET issued=%s, use_count=%u, "
 				 "key_seq=%u, rand=%s, sres=%s, kc=%s "
 				"WHERE subscriber_id = %u",
@@ -1014,7 +1025,7 @@
 }
 
 /* retrieve the next unsent SMS with ID >= min_id */
-struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id)
+struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, unsigned long long min_id)
 {
 	dbi_result result;
 	struct gsm_sms *sms;
@@ -1041,7 +1052,7 @@
 	return sms;
 }
 
-struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, int min_subscr_id)
+struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, unsigned long long min_subscr_id)
 {
 	dbi_result result;
 	struct gsm_sms *sms;
@@ -1049,7 +1060,7 @@
 	result = dbi_conn_queryf(conn,
 		"SELECT * FROM SMS,Subscriber "
 		"WHERE sms.receiver_id >= %llu AND sms.sent is NULL "
-			"AND sms.receiver_id = subscriber.id " 
+			"AND sms.receiver_id = subscriber.id "
 			"AND subscriber.lac > 0 "
 		"ORDER BY sms.receiver_id, id LIMIT 1",
 		min_subscr_id);
@@ -1133,7 +1144,7 @@
 	return 0;
 }
 
-int db_apdu_blob_store(struct gsm_subscriber *subscr, 
+int db_apdu_blob_store(struct gsm_subscriber *subscr,
 			u_int8_t apdu_id_flags, u_int8_t len,
 			u_int8_t *apdu)
 {
@@ -1177,3 +1188,42 @@
 	dbi_result_free(result);
 	return 0;
 }
+
+static int db_store_rate_ctr(struct rate_ctr_group *ctrg, unsigned int num,
+			     char *q_prefix)
+{
+	dbi_result result;
+	char *q_name;
+
+	dbi_conn_quote_string_copy(conn, ctrg->desc->ctr_desc[num].name,
+				   &q_name);
+
+	result = dbi_conn_queryf(conn,
+		"Insert INTO RateCounters "
+		"(timestamp,name,idx,value) VALUES "
+		"(datetime('now'),%s.%s,%u,%"PRIu64")",
+		q_prefix, q_name, ctrg->idx, ctrg->ctr[num].current);
+
+	free(q_name);
+
+	if (!result)
+		return -EIO;
+
+	dbi_result_free(result);
+	return 0;
+}
+
+int db_store_rate_ctr_group(struct rate_ctr_group *ctrg)
+{
+	unsigned int i;
+	char *q_prefix;
+
+	dbi_conn_quote_string_copy(conn, ctrg->desc->group_name_prefix, &q_prefix);
+
+	for (i = 0; i < ctrg->desc->num_ctr; i++)
+		db_store_rate_ctr(ctrg, i, q_prefix);
+
+	free(q_prefix);
+
+	return 0;
+}
diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c
index 8f7a1c3..512935a 100644
--- a/openbsc/src/debug.c
+++ b/openbsc/src/debug.c
@@ -1,5 +1,6 @@
-/* Debugging/Logging support code */
-/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
+/* OpenBSC 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
  *
@@ -27,401 +28,218 @@
 #include <time.h>
 #include <errno.h>
 
-#include <openbsc/debug.h>
 #include <osmocore/talloc.h>
 #include <osmocore/utils.h>
+#include <osmocore/logging.h>
 #include <openbsc/gsm_data.h>
 #include <openbsc/gsm_subscriber.h>
+#include <openbsc/debug.h>
 
 /* default categories */
-static struct debug_category default_categories[Debug_LastEntry] = {
-    [DRLL]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DCC]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DNM]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DRR]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DRSL]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DMM]	= { .enabled = 1, .loglevel = LOGL_INFO },
-    [DMNCC]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DSMS]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DPAG]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DMEAS]	= { .enabled = 0, .loglevel = LOGL_NOTICE },
-    [DMI]	= { .enabled = 0, .loglevel = LOGL_NOTICE },
-    [DMIB]	= { .enabled = 0, .loglevel = LOGL_NOTICE },
-    [DMUX]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DINP]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DSCCP]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DMSC]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DMGCP]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DHO]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DDB]	= { .enabled = 1, .loglevel = LOGL_NOTICE },
-    [DREF]	= { .enabled = 0, .loglevel = LOGL_NOTICE },
+static const struct log_info_cat default_categories[] = {
+	[DRLL] = {
+		.name = "DRLL",
+		.description = "A-bis Radio Link Layer (RLL)",
+		.color = "\033[1;31m",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DCC] = {
+		.name = "DCC",
+		.description = "Layer3 Call Control (CC)",
+		.color = "\033[1;32m",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DMM] = {
+		.name = "DMM",
+		.description = "Layer3 Mobility Management (MM)",
+		.color = "\033[1;33m",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DRR] = {
+		.name = "DRR",
+		.description = "Layer3 Radio Resource (RR)",
+		.color = "\033[1;34m",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DRSL] = {
+		.name = "DRSL",
+		.description = "A-bis Radio Siganlling Link (RSL)",
+		.color = "\033[1;35m",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DNM] =	{
+		.name = "DNM",
+		.description = "A-bis Network Management / O&M (NM/OML)",
+		.color = "\033[1;36m",
+		.enabled = 1, .loglevel = LOGL_INFO,
+	},
+	[DMNCC] = {
+		.name = "DMNCC",
+		.description = "MNCC API for Call Control application",
+		.color = "\033[1;39m",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DSMS] = {
+		.name = "DSMS",
+		.description = "Layer3 Short Message Service (SMS)",
+		.color = "\033[1;37m",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DPAG]	= {
+		.name = "DPAG",
+		.description = "Paging Subsystem",
+		.color = "\033[1;38m",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DMEAS] = {
+		.name = "DMEAS",
+		.description = "Radio Measurement Processing",
+		.enabled = 0, .loglevel = LOGL_NOTICE,
+	},
+	[DMI] = {
+		.name = "DMI",
+		.description = "A-bis Input Driver for Signalling",
+		.enabled = 0, .loglevel = LOGL_NOTICE,
+	},
+	[DMIB] = {
+		.name = "DMIB",
+		.description = "A-bis Input Driver for B-Channels (voice)",
+		.enabled = 0, .loglevel = LOGL_NOTICE,
+	},
+	[DMUX] = {
+		.name = "DMUX",
+		.description = "A-bis B-Subchannel TRAU Frame Multiplex",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DINP] = {
+		.name = "DINP",
+		.description = "A-bis Intput Subsystem",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DSCCP] = {
+		.name = "DSCCP",
+		.description = "SCCP Protocol",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DMSC] = {
+		.name = "DMSC",
+		.description = "Mobile Switching Center",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DMGCP] = {
+		.name = "DMGCP",
+		.description = "Media Gateway Control Protocol",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DHO] = {
+		.name = "DHO",
+		.description = "Hand-Over",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DDB] = {
+		.name = "DDB",
+		.description = "Database Layer",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
+	[DREF] = {
+		.name = "DREF",
+		.description = "Reference Counting",
+		.enabled = 0, .loglevel = LOGL_NOTICE,
+	},
+	[DGPRS] = {
+		.name = "DGPRS",
+		.description = "GPRS Packet Service",
+		.enabled = 1, .loglevel = LOGL_DEBUG,
+	},
+	[DNS] = {
+		.name = "DNS",
+		.description = "GPRS Network Service (NS)",
+		.enabled = 1, .loglevel = LOGL_INFO,
+	},
+	[DBSSGP] = {
+		.name = "DBSSGP",
+		.description = "GPRS BSS Gateway Protocol (BSSGP)",
+		.enabled = 1, .loglevel = LOGL_DEBUG,
+	},
+	[DLLC] = {
+		.name = "DLLC",
+		.description = "GPRS Logical Link Control Protocol (LLC)",
+		.enabled = 1, .loglevel = LOGL_DEBUG,
+	},
+	[DSNDCP] = {
+		.name = "DSNDCP",
+		.description = "GPRS Sub-Network Dependent Control Protocol (SNDCP)",
+		.enabled = 1, .loglevel = LOGL_DEBUG,
+	},
 };
 
-struct debug_info {
-	const char *name;
-	const char *color;
-	const char *description;
-	int number;
-	int position;
+enum log_filter {
+	_FLT_ALL = LOG_FILTER_ALL,	/* libosmocore */
+	FLT_IMSI = 1,
+	FLT_NSVC = 2,
+	FLT_BVC  = 3,
 };
 
-struct debug_context {
-	struct gsm_lchan *lchan;
-	struct gsm_subscriber *subscr;
-	struct gsm_bts *bts;
+static int filter_fn(const struct log_context *ctx,
+		     struct log_target *tar)
+{
+	struct gsm_subscriber *subscr = ctx->ctx[BSC_CTX_SUBSCR];
+	const struct gprs_nsvc *nsvc = ctx->ctx[BSC_CTX_NSVC];
+	const struct gprs_nsvc *bvc = ctx->ctx[BSC_CTX_BVC];
+
+	if ((tar->filter_map & (1 << FLT_IMSI)) != 0
+	    && subscr && strcmp(subscr->imsi, tar->filter_data[FLT_IMSI]) == 0)
+		return 1;
+
+	/* Filter on the NS Virtual Connection */
+	if ((tar->filter_map & (1 << FLT_NSVC)) != 0
+	    && nsvc && (nsvc == tar->filter_data[FLT_NSVC]))
+		return 1;
+
+	/* Filter on the NS Virtual Connection */
+	if ((tar->filter_map & (1 << FLT_BVC)) != 0
+	    && bvc && (bvc == tar->filter_data[FLT_BVC]))
+		return 1;
+
+	return 0;
+}
+
+const struct log_info log_info = {
+	.filter_fn = filter_fn,
+	.cat = default_categories,
+	.num_cat = ARRAY_SIZE(default_categories),
 };
 
-static struct debug_context debug_context;
-static void *tall_dbg_ctx = NULL;
-static LLIST_HEAD(target_list);
-
-#define DEBUG_CATEGORY(NUMBER, NAME, COLOR, DESCRIPTION) \
-	{ .name = NAME, .color = COLOR, .description = DESCRIPTION, .number = NUMBER },
-
-static const struct debug_info debug_info[] = {
-	DEBUG_CATEGORY(DRLL,  "DRLL", "\033[1;31m", "")
-	DEBUG_CATEGORY(DCC,   "DCC",  "\033[1;32m", "")
-	DEBUG_CATEGORY(DMM,   "DMM",  "\033[1;33m", "")
-	DEBUG_CATEGORY(DRR,   "DRR",  "\033[1;34m", "")
-	DEBUG_CATEGORY(DRSL,  "DRSL", "\033[1;35m", "")
-	DEBUG_CATEGORY(DNM,   "DNM",  "\033[1;36m", "")
-	DEBUG_CATEGORY(DSMS,  "DSMS", "\033[1;37m", "")
-	DEBUG_CATEGORY(DPAG,  "DPAG", "\033[1;38m", "")
-	DEBUG_CATEGORY(DMNCC, "DMNCC","\033[1;39m", "")
-	DEBUG_CATEGORY(DINP,  "DINP", "", "")
-	DEBUG_CATEGORY(DMI,  "DMI", "", "")
-	DEBUG_CATEGORY(DMIB,  "DMIB", "", "")
-	DEBUG_CATEGORY(DMUX,  "DMUX", "", "")
-	DEBUG_CATEGORY(DMEAS,  "DMEAS", "", "")
-	DEBUG_CATEGORY(DSCCP, "DSCCP", "", "")
-	DEBUG_CATEGORY(DMSC, "DMSC", "", "")
-	DEBUG_CATEGORY(DMGCP, "DMGCP", "", "")
-	DEBUG_CATEGORY(DHO, "DHO", "", "")
-	DEBUG_CATEGORY(DDB, "DDB", "", "")
-	DEBUG_CATEGORY(DREF, "DREF", "", "")
-};
-
-static const struct value_string loglevel_strs[] = {
-	{ 0,	"EVERYTHING" },
-	{ 1,	"DEBUG" },
-	{ 3,	"INFO" },
-	{ 5,	"NOTICE" },
-	{ 7,	"ERROR" },
-	{ 8,	"FATAL" },
-	{ 0, NULL },
-};
-
-int debug_parse_level(const char *lvl)
-{
-	return get_string_value(loglevel_strs, lvl);
-}
-
-int debug_parse_category(const char *category)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(debug_info); ++i) {
-		if (!strcasecmp(debug_info[i].name+1, category))
-			return debug_info[i].number;
-	}
-
-	return -EINVAL;
-}
-
-/*
- * Parse the category mask.
- * The format can be this: category1:category2:category3
- * or category1,2:category2,3:...
- */
-void debug_parse_category_mask(struct debug_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 < ARRAY_SIZE(debug_info); ++i) {
-			char* colon = strstr(category_token, ",");
-			int length = strlen(category_token);
-
-			if (colon)
-			    length = colon - category_token;
-
-			if (strncasecmp(debug_info[i].name, category_token, length) == 0) {
-				int number = debug_info[i].number;
-				int level = 0;
-
-				if (colon)
-					level = atoi(colon+1);
-
-				target->categories[number].enabled = 1;
-				target->categories[number].loglevel = level;
-			}
-		}
-	} while ((category_token = strtok(NULL, ":")));
-
-	free(mask);
-}
-
-static const char* color(int subsys)
-{
-	int i = 0;
-
-	for (i = 0; i < ARRAY_SIZE(debug_info); ++i) {
-		if (debug_info[i].number == subsys)
-			return debug_info[i].color;
-	}
-
-	return "";
-}
-
-static void _output(struct debug_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) {
-		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 _debugp(unsigned int subsys, int level, char *file, int line,
-		    int cont, const char *format, va_list ap)
-{
-	struct debug_target *tar;
-
-	llist_for_each_entry(tar, &target_list, entry) {
-		struct debug_category *category;
-		int output = 0;
-
-		category = &tar->categories[subsys];
-		/* subsystem is not supposed to be debugged */
-		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 & DEBUG_FILTER_ALL) != 0) {
-			output = 1;
-		} else if ((tar->filter_map & DEBUG_FILTER_IMSI) != 0
-			      && debug_context.subscr && strcmp(debug_context.subscr->imsi, tar->imsi_filter) == 0) {
-			output = 1;
-		}
-
-		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 debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...)
-{
-	va_list ap;
-
-	va_start(ap, format);
-	_debugp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
-	va_end(ap);
-}
-
-void debugp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
-{
-	va_list ap;
-
-	va_start(ap, format);
-	_debugp(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 debug_add_target(struct debug_target *target)
-{
-	llist_add_tail(&target->entry, &target_list);
-}
-
-void debug_del_target(struct debug_target *target)
-{
-	llist_del(&target->entry);
-}
-
-void debug_reset_context(void)
-{
-	memset(&debug_context, 0, sizeof(debug_context));
-}
-
-/* currently we are not reffing these */
-void debug_set_context(int ctx, void *value)
-{
-	switch (ctx) {
-	case BSC_CTX_LCHAN:
-		debug_context.lchan = (struct gsm_lchan *) value;
-		break;
-	case BSC_CTX_SUBSCR:
-		debug_context.subscr = (struct gsm_subscriber *) value;
-		break;
-	case BSC_CTX_BTS:
-		debug_context.bts = (struct gsm_bts *) value;
-		break;
-	case BSC_CTX_SCCP:
-		break;
-	default:
-		break;
-	}
-}
-
-void debug_set_imsi_filter(struct debug_target *target, const char *imsi)
+void log_set_imsi_filter(struct log_target *target, const char *imsi)
 {
 	if (imsi) {
-		target->filter_map |= DEBUG_FILTER_IMSI;
-		target->imsi_filter = talloc_strdup(target, imsi);
-	} else if (target->imsi_filter) {
-		target->filter_map &= ~DEBUG_FILTER_IMSI;
-		talloc_free(target->imsi_filter);
-		target->imsi_filter = NULL;
+		target->filter_map |= (1 << FLT_IMSI);
+		target->filter_data[FLT_IMSI] = talloc_strdup(target, imsi);
+	} else if (target->filter_data[FLT_IMSI]) {
+		target->filter_map &= ~(1 << FLT_IMSI);
+		talloc_free(target->filter_data[FLT_IMSI]);
+		target->filter_data[FLT_IMSI] = NULL;
 	}
 }
 
-void debug_set_all_filter(struct debug_target *target, int all)
+void log_set_nsvc_filter(struct log_target *target, struct gprs_nsvc *nsvc)
 {
-	if (all)
-		target->filter_map |= DEBUG_FILTER_ALL;
-	else
-		target->filter_map &= ~DEBUG_FILTER_ALL;
+	if (nsvc) {
+		target->filter_map |= (1 << FLT_NSVC);
+		target->filter_data[FLT_NSVC] = nsvc;
+	} else if (target->filter_data[FLT_NSVC]) {
+		target->filter_map = ~(1 << FLT_NSVC);
+		target->filter_data[FLT_NSVC] = NULL;
+	}
 }
 
-void debug_set_use_color(struct debug_target *target, int use_color)
+void log_set_bvc_filter(struct log_target *target, struct bssgp_bvc_ctx *bctx)
 {
-	target->use_color = use_color;
-}
-
-void debug_set_print_timestamp(struct debug_target *target, int print_timestamp)
-{
-	target->print_timestamp = print_timestamp;
-}
-
-void debug_set_log_level(struct debug_target *target, int log_level)
-{
-	target->loglevel = log_level;
-}
-
-void debug_set_category_filter(struct debug_target *target, int category, int enable, int level)
-{
-	if (category >= Debug_LastEntry)
-		return;
-	target->categories[category].enabled = !!enable;
-	target->categories[category].loglevel = level;
-}
-
-static void _stderr_output(struct debug_target *target, const char *log)
-{
-	fprintf(target->tgt_stdout.out, "%s", log);
-	fflush(target->tgt_stdout.out);
-}
-
-struct debug_target *debug_target_create(void)
-{
-	struct debug_target *target;
-
-	target = talloc_zero(tall_dbg_ctx, struct debug_target);
-	if (!target)
-		return NULL;
-
-	INIT_LLIST_HEAD(&target->entry);
-	memcpy(target->categories, default_categories, sizeof(default_categories));
-	target->use_color = 1;
-	target->print_timestamp = 0;
-	target->loglevel = 0;
-	return target;
-}
-
-struct debug_target *debug_target_create_stderr(void)
-{
-	struct debug_target *target;
-
-	target = debug_target_create();
-	if (!target)
-		return NULL;
-
-	target->tgt_stdout.out = stderr;
-	target->output = _stderr_output;
-	return target;
-}
-
-void debug_init(void)
-{
-	tall_dbg_ctx = talloc_named_const(NULL, 1, "debug");
+	if (bctx) {
+		target->filter_map |= (1 << FLT_BVC);
+		target->filter_data[FLT_BVC] = bctx;
+	} else if (target->filter_data[FLT_NSVC]) {
+		target->filter_map = ~(1 << FLT_BVC);
+		target->filter_data[FLT_BVC] = NULL;
+	}
 }
diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c
index c20359c..b1dfe9b 100644
--- a/openbsc/src/e1_input.c
+++ b/openbsc/src/e1_input.c
@@ -420,7 +420,17 @@
 
 void e1inp_sign_link_destroy(struct e1inp_sign_link *link)
 {
+	struct msgb *msg;
+
 	llist_del(&link->list);
+	while (!llist_empty(&link->tx_list)) {
+		msg = msgb_dequeue(&link->tx_list);
+		msgb_free(msg);
+	}
+
+	if (link->ts->type == E1INP_TS_TYPE_SIGN)
+		bsc_del_timer(&link->ts->sign.tx_timer);
+
 	talloc_free(link);
 }
 
@@ -442,7 +452,7 @@
 			return -EINVAL;
 		}
 
-		debug_set_context(BSC_CTX_BTS, link->trx->bts);
+		log_set_context(BSC_CTX_BTS, link->trx->bts);
 		switch (link->type) {
 		case E1INP_SIGN_OML:
 			msg->trx = link->trx;
diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am
new file mode 100644
index 0000000..30b45f6
--- /dev/null
+++ b/openbsc/src/gprs/Makefile.am
@@ -0,0 +1,25 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
+AM_CFLAGS=-Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS)
+AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS)
+
+noinst_LIBRARIES = libgb.a
+
+if HAVE_LIBGTP
+sbin_PROGRAMS = osmo-gbproxy osmo-sgsn
+else
+sbin_PROGRAMS = osmo-gbproxy
+endif
+
+
+libgb_a_SOURCES = gprs_ns.c gprs_ns_frgre.c gprs_ns_vty.c \
+		  gprs_bssgp.c gprs_bssgp_util.c gprs_bssgp_vty.c \
+		  gprs_llc.c gprs_llc_vty.c crc24.c
+
+osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \
+			$(top_srcdir)/src/socket.c $(top_srcdir)/src/debug.c
+osmo_gbproxy_LDADD = libgb.a $(top_builddir)/src/libvty.a
+
+osmo_sgsn_SOURCES =	gprs_gmm.c gprs_sgsn.c gprs_sndcp.c \
+			sgsn_main.c sgsn_vty.c sgsn_libgtp.c \
+			$(top_srcdir)/src/socket.c $(top_srcdir)/src/debug.c
+osmo_sgsn_LDADD = libgb.a $(top_builddir)/src/libvty.a -lgtp
diff --git a/openbsc/src/gprs/crc24.c b/openbsc/src/gprs/crc24.c
new file mode 100644
index 0000000..1082120
--- /dev/null
+++ b/openbsc/src/gprs/crc24.c
@@ -0,0 +1,69 @@
+/* GPRS LLC CRC-24 Implementation */
+
+/* (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 <sys/types.h>
+#include <openbsc/crc24.h>
+
+/* CRC24 table - FCS */
+static const u_int32_t tbl_crc24[256] = {
+	0x00000000, 0x00d6a776, 0x00f64557, 0x0020e221, 0x00b78115, 0x00612663, 0x0041c442, 0x00976334,
+	0x00340991, 0x00e2aee7, 0x00c24cc6, 0x0014ebb0, 0x00838884, 0x00552ff2, 0x0075cdd3, 0x00a36aa5,
+	0x00681322, 0x00beb454, 0x009e5675, 0x0048f103, 0x00df9237, 0x00093541, 0x0029d760, 0x00ff7016,
+	0x005c1ab3, 0x008abdc5, 0x00aa5fe4, 0x007cf892, 0x00eb9ba6, 0x003d3cd0, 0x001ddef1, 0x00cb7987,
+	0x00d02644, 0x00068132, 0x00266313, 0x00f0c465, 0x0067a751, 0x00b10027, 0x0091e206, 0x00474570,
+	0x00e42fd5, 0x003288a3, 0x00126a82, 0x00c4cdf4, 0x0053aec0, 0x008509b6, 0x00a5eb97, 0x00734ce1,
+	0x00b83566, 0x006e9210, 0x004e7031, 0x0098d747, 0x000fb473, 0x00d91305, 0x00f9f124, 0x002f5652,
+	0x008c3cf7, 0x005a9b81, 0x007a79a0, 0x00acded6, 0x003bbde2, 0x00ed1a94, 0x00cdf8b5, 0x001b5fc3,
+	0x00fb4733, 0x002de045, 0x000d0264, 0x00dba512, 0x004cc626, 0x009a6150, 0x00ba8371, 0x006c2407,
+	0x00cf4ea2, 0x0019e9d4, 0x00390bf5, 0x00efac83, 0x0078cfb7, 0x00ae68c1, 0x008e8ae0, 0x00582d96,
+	0x00935411, 0x0045f367, 0x00651146, 0x00b3b630, 0x0024d504, 0x00f27272, 0x00d29053, 0x00043725,
+	0x00a75d80, 0x0071faf6, 0x005118d7, 0x0087bfa1, 0x0010dc95, 0x00c67be3, 0x00e699c2, 0x00303eb4,
+	0x002b6177, 0x00fdc601, 0x00dd2420, 0x000b8356, 0x009ce062, 0x004a4714, 0x006aa535, 0x00bc0243,
+	0x001f68e6, 0x00c9cf90, 0x00e92db1, 0x003f8ac7, 0x00a8e9f3, 0x007e4e85, 0x005eaca4, 0x00880bd2,
+	0x00437255, 0x0095d523, 0x00b53702, 0x00639074, 0x00f4f340, 0x00225436, 0x0002b617, 0x00d41161,
+	0x00777bc4, 0x00a1dcb2, 0x00813e93, 0x005799e5, 0x00c0fad1, 0x00165da7, 0x0036bf86, 0x00e018f0,
+	0x00ad85dd, 0x007b22ab, 0x005bc08a, 0x008d67fc, 0x001a04c8, 0x00cca3be, 0x00ec419f, 0x003ae6e9,
+	0x00998c4c, 0x004f2b3a, 0x006fc91b, 0x00b96e6d, 0x002e0d59, 0x00f8aa2f, 0x00d8480e, 0x000eef78,
+	0x00c596ff, 0x00133189, 0x0033d3a8, 0x00e574de, 0x007217ea, 0x00a4b09c, 0x008452bd, 0x0052f5cb,
+	0x00f19f6e, 0x00273818, 0x0007da39, 0x00d17d4f, 0x00461e7b, 0x0090b90d, 0x00b05b2c, 0x0066fc5a,
+	0x007da399, 0x00ab04ef, 0x008be6ce, 0x005d41b8, 0x00ca228c, 0x001c85fa, 0x003c67db, 0x00eac0ad,
+	0x0049aa08, 0x009f0d7e, 0x00bfef5f, 0x00694829, 0x00fe2b1d, 0x00288c6b, 0x00086e4a, 0x00dec93c,
+	0x0015b0bb, 0x00c317cd, 0x00e3f5ec, 0x0035529a, 0x00a231ae, 0x007496d8, 0x005474f9, 0x0082d38f,
+	0x0021b92a, 0x00f71e5c, 0x00d7fc7d, 0x00015b0b, 0x0096383f, 0x00409f49, 0x00607d68, 0x00b6da1e,
+	0x0056c2ee, 0x00806598, 0x00a087b9, 0x007620cf, 0x00e143fb, 0x0037e48d, 0x001706ac, 0x00c1a1da,
+	0x0062cb7f, 0x00b46c09, 0x00948e28, 0x0042295e, 0x00d54a6a, 0x0003ed1c, 0x00230f3d, 0x00f5a84b,
+	0x003ed1cc, 0x00e876ba, 0x00c8949b, 0x001e33ed, 0x008950d9, 0x005ff7af, 0x007f158e, 0x00a9b2f8,
+	0x000ad85d, 0x00dc7f2b, 0x00fc9d0a, 0x002a3a7c, 0x00bd5948, 0x006bfe3e, 0x004b1c1f, 0x009dbb69,
+	0x0086e4aa, 0x005043dc, 0x0070a1fd, 0x00a6068b, 0x003165bf, 0x00e7c2c9, 0x00c720e8, 0x0011879e,
+	0x00b2ed3b, 0x00644a4d, 0x0044a86c, 0x00920f1a, 0x00056c2e, 0x00d3cb58, 0x00f32979, 0x00258e0f,
+	0x00eef788, 0x003850fe, 0x0018b2df, 0x00ce15a9, 0x0059769d, 0x008fd1eb, 0x00af33ca, 0x007994bc,
+	0x00dafe19, 0x000c596f, 0x002cbb4e, 0x00fa1c38, 0x006d7f0c, 0x00bbd87a, 0x009b3a5b, 0x004d9d2d
+};
+
+#define INIT_CRC24	0xffffff
+
+u_int32_t crc24_calc(u_int32_t fcs, u_int8_t *cp, unsigned int len)
+{
+	while (len--)
+		fcs = (fcs >> 8) ^ tbl_crc24[(fcs ^ *cp++) & 0xff];
+	return fcs;
+}
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c
new file mode 100644
index 0000000..a95929b
--- /dev/null
+++ b/openbsc/src/gprs/gb_proxy.c
@@ -0,0 +1,616 @@
+/* NS-over-IP proxy */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+
+#include <osmocore/talloc.h>
+#include <osmocore/select.h>
+
+#include <openbsc/signal.h>
+#include <openbsc/debug.h>
+#include <openbsc/gprs_ns.h>
+#include <openbsc/gprs_bssgp.h>
+#include <openbsc/gb_proxy.h>
+
+struct gbprox_peer {
+	struct llist_head list;
+
+	/* NS-VC over which we send/receive data to this BVC */
+	struct gprs_nsvc *nsvc;
+
+	/* BVCI used for Point-to-Point to this peer */
+	uint16_t bvci;
+
+	/* Routeing Area that this peer is part of (raw 04.08 encoding) */
+	uint8_t ra[6];
+};
+
+/* Linked list of all Gb peers (except SGSN) */
+static LLIST_HEAD(gbprox_bts_peers);
+
+/* Find the gbprox_peer by its BVCI */
+static struct gbprox_peer *peer_by_bvci(uint16_t bvci)
+{
+	struct gbprox_peer *peer;
+	llist_for_each_entry(peer, &gbprox_bts_peers, list) {
+		if (peer->bvci == bvci)
+			return peer;
+	}
+	return NULL;
+}
+
+static struct gbprox_peer *peer_by_nsvc(struct gprs_nsvc *nsvc)
+{
+	struct gbprox_peer *peer;
+	llist_for_each_entry(peer, &gbprox_bts_peers, list) {
+		if (peer->nsvc == nsvc)
+			return peer;
+	}
+	return NULL;
+}
+
+/* look-up a peer by its Routeing Area Code (RAC) */
+static struct gbprox_peer *peer_by_rac(const uint8_t *ra)
+{
+	struct gbprox_peer *peer;
+	llist_for_each_entry(peer, &gbprox_bts_peers, list) {
+		if (!memcmp(peer->ra, ra, 6))
+			return peer;
+	}
+	return NULL;
+}
+
+/* look-up a peer by its Location Area Code (LAC) */
+static struct gbprox_peer *peer_by_lac(const uint8_t *la)
+{
+	struct gbprox_peer *peer;
+	llist_for_each_entry(peer, &gbprox_bts_peers, list) {
+		if (!memcmp(peer->ra, la, 5))
+			return peer;
+	}
+	return NULL;
+}
+
+static struct gbprox_peer *peer_alloc(uint16_t bvci)
+{
+	struct gbprox_peer *peer;
+
+	peer = talloc_zero(tall_bsc_ctx, struct gbprox_peer);
+	if (!peer)
+		return NULL;
+
+	peer->bvci = bvci;
+	llist_add(&peer->list, &gbprox_bts_peers);
+
+	return peer;
+}
+
+static void peer_free(struct gbprox_peer *peer)
+{
+	llist_del(&peer->list);
+	talloc_free(peer);
+}
+
+/* FIXME: this needs to go to libosmocore/msgb.c */
+static struct msgb *msgb_copy(const struct msgb *msg, const char *name)
+{
+	struct openbsc_msgb_cb *old_cb, *new_cb;
+	struct msgb *new_msg;
+
+	new_msg = msgb_alloc(msg->data_len, name);
+	if (!new_msg)
+		return NULL;
+
+	/* copy data */
+	memcpy(new_msg->_data, msg->_data, new_msg->data_len);
+
+	/* copy header */
+	new_msg->len = msg->len;
+	new_msg->data += msg->data - msg->_data;
+	new_msg->head += msg->head - msg->_data;
+	new_msg->tail += msg->tail - msg->_data;
+
+	new_msg->l1h = new_msg->_data + (msg->l1h - msg->_data);
+	new_msg->l2h = new_msg->_data + (msg->l2h - msg->_data);
+	new_msg->l3h = new_msg->_data + (msg->l3h - msg->_data);
+	new_msg->l4h = new_msg->_data + (msg->l4h - msg->_data);
+
+	/* copy GB specific data */
+	old_cb = OBSC_MSGB_CB(msg);
+	new_cb = OBSC_MSGB_CB(new_msg);
+
+	new_cb->bssgph = new_msg->_data + (old_cb->bssgph - msg->_data);
+	new_cb->llch = new_msg->_data + (old_cb->llch - msg->_data);
+
+	new_cb->bssgp_cell_id = old_cb->bssgp_cell_id;
+	new_cb->nsei = old_cb->nsei;
+	new_cb->bvci = old_cb->bvci;
+	new_cb->tlli = old_cb->tlli;
+
+	return new_msg;
+}
+
+/* strip off the NS header */
+static void strip_ns_hdr(struct msgb *msg)
+{
+	int strip_len = msgb_bssgph(msg) - msg->data;
+	msgb_pull(msg, strip_len);
+}
+
+/* feed a message down the NS-VC associated with the specified peer */
+static int gbprox_relay2sgsn(struct msgb *old_msg, uint16_t ns_bvci)
+{
+	/* create a copy of the message so the old one can
+	 * be free()d safely when we return from gbprox_rcvmsg() */
+	struct msgb *msg = msgb_copy(old_msg, "msgb_relay2sgsn");
+
+	DEBUGP(DGPRS, "NSEI=%u proxying BTS->SGSN (NS_BVCI=%u, NSEI=%u)\n",
+		msgb_nsei(msg), ns_bvci, gbcfg.nsip_sgsn_nsei);
+
+	msgb_bvci(msg) = ns_bvci;
+	msgb_nsei(msg) = gbcfg.nsip_sgsn_nsei;
+
+	strip_ns_hdr(msg);
+
+	return gprs_ns_sendmsg(bssgp_nsi, msg);
+}
+
+/* feed a message down the NS-VC associated with the specified peer */
+static int gbprox_relay2peer(struct msgb *old_msg, struct gbprox_peer *peer,
+			  uint16_t ns_bvci)
+{
+	/* create a copy of the message so the old one can
+	 * be free()d safely when we return from gbprox_rcvmsg() */
+	struct msgb *msg = msgb_copy(old_msg, "msgb_relay2peer");
+
+	DEBUGP(DGPRS, "NSEI=%u proxying SGSN->BSS (NS_BVCI=%u, NSEI=%u)\n",
+		msgb_nsei(msg), ns_bvci, peer->nsvc->nsei);
+
+	msgb_bvci(msg) = ns_bvci;
+	msgb_nsei(msg) = peer->nsvc->nsei;
+
+	/* Strip the old NS header, it will be replaced with a new one */
+	strip_ns_hdr(msg);
+
+	return gprs_ns_sendmsg(bssgp_nsi, msg);
+}
+
+/* Send a message to a peer identified by ptp_bvci but using ns_bvci
+ * in the NS hdr */
+static int gbprox_relay2bvci(struct msgb *msg, uint16_t ptp_bvci,
+			  uint16_t ns_bvci)
+{
+	struct gbprox_peer *peer;
+
+	peer = peer_by_bvci(ptp_bvci);
+	if (!peer) {
+		LOGP(DGPRS, LOGL_ERROR, "BVCI=%u: Cannot find BSS\n",
+			ptp_bvci);
+		return -ENOENT;
+	}
+
+	return gbprox_relay2peer(msg, peer, ns_bvci);
+}
+
+/* Receive an incoming signalling message from a BSS-side NS-VC */
+static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc,
+				  uint16_t ns_bvci)
+{
+	struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
+	struct tlv_parsed tp;
+	uint8_t pdu_type = bgph->pdu_type;
+	int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
+	struct gbprox_peer *from_peer;
+	struct gprs_ra_id raid;
+
+	if (ns_bvci != 0) {
+		LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u BVCI=%u is not signalling\n",
+			nsvc->nsei, ns_bvci);
+		return -EINVAL;
+	}
+
+	/* we actually should never see those two for BVCI == 0, but double-check
+	 * just to make sure  */
+	if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
+	    pdu_type == BSSGP_PDUT_DL_UNITDATA) {
+		LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u UNITDATA not allowed in "
+			"signalling\n", nsvc->nsei);
+		return -EINVAL;
+	}
+
+	bssgp_tlv_parse(&tp, bgph->data, data_len);
+
+	switch (pdu_type) {
+	case BSSGP_PDUT_SUSPEND:
+	case BSSGP_PDUT_RESUME:
+		/* We implement RAC snooping during SUSPEND/RESUME, since
+		 * it establishes a relationsip between BVCI/peer and the
+		 * routeing area code.  The snooped information is then
+		 * used for routing the {SUSPEND,RESUME}_[N]ACK back to
+		 * the correct BSSGP */
+		if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
+			goto err_mand_ie;
+		from_peer = peer_by_nsvc(nsvc);
+		if (!from_peer)
+			goto err_no_peer;
+		memcpy(from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA),
+			sizeof(from_peer->ra));
+		gsm48_parse_ra(&raid, from_peer->ra);
+		LOGP(DGPRS, LOGL_INFO, "NSEI=%u BSSGP SUSPEND/RESUME "
+			"RAC snooping: RAC %u-%u-%u-%u behind BVCI=%u, "
+			"NSVCI=%u\n",nsvc->nsei, raid.mcc, raid.mnc, raid.lac,
+			raid.rac , from_peer->bvci, nsvc->nsvci);
+		/* FIXME: This only supports one BSS per RA */
+		break;
+	case BSSGP_PDUT_BVC_RESET:
+		/* If we receive a BVC reset on the signalling endpoint, we
+		 * don't want the SGSN to reset, as the signalling endpoint
+		 * is common for all point-to-point BVCs (and thus all BTS) */
+		if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) {
+			uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
+			LOGP(DGPRS, LOGL_INFO, "NSEI=%u Rx BVC RESET (BVCI=%u)\n",
+				nsvc->nsei, bvci);
+			if (bvci == 0) {
+				/* FIXME: only do this if SGSN is alive! */
+				LOGP(DGPRS, LOGL_INFO, "NSEI=%u Tx fake "
+					"BVC RESET ACK of BVCI=0\n", nsvc->nsei);
+				return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK,
+							    nsvc->nsei, 0, ns_bvci);
+			}
+			from_peer = peer_by_bvci(bvci);
+			if (!from_peer) {
+				/* if a PTP-BVC is reset, and we don't know that
+				 * PTP-BVCI yet, we should allocate a new peer */
+				LOGP(DGPRS, LOGL_INFO, "Allocationg new peer for "
+				     "BVCI=%u via NSVCI=%u/NSEI=%u\n", bvci,
+				     nsvc->nsvci, nsvc->nsei);
+				from_peer = peer_alloc(bvci);
+				from_peer->nsvc = nsvc;
+			}
+			if (TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID)) {
+				struct gprs_ra_id raid;
+				/* We have a Cell Identifier present in this
+				 * PDU, this means we can extend our local
+				 * state information about this particular cell
+				 * */
+				memcpy(from_peer->ra,
+					TLVP_VAL(&tp, BSSGP_IE_CELL_ID),
+					sizeof(from_peer->ra));
+				gsm48_parse_ra(&raid, from_peer->ra);
+				LOGP(DGPRS, LOGL_INFO, "NSEI=%u/BVCI=%u "
+				     "Cell ID %u-%u-%u-%u\n", nsvc->nsei,
+				     bvci, raid.mcc, raid.mnc, raid.lac,
+				     raid.rac);
+			}
+		}
+		break;
+	}
+
+	/* Normally, we can simply pass on all signalling messages from BSS to
+	 * SGSN */
+	return gbprox_relay2sgsn(msg, ns_bvci);
+err_no_peer:
+	LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(BSS) cannot find peer based on RAC\n",
+		nsvc->nsei);
+	return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, NULL, msg);
+err_mand_ie:
+	LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(BSS) missing mandatory RA IE\n",
+		nsvc->nsei);
+	return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
+}
+
+/* Receive paging request from SGSN, we need to relay to proper BSS */
+static int gbprox_rx_paging(struct msgb *msg, struct tlv_parsed *tp,
+			    struct gprs_nsvc *nsvc, uint16_t ns_bvci)
+{
+	struct gbprox_peer *peer = NULL;
+
+	LOGP(DGPRS, LOGL_INFO, "NSEI=%u(SGSN) BSSGP PAGING ",
+		nsvc->nsei);
+	if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
+		uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI));
+		LOGPC(DGPRS, LOGL_INFO, "routing by BVCI to peer BVCI=%u\n",
+			bvci);
+	} else if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
+		peer = peer_by_rac(TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));
+		LOGPC(DGPRS, LOGL_INFO, "routing by RAC to peer BVCI=%u\n",
+			peer ? peer->bvci : -1);
+	} else if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) {
+		peer = peer_by_lac(TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA));
+		LOGPC(DGPRS, LOGL_INFO, "routing by LAC to peer BVCI=%u\n",
+			peer ? peer->bvci : -1);
+	} else
+		LOGPC(DGPRS, LOGL_INFO, "\n");
+
+	if (!peer) {
+		LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) BSSGP PAGING: "
+			"unable to route, missing IE\n", nsvc->nsei);
+		return -EINVAL;
+	}
+	return gbprox_relay2peer(msg, peer, ns_bvci);
+}
+
+/* Receive an incoming BVC-RESET message from the SGSN */
+static int rx_reset_from_sgsn(struct msgb *msg, struct tlv_parsed *tp,
+			      struct gprs_nsvc *nsvc, uint16_t ns_bvci)
+{
+	struct gbprox_peer *peer;
+	uint16_t ptp_bvci;
+
+	if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
+		return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE,
+				       NULL, msg);
+	}
+	ptp_bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI));
+
+	if (ptp_bvci >= 2) {
+		/* A reset for a PTP BVC was received, forward it to its
+		 * respective peer */
+		peer = peer_by_bvci(ptp_bvci);
+		if (!peer) {
+			LOGP(DGPRS, LOGL_ERROR, "NSEI=%u BVCI=%u: Cannot find BSS\n",
+				nsvc->nsei, ptp_bvci);
+			return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI,
+					       NULL, msg);
+		}
+		return gbprox_relay2peer(msg, peer, ns_bvci);
+	}
+
+	/* A reset for the Signalling entity has been received
+	 * from the SGSN.  As the signalling BVCI is shared
+	 * among all the BSS's that we multiplex, it needs to
+	 * be relayed  */
+	llist_for_each_entry(peer, &gbprox_bts_peers, list)
+		gbprox_relay2peer(msg, peer, ns_bvci);
+
+	return 0;
+}
+
+/* Receive an incoming signalling message from the SGSN-side NS-VC */
+static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc,
+				   uint16_t ns_bvci)
+{
+	struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
+	struct tlv_parsed tp;
+	uint8_t pdu_type = bgph->pdu_type;
+	int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
+	struct gbprox_peer *peer;
+	uint16_t bvci;
+	int rc = 0;
+
+	if (ns_bvci != 0) {
+		LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) BVCI=%u is not "
+			"signalling\n", nsvc->nsei, ns_bvci);
+		/* FIXME: Send proper error message */
+		return -EINVAL;
+	}
+
+	/* we actually should never see those two for BVCI == 0, but double-check
+	 * just to make sure  */
+	if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
+	    pdu_type == BSSGP_PDUT_DL_UNITDATA) {
+		LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) UNITDATA not allowed in "
+			"signalling\n", nsvc->nsei);
+		return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
+	}
+
+	rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
+
+	switch (pdu_type) {
+	case BSSGP_PDUT_BVC_RESET:
+		rc = rx_reset_from_sgsn(msg, &tp, nsvc, ns_bvci);
+		break;
+	case BSSGP_PDUT_FLUSH_LL:
+	case BSSGP_PDUT_BVC_BLOCK_ACK:
+	case BSSGP_PDUT_BVC_UNBLOCK_ACK:
+	case BSSGP_PDUT_BVC_RESET_ACK:
+		/* simple case: BVCI IE is mandatory */
+		if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI))
+			goto err_mand_ie;
+		bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
+		rc = gbprox_relay2bvci(msg, bvci, ns_bvci);
+		break;
+	case BSSGP_PDUT_PAGING_PS:
+	case BSSGP_PDUT_PAGING_CS:
+		/* process the paging request (LAC/RAC lookup) */
+		rc = gbprox_rx_paging(msg, &tp, nsvc, ns_bvci);
+		break;
+	case BSSGP_PDUT_STATUS:
+		/* Some exception has occurred */
+		LOGP(DGPRS, LOGL_NOTICE,
+			"NSEI=%u(SGSN) BSSGP STATUS ", nsvc->nsei);
+		if (!TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) {
+			LOGPC(DGPRS, LOGL_NOTICE, "\n");
+			goto err_mand_ie;
+		}
+		LOGPC(DGPRS, LOGL_NOTICE,
+			"cause=0x%02x(%s) ", *TLVP_VAL(&tp, BSSGP_IE_CAUSE),
+			bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE)));
+		if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) {
+			uint16_t *bvci = (uint16_t *)
+						TLVP_VAL(&tp, BSSGP_IE_BVCI);
+			LOGPC(DGPRS, LOGL_NOTICE,
+				"BVCI=%u\n", ntohs(*bvci));
+		} else
+			LOGPC(DGPRS, LOGL_NOTICE, "\n");
+		break;
+	/* those only exist in the SGSN -> BSS direction */
+	case BSSGP_PDUT_SUSPEND_ACK:
+	case BSSGP_PDUT_SUSPEND_NACK:
+	case BSSGP_PDUT_RESUME_ACK:
+	case BSSGP_PDUT_RESUME_NACK:
+		/* RAC IE is mandatory */
+		if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
+			goto err_mand_ie;
+		peer = peer_by_rac(TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA));
+		if (!peer)
+			goto err_no_peer;
+		rc = gbprox_relay2peer(msg, peer, ns_bvci);
+		break;
+	case BSSGP_PDUT_SGSN_INVOKE_TRACE:
+		LOGP(DGPRS, LOGL_ERROR,
+		     "NSEI=%u(SGSN) BSSGP INVOKE TRACE not supported\n",nsvc->nsei);
+		rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg);
+		break;
+	default:
+		LOGP(DGPRS, LOGL_NOTICE, "BSSGP PDU type 0x%02x unknown\n",
+			pdu_type);
+		rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
+		break;
+	}
+
+	return rc;
+err_mand_ie:
+	LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) missing mandatory IE\n",
+		nsvc->nsei);
+	return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
+err_no_peer:
+	LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) cannot find peer based on RAC\n",
+		nsvc->nsei);
+	return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, NULL, msg);
+}
+
+/* Main input function for Gb proxy */
+int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci)
+{
+	int rc;
+
+	/* Only BVCI=0 messages need special treatment */
+	if (ns_bvci == 0 || ns_bvci == 1) {
+		if (nsvc->remote_end_is_sgsn)
+			rc = gbprox_rx_sig_from_sgsn(msg, nsvc, ns_bvci);
+		else
+			rc = gbprox_rx_sig_from_bss(msg, nsvc, ns_bvci);
+	} else {
+		/* All other BVCI are PTP and thus can be simply forwarded */
+		if (!nsvc->remote_end_is_sgsn) {
+			rc = gbprox_relay2sgsn(msg, ns_bvci);
+		} else {
+			struct gbprox_peer *peer = peer_by_bvci(ns_bvci);
+			if (!peer) {
+				LOGP(DGPRS, LOGL_INFO, "Allocationg new peer for "
+				     "BVCI=%u via NSVC=%u/NSEI=%u\n", ns_bvci,
+				     nsvc->nsvci, nsvc->nsei);
+				peer = peer_alloc(ns_bvci);
+				peer->nsvc = nsvc;
+			}
+			rc = gbprox_relay2peer(msg, peer, ns_bvci);
+		}
+	}
+
+	return rc;
+}
+
+int gbprox_reset_persistent_nsvcs(struct gprs_ns_inst *nsi)
+{
+	struct gprs_nsvc *nsvc;
+
+	llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) {
+		if (!nsvc->persistent)
+			continue;
+		gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION);
+	}
+	return 0;
+}
+
+/* Signal handler for signals from NS layer */
+int gbprox_signal(unsigned int subsys, unsigned int signal,
+		  void *handler_data, void *signal_data)
+{
+	struct ns_signal_data *nssd = signal_data;
+	struct gprs_nsvc *nsvc = nssd->nsvc;
+	struct gbprox_peer *peer;
+
+	if (subsys != SS_NS)
+		return 0;
+
+	if (signal == S_NS_RESET && nsvc->nsei == gbcfg.nsip_sgsn_nsei) {
+		/* We have received a NS-RESET from the NSEI and NSVC
+		 * of the SGSN.  This might happen with SGSN that start
+		 * their own NS-RESET procedure without waiting for our
+		 * NS-RESET */
+		nsvc->remote_end_is_sgsn = 1;
+	}
+
+	if (signal == S_NS_ALIVE_EXP && nsvc->remote_end_is_sgsn) {
+		LOGP(DGPRS, LOGL_NOTICE, "Tns alive expired too often, "
+			"re-starting RESET procedure\n");
+		nsip_connect(nsvc->nsi, &nsvc->ip.bts_addr, nsvc->nsei,
+			     nsvc->nsvci);
+	}
+
+	/* We currently only care about signals from the SGSN */
+	if (!nsvc->remote_end_is_sgsn)
+		return 0;
+
+	/* iterate over all BTS peers and send the respective PDU */
+	llist_for_each_entry(peer, &gbprox_bts_peers, list) {
+		switch (signal) {
+		case S_NS_RESET:
+			gprs_ns_tx_reset(peer->nsvc, nssd->cause);
+			break;
+		case S_NS_BLOCK:
+			gprs_ns_tx_block(peer->nsvc, nssd->cause);
+			break;
+		case S_NS_UNBLOCK:
+			gprs_ns_tx_unblock(peer->nsvc);
+			break;
+		}
+	}
+	return 0;
+}
+
+
+#include <osmocom/vty/command.h>
+
+gDEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy",
+       SHOW_STR "Display information about the Gb proxy")
+{
+	struct gbprox_peer *peer;
+
+	llist_for_each_entry(peer, &gbprox_bts_peers, list) {
+		struct gprs_nsvc *nsvc = peer->nsvc;
+		struct gprs_ra_id raid;
+		gsm48_parse_ra(&raid, peer->ra);
+
+		vty_out(vty, "NSEI %5u, NS-VC %5u, PTP-BVCI %5u, "
+			"RAC %u-%u-%u-%u",
+			nsvc->nsei, nsvc->nsvci, peer->bvci,
+			raid.mcc, raid.mnc, raid.lac, raid.rac);
+		if (nsvc->ll == GPRS_NS_LL_UDP || nsvc->ll == GPRS_NS_LL_FR_GRE)
+			vty_out(vty, " %s:%u%s",
+				inet_ntoa(nsvc->ip.bts_addr.sin_addr),
+				ntohs(nsvc->ip.bts_addr.sin_port), VTY_NEWLINE);
+		else
+			vty_out(vty, "%s", VTY_NEWLINE);
+	}
+	return CMD_SUCCESS;
+}
diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c
new file mode 100644
index 0000000..32bbe38
--- /dev/null
+++ b/openbsc/src/gprs/gb_proxy_main.c
@@ -0,0 +1,273 @@
+/* NS-over-IP proxy */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <osmocore/talloc.h>
+#include <osmocore/select.h>
+#include <osmocore/rate_ctr.h>
+
+#include <openbsc/signal.h>
+#include <openbsc/debug.h>
+#include <openbsc/gprs_ns.h>
+#include <openbsc/gprs_bssgp.h>
+#include <openbsc/vty.h>
+#include <openbsc/gb_proxy.h>
+
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/telnet_interface.h>
+
+#include "../../bscconfig.h"
+
+/* this is here for the vty... it will never be called */
+void subscr_put() { abort(); }
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+void *tall_bsc_ctx;
+
+const char *openbsc_copyright =
+	"Copyright (C) 2010 Harald Welte and On-Waves\n"
+	"License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\n"
+	"This is free software: you are free to change and redistribute it.\n"
+	"There is NO WARRANTY, to the extent permitted by law.\n";
+
+static struct log_target *stderr_target;
+static char *config_file = "osmo_gbproxy.cfg";
+struct gbproxy_config gbcfg;
+
+/* Pointer to the SGSN peer */
+extern struct gbprox_peer *gbprox_peer_sgsn;
+
+/* call-back function for the NS protocol */
+static int proxy_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
+		      struct msgb *msg, u_int16_t bvci)
+{
+	int rc = 0;
+
+	switch (event) {
+	case GPRS_NS_EVT_UNIT_DATA:
+		rc = gbprox_rcvmsg(msg, nsvc, bvci);
+		break;
+	default:
+		LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event);
+		if (msg)
+			talloc_free(msg);
+		rc = -EIO;
+		break;
+	}
+	return rc;
+}
+
+static void signal_handler(int signal)
+{
+	fprintf(stdout, "signal %u received\n", signal);
+
+	switch (signal) {
+	case SIGINT:
+		dispatch_signal(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL);
+		sleep(1);
+		exit(0);
+		break;
+	case SIGABRT:
+		/* in case of abort, we want to obtain a talloc report
+		 * and then return to the caller, who will abort the process */
+	case SIGUSR1:
+		talloc_report(tall_vty_ctx, stderr);
+		talloc_report_full(tall_bsc_ctx, stderr);
+		break;
+	case SIGUSR2:
+		talloc_report_full(tall_vty_ctx, stderr);
+		break;
+	default:
+		break;
+	}
+}
+
+static void print_usage()
+{
+	printf("Usage: bsc_hack\n");
+}
+
+static void print_help()
+{
+	printf("  Some useful help...\n");
+	printf("  -h --help this text\n");
+	printf("  -d option --debug=DNS:DGPRS,0:0 enable debugging\n");
+	printf("  -c --config-file filename The config file to use.\n");
+	printf("  -s --disable-color\n");
+	printf("  -T --timestamp Prefix every log line with a timestamp\n");
+	printf("  -V --version. Print the version of OpenBSC.\n");
+	printf("  -e --log-level number. Set a global loglevel.\n");
+}
+
+static void handle_options(int argc, char **argv)
+{
+	while (1) {
+		int option_index = 0, c;
+		static struct option long_options[] = {
+			{ "help", 0, 0, 'h' },
+			{ "debug", 1, 0, 'd' },
+			{ "config-file", 1, 0, 'c' },
+			{ "disable-color", 0, 0, 's' },
+			{ "timestamp", 0, 0, 'T' },
+			{ "version", 0, 0, 'V' },
+			{ "log-level", 1, 0, 'e' },
+			{ 0, 0, 0, 0 }
+		};
+
+		c = getopt_long(argc, argv, "hd:c:sTVe:",
+				long_options, &option_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'h':
+			print_usage();
+			print_help();
+			exit(0);
+		case 's':
+			log_set_use_color(stderr_target, 0);
+			break;
+		case 'd':
+			log_parse_category_mask(stderr_target, optarg);
+			break;
+		case 'c':
+			config_file = strdup(optarg);
+			break;
+		case 'T':
+			log_set_print_timestamp(stderr_target, 1);
+			break;
+		case 'e':
+			log_set_log_level(stderr_target, atoi(optarg));
+			break;
+		case 'V':
+			print_version(1);
+			exit(0);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+extern void *tall_msgb_ctx;
+
+extern enum node_type bsc_vty_go_parent(struct vty *vty);
+
+static struct vty_app_info vty_info = {
+	.name 		= "Osmocom Gb Proxy",
+	.version	= PACKAGE_VERSION,
+	.go_parent_cb	= bsc_vty_go_parent,
+};
+
+int main(int argc, char **argv)
+{
+	struct gsm_network dummy_network;
+	int rc;
+
+	tall_bsc_ctx = talloc_named_const(NULL, 0, "nsip_proxy");
+	tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb");
+
+	signal(SIGINT, &signal_handler);
+	signal(SIGABRT, &signal_handler);
+	signal(SIGUSR1, &signal_handler);
+	signal(SIGUSR2, &signal_handler);
+	signal(SIGPIPE, SIG_IGN);
+
+	log_init(&log_info);
+	stderr_target = log_target_create_stderr();
+	log_add_target(stderr_target);
+	log_set_all_filter(stderr_target, 1);
+
+	vty_info.copyright = openbsc_copyright;
+	vty_init(&vty_info);
+	logging_vty_add_cmds();
+	gbproxy_vty_init();
+
+	handle_options(argc, argv);
+
+	rate_ctr_init(tall_bsc_ctx);
+
+	rc = telnet_init(tall_bsc_ctx, &dummy_network, 4246);
+	if (rc < 0)
+		exit(1);
+
+	bssgp_nsi = gprs_ns_instantiate(&proxy_ns_cb);
+	if (!bssgp_nsi) {
+		LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
+		exit(1);
+	}
+	gbcfg.nsi = bssgp_nsi;
+	gprs_ns_vty_init(bssgp_nsi);
+	register_signal_handler(SS_NS, &gbprox_signal, NULL);
+
+	rc = gbproxy_parse_config(config_file, &gbcfg);
+	if (rc < 0) {
+		LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n");
+		exit(2);
+	}
+
+	if (!nsvc_by_nsei(gbcfg.nsi, gbcfg.nsip_sgsn_nsei)) {
+		LOGP(DGPRS, LOGL_FATAL, "You cannot proxy to NSEI %u "
+			"without creating that NSEI before\n",
+			gbcfg.nsip_sgsn_nsei);
+		exit(2);
+	}
+
+	rc = gprs_ns_nsip_listen(bssgp_nsi);
+	if (rc < 0) {
+		LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen on NSIP socket\n");
+		exit(2);
+	}
+
+	rc = gprs_ns_frgre_listen(bssgp_nsi);
+	if (rc < 0) {
+		LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen GRE "
+			"socket. Do you have CAP_NET_RAW?\n");
+		exit(2);
+	}
+
+	/* Reset all the persistent NS-VCs that we've read from the config */
+	gbprox_reset_persistent_nsvcs(bssgp_nsi);
+
+	while (1) {
+		rc = bsc_select_main(0);
+		if (rc < 0)
+			exit(3);
+	}
+
+	exit(0);
+}
diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c
new file mode 100644
index 0000000..7b6d2da
--- /dev/null
+++ b/openbsc/src/gprs/gb_proxy_vty.c
@@ -0,0 +1,105 @@
+/*
+ * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (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 <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <osmocore/talloc.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/gb_proxy.h>
+#include <openbsc/gprs_ns.h>
+#include <openbsc/vty.h>
+
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/vty.h>
+
+static struct gbproxy_config *g_cfg = NULL;
+
+/*
+ * vty code for mgcp below
+ */
+static struct cmd_node gbproxy_node = {
+	GBPROXY_NODE,
+	"%s(gbproxy)#",
+	1,
+};
+
+static int config_write_gbproxy(struct vty *vty)
+{
+	vty_out(vty, "gbproxy%s", VTY_NEWLINE);
+
+	vty_out(vty, " sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei,
+		VTY_NEWLINE);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_gbproxy,
+      cfg_gbproxy_cmd,
+      "gbproxy",
+      "Configure the Gb proxy")
+{
+	vty->node = GBPROXY_NODE;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nsip_sgsn_nsei,
+      cfg_nsip_sgsn_nsei_cmd,
+      "sgsn nsei <0-65534>",
+      "Set the NSEI to be used in the connection with the SGSN")
+{
+	unsigned int port = atoi(argv[0]);
+
+	g_cfg->nsip_sgsn_nsei = port;
+	return CMD_SUCCESS;
+}
+
+int gbproxy_vty_init(void)
+{
+	install_element_ve(&show_gbproxy_cmd);
+
+	install_element(CONFIG_NODE, &cfg_gbproxy_cmd);
+	install_node(&gbproxy_node, config_write_gbproxy);
+	install_default(GBPROXY_NODE);
+	install_element(GBPROXY_NODE, &ournode_exit_cmd);
+	install_element(GBPROXY_NODE, &ournode_end_cmd);
+	install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd);
+
+	return 0;
+}
+
+int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg)
+{
+	int rc;
+
+	g_cfg = cfg;
+	rc = vty_read_config_file(config_file, NULL);
+	if (rc < 0) {
+		fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
+		return rc;
+	}
+
+	return 0;
+}
+
diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c
new file mode 100644
index 0000000..0ec873c
--- /dev/null
+++ b/openbsc/src/gprs/gprs_bssgp.c
@@ -0,0 +1,852 @@
+/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */
+
+/* (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.
+ *
+ * TODO:
+ *  o  properly count incoming BVC-RESET packets in counter group
+ *  o  set log context as early as possible for outgoing packets
+ */
+
+#include <errno.h>
+#include <stdint.h>
+
+#include <netinet/in.h>
+
+#include <osmocore/msgb.h>
+#include <osmocore/tlv.h>
+#include <osmocore/talloc.h>
+#include <osmocore/rate_ctr.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/gsm_04_08_gprs.h>
+#include <openbsc/gprs_bssgp.h>
+#include <openbsc/gprs_llc.h>
+#include <openbsc/gprs_ns.h>
+#include <openbsc/gprs_sgsn.h>
+#include <openbsc/gprs_gmm.h>
+
+void *bssgp_tall_ctx = NULL;
+
+#define BVC_F_BLOCKED	0x0001
+
+enum bssgp_ctr {
+	BSSGP_CTR_PKTS_IN,
+	BSSGP_CTR_PKTS_OUT,
+	BSSGP_CTR_BYTES_IN,
+	BSSGP_CTR_BYTES_OUT,
+	BSSGP_CTR_BLOCKED,
+	BSSGP_CTR_DISCARDED,
+};
+
+static const struct rate_ctr_desc bssgp_ctr_description[] = {
+	{ "packets.in",	"Packets at BSSGP Level ( In)" },
+	{ "packets.out","Packets at BSSGP Level (Out)" },
+	{ "bytes.in",	"Bytes at BSSGP Level   ( In)" },
+	{ "bytes.out",	"Bytes at BSSGP Level   (Out)" },
+	{ "blocked",	"BVC Blocking count" },
+	{ "discarded",	"BVC LLC Discarded count" },
+};
+
+static const struct rate_ctr_group_desc bssgp_ctrg_desc = {
+	.group_name_prefix = "bssgp.bss_ctx",
+	.group_description = "BSSGP Peer Statistics",
+	.num_ctr = ARRAY_SIZE(bssgp_ctr_description),
+	.ctr_desc = bssgp_ctr_description,
+};
+
+LLIST_HEAD(bssgp_bvc_ctxts);
+
+/* Find a BTS Context based on parsed RA ID and Cell ID */
+struct bssgp_bvc_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid)
+{
+	struct bssgp_bvc_ctx *bctx;
+
+	llist_for_each_entry(bctx, &bssgp_bvc_ctxts, list) {
+		if (!memcmp(&bctx->ra_id, raid, sizeof(bctx->ra_id)) &&
+		    bctx->cell_id == cid)
+			return bctx;
+	}
+	return NULL;
+}
+
+/* Find a BTS context based on BVCI+NSEI tuple */
+struct bssgp_bvc_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei)
+{
+	struct bssgp_bvc_ctx *bctx;
+
+	llist_for_each_entry(bctx, &bssgp_bvc_ctxts, list) {
+		if (bctx->nsei == nsei && bctx->bvci == bvci)
+			return bctx;
+	}
+	return NULL;
+}
+
+struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei)
+{
+	struct bssgp_bvc_ctx *ctx;
+
+	ctx = talloc_zero(bssgp_tall_ctx, struct bssgp_bvc_ctx);
+	if (!ctx)
+		return NULL;
+	ctx->bvci = bvci;
+	ctx->nsei = nsei;
+	/* FIXME: BVCI is not unique, only BVCI+NSEI ?!? */
+	ctx->ctrg = rate_ctr_group_alloc(ctx, &bssgp_ctrg_desc, bvci);
+
+	llist_add(&ctx->list, &bssgp_bvc_ctxts);
+
+	return ctx;
+}
+
+/* Chapter 10.4.5: Flow Control BVC ACK */
+static int bssgp_tx_fc_bvc_ack(uint16_t nsei, uint8_t tag, uint16_t ns_bvci)
+{
+	struct msgb *msg = bssgp_msgb_alloc();
+	struct bssgp_normal_hdr *bgph =
+			(struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+
+	msgb_nsei(msg) = nsei;
+	msgb_bvci(msg) = ns_bvci;
+
+	bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK;
+	msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag);
+
+	return gprs_ns_sendmsg(bssgp_nsi, msg);
+}
+
+/* 10.3.7 SUSPEND-ACK PDU */
+int bssgp_tx_suspend_ack(uint16_t nsei, uint32_t tlli,
+			 const struct gprs_ra_id *ra_id, uint8_t suspend_ref)
+{
+	struct msgb *msg = bssgp_msgb_alloc();
+	struct bssgp_normal_hdr *bgph =
+		(struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+	uint32_t _tlli;
+	uint8_t ra[6];
+
+	msgb_nsei(msg) = nsei;
+	msgb_bvci(msg) = 0; /* Signalling */
+	bgph->pdu_type = BSSGP_PDUT_SUSPEND_ACK;
+
+	_tlli = htonl(tlli);
+	msgb_tvlv_put(msg, BSSGP_IE_TLLI, 4, (uint8_t *) &_tlli);
+	gsm48_construct_ra(ra, ra_id);
+	msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra);
+	msgb_tvlv_put(msg, BSSGP_IE_SUSPEND_REF_NR, 1, &suspend_ref);
+
+	return gprs_ns_sendmsg(bssgp_nsi, msg);
+}
+
+/* 10.3.8 SUSPEND-NACK PDU */
+int bssgp_tx_suspend_nack(uint16_t nsei, uint32_t tlli,
+			  uint8_t *cause)
+{
+	struct msgb *msg = bssgp_msgb_alloc();
+	struct bssgp_normal_hdr *bgph =
+		(struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+	uint32_t _tlli;
+
+	msgb_nsei(msg) = nsei;
+	msgb_bvci(msg) = 0; /* Signalling */
+	bgph->pdu_type = BSSGP_PDUT_SUSPEND_NACK;
+
+	_tlli = htonl(tlli);
+	msgb_tvlv_put(msg, BSSGP_IE_TLLI, 4, (uint8_t *) &_tlli);
+	if (cause)
+		msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, cause);
+
+	return gprs_ns_sendmsg(bssgp_nsi, msg);
+}
+
+/* 10.3.10 RESUME-ACK PDU */
+int bssgp_tx_resume_ack(uint16_t nsei, uint32_t tlli,
+			const struct gprs_ra_id *ra_id)
+{
+	struct msgb *msg = bssgp_msgb_alloc();
+	struct bssgp_normal_hdr *bgph =
+		(struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+	uint32_t _tlli;
+	uint8_t ra[6];
+
+	msgb_nsei(msg) = nsei;
+	msgb_bvci(msg) = 0; /* Signalling */
+	bgph->pdu_type = BSSGP_PDUT_RESUME_ACK;
+
+	_tlli = htonl(tlli);
+	msgb_tvlv_put(msg, BSSGP_IE_TLLI, 4, (uint8_t *) &_tlli);
+	gsm48_construct_ra(ra, ra_id);
+	msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra);
+
+	return gprs_ns_sendmsg(bssgp_nsi, msg);
+}
+
+/* 10.3.11 RESUME-NACK PDU */
+int bssgp_tx_resume_nack(uint16_t nsei, uint32_t tlli,
+			 const struct gprs_ra_id *ra_id, uint8_t *cause)
+{
+	struct msgb *msg = bssgp_msgb_alloc();
+	struct bssgp_normal_hdr *bgph =
+		(struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+	uint32_t _tlli;
+	uint8_t ra[6];
+
+	msgb_nsei(msg) = nsei;
+	msgb_bvci(msg) = 0; /* Signalling */
+	bgph->pdu_type = BSSGP_PDUT_SUSPEND_NACK;
+
+	_tlli = htonl(tlli);
+	msgb_tvlv_put(msg, BSSGP_IE_TLLI, 4, (uint8_t *) &_tlli);
+	gsm48_construct_ra(ra, ra_id);
+	msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra);
+	if (cause)
+		msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, cause);
+
+	return gprs_ns_sendmsg(bssgp_nsi, msg);
+}
+
+uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf)
+{
+	/* 6 octets RAC */
+	gsm48_parse_ra(raid, buf);
+	/* 2 octets CID */
+	return ntohs(*(uint16_t *) (buf+6));
+}
+
+/* Chapter 8.4 BVC-Reset Procedure */
+static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp,	
+			      uint16_t ns_bvci)
+{
+	struct bssgp_bvc_ctx *bctx;
+	uint16_t nsei = msgb_nsei(msg);
+	uint16_t bvci;
+	int rc;
+
+	bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI));
+	DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx RESET cause=%s\n", bvci,
+		bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE)));
+
+	/* look-up or create the BTS context for this BVC */
+	bctx = btsctx_by_bvci_nsei(bvci, nsei);
+	if (!bctx)
+		bctx = btsctx_alloc(bvci, nsei);
+
+	/* As opposed to NS-VCs, BVCs are NOT blocked after RESET */
+	bctx->state &= ~BVC_S_BLOCKED;
+
+	/* When we receive a BVC-RESET PDU (at least of a PTP BVCI), the BSS
+	 * informs us about its RAC + Cell ID, so we can create a mapping */
+	if (bvci != 0 && bvci != 1) {
+		if (!TLVP_PRESENT(tp, BSSGP_IE_CELL_ID)) {
+			LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u RESET "
+				"missing mandatory IE\n", bvci);
+			return -EINVAL;
+		}
+		/* actually extract RAC / CID */
+		bctx->cell_id = bssgp_parse_cell_id(&bctx->ra_id,
+						TLVP_VAL(tp, BSSGP_IE_CELL_ID));
+		LOGP(DBSSGP, LOGL_NOTICE, "Cell %u-%u-%u-%u CI %u on BVCI %u\n",
+			bctx->ra_id.mcc, bctx->ra_id.mnc, bctx->ra_id.lac,
+			bctx->ra_id.rac, bctx->cell_id, bvci);
+	}
+
+	/* Acknowledge the RESET to the BTS */
+	rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK,
+				  nsei, bvci, ns_bvci);
+	return 0;
+}
+
+static int bssgp_rx_bvc_block(struct msgb *msg, struct tlv_parsed *tp)
+{
+	uint16_t bvci;
+	struct bssgp_bvc_ctx *ptp_ctx;
+
+	bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI));
+	if (bvci == BVCI_SIGNALLING) {
+		/* 8.3.2: Signalling BVC shall never be blocked */
+		LOGP(DBSSGP, LOGL_ERROR, "NSEI=%u/BVCI=%u "
+			"received block for signalling BVC!?!\n",
+			msgb_nsei(msg), msgb_bvci(msg));
+		return 0;
+	}
+
+	LOGP(DBSSGP, LOGL_INFO, "BSSGP BVCI=%u BVC-BLOCK\n", bvci);
+
+	ptp_ctx = btsctx_by_bvci_nsei(bvci, msgb_nsei(msg));
+	if (!ptp_ctx)
+		return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, &bvci, msg);
+
+	ptp_ctx->state |= BVC_S_BLOCKED;
+	rate_ctr_inc(&ptp_ctx->ctrg->ctr[BSSGP_CTR_BLOCKED]);
+
+	/* FIXME: Send NM_BVC_BLOCK.ind to NM */
+
+	/* We always acknowledge the BLOCKing */
+	return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, msgb_nsei(msg),
+				    bvci, msgb_bvci(msg));
+};
+
+static int bssgp_rx_bvc_unblock(struct msgb *msg, struct tlv_parsed *tp)
+{
+	uint16_t bvci;
+	struct bssgp_bvc_ctx *ptp_ctx;
+
+	bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI));
+	if (bvci == BVCI_SIGNALLING) {
+		/* 8.3.2: Signalling BVC shall never be blocked */
+		LOGP(DBSSGP, LOGL_ERROR, "NSEI=%u/BVCI=%u "
+			"received unblock for signalling BVC!?!\n",
+			msgb_nsei(msg), msgb_bvci(msg));
+		return 0;
+	}
+
+	DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx BVC-UNBLOCK\n", bvci);
+
+	ptp_ctx = btsctx_by_bvci_nsei(bvci, msgb_nsei(msg));
+	if (!ptp_ctx)
+		return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, &bvci, msg);
+
+	ptp_ctx->state &= ~BVC_S_BLOCKED;
+
+	/* FIXME: Send NM_BVC_UNBLOCK.ind to NM */
+
+	/* We always acknowledge the unBLOCKing */
+	return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, msgb_nsei(msg),
+				    bvci, msgb_bvci(msg));
+};
+
+/* Uplink unit-data */
+static int bssgp_rx_ul_ud(struct msgb *msg, struct tlv_parsed *tp,
+			  struct bssgp_bvc_ctx *ctx)
+{
+	struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);
+
+	/* extract TLLI and parse TLV IEs */
+	msgb_tlli(msg) = ntohl(budh->tlli);
+
+	DEBUGP(DBSSGP, "BSSGP TLLI=0x%08x UPLINK-UNITDATA\n", msgb_tlli(msg));
+
+	/* Cell ID and LLC_PDU are the only mandatory IE */
+	if (!TLVP_PRESENT(tp, BSSGP_IE_CELL_ID) ||
+	    !TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) {
+		LOGP(DBSSGP, LOGL_ERROR, "BSSGP TLLI=0x%08x Rx UL-UD "
+			"missing mandatory IE\n", msgb_tlli(msg));
+		return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
+	}
+
+	/* store pointer to LLC header and CELL ID in msgb->cb */
+	msgb_llch(msg) = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
+	msgb_bcid(msg) = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_CELL_ID);
+
+	return gprs_llc_rcvmsg(msg, tp);
+}
+
+static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp,
+			    struct bssgp_bvc_ctx *ctx)
+{
+	struct bssgp_normal_hdr *bgph =
+			(struct bssgp_normal_hdr *) msgb_bssgph(msg);
+	struct gprs_ra_id raid;
+	uint32_t tlli;
+	int rc;
+
+	if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) ||
+	    !TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
+		LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u Rx SUSPEND "
+			"missing mandatory IE\n", ctx->bvci);
+		return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
+	}
+
+	tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI));
+
+	DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=0x%08x Rx SUSPEND\n",
+		ctx->bvci, tlli);
+
+	gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));
+
+	/* Inform GMM about the SUSPEND request */
+	rc = gprs_gmm_rx_suspend(&raid, tlli);
+	if (rc < 0)
+		return bssgp_tx_suspend_nack(msgb_nsei(msg), tlli, NULL);
+
+	bssgp_tx_suspend_ack(msgb_nsei(msg), tlli, &raid, 0);
+
+	return 0;
+}
+
+static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp,
+			   struct bssgp_bvc_ctx *ctx)
+{
+	struct bssgp_normal_hdr *bgph =
+			(struct bssgp_normal_hdr *) msgb_bssgph(msg);
+	struct gprs_ra_id raid;
+	uint32_t tlli;
+	uint8_t suspend_ref;
+	int rc;
+
+	if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) ||
+	    !TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA) ||
+	    !TLVP_PRESENT(tp, BSSGP_IE_SUSPEND_REF_NR)) {
+		LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u Rx RESUME "
+			"missing mandatory IE\n", ctx->bvci);
+		return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
+	}
+
+	tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI));
+	suspend_ref = *TLVP_VAL(tp, BSSGP_IE_SUSPEND_REF_NR);
+
+	DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=0x%08x RESUME\n", ctx->bvci, tlli);
+
+	gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));
+
+	/* Inform GMM about the RESUME request */
+	rc = gprs_gmm_rx_resume(&raid, tlli, suspend_ref);
+	if (rc < 0)
+		return bssgp_tx_resume_nack(msgb_nsei(msg), tlli, &raid,
+					    NULL);
+
+	bssgp_tx_resume_ack(msgb_nsei(msg), tlli, &raid);
+	return 0;
+}
+
+
+static int bssgp_rx_llc_disc(struct msgb *msg, struct tlv_parsed *tp,
+			     struct bssgp_bvc_ctx *ctx)
+{
+	uint32_t tlli;
+
+	if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) ||
+	    !TLVP_PRESENT(tp, BSSGP_IE_LLC_FRAMES_DISCARDED) ||
+	    !TLVP_PRESENT(tp, BSSGP_IE_BVCI) ||
+	    !TLVP_PRESENT(tp, BSSGP_IE_NUM_OCT_AFF)) {
+		LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u Rx LLC DISCARDED "
+			"missing mandatory IE\n", ctx->bvci);
+	}
+
+	tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI));
+
+	DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=%u LLC DISCARDED\n",
+		ctx->bvci, tlli);
+
+	rate_ctr_inc(&ctx->ctrg->ctr[BSSGP_CTR_DISCARDED]);
+
+	/* FIXME: send NM_LLC_DISCARDED to NM */
+	return 0;
+}
+
+static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp,
+			   struct bssgp_bvc_ctx *bctx)
+{
+
+	DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx Flow Control BVC\n",
+		bctx->bvci);
+
+	if (!TLVP_PRESENT(tp, BSSGP_IE_TAG) ||
+	    !TLVP_PRESENT(tp, BSSGP_IE_BVC_BUCKET_SIZE) ||
+	    !TLVP_PRESENT(tp, BSSGP_IE_BUCKET_LEAK_RATE) ||
+	    !TLVP_PRESENT(tp, BSSGP_IE_BMAX_DEFAULT_MS) ||
+	    !TLVP_PRESENT(tp, BSSGP_IE_R_DEFAULT_MS)) {
+		LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u Rx FC BVC "
+			"missing mandatory IE\n", bctx->bvci);
+		return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
+	}
+
+	/* FIXME: actually implement flow control */
+
+	/* Send FLOW_CONTROL_BVC_ACK */
+	return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG),
+				   msgb_bvci(msg));
+}
+
+/* Receive a BSSGP PDU from a BSS on a PTP BVCI */
+static int gprs_bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp,
+			     struct bssgp_bvc_ctx *bctx)
+{
+	struct bssgp_normal_hdr *bgph =
+			(struct bssgp_normal_hdr *) msgb_bssgph(msg);
+	uint8_t pdu_type = bgph->pdu_type;
+	int rc = 0;
+
+	/* If traffic is received on a BVC that is marked as blocked, the
+	 * received PDU shall not be accepted and a STATUS PDU (Cause value:
+	 * BVC Blocked) shall be sent to the peer entity on the signalling BVC */
+	if (bctx->state & BVC_S_BLOCKED && pdu_type != BSSGP_PDUT_STATUS) {
+		uint16_t bvci = msgb_bvci(msg);
+		return bssgp_tx_status(BSSGP_CAUSE_BVCI_BLOCKED, &bvci, msg);
+	}
+
+	switch (pdu_type) {
+	case BSSGP_PDUT_UL_UNITDATA:
+		/* some LLC data from the MS */
+		rc = bssgp_rx_ul_ud(msg, tp, bctx);
+		break;
+	case BSSGP_PDUT_RA_CAPABILITY:
+		/* BSS requests RA capability or IMSI */
+		DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx RA CAPABILITY UPDATE\n",
+			bctx->bvci);
+		/* FIXME: send GMM_RA_CAPABILITY_UPDATE.ind to GMM */
+		/* FIXME: send RA_CAPA_UPDATE_ACK */
+		break;
+	case BSSGP_PDUT_RADIO_STATUS:
+		DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx RADIO STATUS\n", bctx->bvci);
+		/* BSS informs us of some exception */
+		/* FIXME: send GMM_RADIO_STATUS.ind to GMM */
+		break;
+	case BSSGP_PDUT_FLOW_CONTROL_BVC:
+		/* BSS informs us of available bandwidth in Gb interface */
+		rc = bssgp_rx_fc_bvc(msg, tp, bctx);
+		break;
+	case BSSGP_PDUT_FLOW_CONTROL_MS:
+		/* BSS informs us of available bandwidth to one MS */
+		DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx Flow Control MS\n",
+			bctx->bvci);
+		/* FIXME: actually implement flow control */
+		/* FIXME: Send FLOW_CONTROL_MS_ACK */
+		break;
+	case BSSGP_PDUT_STATUS:
+		/* Some exception has occurred */
+		/* FIXME: send NM_STATUS.ind to NM */
+	case BSSGP_PDUT_DOWNLOAD_BSS_PFC:
+	case BSSGP_PDUT_CREATE_BSS_PFC_ACK:
+	case BSSGP_PDUT_CREATE_BSS_PFC_NACK:
+	case BSSGP_PDUT_MODIFY_BSS_PFC:
+	case BSSGP_PDUT_DELETE_BSS_PFC_ACK:
+		DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx PDU type 0x%02x not [yet] "
+			"implemented\n", bctx->bvci, pdu_type);
+		rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg);
+		break;
+	/* those only exist in the SGSN -> BSS direction */
+	case BSSGP_PDUT_DL_UNITDATA:
+	case BSSGP_PDUT_PAGING_PS:
+	case BSSGP_PDUT_PAGING_CS:
+	case BSSGP_PDUT_RA_CAPA_UPDATE_ACK:
+	case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK:
+	case BSSGP_PDUT_FLOW_CONTROL_MS_ACK:
+		DEBUGP(DBSSGP, "BSSGP BVCI=%u PDU type 0x%02x only exists "
+			"in DL\n", bctx->bvci, pdu_type);
+		bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
+		rc = -EINVAL;
+		break;
+	default:
+		DEBUGP(DBSSGP, "BSSGP BVCI=%u PDU type 0x%02x unknown\n",
+			bctx->bvci, pdu_type);
+		rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
+		break;
+	}
+
+	return rc;
+}
+
+/* Receive a BSSGP PDU from a BSS on a SIGNALLING BVCI */
+static int gprs_bssgp_rx_sign(struct msgb *msg, struct tlv_parsed *tp,
+				struct bssgp_bvc_ctx *bctx)
+{
+	struct bssgp_normal_hdr *bgph =
+			(struct bssgp_normal_hdr *) msgb_bssgph(msg);
+	uint8_t pdu_type = bgph->pdu_type;
+	int rc = 0;
+	uint16_t ns_bvci = msgb_bvci(msg);
+	uint16_t bvci;
+
+	switch (bgph->pdu_type) {
+	case BSSGP_PDUT_SUSPEND:
+		/* MS wants to suspend */
+		rc = bssgp_rx_suspend(msg, tp, bctx);
+		break;
+	case BSSGP_PDUT_RESUME:
+		/* MS wants to resume */
+		rc = bssgp_rx_resume(msg, tp, bctx);
+		break;
+	case BSSGP_PDUT_FLUSH_LL_ACK:
+		/* BSS informs us it has performed LL FLUSH */
+		DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx FLUSH LL ACK\n", bctx->bvci);
+		/* FIXME: send NM_FLUSH_LL.res to NM */
+		break;
+	case BSSGP_PDUT_LLC_DISCARD:
+		/* BSS informs that some LLC PDU's have been discarded */
+		rc = bssgp_rx_llc_disc(msg, tp, bctx);
+		break;
+	case BSSGP_PDUT_BVC_BLOCK:
+		/* BSS tells us that BVC shall be blocked */
+		if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI) ||
+		    !TLVP_PRESENT(tp, BSSGP_IE_CAUSE)) {
+			LOGP(DBSSGP, LOGL_ERROR, "BSSGP Rx BVC-BLOCK "
+				"missing mandatory IE\n");
+			goto err_mand_ie;
+		}
+		rc = bssgp_rx_bvc_block(msg, tp);
+		break;
+	case BSSGP_PDUT_BVC_UNBLOCK:
+		/* BSS tells us that BVC shall be unblocked */
+		if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
+			LOGP(DBSSGP, LOGL_ERROR, "BSSGP Rx BVC-UNBLOCK "
+				"missing mandatory IE\n");
+			goto err_mand_ie;
+		}
+		rc = bssgp_rx_bvc_unblock(msg, tp);
+		break;
+	case BSSGP_PDUT_BVC_RESET:
+		/* BSS tells us that BVC init is required */
+		if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI) ||
+		    !TLVP_PRESENT(tp, BSSGP_IE_CAUSE)) {
+			LOGP(DBSSGP, LOGL_ERROR, "BSSGP Rx BVC-RESET "
+				"missing mandatory IE\n");
+			goto err_mand_ie;
+		}
+		rc = bssgp_rx_bvc_reset(msg, tp, ns_bvci);
+		break;
+	case BSSGP_PDUT_STATUS:
+		/* Some exception has occurred */
+		DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx BVC STATUS\n", bctx->bvci);
+		/* FIXME: send NM_STATUS.ind to NM */
+		break;
+	/* those only exist in the SGSN -> BSS direction */
+	case BSSGP_PDUT_PAGING_PS:
+	case BSSGP_PDUT_PAGING_CS:
+	case BSSGP_PDUT_SUSPEND_ACK:
+	case BSSGP_PDUT_SUSPEND_NACK:
+	case BSSGP_PDUT_RESUME_ACK:
+	case BSSGP_PDUT_RESUME_NACK:
+	case BSSGP_PDUT_FLUSH_LL:
+	case BSSGP_PDUT_BVC_BLOCK_ACK:
+	case BSSGP_PDUT_BVC_UNBLOCK_ACK:
+	case BSSGP_PDUT_SGSN_INVOKE_TRACE:
+		DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx PDU type 0x%02x only exists "
+			"in DL\n", bctx->bvci, pdu_type);
+		bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
+		rc = -EINVAL;
+		break;
+	default:
+		DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx PDU type 0x%02x unknown\n",
+			bctx->bvci, pdu_type);
+		rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
+		break;
+	}
+
+	return rc;
+err_mand_ie:
+	return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
+}
+
+/* We expect msgb_bssgph() to point to the BSSGP header */
+int gprs_bssgp_rcvmsg(struct msgb *msg)
+{
+	struct bssgp_normal_hdr *bgph =
+			(struct bssgp_normal_hdr *) msgb_bssgph(msg);
+	struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);
+	struct tlv_parsed tp;
+	struct bssgp_bvc_ctx *bctx;
+	uint8_t pdu_type = bgph->pdu_type;
+	uint16_t ns_bvci = msgb_bvci(msg);
+	int data_len;
+	int rc = 0;
+
+	/* Identifiers from DOWN: NSEI, BVCI (both in msg->cb) */
+
+	/* UNITDATA BSSGP headers have TLLI in front */
+	if (pdu_type != BSSGP_PDUT_UL_UNITDATA &&
+	    pdu_type != BSSGP_PDUT_DL_UNITDATA) {
+		data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
+		rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
+	} else {
+		data_len = msgb_bssgp_len(msg) - sizeof(*budh);
+		rc = bssgp_tlv_parse(&tp, budh->data, data_len);
+	}
+
+	/* look-up or create the BTS context for this BVC */
+	bctx = btsctx_by_bvci_nsei(ns_bvci, msgb_nsei(msg));
+	/* Only a RESET PDU can create a new BVC context */
+	if (!bctx && pdu_type != BSSGP_PDUT_BVC_RESET) {
+		LOGP(DBSSGP, LOGL_NOTICE, "NSEI=%u/BVCI=%u Rejecting PDU "
+			"type %u for unknown BVCI\n", msgb_nsei(msg), ns_bvci,
+			pdu_type);
+		return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, NULL, msg);
+	}
+
+	if (bctx) {
+		log_set_context(BSC_CTX_BVC, bctx);
+		rate_ctr_inc(&bctx->ctrg->ctr[BSSGP_CTR_PKTS_IN]);
+		rate_ctr_add(&bctx->ctrg->ctr[BSSGP_CTR_BYTES_IN],
+			     msgb_bssgp_len(msg));
+	}
+
+	if (ns_bvci == BVCI_SIGNALLING)
+		rc = gprs_bssgp_rx_sign(msg, &tp, bctx);
+	else if (ns_bvci == BVCI_PTM)
+		rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg);
+	else
+		rc = gprs_bssgp_rx_ptp(msg, &tp, bctx);
+
+	return rc;
+}
+
+/* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU
+ * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */
+int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx)
+{
+	struct bssgp_bvc_ctx *bctx;
+	struct bssgp_ud_hdr *budh;
+	uint8_t llc_pdu_tlv_hdr_len = 2;
+	uint8_t *llc_pdu_tlv, *qos_profile;
+	uint16_t pdu_lifetime = 1000; /* centi-seconds */
+	uint8_t qos_profile_default[3] = { 0x00, 0x00, 0x20 };
+	uint16_t msg_len = msg->len;
+	uint16_t bvci = msgb_bvci(msg);
+	uint16_t nsei = msgb_nsei(msg);
+	uint16_t drx_params;
+
+	/* Identifiers from UP: TLLI, BVCI, NSEI (all in msgb->cb) */
+	if (bvci <= BVCI_PTM ) {
+		LOGP(DBSSGP, LOGL_ERROR, "Cannot send DL-UD to BVCI %u\n",
+			bvci);
+		return -EINVAL;
+	}
+
+	bctx = btsctx_by_bvci_nsei(bvci, nsei);
+	if (!bctx) {
+		/* FIXME: don't simply create missing context, but reject message */
+		bctx = btsctx_alloc(bvci, nsei);
+	}
+
+	if (msg->len > TVLV_MAX_ONEBYTE)
+		llc_pdu_tlv_hdr_len += 1;
+
+	/* prepend the tag and length of the LLC-PDU TLV */
+	llc_pdu_tlv = msgb_push(msg, llc_pdu_tlv_hdr_len);
+	llc_pdu_tlv[0] = BSSGP_IE_LLC_PDU;
+	if (llc_pdu_tlv_hdr_len > 2) {
+		llc_pdu_tlv[1] = msg_len >> 8;
+		llc_pdu_tlv[2] = msg_len & 0xff;
+	} else {
+		llc_pdu_tlv[1] = msg_len & 0x7f;
+		llc_pdu_tlv[1] |= 0x80;
+	}
+
+	/* FIXME: optional elements: Alignment, UTRAN CCO, LSA, PFI */
+
+	if (mmctx) {
+		/* Old TLLI to help BSS map from old->new */
+#if 0
+		if (mmctx->tlli_old)
+			msgb_tvlv_push(msg, BSSGP_IE_TLLI, 4, htonl(*tlli_old));
+#endif
+
+		/* IMSI */
+		if (strlen(mmctx->imsi)) {
+			uint8_t mi[10];
+			int imsi_len = gsm48_generate_mid_from_imsi(mi, mmctx->imsi);
+			if (imsi_len > 2)
+				msgb_tvlv_push(msg, BSSGP_IE_IMSI,
+							imsi_len-2, mi+2);
+		}
+
+		/* DRX parameters */
+		drx_params = htons(mmctx->drx_parms);
+		msgb_tvlv_push(msg, BSSGP_IE_DRX_PARAMS, 2,
+				(uint8_t *) &drx_params);
+
+		/* FIXME: Priority */
+
+		/* MS Radio Access Capability */
+		if (mmctx->ms_radio_access_capa.len)
+			msgb_tvlv_push(msg, BSSGP_IE_MS_RADIO_ACCESS_CAP,
+					mmctx->ms_radio_access_capa.len,
+					mmctx->ms_radio_access_capa.buf);
+	}
+
+	/* prepend the pdu lifetime */
+	pdu_lifetime = htons(pdu_lifetime);
+	msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (uint8_t *)&pdu_lifetime);
+
+	/* prepend the QoS profile, TLLI and pdu type */
+	budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh));
+	memcpy(budh->qos_profile, qos_profile_default, sizeof(qos_profile_default));
+	budh->tlli = htonl(msgb_tlli(msg));
+	budh->pdu_type = BSSGP_PDUT_DL_UNITDATA;
+
+	rate_ctr_inc(&bctx->ctrg->ctr[BSSGP_CTR_PKTS_OUT]);
+	rate_ctr_add(&bctx->ctrg->ctr[BSSGP_CTR_BYTES_OUT], msg->len);
+
+	/* Identifiers down: BVCI, NSEI (in msgb->cb) */
+
+	return gprs_ns_sendmsg(bssgp_nsi, msg);
+}
+
+/* Send a single GMM-PAGING.req to a given NSEI/NS-BVCI */
+int gprs_bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci,
+			 struct bssgp_paging_info *pinfo)
+{
+	struct msgb *msg = bssgp_msgb_alloc();
+	struct bssgp_normal_hdr *bgph =
+			(struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+	uint16_t drx_params = htons(pinfo->drx_params);
+	uint8_t mi[10];
+	int imsi_len = gsm48_generate_mid_from_imsi(mi, pinfo->imsi);
+	uint8_t ra[6];
+
+	if (imsi_len < 2)
+		return -EINVAL;
+
+	msgb_nsei(msg) = nsei;
+	msgb_bvci(msg) = ns_bvci;
+
+	if (pinfo->mode == BSSGP_PAGING_PS)
+		bgph->pdu_type = BSSGP_PDUT_PAGING_PS;
+	else
+		bgph->pdu_type = BSSGP_PDUT_PAGING_CS;
+	/* IMSI */
+	msgb_tvlv_put(msg, BSSGP_IE_IMSI, imsi_len-2, mi+2);
+	/* DRX Parameters */
+	msgb_tvlv_put(msg, BSSGP_IE_DRX_PARAMS, 2,
+			(uint8_t *) &drx_params);
+	/* Scope */
+	switch (pinfo->scope) {
+	case BSSGP_PAGING_BSS_AREA:
+		{
+			uint8_t null = 0;
+			msgb_tvlv_put(msg, BSSGP_IE_BSS_AREA_ID, 1, &null);
+		}
+		break;
+	case BSSGP_PAGING_LOCATION_AREA:
+		gsm48_construct_ra(ra, &pinfo->raid);
+		msgb_tvlv_put(msg, BSSGP_IE_LOCATION_AREA, 4, ra);
+		break;
+	case BSSGP_PAGING_ROUTEING_AREA:
+		gsm48_construct_ra(ra, &pinfo->raid);
+		msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra);
+		break;
+	case BSSGP_PAGING_BVCI:
+		{
+			uint16_t bvci = htons(pinfo->bvci);
+			msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *)&bvci);
+		}
+		break;
+	}
+	/* QoS profile mandatory for PS */
+	if (pinfo->mode == BSSGP_PAGING_PS)
+		msgb_tvlv_put(msg, BSSGP_IE_QOS_PROFILE, 3, pinfo->qos);
+
+	/* Optional (P-)TMSI */
+	if (pinfo->ptmsi) {
+		uint32_t ptmsi = htonl(*pinfo->ptmsi);
+		msgb_tvlv_put(msg, BSSGP_IE_TMSI, 4, (uint8_t *) &ptmsi);
+	}
+
+	return gprs_ns_sendmsg(bssgp_nsi, msg);
+}
diff --git a/openbsc/src/gprs/gprs_bssgp_util.c b/openbsc/src/gprs/gprs_bssgp_util.c
new file mode 100644
index 0000000..e760252
--- /dev/null
+++ b/openbsc/src/gprs/gprs_bssgp_util.c
@@ -0,0 +1,120 @@
+/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */
+
+/* (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 <errno.h>
+#include <stdint.h>
+
+#include <netinet/in.h>
+
+#include <osmocore/msgb.h>
+#include <osmocore/tlv.h>
+#include <osmocore/talloc.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/gprs_bssgp.h>
+#include <openbsc/gprs_ns.h>
+
+struct gprs_ns_inst *bssgp_nsi;
+
+/* BSSGP Protocol specific, not implementation specific */
+/* FIXME: This needs to go into libosmocore after finished */
+
+/* Chapter 11.3.9 / Table 11.10: Cause coding */
+static const struct value_string bssgp_cause_strings[] = {
+	{ BSSGP_CAUSE_PROC_OVERLOAD,	"Processor overload" },
+	{ BSSGP_CAUSE_EQUIP_FAIL,	"Equipment Failure" },
+	{ BSSGP_CAUSE_TRASIT_NET_FAIL,	"Transit netowkr service failure" },
+	{ BSSGP_CAUSE_CAPA_GREATER_0KPBS,"Transmission capacity modified" },
+	{ BSSGP_CAUSE_UNKNOWN_MS,	"Unknown MS" },
+	{ BSSGP_CAUSE_UNKNOWN_BVCI,	"Unknown BVCI" },
+	{ BSSGP_CAUSE_CELL_TRAF_CONG,	"Cell traffic congestion" },
+	{ BSSGP_CAUSE_SGSN_CONG,	"SGSN congestion" },
+	{ BSSGP_CAUSE_OML_INTERV,	"O&M intervention" },
+	{ BSSGP_CAUSE_BVCI_BLOCKED,	"BVCI blocked" },
+	{ BSSGP_CAUSE_PFC_CREATE_FAIL,	"PFC create failure" },
+	{ BSSGP_CAUSE_SEM_INCORR_PDU,	"Semantically incorrect PDU" },
+	{ BSSGP_CAUSE_INV_MAND_INF,	"Invalid mandatory information" },
+	{ BSSGP_CAUSE_MISSING_MAND_IE,	"Missing mandatory IE" },
+	{ BSSGP_CAUSE_MISSING_COND_IE,	"Missing conditional IE" },
+	{ BSSGP_CAUSE_UNEXP_COND_IE,	"Unexpected conditional IE" },
+	{ BSSGP_CAUSE_COND_IE_ERR,	"Conditional IE error" },
+	{ BSSGP_CAUSE_PDU_INCOMP_STATE,	"PDU incompatible with protocol state" },
+	{ BSSGP_CAUSE_PROTO_ERR_UNSPEC,	"Protocol error - unspecified" },
+	{ BSSGP_CAUSE_PDU_INCOMP_FEAT, 	"PDU not compatible with feature set" },
+	{ 0, NULL },
+};
+
+const char *bssgp_cause_str(enum gprs_bssgp_cause cause)
+{
+	return get_value_string(bssgp_cause_strings, cause);
+}
+
+
+struct msgb *bssgp_msgb_alloc(void)
+{
+	return msgb_alloc_headroom(4096, 128, "BSSGP");
+}
+
+/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */
+int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei,
+			 uint16_t bvci, uint16_t ns_bvci)
+{
+	struct msgb *msg = bssgp_msgb_alloc();
+	struct bssgp_normal_hdr *bgph =
+			(struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+	uint16_t _bvci;
+
+	msgb_nsei(msg) = nsei;
+	msgb_bvci(msg) = ns_bvci;
+
+	bgph->pdu_type = pdu_type;
+	_bvci = htons(bvci);
+	msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);
+
+	return gprs_ns_sendmsg(bssgp_nsi, msg);
+}
+
+/* Chapter 10.4.14: Status */
+int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg)
+{
+	struct msgb *msg = bssgp_msgb_alloc();
+	struct bssgp_normal_hdr *bgph =
+			(struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+
+	LOGP(DBSSGP, LOGL_NOTICE, "BSSGP BVCI=%u Tx STATUS, cause=%s\n",
+		bvci ? *bvci : 0, bssgp_cause_str(cause));
+	msgb_nsei(msg) = msgb_nsei(orig_msg);
+	msgb_bvci(msg) = 0;
+
+	bgph->pdu_type = BSSGP_PDUT_STATUS;
+	msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause);
+	if (bvci) {
+		uint16_t _bvci = htons(*bvci);
+		msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);
+	}
+	if (orig_msg)
+		msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR,
+			      msgb_bssgp_len(orig_msg), msgb_bssgph(orig_msg));
+
+	return gprs_ns_sendmsg(bssgp_nsi, msg);
+}
diff --git a/openbsc/src/gprs/gprs_bssgp_vty.c b/openbsc/src/gprs/gprs_bssgp_vty.c
new file mode 100644
index 0000000..dc1f65c
--- /dev/null
+++ b/openbsc/src/gprs/gprs_bssgp_vty.c
@@ -0,0 +1,178 @@
+/* VTY interface for our GPRS BSS Gateway Protocol (BSSGP) implementation */
+
+/* (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 <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <arpa/inet.h>
+
+#include <openbsc/gsm_data.h>
+#include <osmocore/msgb.h>
+#include <osmocore/tlv.h>
+#include <osmocore/talloc.h>
+#include <osmocore/select.h>
+#include <osmocore/rate_ctr.h>
+#include <openbsc/debug.h>
+#include <openbsc/signal.h>
+#include <openbsc/gprs_ns.h>
+#include <openbsc/gprs_bssgp.h>
+#include <openbsc/vty.h>
+
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/logging.h>
+#include <osmocom/vty/telnet_interface.h>
+
+/* FIXME: this should go to some common file as it is copied
+ * in vty_interface.c of the BSC */
+static const struct value_string gprs_bssgp_timer_strs[] = {
+	{ 0, NULL }
+};
+
+static struct cmd_node bssgp_node = {
+	BSSGP_NODE,
+	"%s(bssgp)#",
+	1,
+};
+
+static int config_write_bssgp(struct vty *vty)
+{
+	vty_out(vty, "bssgp%s", VTY_NEWLINE);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bssgp, cfg_bssgp_cmd,
+      "bssgp",
+      "Configure the GPRS BSS Gateway Protocol")
+{
+	vty->node = BSSGP_NODE;
+	return CMD_SUCCESS;
+}
+
+static void dump_bvc(struct vty *vty, struct bssgp_bvc_ctx *bvc, int stats)
+{
+	vty_out(vty, "NSEI %5u, BVCI %5u, RA-ID: %u-%u-%u-%u, CID: %u, "
+		"STATE: %s%s", bvc->nsei, bvc->bvci, bvc->ra_id.mcc,
+		bvc->ra_id.mnc, bvc->ra_id.lac, bvc->ra_id.rac, bvc->cell_id,
+		bvc->state & BVC_S_BLOCKED ? "BLOCKED" : "UNBLOCKED",
+		VTY_NEWLINE);
+	if (stats)
+		vty_out_rate_ctr_group(vty, " ", bvc->ctrg);
+}
+
+static void dump_bssgp(struct vty *vty, int stats)
+{
+	struct bssgp_bvc_ctx *bvc;
+
+	llist_for_each_entry(bvc, &bssgp_bvc_ctxts, list) {
+		dump_bvc(vty, bvc, stats);
+	}
+}
+
+#define BSSGP_STR "Show information about the BSSGP protocol\n"
+
+DEFUN(show_bssgp, show_bssgp_cmd, "show bssgp",
+	SHOW_STR BSSGP_STR)
+{
+	dump_bssgp(vty, 0);
+	return CMD_SUCCESS;
+}
+
+DEFUN(show_bssgp_stats, show_bssgp_stats_cmd, "show bssgp stats",
+	SHOW_STR BSSGP_STR
+	"Include statistics\n")
+{
+	dump_bssgp(vty, 1);
+	return CMD_SUCCESS;
+}
+
+DEFUN(show_bvc, show_bvc_cmd, "show bssgp nsei <0-65535> [stats]",
+	SHOW_STR BSSGP_STR
+	"Show all BVCs on one NSE\n"
+	"The NSEI\n" "Include Statistics\n")
+{
+	struct bssgp_bvc_ctx *bvc;
+	uint16_t nsei = atoi(argv[1]);
+	int show_stats = 0;
+
+	if (argc >= 2)
+		show_stats = 1;
+
+	llist_for_each_entry(bvc, &bssgp_bvc_ctxts, list) {
+		if (bvc->nsei != nsei)
+			continue;
+		dump_bvc(vty, bvc, show_stats);
+	}
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(logging_fltr_bvc,
+      logging_fltr_bvc_cmd,
+      "logging filter bvc nsei <0-65535> bvci <0-65535>",
+	LOGGING_STR FILTER_STR
+	"Filter based on BSSGP Virtual Connection\n"
+	"NSEI of the BVC to be filtered\n"
+	"Network Service Entity Identifier (NSEI)\n"
+	"BVCI of the BVC to be filtered\n"
+	"BSSGP Virtual Connection Identifier (BVCI)\n")
+{
+	struct telnet_connection *conn;
+	struct bssgp_bvc_ctx *bvc;
+	uint16_t nsei = atoi(argv[0]);
+	uint16_t bvci = atoi(argv[1]);
+
+	conn = (struct telnet_connection *) vty->priv;
+	if (!conn->dbg) {
+		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	bvc = btsctx_by_bvci_nsei(bvci, nsei);
+	if (!bvc) {
+		vty_out(vty, "No BVC by that identifier%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	log_set_bvc_filter(conn->dbg, bvc);
+	return CMD_SUCCESS;
+}
+
+int gprs_bssgp_vty_init(void)
+{
+	install_element_ve(&show_bssgp_cmd);
+	install_element_ve(&show_bssgp_stats_cmd);
+	install_element_ve(&show_bvc_cmd);
+	install_element_ve(&logging_fltr_bvc_cmd);
+
+	install_element(CONFIG_NODE, &cfg_bssgp_cmd);
+	install_node(&bssgp_node, config_write_bssgp);
+	install_default(BSSGP_NODE);
+	install_element(BSSGP_NODE, &ournode_exit_cmd);
+	install_element(BSSGP_NODE, &ournode_end_cmd);
+	//install_element(BSSGP_NODE, &cfg_bssgp_timer_cmd);
+
+	return 0;
+}
diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c
new file mode 100644
index 0000000..17d2ed0
--- /dev/null
+++ b/openbsc/src/gprs/gprs_gmm.c
@@ -0,0 +1,1320 @@
+/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
+ * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
+
+/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
+ * (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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <openbsc/db.h>
+#include <osmocore/msgb.h>
+#include <osmocore/tlv.h>
+#include <osmocore/gsm_utils.h>
+#include <osmocore/signal.h>
+#include <osmocore/talloc.h>
+#include <osmocore/rate_ctr.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/gsm_subscriber.h>
+#include <openbsc/gsm_04_08.h>
+#include <openbsc/gsm_04_08_gprs.h>
+#include <openbsc/paging.h>
+#include <openbsc/transaction.h>
+#include <openbsc/gprs_bssgp.h>
+#include <openbsc/gprs_llc.h>
+#include <openbsc/gprs_sgsn.h>
+#include <openbsc/gprs_gmm.h>
+#include <openbsc/sgsn.h>
+
+#include <pdp.h>
+
+#define PTMSI_ALLOC
+
+/* Section 11.2.2 / Table 11.4 MM timers netowkr side */
+#define GSM0408_T3322_SECS	6	/* DETACH_REQ -> DETACH_ACC */
+#define GSM0408_T3350_SECS	6	/* waiting for ATT/RAU/TMSI COMPL */
+#define GSM0408_T3360_SECS	6	/* waiting for AUTH/CIPH RESP */
+#define GSM0408_T3370_SECS	6	/* waiting for ID RESP */
+
+/* Section 11.2.2 / Table 11.4a MM timers netowkr side */
+#define GSM0408_T3313_SECS	30	/* waiting for paging response */
+#define GSM0408_T3314_SECS	44	/* force to STBY on expiry */
+#define GSM0408_T3316_SECS	44
+
+extern struct sgsn_instance *sgsn;
+
+/* Protocol related stuff, should go into libosmocore */
+
+/* 10.5.5.14 GPRS MM Cause / Table 10.5.147 */
+const struct value_string gmm_cause_names[] = {
+	/* FIXME */
+	{ GMM_CAUSE_SEM_INCORR_MSG, "Semantically incorrect message" },
+	{ GMM_CAUSE_INV_MAND_INFO, "Invalid mandatory information" },
+	{ GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL,
+			"Message type non-existant or not implemented" },
+	{ GMM_CAUSE_MSGT_INCOMP_P_STATE,
+			"Message type not compatible with protocol state" },
+	{ GMM_CAUSE_IE_NOTEXIST_NOTIMPL,
+			"Information element non-existent or not implemented" },
+	{ GMM_CAUSE_COND_IE_ERR, "Conditional IE error" },
+	{ GMM_CAUSE_MSG_INCOMP_P_STATE,
+				"Message not compatible with protocol state " },
+	{ GMM_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" },
+	{ 0, NULL }
+};
+
+/* 10.5.6.6 SM Cause / Table 10.5.157 */
+const struct value_string gsm_cause_names[] = {
+	{ GSM_CAUSE_INSUFF_RSRC, "Insufficient resources" },
+	{ GSM_CAUSE_MISSING_APN, "Missing or unknown APN" },
+	{ GSM_CAUSE_UNKNOWN_PDP, "Unknown PDP address or PDP type" },
+	{ GSM_CAUSE_AUTH_FAILED, "User Authentication failed" },
+	{ GSM_CAUSE_ACT_REJ_GGSN, "Activation rejected by GGSN" },
+	{ GSM_CAUSE_ACT_REJ_UNSPEC, "Activation rejected, unspecified" },
+	{ GSM_CAUSE_SERV_OPT_NOTSUPP, "Service option not supported" },
+	{ GSM_CAUSE_REQ_SERV_OPT_NOTSUB,
+				"Requested service option not subscribed" },
+	{ GSM_CAUSE_SERV_OPT_TEMP_OOO,
+				"Service option temporarily out of order" },
+	{ GSM_CAUSE_NSAPI_IN_USE, "NSAPI already used" },
+	{ GSM_CAUSE_DEACT_REGULAR, "Regular deactivation" },
+	{ GSM_CAUSE_QOS_NOT_ACCEPTED, "QoS not accepted" },
+	{ GSM_CAUSE_NET_FAIL, "Network Failure" },
+	{ GSM_CAUSE_REACT_RQD, "Reactivation required" },
+	{ GSM_CAUSE_FEATURE_NOTSUPP, "Feature not supported " },
+	{ GSM_CAUSE_INVALID_TRANS_ID, "Invalid transaction identifier" },
+	{ GSM_CAUSE_SEM_INCORR_MSG, "Semantically incorrect message" },
+	{ GSM_CAUSE_INV_MAND_INFO, "Invalid mandatory information" },
+	{ GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL,
+			"Message type non-existant or not implemented" },
+	{ GSM_CAUSE_MSGT_INCOMP_P_STATE,
+			"Message type not compatible with protocol state" },
+	{ GSM_CAUSE_IE_NOTEXIST_NOTIMPL,
+			"Information element non-existent or not implemented" },
+	{ GSM_CAUSE_COND_IE_ERR, "Conditional IE error" },
+	{ GSM_CAUSE_MSG_INCOMP_P_STATE,
+				"Message not compatible with protocol state " },
+	{ GSM_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" },
+	{ 0, NULL }
+};
+
+/* 10.5.5.2 */
+const struct value_string gprs_att_t_strs[] = {
+	{ GPRS_ATT_T_ATTACH, 		"GPRS attach" },
+	{ GPRS_ATT_T_ATT_WHILE_IMSI, 	"GPRS attach while IMSI attached" },
+	{ GPRS_ATT_T_COMBINED, 		"Combined GPRS/IMSI attach" },
+	{ 0, NULL }
+};
+
+const struct value_string gprs_upd_t_strs[] = {
+	{ GPRS_UPD_T_RA,		"RA updating" },
+	{ GPRS_UPD_T_RA_LA,		"combined RA/LA updating" },
+	{ GPRS_UPD_T_RA_LA_IMSI_ATT,	"combined RA/LA updating + IMSI attach" },
+	{ GPRS_UPD_T_PERIODIC,		"periodic updating" },
+	{ 0, NULL }
+};
+
+/* 10.5.5.5 */
+const struct value_string gprs_det_t_mo_strs[] = {
+	{ GPRS_DET_T_MO_GPRS,		"GPRS detach" },
+	{ GPRS_DET_T_MO_IMSI,		"IMSI detach" },
+	{ GPRS_DET_T_MO_COMBINED,	"Combined GPRS/IMSI detach" },
+	{ 0, NULL }
+};
+
+static const struct tlv_definition gsm48_gmm_att_tlvdef = {
+	.def = {
+		[GSM48_IE_GMM_TIMER_READY]	= { TLV_TYPE_TV, 1 },
+		[GSM48_IE_GMM_ALLOC_PTMSI]	= { TLV_TYPE_TLV, 0 },
+		[GSM48_IE_GMM_PTMSI_SIG]	= { TLV_TYPE_TV, 3 },
+		[GSM48_IE_GMM_AUTH_RAND]	= { TLV_TYPE_TV, 16 },
+		[GSM48_IE_GMM_AUTH_SRES]	= { TLV_TYPE_TV, 4 },
+		[GSM48_IE_GMM_IMEISV]		= { TLV_TYPE_TLV, 0 },
+		[GSM48_IE_GMM_DRX_PARAM]	= { TLV_TYPE_TV, 2 },
+		[GSM48_IE_GMM_MS_NET_CAPA]	= { TLV_TYPE_TLV, 0 },
+		[GSM48_IE_GMM_PDP_CTX_STATUS]	= { TLV_TYPE_TLV, 0 },
+		[GSM48_IE_GMM_PS_LCS_CAPA]	= { TLV_TYPE_TLV, 0 },
+		[GSM48_IE_GMM_GMM_MBMS_CTX_ST]	= { TLV_TYPE_TLV, 0 },
+	},
+};
+
+static const struct tlv_definition gsm48_sm_att_tlvdef = {
+	.def = {
+		[GSM48_IE_GSM_APN]		= { TLV_TYPE_TLV, 0 },
+		[GSM48_IE_GSM_PROTO_CONF_OPT]	= { TLV_TYPE_TLV, 0 },
+		[GSM48_IE_GSM_PDP_ADDR]		= { TLV_TYPE_TLV, 0 },
+		[GSM48_IE_GSM_AA_TMR]		= { TLV_TYPE_TV, 1 },
+		[GSM48_IE_GSM_NAME_FULL]	= { TLV_TYPE_TLV, 0 },
+		[GSM48_IE_GSM_NAME_SHORT]	= { TLV_TYPE_TLV, 0 },
+		[GSM48_IE_GSM_TIMEZONE]		= { TLV_TYPE_TV, 1 },
+		[GSM48_IE_GSM_UTC_AND_TZ]	= { TLV_TYPE_TV, 7 },
+		[GSM48_IE_GSM_LSA_ID]		= { TLV_TYPE_TLV, 0 },
+	},
+};
+
+/* Our implementation, should be kept in SGSN */
+
+static void mmctx_timer_cb(void *_mm);
+
+static void mmctx_timer_start(struct sgsn_mm_ctx *mm, unsigned int T,
+				unsigned int seconds)
+{
+	if (bsc_timer_pending(&mm->timer))
+		LOGP(DMM, LOGL_ERROR, "Starting MM timer %u while old "
+			"timer %u pending\n", T, mm->T);
+	mm->T = T;
+	mm->num_T_exp = 0;
+
+	/* FIXME: we should do this only once ? */
+	mm->timer.data = mm;
+	mm->timer.cb = &mmctx_timer_cb;
+
+	bsc_schedule_timer(&mm->timer, seconds, 0);
+}
+
+static void mmctx_timer_stop(struct sgsn_mm_ctx *mm, unsigned int T)
+{
+	if (mm->T != T)
+		LOGP(DMM, LOGL_ERROR, "Stopping MM timer %u but "
+			"%u is running\n", T, mm->T);
+	bsc_del_timer(&mm->timer);
+}
+
+/* Send a message through the underlying layer */
+static int gsm48_gmm_sendmsg(struct msgb *msg, int command,
+			     const struct sgsn_mm_ctx *mm)
+{
+	if (mm)
+		rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]);
+
+	/* caller needs to provide TLLI, BVCI and NSEI */
+	return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command, mm);
+}
+
+/* copy identifiers from old message to new message, this
+ * is required so lower layers can route it correctly */
+static void gmm_copy_id(struct msgb *msg, const struct msgb *old)
+{
+	msgb_tlli(msg) = msgb_tlli(old);
+	msgb_bvci(msg) = msgb_bvci(old);
+	msgb_nsei(msg) = msgb_nsei(old);
+}
+
+/* Store BVCI/NSEI in MM context */
+static void msgid2mmctx(struct sgsn_mm_ctx *mm, const struct msgb *msg)
+{
+	mm->bvci = msgb_bvci(msg);
+	mm->nsei = msgb_nsei(msg);
+}
+
+/* Store BVCI/NSEI in MM context */
+static void mmctx2msgid(struct msgb *msg, const struct sgsn_mm_ctx *mm)
+{
+	msgb_tlli(msg) = mm->tlli;
+	msgb_bvci(msg) = mm->bvci;
+	msgb_nsei(msg) = mm->nsei;
+}
+
+/* Chapter 9.4.18 */
+static int _tx_status(struct msgb *msg, uint8_t cause,
+		      struct sgsn_mm_ctx *mmctx, int sm)
+{
+	struct gsm48_hdr *gh;
+
+	/* MMCTX might be NULL! */
+
+	DEBUGP(DMM, "<- GPRS MM STATUS (cause: %s)\n",
+		get_value_string(gmm_cause_names, cause));
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
+	if (sm) {
+		gh->proto_discr = GSM48_PDISC_SM_GPRS;
+		gh->msg_type = GSM48_MT_GSM_STATUS;
+	} else {
+		gh->proto_discr = GSM48_PDISC_MM_GPRS;
+		gh->msg_type = GSM48_MT_GMM_STATUS;
+	}
+	gh->data[0] = cause;
+
+	return gsm48_gmm_sendmsg(msg, 0, mmctx);
+}
+static int gsm48_tx_gmm_status(struct sgsn_mm_ctx *mmctx, uint8_t cause)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+
+	mmctx2msgid(msg, mmctx);
+	return _tx_status(msg, cause, mmctx, 0);
+};
+static int gsm48_tx_gmm_status_oldmsg(struct msgb *oldmsg, uint8_t cause)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+
+	gmm_copy_id(msg, oldmsg);
+	return _tx_status(msg, cause, NULL, 0);
+}
+static int gsm48_tx_sm_status(struct sgsn_mm_ctx *mmctx, uint8_t cause)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+
+	mmctx2msgid(msg, mmctx);
+	return _tx_status(msg, cause, mmctx, 1);
+};
+static int gsm48_tx_sm_status_oldmsg(struct msgb *oldmsg, uint8_t cause)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+
+	gmm_copy_id(msg, oldmsg);
+	return _tx_status(msg, cause, NULL, 1);
+}
+
+
+static struct gsm48_qos default_qos = {
+	.delay_class = 4,	/* best effort */
+	.reliab_class = GSM48_QOS_RC_LLC_UN_RLC_ACK_DATA_PROT,
+	.peak_tput = GSM48_QOS_PEAK_TPUT_32000bps,
+	.preced_class = GSM48_QOS_PC_NORMAL,
+	.mean_tput = GSM48_QOS_MEAN_TPUT_BEST_EFFORT,
+	.traf_class = GSM48_QOS_TC_INTERACTIVE,
+	.deliv_order = GSM48_QOS_DO_UNORDERED,
+	.deliv_err_sdu = GSM48_QOS_ERRSDU_YES,
+	.max_sdu_size = GSM48_QOS_MAXSDU_1520,
+	.max_bitrate_up = GSM48_QOS_MBRATE_63k,
+	.max_bitrate_down = GSM48_QOS_MBRATE_63k,
+	.resid_ber = GSM48_QOS_RBER_5e_2,
+	.sdu_err_ratio = GSM48_QOS_SERR_1e_2,
+	.handling_prio = 3,
+	.xfer_delay = 0x10,	/* 200ms */
+	.guar_bitrate_up = GSM48_QOS_MBRATE_0k,
+	.guar_bitrate_down = GSM48_QOS_MBRATE_0k,
+	.sig_ind = 0,	/* not optimised for signalling */
+	.max_bitrate_down_ext = 0,	/* use octet 9 */
+	.guar_bitrate_down_ext = 0,	/* use octet 13 */
+};
+
+/* Chapter 9.4.2: Attach accept */
+static int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	struct gsm48_hdr *gh;
+	struct gsm48_attach_ack *aa;
+	uint8_t *ptsig, *mid;
+
+	DEBUGP(DMM, "<- GPRS ATTACH ACCEPT (new P-TMSI=0x%08x)\n", mm->p_tmsi);
+
+	mmctx2msgid(msg, mm);
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+	gh->proto_discr = GSM48_PDISC_MM_GPRS;
+	gh->msg_type = GSM48_MT_GMM_ATTACH_ACK;
+
+	aa = (struct gsm48_attach_ack *) msgb_put(msg, sizeof(*aa));
+	aa->force_stby = 0;	/* not indicated */
+	aa->att_result = 1;	/* GPRS only */
+	aa->ra_upd_timer = GPRS_TMR_MINUTE | 10;
+	aa->radio_prio = 4;	/* lowest */
+	gsm48_construct_ra(aa->ra_id.digits, &mm->ra);
+
+#if 0
+	/* Optional: P-TMSI signature */
+	msgb_v_put(msg, GSM48_IE_GMM_PTMSI_SIG);
+	ptsig = msgb_put(msg, 3);
+	ptsig[0] = mm->p_tmsi_sig >> 16;
+	ptsig[1] = mm->p_tmsi_sig >> 8;
+	ptsig[2] = mm->p_tmsi_sig & 0xff;
+
+	/* Optional: Negotiated Ready timer value */
+#endif
+
+#ifdef PTMSI_ALLOC
+	/* Optional: Allocated P-TMSI */
+	mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
+	gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi);
+	mid[0] = GSM48_IE_GMM_ALLOC_PTMSI;
+#endif
+
+	/* Optional: MS-identity (combined attach) */
+	/* Optional: GMM cause (partial attach result for combined attach) */
+
+	return gsm48_gmm_sendmsg(msg, 0, mm);
+}
+
+/* Chapter 9.4.5: Attach reject */
+static int _tx_gmm_att_rej(struct msgb *msg, uint8_t gmm_cause)
+{
+	struct gsm48_hdr *gh;
+
+	DEBUGP(DMM, "<- GPRS ATTACH REJECT\n");
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
+	gh->proto_discr = GSM48_PDISC_MM_GPRS;
+	gh->msg_type = GSM48_MT_GMM_ATTACH_REJ;
+	gh->data[0] = gmm_cause;
+
+	return gsm48_gmm_sendmsg(msg, 0, NULL);
+}
+static int gsm48_tx_gmm_att_rej_oldmsg(const struct msgb *old_msg,
+					uint8_t gmm_cause)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	gmm_copy_id(msg, old_msg);
+	return _tx_gmm_att_rej(msg, gmm_cause);
+}
+static int gsm48_tx_gmm_att_rej(struct sgsn_mm_ctx *mm,
+				uint8_t gmm_cause)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	mmctx2msgid(msg, mm);
+	return _tx_gmm_att_rej(msg, gmm_cause);
+}
+
+/* Chapter 9.4.6.2 Detach accept */
+static int gsm48_tx_gmm_det_ack(struct sgsn_mm_ctx *mm, uint8_t force_stby)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	struct gsm48_hdr *gh;
+
+	DEBUGP(DMM, "<- GPRS DETACH ACCEPT\n");
+
+	mmctx2msgid(msg, mm);
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
+	gh->proto_discr = GSM48_PDISC_MM_GPRS;
+	gh->msg_type = GSM48_MT_GMM_DETACH_ACK;
+	gh->data[0] = force_stby;
+
+	return gsm48_gmm_sendmsg(msg, 0, mm);
+}
+
+/* Transmit Chapter 9.4.12 Identity Request */
+static int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	struct gsm48_hdr *gh;
+
+	DEBUGP(DMM, "<- GPRS IDENTITY REQUEST: mi_type=%02x\n", id_type);
+
+	mmctx2msgid(msg, mm);
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
+	gh->proto_discr = GSM48_PDISC_MM_GPRS;
+	gh->msg_type = GSM48_MT_GMM_ID_REQ;
+	/* 10.5.5.9 ID type 2 + identity type and 10.5.5.7 'force to standby' IE */
+	gh->data[0] = id_type & 0xf;
+
+	return gsm48_gmm_sendmsg(msg, 1, mm);
+}
+
+/* Check if we can already authorize a subscriber */
+static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx,
+				enum gprs_t3350_mode t3350_mode)
+{
+	if (strlen(ctx->imei) && strlen(ctx->imsi)) {
+#ifdef PTMSI_ALLOC
+		/* Start T3350 and re-transmit up to 5 times until ATTACH COMPLETE */
+		ctx->t3350_mode = t3350_mode;
+		mmctx_timer_start(ctx, 3350, GSM0408_T3350_SECS);
+#endif
+		ctx->mm_state = GMM_REGISTERED_NORMAL;
+		return gsm48_tx_gmm_att_ack(ctx);
+	} 
+	if (!strlen(ctx->imei)) {
+		ctx->mm_state = GMM_COMMON_PROC_INIT;
+		ctx->t3370_id_type = GSM_MI_TYPE_IMEI;
+		mmctx_timer_start(ctx, 3370, GSM0408_T3370_SECS);
+		return gsm48_tx_gmm_id_req(ctx, GSM_MI_TYPE_IMEI);
+	}
+
+	if (!strlen(ctx->imsi)) {
+		ctx->mm_state = GMM_COMMON_PROC_INIT;
+		ctx->t3370_id_type = GSM_MI_TYPE_IMSI;
+		mmctx_timer_start(ctx, 3370, GSM0408_T3370_SECS);
+		return gsm48_tx_gmm_id_req(ctx, GSM_MI_TYPE_IMSI);
+	}
+
+	return 0;
+}
+
+/* Parse Chapter 9.4.13 Identity Response */
+static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
+{
+	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
+	uint8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;
+	char mi_string[GSM48_MI_SIZE];
+
+	gsm48_mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
+	DEBUGP(DMM, "-> GMM IDENTITY RESPONSE: mi_type=0x%02x MI(%s) ",
+		mi_type, mi_string);
+
+	if (!ctx) {
+		DEBUGP(DMM, "from unknown TLLI 0x%08x?!?\n", msgb_tlli(msg));
+		return -EINVAL;
+	}
+
+	if (mi_type == ctx->t3370_id_type)
+		mmctx_timer_stop(ctx, 3370);
+
+	switch (mi_type) {
+	case GSM_MI_TYPE_IMSI:
+		/* we already have a mm context with current TLLI, but no
+		 * P-TMSI / IMSI yet.  What we now need to do is to fill
+		 * this initial context with data from the HLR */
+		strncpy(ctx->imsi, mi_string, sizeof(ctx->imei));
+		break;
+	case GSM_MI_TYPE_IMEI:
+		strncpy(ctx->imei, mi_string, sizeof(ctx->imei));
+		break;
+	case GSM_MI_TYPE_IMEISV:
+		break;
+	}
+
+	DEBUGPC(DMM, "\n");
+	/* Check if we can let the mobile station enter */
+	return gsm48_gmm_authorize(ctx, ctx->t3350_mode);
+}
+
+/* Section 9.4.1 Attach request */
+static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
+				struct gprs_llc_llme *llme)
+{
+	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
+	uint8_t *cur = gh->data, *msnc, *mi, *old_ra_info, *ms_ra_acc_cap;
+	uint8_t msnc_len, att_type, mi_len, mi_type, ms_ra_acc_cap_len;
+	uint16_t drx_par;
+	uint32_t tmsi;
+	char mi_string[GSM48_MI_SIZE];
+	struct gprs_ra_id ra_id;
+	uint16_t cid;
+
+	DEBUGP(DMM, "-> GMM ATTACH REQUEST ");
+
+	/* As per TS 04.08 Chapter 4.7.1.4, the attach request arrives either
+	 * with a foreign TLLI (P-TMSI that was allocated to the MS before),
+	 * or with random TLLI. */
+
+	cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
+
+	/* MS network capability 10.5.5.12 */
+	msnc_len = *cur++;
+	msnc = cur;
+	if (msnc_len > 2)
+		goto err_inval;
+	cur += msnc_len;
+
+	/* aTTACH Type 10.5.5.2 */
+	att_type = *cur++ & 0x0f;
+
+	/* DRX parameter 10.5.5.6 */
+	drx_par = *cur++ << 8;
+	drx_par |= *cur++;
+
+	/* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */
+	mi_len = *cur++;
+	mi = cur;
+	if (mi_len > 8)
+		goto err_inval;
+	mi_type = *mi & GSM_MI_TYPE_MASK;
+	cur += mi_len;
+
+	gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
+
+	DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string,
+		get_value_string(gprs_att_t_strs, att_type));
+
+	/* Old routing area identification 10.5.5.15 */
+	old_ra_info = cur;
+	cur += 6;
+
+	/* MS Radio Access Capability 10.5.5.12a */
+	ms_ra_acc_cap_len = *cur++;
+	ms_ra_acc_cap = cur;
+
+	/* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status */
+
+	switch (mi_type) {
+	case GSM_MI_TYPE_IMSI:
+		/* Try to find MM context based on IMSI */
+		if (!ctx)
+			ctx = sgsn_mm_ctx_by_imsi(mi_string);
+		if (!ctx) {
+#if 0
+			return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_IMSI_UNKNOWN);
+#else
+			/* As a temorary hack, we simply assume that the IMSI exists */
+			ctx = sgsn_mm_ctx_alloc(0, &ra_id);
+			if (!ctx)
+				return gsm48_tx_gmm_att_rej_oldmsg(msg, GMM_CAUSE_NET_FAIL);
+			strncpy(ctx->imsi, mi_string, sizeof(ctx->imsi));
+#endif
+		}
+		ctx->tlli = msgb_tlli(msg);
+		ctx->llme = llme;
+		msgid2mmctx(ctx, msg);
+		break;
+	case GSM_MI_TYPE_TMSI:
+		memcpy(&tmsi, mi+1, 4);
+		tmsi = ntohl(tmsi);
+		/* Try to find MM context based on P-TMSI */
+		if (!ctx)
+			ctx = sgsn_mm_ctx_by_ptmsi(tmsi);
+		if (!ctx) {
+			ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id);
+			ctx->p_tmsi = tmsi;
+		}
+		ctx->tlli = msgb_tlli(msg);
+		ctx->llme = llme;
+		msgid2mmctx(ctx, msg);
+		break;
+	default:
+		LOGP(DMM, LOGL_NOTICE, "Rejecting ATTACH REQUEST with "
+			"MI type %u\n", mi_type);
+		return gsm48_tx_gmm_att_rej_oldmsg(msg, GMM_CAUSE_MS_ID_NOT_DERIVED);
+	}
+	/* Update MM Context with currient RA and Cell ID */
+	ctx->ra = ra_id;
+	ctx->cell_id = cid;
+	/* Update MM Context with other data */
+	ctx->drx_parms = drx_par;
+	ctx->ms_radio_access_capa.len = ms_ra_acc_cap_len;
+	memcpy(ctx->ms_radio_access_capa.buf, ms_ra_acc_cap, ms_ra_acc_cap_len);
+	ctx->ms_network_capa.len = msnc_len;
+	memcpy(ctx->ms_network_capa.buf, msnc, msnc_len);
+
+#ifdef PTMSI_ALLOC
+	/* Allocate a new P-TMSI (+ P-TMSI signature) and update TLLI */
+	ctx->p_tmsi_old = ctx->p_tmsi;
+	ctx->p_tmsi = sgsn_alloc_ptmsi();
+#endif
+	/* Even if there is no P-TMSI allocated, the MS will switch from
+	 * foreign TLLI to local TLLI */
+	ctx->tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL);
+
+	/* Inform LLC layer about new TLLI but keep old active */
+	gprs_llgmm_assign(ctx->llme, ctx->tlli, ctx->tlli_new, 0, NULL);
+
+	DEBUGPC(DMM, "\n");
+	return ctx ? gsm48_gmm_authorize(ctx, GMM_T3350_MODE_ATT) : 0;
+
+err_inval:
+	DEBUGPC(DMM, "\n");
+	return gsm48_tx_gmm_att_rej_oldmsg(msg, GMM_CAUSE_SEM_INCORR_MSG);
+}
+
+/* Section 4.7.4.1 / 9.4.5.2 MO Detach request */
+static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
+{
+	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
+	uint8_t detach_type, power_off;
+
+	detach_type = gh->data[0] & 0x7;
+	power_off = gh->data[0] & 0x8;
+
+	/* FIXME: In 24.008 there is an optional P-TMSI and P-TMSI signature IE */
+
+	DEBUGP(DMM, "-> GMM DETACH REQUEST TLLI=0x%08x type=%s %s\n",
+		msgb_tlli(msg), get_value_string(gprs_det_t_mo_strs, detach_type),
+		power_off ? "Power-off" : "");
+
+	/* Mark MM state as deregistered */
+	ctx->mm_state = GMM_DEREGISTERED;
+
+	/* force_stby = 0 */
+	return gsm48_tx_gmm_det_ack(ctx, 0);
+}
+
+/* Chapter 9.4.15: Routing area update accept */
+static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	struct gsm48_hdr *gh;
+	struct gsm48_ra_upd_ack *rua;
+	uint8_t *mid;
+
+	DEBUGP(DMM, "<- ROUTING AREA UPDATE ACCEPT\n");
+
+	mmctx2msgid(msg, mm);
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+	gh->proto_discr = GSM48_PDISC_MM_GPRS;
+	gh->msg_type = GSM48_MT_GMM_RA_UPD_ACK;
+
+	rua = (struct gsm48_ra_upd_ack *) msgb_put(msg, sizeof(*rua));
+	rua->force_stby = 0;	/* not indicated */
+	rua->upd_result = 0;	/* RA updated */
+	rua->ra_upd_timer = GPRS_TMR_MINUTE | 10;
+
+	gsm48_construct_ra(rua->ra_id.digits, &mm->ra);
+
+#if 0
+	/* Optional: P-TMSI signature */
+	msgb_v_put(msg, GSM48_IE_GMM_PTMSI_SIG);
+	ptsig = msgb_put(msg, 3);
+	ptsig[0] = mm->p_tmsi_sig >> 16;
+	ptsig[1] = mm->p_tmsi_sig >> 8;
+	ptsig[2] = mm->p_tmsi_sig & 0xff;
+#endif
+
+#ifdef PTMSI_ALLOC
+	/* Optional: Allocated P-TMSI */
+	mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
+	gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi);
+	mid[0] = GSM48_IE_GMM_ALLOC_PTMSI;
+#endif
+
+	/* Option: MS ID, ... */
+	return gsm48_gmm_sendmsg(msg, 0, mm);
+}
+
+/* Chapter 9.4.17: Routing area update reject */
+static int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	struct gsm48_hdr *gh;
+
+	DEBUGP(DMM, "<- ROUTING AREA UPDATE REJECT\n");
+
+	gmm_copy_id(msg, old_msg);
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 2);
+	gh->proto_discr = GSM48_PDISC_MM_GPRS;
+	gh->msg_type = GSM48_MT_GMM_RA_UPD_REJ;
+	gh->data[0] = cause;
+	gh->data[1] = 0; /* ? */
+
+	/* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */
+	return gsm48_gmm_sendmsg(msg, 0, NULL);
+}
+
+static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx,
+				  uint16_t pdp_status)
+{
+	struct sgsn_pdp_ctx *pdp, *pdp2;
+	/* 24.008 4.7.5.1.3: If the PDP context status information element is
+	 * included in ROUTING AREA UPDATE REQUEST message, then the network
+	 * shall deactivate all those PDP contexts locally (without peer to
+	 * peer signalling between the MS and the network), which are not in SM
+	 * state PDP-INACTIVE on network side but are indicated by the MS as
+	 * being in state PDP-INACTIVE. */
+
+	llist_for_each_entry_safe(pdp, pdp2, &mmctx->pdp_list, list) {
+		if (!(pdp_status & (1 << pdp->nsapi))) {
+			LOGP(DMM, LOGL_NOTICE, "Dropping PDP context for NSAPI=%u "
+				"due to PDP CTX STATUS IE= 0x%04x\n",
+				pdp->nsapi, pdp_status);
+			sgsn_delete_pdp_ctx(pdp);
+		}
+	}
+}
+
+/* Chapter 9.4.14: Routing area update request */
+static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
+				   struct gprs_llc_llme *llme)
+{
+	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
+	uint8_t *cur = gh->data;
+	uint8_t *ms_ra_acc_cap;
+	uint8_t ms_ra_acc_cap_len;
+	struct gprs_ra_id old_ra_id;
+	struct tlv_parsed tp;
+	uint8_t upd_type;
+	int rc;
+
+	/* Update Type 10.5.5.18 */
+	upd_type = *cur++ & 0x0f;
+
+	DEBUGP(DMM, "-> GMM RA UPDATE REQUEST type=\"%s\" ",
+		get_value_string(gprs_upd_t_strs, upd_type));
+
+	/* Old routing area identification 10.5.5.15 */
+	gsm48_parse_ra(&old_ra_id, cur);
+	cur += 6;
+
+	/* MS Radio Access Capability 10.5.5.12a */
+	ms_ra_acc_cap_len = *cur++;
+	ms_ra_acc_cap = cur;
+
+	/* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status,
+	 * DRX parameter, MS network capability */
+	rc = tlv_parse(&tp, &gsm48_gmm_att_tlvdef, cur,
+			(msg->data + msg->len) - cur, 0, 0);
+
+	switch (upd_type) {
+	case GPRS_UPD_T_RA_LA:
+	case GPRS_UPD_T_RA_LA_IMSI_ATT:
+		DEBUGPC(DMM, " unsupported in Mode III, is your SI13 corrupt?\n");
+		return gsm48_tx_gmm_ra_upd_rej(msg, GMM_CAUSE_PROTO_ERR_UNSPEC);
+		break;
+	case GPRS_UPD_T_RA:
+	case GPRS_UPD_T_PERIODIC:
+		break;
+	}
+
+	/* Look-up the MM context based on old RA-ID and TLLI */
+	if (!mmctx || mmctx->mm_state == GMM_DEREGISTERED) {
+		/* The MS has to perform GPRS attach */
+		DEBUGPC(DMM, " REJECT\n");
+		/* Device is still IMSI atached for CS but initiate GPRS ATTACH */
+		return gsm48_tx_gmm_ra_upd_rej(msg, GMM_CAUSE_MS_ID_NOT_DERIVED);
+	}
+
+	/* Update the MM context with the new RA-ID */
+	bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg));
+	/* Update the MM context with the new TLLI */
+	mmctx->tlli = msgb_tlli(msg);
+	/* FIXME: Update the MM context with the MS radio acc capabilities */
+	/* FIXME: Update the MM context with the MS network capabilities */
+
+	rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_RA_UPDATE]);
+
+	DEBUGPC(DMM, " ACCEPT\n");
+#ifdef PTMSI_ALLOC
+	mmctx->p_tmsi_old = mmctx->p_tmsi;
+	mmctx->p_tmsi = sgsn_alloc_ptmsi();
+	/* Start T3350 and re-transmit up to 5 times until ATTACH COMPLETE */
+	mmctx->t3350_mode = GMM_T3350_MODE_RAU;
+	mmctx_timer_start(mmctx, 3350, GSM0408_T3350_SECS);
+#endif
+	/* Even if there is no P-TMSI allocated, the MS will switch from
+	 * foreign TLLI to local TLLI */
+	mmctx->tlli_new = gprs_tmsi2tlli(mmctx->p_tmsi, TLLI_LOCAL);
+
+	/* Inform LLC layer about new TLLI but keep old active */
+	gprs_llgmm_assign(mmctx->llme, mmctx->tlli, mmctx->tlli_new, 0, NULL);
+
+	/* Look at PDP Context Status IE and see if MS's view of
+	 * activated/deactivated NSAPIs agrees with our view */
+	if (TLVP_PRESENT(&tp, GSM48_IE_GMM_PDP_CTX_STATUS)) {
+		uint16_t pdp_status = ntohs(*(uint16_t *)
+				TLVP_VAL(&tp, GSM48_IE_GMM_PDP_CTX_STATUS));
+		process_ms_ctx_status(mmctx, pdp_status);
+	}
+
+	/* Send RA UPDATE ACCEPT */
+	return gsm48_tx_gmm_ra_upd_ack(mmctx);
+}
+
+static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
+{
+	struct gsm48_hdr *gh = msgb_l3(msg);
+
+	DEBUGP(DMM, "-> GPRS MM STATUS (cause: %s)\n",
+		get_value_string(gmm_cause_names, gh->data[0]));
+
+	return 0;
+}
+
+/* GPRS Mobility Management */
+static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
+			   struct gprs_llc_llme *llme)
+{
+	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
+	int rc;
+
+	/* MMCTX can be NULL when called */
+
+	if (!mmctx &&
+	    gh->msg_type != GSM48_MT_GMM_ATTACH_REQ &&
+	    gh->msg_type != GSM48_MT_GMM_RA_UPD_REQ) {
+		LOGP(DMM, LOGL_NOTICE, "Cannot handle GMM for unknown MM CTX\n");
+		return gsm48_tx_gmm_status_oldmsg(msg, GMM_CAUSE_MS_ID_NOT_DERIVED);
+	}
+
+	switch (gh->msg_type) {
+	case GSM48_MT_GMM_RA_UPD_REQ:
+		rc = gsm48_rx_gmm_ra_upd_req(mmctx, msg, llme);
+		break;
+	case GSM48_MT_GMM_ATTACH_REQ:
+		rc = gsm48_rx_gmm_att_req(mmctx, msg, llme);
+		break;
+	case GSM48_MT_GMM_ID_RESP:
+		rc = gsm48_rx_gmm_id_resp(mmctx, msg);
+		break;
+	case GSM48_MT_GMM_STATUS:
+		rc = gsm48_rx_gmm_status(mmctx, msg);
+		break;
+	case GSM48_MT_GMM_DETACH_REQ:
+		rc = gsm48_rx_gmm_det_req(mmctx, msg);
+		break;
+	case GSM48_MT_GMM_ATTACH_COMPL:
+		/* only in case SGSN offered new P-TMSI */
+		DEBUGP(DMM, "-> ATTACH COMPLETE\n");
+		mmctx_timer_stop(mmctx, 3350);
+		mmctx->p_tmsi_old = 0;
+		/* Unassign the old TLLI */
+		mmctx->tlli = mmctx->tlli_new;
+		//gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new, 0, NULL);
+		break;
+	case GSM48_MT_GMM_RA_UPD_COMPL:
+		/* only in case SGSN offered new P-TMSI */
+		DEBUGP(DMM, "-> ROUTEING AREA UPDATE COMPLETE\n");
+		mmctx_timer_stop(mmctx, 3350);
+		mmctx->p_tmsi_old = 0;
+		/* Unassign the old TLLI */
+		mmctx->tlli = mmctx->tlli_new;
+		//gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new, 0, NULL);
+		break;
+	case GSM48_MT_GMM_PTMSI_REALL_COMPL:
+		DEBUGP(DMM, "-> PTMSI REALLLICATION COMPLETE\n");
+		mmctx_timer_stop(mmctx, 3350);
+		mmctx->p_tmsi_old = 0;
+		/* Unassign the old TLLI */
+		mmctx->tlli = mmctx->tlli_new;
+		//gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new, 0, NULL);
+		break;
+	case GSM48_MT_GMM_AUTH_CIPH_RESP:
+		DEBUGP(DMM, "Unimplemented GSM 04.08 GMM msg type 0x%02x\n",
+			gh->msg_type);
+		rc = gsm48_tx_gmm_status(mmctx, GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
+		break;
+	default:
+		DEBUGP(DMM, "Unknown GSM 04.08 GMM msg type 0x%02x\n",
+			gh->msg_type);
+		rc = gsm48_tx_gmm_status(mmctx, GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
+		break;
+	}
+
+	return rc;
+}
+
+static void mmctx_timer_cb(void *_mm)
+{
+	struct sgsn_mm_ctx *mm = _mm;
+
+	mm->num_T_exp++;
+
+	switch (mm->T) {
+	case 3350:	/* waiting for ATTACH COMPLETE */
+		if (mm->num_T_exp >= 5) {
+			LOGP(DMM, LOGL_NOTICE, "T3350 expired >= 5 times\n");
+			mm->mm_state = GMM_DEREGISTERED;
+			/* FIXME: should we return some error? */
+			break;
+		}
+		/* re-transmit the respective msg and re-start timer */
+		switch (mm->t3350_mode) {
+		case GMM_T3350_MODE_ATT:
+			gsm48_tx_gmm_att_ack(mm);
+			break;
+		case GMM_T3350_MODE_RAU:
+			gsm48_tx_gmm_ra_upd_ack(mm);
+			break;
+		case GMM_T3350_MODE_PTMSI_REALL:
+			/* FIXME */
+			break;
+		}
+		bsc_schedule_timer(&mm->timer, GSM0408_T3350_SECS, 0);
+		break;
+	case 3370:	/* waiting for IDENTITY RESPONSE */
+		if (mm->num_T_exp >= 5) {
+			LOGP(DMM, LOGL_NOTICE, "T3370 expired >= 5 times\n");
+			gsm48_tx_gmm_att_rej(mm, GMM_CAUSE_MS_ID_NOT_DERIVED);
+			mm->mm_state = GMM_DEREGISTERED;
+			break;
+		}
+		/* re-tranmit IDENTITY REQUEST and re-start timer */
+		gsm48_tx_gmm_id_req(mm, mm->t3370_id_type);
+		bsc_schedule_timer(&mm->timer, GSM0408_T3370_SECS, 0);
+		break;
+	default:
+		LOGP(DMM, LOGL_ERROR, "timer expired in unknown mode %u\n",
+			mm->T);
+	}
+}
+
+/* GPRS SESSION MANAGEMENT */
+
+static void msgb_put_pdp_addr_ipv4(struct msgb *msg, uint32_t ipaddr)
+{
+	uint8_t v[6];
+
+	v[0] = PDP_TYPE_ORG_IETF;
+	v[1] = PDP_TYPE_N_IETF_IPv4;
+	*(uint32_t *)(v+2) = htonl(ipaddr);
+
+	msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v);
+}
+
+static void msgb_put_pdp_addr_ppp(struct msgb *msg)
+{
+	uint8_t v[2];
+
+	v[0] = PDP_TYPE_ORG_ETSI;
+	v[1] = PDP_TYPE_N_ETSI_PPP;
+
+	msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v);
+}
+
+/* Section 9.5.2: Ativate PDP Context Accept */
+int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	struct gsm48_hdr *gh;
+	uint8_t transaction_id = pdp->ti ^ 0x8; /* flip */
+
+	DEBUGP(DMM, "<- ACTIVATE PDP CONTEXT ACK\n");
+
+	mmctx2msgid(msg, pdp->mm);
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+	gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
+	gh->msg_type = GSM48_MT_GSM_ACT_PDP_ACK;
+
+	/* Negotiated LLC SAPI */
+	msgb_v_put(msg, pdp->sapi);
+
+	/* FIXME: copy QoS parameters from original request */
+	//msgb_lv_put(msg, pdp->lib->qos_neg.l, pdp->lib->qos_neg.v);
+	msgb_lv_put(msg, sizeof(default_qos), (uint8_t *)&default_qos);
+
+	/* Radio priority 10.5.7.2 */
+	msgb_v_put(msg, pdp->lib->radio_pri);
+
+	/* PDP address */
+	/* Highest 4 bits of first byte need to be set to 1, otherwise
+	 * the IE is identical with the 04.08 PDP Address IE */
+	pdp->lib->eua.v[0] &= ~0xf0;
+	msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR,
+		     pdp->lib->eua.l, pdp->lib->eua.v);
+	pdp->lib->eua.v[0] |= 0xf0;
+
+	/* Optional: Protocol configuration options (FIXME: why 'req') */
+	if (pdp->lib->pco_req.l && pdp->lib->pco_req.v)
+		msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT,
+			     pdp->lib->pco_req.l, pdp->lib->pco_req.v);
+
+	/* Optional: Packet Flow Identifier */
+
+	return gsm48_gmm_sendmsg(msg, 0, pdp->mm);
+}
+
+/* Section 9.5.3: Activate PDP Context reject */
+int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
+			     uint8_t cause, uint8_t pco_len, uint8_t *pco_v)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	struct gsm48_hdr *gh;
+	uint8_t transaction_id = tid ^ 0x8; /* flip */
+
+	DEBUGP(DMM, "<- ACTIVATE PDP CONTEXT REJ(cause=%u)\n", cause);
+
+	mmctx2msgid(msg, mm);
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+	gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
+	gh->msg_type = GSM48_MT_GSM_ACT_PDP_REJ;
+
+	msgb_v_put(msg, cause);
+	if (pco_len && pco_v)
+		msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT, pco_len, pco_v);
+
+	return gsm48_gmm_sendmsg(msg, 0, mm);
+}
+
+/* Section 9.5.9: Deactivate PDP Context Accept */
+static int _gsm48_tx_gsm_deact_pdp_acc(struct sgsn_mm_ctx *mm, uint8_t tid)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	struct gsm48_hdr *gh;
+	uint8_t transaction_id = tid ^ 0x8; /* flip */
+
+	DEBUGP(DMM, "<- DEACTIVATE PDP CONTEXT ACK\n");
+
+	mmctx2msgid(msg, mm);
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+	gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
+	gh->msg_type = GSM48_MT_GSM_DEACT_PDP_ACK;
+
+	return gsm48_gmm_sendmsg(msg, 0, mm);
+}
+int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp)
+{
+	return _gsm48_tx_gsm_deact_pdp_acc(pdp->mm, pdp->ti);
+}
+
+/* Section 9.5.1: Activate PDP Context Request */
+static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx,
+				    struct msgb *msg)
+{
+	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
+	struct gsm48_act_pdp_ctx_req *act_req = (struct gsm48_act_pdp_ctx_req *) gh->data;
+	uint8_t req_qos_len, req_pdpa_len;
+	uint8_t *req_qos, *req_pdpa;
+	struct tlv_parsed tp;
+	uint8_t transaction_id = (gh->proto_discr >> 4);
+	struct sgsn_pdp_ctx *pdp;
+
+	memset(&tp, 0, sizeof(tp));
+
+	DEBUGP(DMM, "-> ACTIVATE PDP CONTEXT REQ: SAPI=%u NSAPI=%u ",
+		act_req->req_llc_sapi, act_req->req_nsapi);
+
+	rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PDP_CTX_ACT]);
+
+	req_qos_len = act_req->data[0];
+	req_qos = act_req->data + 1;	/* 10.5.6.5 */
+	req_pdpa_len = act_req->data[1 + req_qos_len];
+	req_pdpa = act_req->data + 1 + req_qos_len + 1;	/* 10.5.6.4 */
+
+	switch (req_pdpa[0] & 0xf) {
+	case 0x0:
+		DEBUGPC(DMM, "ETSI ");
+		break;
+	case 0x1:
+		DEBUGPC(DMM, "IETF ");
+		break;
+	case 0xf:
+		DEBUGPC(DMM, "Empty ");
+		break;
+	}
+
+	switch (req_pdpa[1]) {
+	case 0x21:
+		DEBUGPC(DMM, "IPv4 ");
+		if (req_pdpa_len >= 6) {
+			struct in_addr ia;
+			ia.s_addr = ntohl(*((uint32_t *) (req_pdpa+2)));
+			DEBUGPC(DMM, "%s ", inet_ntoa(ia));
+		}
+		break;
+	case 0x57:
+		DEBUGPC(DMM, "IPv6 ");
+		if (req_pdpa_len >= 18) {
+			/* FIXME: print IPv6 address */
+		}
+		break;
+	default:	
+		DEBUGPC(DMM, "0x%02x ", req_pdpa[1]);
+		break;
+	}
+
+	DEBUGPC(DMM, "\n");
+
+	/* put the non-TLV elements in the TLV parser structure to
+	 * pass them on to the SGSN / GTP code */
+	tp.lv[OSMO_IE_GSM_REQ_QOS].len = req_qos_len;
+	tp.lv[OSMO_IE_GSM_REQ_QOS].val = req_qos;
+	tp.lv[OSMO_IE_GSM_REQ_PDP_ADDR].len = req_pdpa_len;
+	tp.lv[OSMO_IE_GSM_REQ_PDP_ADDR].val = req_pdpa;
+
+	/* FIXME:  determine GGSN based on APN and subscription options */
+	if (TLVP_PRESENT(&tp, GSM48_IE_GSM_APN)) {}
+
+	/* Check if NSAPI is out of range (TS 04.65 / 7.2) */
+	if (act_req->req_nsapi < 5 || act_req->req_nsapi > 15) {
+		/* Send reject with GSM_CAUSE_INV_MAND_INFO */
+		return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,
+						GSM_CAUSE_INV_MAND_INFO,
+						0, NULL);
+	}
+
+	/* Check if NSAPI is already in use */
+	if (sgsn_pdp_ctx_by_nsapi(mmctx, act_req->req_nsapi)) {
+		/* FIXME: send reject with GSM_CAUSE_NSAPI_IN_USE */
+		return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,
+						GSM_CAUSE_NSAPI_IN_USE,
+						0, NULL);
+	}
+
+#if 1
+	{
+		struct sgsn_ggsn_ctx *ggsn = sgsn_ggsn_ctx_by_id(0);
+		if (!ggsn) {
+			LOGP(DGPRS, LOGL_ERROR, "No GGSN context 0 found!\n");
+			return -EIO;
+		}
+		ggsn->gsn = sgsn->gsn;
+		pdp = sgsn_create_pdp_ctx(ggsn, mmctx, act_req->req_nsapi, &tp);
+		if (!pdp)
+			return -1;
+		pdp->sapi = act_req->req_llc_sapi;
+		pdp->ti = transaction_id;
+		
+	}
+	return 0;
+#else
+	return gsm48_tx_gsm_act_pdp_acc(mmctx, transaction_id, act_req);
+#endif
+}
+
+/* Section 9.5.8: Deactivate PDP Context Request */
+static int gsm48_rx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, struct msgb *msg)
+{
+	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
+	uint8_t transaction_id = (gh->proto_discr >> 4);
+	struct sgsn_pdp_ctx *pdp;
+
+	DEBUGP(DMM, "-> DEACTIVATE PDP CONTEXT REQ (cause: %s)\n",
+		get_value_string(gsm_cause_names, gh->data[0]));
+
+	pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);
+	if (!pdp) {
+		LOGP(DMM, LOGL_NOTICE, "Deactivate PDP Context Request for "
+			"non-existing PDP Context (IMSI=%s, TI=%u)\n",
+			mm->imsi, transaction_id);
+		return _gsm48_tx_gsm_deact_pdp_acc(mm, transaction_id);
+	}
+
+	return sgsn_delete_pdp_ctx(pdp);
+}
+
+static int gsm48_rx_gsm_status(struct sgsn_mm_ctx *ctx, struct msgb *msg)
+{
+	struct gsm48_hdr *gh = msgb_l3(msg);
+
+	DEBUGP(DMM, "-> GPRS SM STATUS (cause: %s)\n",
+		get_value_string(gsm_cause_names, gh->data[0]));
+
+	return 0;
+}
+
+/* GPRS Session Management */
+static int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
+			   struct gprs_llc_llme *llme)
+{
+	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
+	int rc;
+
+	/* MMCTX can be NULL when called */
+
+	if (!mmctx) {
+		LOGP(DMM, LOGL_NOTICE, "Cannot handle SM for unknown MM CTX\n");
+		return gsm48_tx_gmm_status_oldmsg(msg, GSM_CAUSE_PROTO_ERR_UNSPEC);
+	}
+
+	switch (gh->msg_type) {
+	case GSM48_MT_GSM_ACT_PDP_REQ:
+		rc = gsm48_rx_gsm_act_pdp_req(mmctx, msg);
+		break;
+	case GSM48_MT_GSM_DEACT_PDP_REQ:
+		rc = gsm48_rx_gsm_deact_pdp_req(mmctx, msg);
+		break;
+	case GSM48_MT_GSM_STATUS:
+		rc = gsm48_rx_gsm_status(mmctx, msg);
+		break;
+	case GSM48_MT_GSM_REQ_PDP_ACT_REJ:
+	case GSM48_MT_GSM_ACT_AA_PDP_REQ:
+	case GSM48_MT_GSM_DEACT_AA_PDP_REQ:
+		DEBUGP(DMM, "Unimplemented GSM 04.08 GSM msg type 0x%02x\n",
+			gh->msg_type);
+		rc = gsm48_tx_sm_status(mmctx, GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
+		break;
+	default:
+		DEBUGP(DMM, "Unknown GSM 04.08 GSM msg type 0x%02x\n",
+			gh->msg_type);
+		rc = gsm48_tx_sm_status(mmctx, GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
+		break;
+
+	}
+
+	return rc;
+}
+
+/* Main entry point for incoming 04.08 GPRS messages */
+int gsm0408_gprs_rcvmsg(struct msgb *msg, struct gprs_llc_llme *llme)
+{
+	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
+	uint8_t pdisc = gh->proto_discr & 0x0f;
+	struct sgsn_mm_ctx *mmctx;
+	struct gprs_ra_id ra_id;
+	int rc = -EINVAL;
+
+	bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
+	mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id);
+	if (mmctx) {
+		msgid2mmctx(mmctx, msg);
+		rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
+		mmctx->llme = llme;
+	}
+
+	/* MMCTX can be NULL */
+
+	switch (pdisc) {
+	case GSM48_PDISC_MM_GPRS:
+		rc = gsm0408_rcv_gmm(mmctx, msg, llme);
+		break;
+	case GSM48_PDISC_SM_GPRS:
+		rc = gsm0408_rcv_gsm(mmctx, msg, llme);
+		break;
+	default:
+		DEBUGP(DMM, "Unknown GSM 04.08 discriminator 0x%02x\n",
+			pdisc);
+		/* FIXME: return status message */
+		break;
+	}
+
+	return rc;
+}
+
+int gprs_gmm_rx_suspend(struct gprs_ra_id *raid, uint32_t tlli)
+{
+	struct sgsn_mm_ctx *mmctx;
+
+	mmctx = sgsn_mm_ctx_by_tlli(tlli, raid);
+	if (!mmctx) {
+		LOGP(DMM, LOGL_NOTICE, "SUSPEND request for unknown "
+			"TLLI=%08x\n", tlli);
+		return -EINVAL;
+	}
+
+	if (mmctx->mm_state != GMM_REGISTERED_NORMAL) {
+		LOGP(DMM, LOGL_NOTICE, "SUSPEND request while state "
+			"!= REGISTERED (TLLI=%08x)\n", tlli);
+		return -EINVAL;
+	}
+
+	/* Transition from REGISTERED_NORMAL to REGISTERED_SUSPENDED */
+	mmctx->mm_state = GMM_REGISTERED_SUSPENDED;
+	return 0;
+}
+
+int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli,
+		       uint8_t suspend_ref)
+{
+	struct sgsn_mm_ctx *mmctx;
+
+	/* FIXME: make use of suspend reference? */
+
+	mmctx = sgsn_mm_ctx_by_tlli(tlli, raid);
+	if (!mmctx) {
+		LOGP(DMM, LOGL_NOTICE, "RESUME request for unknown "
+			"TLLI=%08x\n", tlli);
+		return -EINVAL;
+	}
+
+	if (mmctx->mm_state != GMM_REGISTERED_SUSPENDED) {
+		LOGP(DMM, LOGL_NOTICE, "RESUME request while state "
+			"!= SUSPENDED (TLLI=%08x)\n", tlli);
+		/* FIXME: should we not simply ignore it? */
+		return -EINVAL;
+	}
+
+	/* Transition from SUSPENDED to NORMAL */
+	mmctx->mm_state = GMM_REGISTERED_NORMAL;
+	return 0;
+}
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
new file mode 100644
index 0000000..54f06f9
--- /dev/null
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -0,0 +1,738 @@
+/* GPRS LLC protocol implementation as per 3GPP TS 04.64 */
+
+/* (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 <errno.h>
+#include <stdint.h>
+
+#include <osmocore/msgb.h>
+#include <osmocore/linuxlist.h>
+#include <osmocore/timer.h>
+#include <osmocore/talloc.h>
+
+#include <openbsc/gsm_data.h>
+#include <openbsc/debug.h>
+#include <openbsc/gprs_sgsn.h>
+#include <openbsc/gprs_gmm.h>
+#include <openbsc/gprs_bssgp.h>
+#include <openbsc/gprs_llc.h>
+#include <openbsc/crc24.h>
+
+/* Section 8.9.9 LLC layer parameter default values */
+static const struct gprs_llc_params llc_default_params[] = {
+	[1] = {
+		.t200_201	= 5,
+		.n200		= 3,
+		.n201_u		= 400,
+	},
+	[2] = {
+		.t200_201	= 5,
+		.n200		= 3,
+		.n201_u		= 270,
+	},
+	[3] = {
+		.iov_i_exp	= 27,
+		.t200_201	= 5,
+		.n200		= 3,
+		.n201_u		= 500,
+		.n201_i		= 1503,
+		.mD		= 1520,
+		.mU		= 1520,
+		.kD		= 16,
+		.kU		= 16,
+	},
+	[5] = {
+		.iov_i_exp	= 27,
+		.t200_201	= 10,
+		.n200		= 3,
+		.n201_u		= 500,
+		.n201_i		= 1503,
+		.mD		= 760,
+		.mU		= 760,
+		.kD		= 8,
+		.kU		= 8,
+	},
+	[7] = {
+		.t200_201	= 20,
+		.n200		= 3,
+		.n201_u		= 270,
+	},
+	[8] = {
+		.t200_201	= 20,
+		.n200		= 3,
+		.n201_u		= 270,
+	},
+	[9] = {
+		.iov_i_exp	= 27,
+		.t200_201	= 20,
+		.n200		= 3,
+		.n201_u		= 500,
+		.n201_i		= 1503,
+		.mD		= 380,
+		.mU		= 380,
+		.kD		= 4,
+		.kU		= 4,
+	},
+	[11] = {
+		.iov_i_exp	= 27,
+		.t200_201	= 40,
+		.n200		= 3,
+		.n201_u		= 500,
+		.n201_i		= 1503,
+		.mD		= 190,
+		.mU		= 190,
+		.kD		= 2,
+		.kU		= 2,
+	},
+};
+
+LLIST_HEAD(gprs_llc_llmes);
+void *llc_tall_ctx;
+
+/* lookup LLC Entity based on DLCI (TLLI+SAPI tuple) */
+static struct gprs_llc_lle *lle_by_tlli_sapi(uint32_t tlli, uint8_t sapi)
+{
+	struct gprs_llc_llme *llme;
+
+	llist_for_each_entry(llme, &gprs_llc_llmes, list) {
+		if (llme->tlli == tlli || llme->old_tlli == tlli)
+			return &llme->lle[sapi];
+	}
+	return NULL;
+}
+
+static void lle_init(struct gprs_llc_llme *llme, uint8_t sapi)
+{
+	struct gprs_llc_lle *lle = &llme->lle[sapi];
+
+	lle->llme = llme;
+	lle->sapi = sapi;
+	lle->state = GPRS_LLES_UNASSIGNED;
+
+	/* Initialize according to parameters */
+	memcpy(&lle->params, &llc_default_params[sapi], sizeof(lle->params));
+}
+
+static struct gprs_llc_llme *llme_alloc(uint32_t tlli)
+{
+	struct gprs_llc_llme *llme;
+	uint32_t i;
+
+	llme = talloc_zero(llc_tall_ctx, struct gprs_llc_llme);
+	if (!llme)
+		return NULL;
+
+	llme->tlli = tlli;
+	llme->state = GPRS_LLMS_UNASSIGNED;
+
+	for (i = 0; i < ARRAY_SIZE(llme->lle); i++)
+		lle_init(llme, i);
+
+	llist_add(&llme->list, &gprs_llc_llmes);
+
+	return llme;
+}
+
+enum gprs_llc_cmd {
+	GPRS_LLC_NULL,
+	GPRS_LLC_RR,
+	GPRS_LLC_ACK,
+	GPRS_LLC_RNR,
+	GPRS_LLC_SACK,
+	GPRS_LLC_DM,
+	GPRS_LLC_DISC,
+	GPRS_LLC_UA,
+	GPRS_LLC_SABM,
+	GPRS_LLC_FRMR,
+	GPRS_LLC_XID,
+	GPRS_LLC_UI,
+};
+
+static const struct value_string llc_cmd_strs[] = {
+	{ GPRS_LLC_NULL,	"NULL" },
+	{ GPRS_LLC_RR,		"RR" },
+	{ GPRS_LLC_ACK,		"ACK" },
+	{ GPRS_LLC_RNR,		"RNR" },
+	{ GPRS_LLC_SACK,	"SACK" },
+	{ GPRS_LLC_DM,		"DM" },
+	{ GPRS_LLC_DISC,	"DISC" },
+	{ GPRS_LLC_UA,		"UA" },
+	{ GPRS_LLC_SABM,	"SABM" },
+	{ GPRS_LLC_FRMR,	"FRMR" },
+	{ GPRS_LLC_XID,		"XID" },
+	{ GPRS_LLC_UI,		"UI" },
+	{ 0, NULL }
+};
+
+struct gprs_llc_hdr_parsed {
+	uint8_t sapi;
+	uint8_t is_cmd:1,
+		 ack_req:1,
+		 is_encrypted:1;
+	uint32_t seq_rx;
+	uint32_t seq_tx;
+	uint32_t fcs;
+	uint32_t fcs_calc;
+	uint8_t *data;
+	uint16_t data_len;
+	enum gprs_llc_cmd cmd;
+};
+
+#define LLC_ALLOC_SIZE 16384
+#define UI_HDR_LEN	3
+#define N202		4
+#define CRC24_LENGTH	3
+
+static int gprs_llc_fcs(uint8_t *data, unsigned int len)
+{
+	uint32_t fcs_calc;
+
+	fcs_calc = crc24_calc(INIT_CRC24, data, len);
+	fcs_calc = ~fcs_calc;
+	fcs_calc &= 0xffffff;
+
+	return fcs_calc;
+}
+
+static void t200_expired(void *data)
+{
+	struct gprs_llc_lle *lle = data;
+
+	/* 8.5.1.3: Expiry of T200 */
+
+	if (lle->retrans_ctr >= lle->params.n200) {
+		/* FIXME: LLGM-STATUS-IND, LL-RELEASE-IND/CNF */
+		lle->state = GPRS_LLES_ASSIGNED_ADM;
+	}
+
+	switch (lle->state) {
+	case GPRS_LLES_LOCAL_EST:
+		/* FIXME: retransmit SABM */
+		/* FIXME: re-start T200 */
+		lle->retrans_ctr++;
+		break;
+	case GPRS_LLES_LOCAL_REL:
+		/* FIXME: retransmit DISC */
+		/* FIXME: re-start T200 */
+		lle->retrans_ctr++;
+		break;
+	}
+
+}
+
+static void t201_expired(void *data)
+{
+	struct gprs_llc_lle *lle = data;
+
+	if (lle->retrans_ctr < lle->params.n200) {
+		/* FIXME: transmit apropriate supervisory frame (8.6.4.1) */
+		/* FIXME: set timer T201 */
+		lle->retrans_ctr++;
+	}
+}
+
+int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command,
+		  enum gprs_llc_u_cmd u_cmd, int pf_bit)
+{
+	uint8_t *fcs, *llch;
+	uint8_t addr, ctrl;
+	uint32_t fcs_calc;
+
+	/* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */
+
+	/* Address Field */
+	addr = sapi & 0xf;
+	if (command)
+		addr |= 0x40;
+
+	/* 6.3 Figure 8 */
+	ctrl = 0xe0 | u_cmd;
+	if (pf_bit)
+		ctrl |= 0x10;
+
+	/* prepend LLC UI header */
+	llch = msgb_push(msg, 2);
+	llch[0] = addr;
+	llch[1] = ctrl;
+
+	/* append FCS to end of frame */
+	fcs = msgb_put(msg, 3);
+	fcs_calc = gprs_llc_fcs(llch, fcs - llch);
+	fcs[0] = fcs_calc & 0xff;
+	fcs[1] = (fcs_calc >> 8) & 0xff;
+	fcs[2] = (fcs_calc >> 16) & 0xff;
+
+	/* Identifiers passed down: (BVCI, NSEI) */
+
+	/* Send BSSGP-DL-UNITDATA.req */
+	return gprs_bssgp_tx_dl_ud(msg, NULL);
+}
+
+/* Send XID response to LLE */
+static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg)
+{
+	/* copy identifiers from LLE to ensure lower layers can route */
+	msgb_tlli(msg) = lle->llme->tlli;
+	msgb_bvci(msg) = lle->llme->bvci;
+	msgb_nsei(msg) = lle->llme->nsei;
+
+	return gprs_llc_tx_u(msg, lle->sapi, 0, GPRS_LLC_U_XID, 1);
+}
+
+/* Transmit a UI frame over the given SAPI */
+int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
+		   void *mmctx)
+{
+	struct gprs_llc_lle *lle;
+	uint8_t *fcs, *llch;
+	uint8_t addr, ctrl[2];
+	uint32_t fcs_calc;
+	uint16_t nu = 0;
+
+	/* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */
+
+	/* look-up or create the LL Entity for this (TLLI, SAPI) tuple */
+	lle = lle_by_tlli_sapi(msgb_tlli(msg), sapi);
+	if (!lle) {
+		struct gprs_llc_llme *llme;
+		llme = llme_alloc(msgb_tlli(msg));
+		lle = &llme->lle[sapi];
+	}
+
+	if (msg->len > lle->params.n201_u) {
+		LOGP(DLLC, LOGL_ERROR, "Cannot Tx %u bytes (N201-U=%u)\n",
+			msg->len, lle->params.n201_u);
+		return -EFBIG;
+	}
+
+	/* Update LLE's (BVCI, NSEI) tuple */
+	lle->llme->bvci = msgb_bvci(msg);
+	lle->llme->nsei = msgb_nsei(msg);
+
+	/* Increment V(U) */
+	nu = lle->vu_send;
+	lle->vu_send = (lle->vu_send + 1) % 512;
+
+	/* Address Field */
+	addr = sapi & 0xf;
+	if (command)
+		addr |= 0x40;
+
+	/* Control Field */
+	ctrl[0] = 0xc0;
+	ctrl[0] |= nu >> 6;
+	ctrl[1] = (nu << 2) & 0xfc;
+	ctrl[1] |= 0x01; /* Protected Mode */
+
+	/* prepend LLC UI header */
+	llch = msgb_push(msg, 3);
+	llch[0] = addr;
+	llch[1] = ctrl[0];
+	llch[2] = ctrl[1];
+
+	/* append FCS to end of frame */
+	fcs = msgb_put(msg, 3);
+	fcs_calc = gprs_llc_fcs(llch, fcs - llch);
+	fcs[0] = fcs_calc & 0xff;
+	fcs[1] = (fcs_calc >> 8) & 0xff;
+	fcs[2] = (fcs_calc >> 16) & 0xff;
+
+	/* Identifiers passed down: (BVCI, NSEI) */
+
+	/* Send BSSGP-DL-UNITDATA.req */
+	return gprs_bssgp_tx_dl_ud(msg, mmctx);
+}
+
+static void gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph)
+{
+	DEBUGP(DLLC, "LLC SAPI=%u %c %c FCS=0x%06x(%s) ",
+		gph->sapi, gph->is_cmd ? 'C' : 'R', gph->ack_req ? 'A' : ' ',
+		gph->fcs, gph->fcs_calc == gph->fcs ? "correct" : "WRONG");
+
+	if (gph->cmd)
+		DEBUGPC(DLLC, "CMD=%s ", get_value_string(llc_cmd_strs, gph->cmd));
+
+	if (gph->data)
+		DEBUGPC(DLLC, "DATA ");
+
+	DEBUGPC(DLLC, "\n");
+}
+static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph,
+			   struct gprs_llc_lle *lle)
+{
+	switch (gph->cmd) {
+	case GPRS_LLC_SABM: /* Section 6.4.1.1 */
+		lle->v_sent = lle->v_ack = lle->v_recv = 0;
+		if (lle->state == GPRS_LLES_ASSIGNED_ADM) {
+			/* start re-establishment (8.7.1) */
+		}
+		lle->state = GPRS_LLES_REMOTE_EST;
+		/* FIXME: Send UA */
+		lle->state = GPRS_LLES_ABM;
+		/* FIXME: process data */
+		break;
+	case GPRS_LLC_DISC: /* Section 6.4.1.2 */
+		/* FIXME: Send UA */
+		/* terminate ABM */
+		lle->state = GPRS_LLES_ASSIGNED_ADM;
+		break;
+	case GPRS_LLC_UA: /* Section 6.4.1.3 */
+		if (lle->state == GPRS_LLES_LOCAL_EST)
+			lle->state = GPRS_LLES_ABM;
+		break;
+	case GPRS_LLC_DM: /* Section 6.4.1.4: ABM cannot be performed */
+		if (lle->state == GPRS_LLES_LOCAL_EST)
+			lle->state = GPRS_LLES_ASSIGNED_ADM;
+		break;
+	case GPRS_LLC_FRMR: /* Section 6.4.1.5 */
+		break;
+	case GPRS_LLC_XID: /* Section 6.4.1.6 */
+		/* FIXME: implement XID negotiation using SNDCP */
+		{
+			struct msgb *resp;
+			uint8_t *xid;
+			resp = msgb_alloc_headroom(4096, 1024, "LLC_XID");
+			xid = msgb_put(resp, gph->data_len);
+			memcpy(xid, gph->data, gph->data_len);
+			gprs_llc_tx_xid(lle, resp);
+		}
+		break;
+	case GPRS_LLC_UI:
+		if (gph->seq_tx < lle->vu_recv) {
+			LOGP(DLLC, "TLLI=%08x dropping UI, vurecv %u <= %u\n",
+				gph->seq_tx, lle->vu_recv);
+			return -EIO;
+		}
+		/* Increment the sequence number that we expect in the next frame */
+		lle->vu_recv = (gph->seq_tx + 1) % 512;
+		break;
+	}
+
+	return 0;
+}
+
+/* parse a GPRS LLC header, also check for invalid frames */
+static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
+			      uint8_t *llc_hdr, int len)
+{
+	uint8_t *ctrl = llc_hdr+1;
+	int is_sack = 0;
+	unsigned int crc_length;
+	uint32_t fcs_calc;
+
+	if (len <= CRC24_LENGTH)
+		return -EIO;
+
+	crc_length = len - CRC24_LENGTH;
+
+	ghp->ack_req = 0;
+
+	/* Section 5.5: FCS */
+	ghp->fcs = *(llc_hdr + len - 3);
+	ghp->fcs |= *(llc_hdr + len - 2) << 8;
+	ghp->fcs |= *(llc_hdr + len - 1) << 16;
+
+	/* Section 6.2.1: invalid PD field */
+	if (llc_hdr[0] & 0x80)
+		return -EIO;
+
+	/* This only works for the MS->SGSN direction */
+	if (llc_hdr[0] & 0x40)
+		ghp->is_cmd = 0;
+	else
+		ghp->is_cmd = 1;
+
+	ghp->sapi = llc_hdr[0] & 0xf;
+
+	/* Section 6.2.3: check for reserved SAPI */
+	switch (ghp->sapi) {
+	case 0:
+	case 4:
+	case 6:
+	case 0xa:
+	case 0xc:
+	case 0xd:
+	case 0xf:
+		return -EINVAL;
+	}
+
+	if ((ctrl[0] & 0x80) == 0) {
+		/* I (Information transfer + Supervisory) format */
+		uint8_t k;
+
+		ghp->data = ctrl + 3;
+
+		if (ctrl[0] & 0x40)
+			ghp->ack_req = 1;
+
+		ghp->seq_tx  = (ctrl[0] & 0x1f) << 4;
+		ghp->seq_tx |= (ctrl[1] >> 4);
+
+		ghp->seq_rx  = (ctrl[1] & 0x7) << 6;
+		ghp->seq_rx |= (ctrl[2] >> 2);
+
+		switch (ctrl[2] & 0x03) {
+		case 0:
+			ghp->cmd = GPRS_LLC_RR;
+			break;
+		case 1:
+			ghp->cmd = GPRS_LLC_ACK;
+			break;
+		case 2:
+			ghp->cmd = GPRS_LLC_RNR;
+			break;
+		case 3:
+			ghp->cmd = GPRS_LLC_SACK;
+			k = ctrl[3] & 0x1f;
+			ghp->data += 1 + k;
+			break;
+		}
+		ghp->data_len = (llc_hdr + len - 3) - ghp->data;
+	} else if ((ctrl[0] & 0xc0) == 0x80) {
+		/* S (Supervisory) format */
+		ghp->data = NULL;
+		ghp->data_len = 0;
+
+		if (ctrl[0] & 0x20)
+			ghp->ack_req = 1;
+		ghp->seq_rx  = (ctrl[0] & 0x7) << 6;
+		ghp->seq_rx |= (ctrl[1] >> 2);
+
+		switch (ctrl[1] & 0x03) {
+		case 0:
+			ghp->cmd = GPRS_LLC_RR;
+			break;
+		case 1:
+			ghp->cmd = GPRS_LLC_ACK;
+			break;
+		case 2:
+			ghp->cmd = GPRS_LLC_RNR;
+			break;
+		case 3:
+			ghp->cmd = GPRS_LLC_SACK;
+			break;
+		}
+	} else if ((ctrl[0] & 0xe0) == 0xc0) {
+		/* UI (Unconfirmed Inforamtion) format */
+		ghp->cmd = GPRS_LLC_UI;
+		ghp->data = ctrl + 2;
+		ghp->data_len = (llc_hdr + len - 3) - ghp->data;
+
+		ghp->seq_tx  = (ctrl[0] & 0x7) << 6;
+		ghp->seq_tx |= (ctrl[1] >> 2);
+		if (ctrl[1] & 0x02) {
+			ghp->is_encrypted = 1;
+			/* FIXME: encryption */
+		}
+		if (ctrl[1] & 0x01) {
+			/* FCS over hdr + all inf fields */
+		} else {
+			/* FCS over hdr + N202 octets (4) */
+			if (crc_length > UI_HDR_LEN + N202)
+				crc_length = UI_HDR_LEN + N202;
+		}
+	} else {
+		/* U (Unnumbered) format: 1 1 1 P/F M4 M3 M2 M1 */
+		ghp->data = NULL;
+		ghp->data_len = 0;
+
+		switch (ctrl[0] & 0xf) {
+		case GPRS_LLC_U_NULL_CMD:
+			ghp->cmd = GPRS_LLC_NULL;
+			break;
+		case GPRS_LLC_U_DM_RESP:
+			ghp->cmd = GPRS_LLC_DM;
+			break;
+		case GPRS_LLC_U_DISC_CMD:
+			ghp->cmd = GPRS_LLC_DISC;
+			break;
+		case GPRS_LLC_U_UA_RESP:
+			ghp->cmd = GPRS_LLC_UA;
+			break;
+		case GPRS_LLC_U_SABM_CMD:
+			ghp->cmd = GPRS_LLC_SABM;
+			break;
+		case GPRS_LLC_U_FRMR_RESP:
+			ghp->cmd = GPRS_LLC_FRMR;
+			break;
+		case GPRS_LLC_U_XID:
+			ghp->cmd = GPRS_LLC_XID;
+			ghp->data = ctrl + 1;
+			ghp->data_len = (llc_hdr + len - 3) - ghp->data;
+			break;
+		default:
+			return -EIO;
+		}
+	}
+
+	/* calculate what FCS we expect */
+	ghp->fcs_calc = gprs_llc_fcs(llc_hdr, crc_length);
+
+	/* FIXME: parse sack frame */
+	if (ghp->cmd == GPRS_LLC_SACK) {
+		LOGP(DLLC, LOGL_NOTICE, "Unsupported SACK frame\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/* receive an incoming LLC PDU (BSSGP-UL-UNITDATA-IND, 7.2.4.2) */
+int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
+{
+	struct bssgp_ud_hdr *udh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);
+	struct gprs_llc_hdr *lh = msgb_llch(msg);
+	struct gprs_llc_hdr_parsed llhp;
+	struct gprs_llc_lle *lle;
+	int rc = 0;
+
+	/* Identifiers from DOWN: NSEI, BVCI, TLLI */
+
+	memset(&llhp, 0, sizeof(llhp));
+	rc = gprs_llc_hdr_parse(&llhp, (uint8_t *) lh, TLVP_LEN(tv, BSSGP_IE_LLC_PDU));
+	gprs_llc_hdr_dump(&llhp);
+	if (rc < 0) {
+		LOGP(DLLC, LOGL_NOTICE, "Error during LLC header parsing\n");
+		return rc;
+	}
+
+	if (llhp.fcs != llhp.fcs_calc) {
+		LOGP(DLLC, LOGL_INFO, "Dropping frame with invalid FCS\n");
+		return -EIO;
+	}
+
+	switch (gprs_tlli_type(msgb_tlli(msg))) {
+	case TLLI_LOCAL:
+	case TLLI_FOREIGN:
+	case TLLI_RANDOM:
+	case TLLI_AUXILIARY:
+		break;
+	default:
+		LOGP(DLLC, LOGL_ERROR,
+			"Discarding frame with strange TLLI type\n");
+		break;
+	}
+
+	/* find the LLC Entity for this TLLI+SAPI tuple */
+	lle = lle_by_tlli_sapi(msgb_tlli(msg), llhp.sapi);
+
+	/* 7.2.1.1 LLC belonging to unassigned TLLI+SAPI shall be discarded,
+	 * except UID and XID frames with SAPI=1 */
+	if (!lle) {
+		if (llhp.sapi == GPRS_SAPI_GMM &&
+		    (llhp.cmd == GPRS_LLC_XID || llhp.cmd == GPRS_LLC_UI)) {
+			struct gprs_llc_llme *llme;
+			/* FIXME: don't use the TLLI but the 0xFFFF unassigned? */
+			llme = llme_alloc(msgb_tlli(msg));
+			lle = &llme->lle[llhp.sapi];
+		} else {
+			LOGP(DLLC, LOGL_NOTICE,
+				"unknown TLLI/SAPI: Silently dropping\n");
+			return 0;
+		}
+	}
+
+	/* Update LLE's (BVCI, NSEI) tuple */
+	lle->llme->bvci = msgb_bvci(msg);
+	lle->llme->nsei = msgb_nsei(msg);
+
+	/* Receive and Process the actual LLC frame */
+	rc = gprs_llc_hdr_rx(&llhp, lle);
+	if (rc < 0)
+		return rc;
+
+	/* llhp.data is only set when we need to send LL_[UNIT]DATA_IND up */
+	if (llhp.data) {
+		msgb_gmmh(msg) = llhp.data;
+		switch (llhp.sapi) {
+		case GPRS_SAPI_GMM:
+			/* send LL_UNITDATA_IND to GMM */
+			rc = gsm0408_gprs_rcvmsg(msg, lle->llme);
+			break;
+		case GPRS_SAPI_SNDCP3:
+		case GPRS_SAPI_SNDCP5:
+		case GPRS_SAPI_SNDCP9:
+		case GPRS_SAPI_SNDCP11:
+			/* send LL_DATA_IND/LL_UNITDATA_IND to SNDCP */
+			rc = sndcp_llunitdata_ind(msg, lle, llhp.data, llhp.data_len);
+			break;
+		case GPRS_SAPI_SMS:
+			/* FIXME */
+		case GPRS_SAPI_TOM2:
+		case GPRS_SAPI_TOM8:
+			/* FIXME: send LL_DATA_IND/LL_UNITDATA_IND to TOM */
+		default:
+			LOGP(DLLC, LOGL_NOTICE, "Unsupported SAPI %u\n", llhp.sapi);
+			rc = -EINVAL;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+/* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */
+int gprs_llgmm_assign(struct gprs_llc_llme *llme,
+		      uint32_t old_tlli, uint32_t new_tlli,
+		      enum gprs_ciph_algo alg, const uint8_t *kc)
+{
+	unsigned int i;
+
+	if (old_tlli == 0xffffffff && new_tlli != 0xffffffff) {
+		/* TLLI Assignment 8.3.1 */
+		/* New TLLI shall be assigned and used when (re)transmitting LLC frames */
+		/* If old TLLI != 0xffffffff was assigned to LLME, then TLLI
+		 * old is unassigned.  Only TLLI new shall be accepted when
+		 * received from peer. */
+
+		/* If TLLI old == 0xffffffff was assigned to LLME, then this is
+		 * TLLI assignmemt according to 8.3.1 */
+		llme->old_tlli = 0;
+		llme->tlli = new_tlli;
+		llme->state = GPRS_LLMS_ASSIGNED;
+		/* 8.5.3.1 For all LLE's */
+		for (i = 0; i < ARRAY_SIZE(llme->lle); i++) {
+			struct gprs_llc_lle *l = &llme->lle[i];
+			l->vu_send = l->vu_recv = 0;
+			l->retrans_ctr = 0;
+			l->state = GPRS_LLES_ASSIGNED_ADM;
+			/* FIXME Set parameters according to table 9 */
+		}
+	} else if (old_tlli != 0xffffffff && new_tlli != 0xffffffff) {
+		/* TLLI Change 8.3.2 */
+		/* Both TLLI Old and TLLI New are assigned; use New when
+		 * (re)transmitting.  Accept toth Old and New on Rx */
+		llme->old_tlli = llme->tlli;
+		llme->tlli = new_tlli;
+		llme->state = GPRS_LLMS_ASSIGNED;
+	} else if (old_tlli != 0xffffffff && new_tlli == 0xffffffff) {
+		/* TLLI Unassignment 8.3.3) */
+		llme->tlli = llme->old_tlli = 0;
+		llme->state = GPRS_LLMS_UNASSIGNED;
+		for (i = 0; i < ARRAY_SIZE(llme->lle); i++) {
+			struct gprs_llc_lle *l = &llme->lle[i];
+			l->state = GPRS_LLES_UNASSIGNED;
+		}
+	} else
+		return -EINVAL;
+
+	return 0;
+}
diff --git a/openbsc/src/gprs/gprs_llc_vty.c b/openbsc/src/gprs/gprs_llc_vty.c
new file mode 100644
index 0000000..cb91a3a
--- /dev/null
+++ b/openbsc/src/gprs/gprs_llc_vty.c
@@ -0,0 +1,109 @@
+/* VTY interface for our GPRS LLC implementation */
+
+/* (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 <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <arpa/inet.h>
+
+#include <openbsc/gsm_data.h>
+#include <osmocore/msgb.h>
+#include <osmocore/tlv.h>
+#include <osmocore/talloc.h>
+#include <osmocore/select.h>
+#include <osmocore/rate_ctr.h>
+#include <openbsc/debug.h>
+#include <openbsc/signal.h>
+#include <openbsc/gprs_llc.h>
+
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/command.h>
+
+struct value_string gprs_llc_state_strs[] = {
+	{ GPRS_LLES_UNASSIGNED, 	"TLLI Unassigned" },
+	{ GPRS_LLES_ASSIGNED_ADM,	"TLLI Assigned" },
+	{ GPRS_LLES_LOCAL_EST,		"Local Establishment" },
+	{ GPRS_LLES_REMOTE_EST,		"Remote Establishment" },
+	{ GPRS_LLES_ABM,		"Asynchronous Balanced Mode" },
+	{ GPRS_LLES_LOCAL_REL,		"Local Release" },
+	{ GPRS_LLES_TIMER_REC,		"Timer Recovery" },
+};
+
+static void vty_dump_lle(struct vty *vty, struct gprs_llc_lle *lle)
+{
+	struct gprs_llc_params *par = &lle->params;
+	vty_out(vty, " SAPI %2u State %s VUsend=%u, VUrecv=%u", lle->sapi, 
+		get_value_string(gprs_llc_state_strs, lle->state),
+		lle->vu_send, lle->vu_recv);
+	vty_out(vty, " Vsent=%u Vack=%u Vrecv=%u, RetransCtr=%u%s",
+		lle->v_sent, lle->v_ack, lle->v_recv,
+		lle->retrans_ctr, VTY_NEWLINE);
+	vty_out(vty, "  T200=%u, N200=%u, N201-U=%u, N201-I=%u, mD=%u, "
+		"mU=%u, kD=%u, kU=%u%s", par->t200_201, par->n200,
+		par->n201_u, par->n201_i, par->mD, par->mU, par->kD,
+		par->kU, VTY_NEWLINE);
+}
+
+static uint8_t valid_sapis[] = { 1, 2, 3, 5, 7, 8, 9, 11 };
+
+static void vty_dump_llme(struct vty *vty, struct gprs_llc_llme *llme)
+{
+	unsigned int i;
+
+	vty_out(vty, "TLLI %08x (Old TLLI %08x) BVCI=%u NSEI=%u: State %s%s",
+		llme->tlli, llme->old_tlli, llme->bvci, llme->nsei,
+		get_value_string(gprs_llc_state_strs, llme->state), VTY_NEWLINE);
+
+	for (i = 0; i < ARRAY_SIZE(valid_sapis); i++) {
+		struct gprs_llc_lle *lle;
+		uint8_t sapi = valid_sapis[i];
+
+		if (sapi >= ARRAY_SIZE(llme->lle))
+			continue;
+
+		lle = &llme->lle[sapi];
+		vty_dump_lle(vty, lle);
+	}
+}
+
+
+DEFUN(show_llc, show_llc_cmd,
+	"show llc",
+	SHOW_STR "Display information about the LLC protocol")
+{
+	struct gprs_llc_llme *llme;
+
+	vty_out(vty, "State of LLC Entities%s", VTY_NEWLINE);
+	llist_for_each_entry(llme, &gprs_llc_llmes, list) {
+		vty_dump_llme(vty, llme);
+	}
+	return CMD_SUCCESS;
+}
+
+int gprs_llc_vty_init(void)
+{
+	install_element_ve(&show_llc_cmd);
+
+	return 0;
+}
diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c
new file mode 100644
index 0000000..3db1d67
--- /dev/null
+++ b/openbsc/src/gprs/gprs_ns.c
@@ -0,0 +1,989 @@
+/* GPRS Networks Service (NS) messages on the Gb interfacebvci = msgb_bvci(msg);
+ * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) */
+
+/* (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.
+ *
+ */
+
+/* Some introduction into NS:  NS is used typically on top of frame relay,
+ * but in the ip.access world it is encapsulated in UDP packets.  It serves
+ * as an intermediate shim betwen BSSGP and the underlying medium.  It doesn't
+ * do much, apart from providing congestion notification and status indication.
+ *
+ * Terms:
+ * 	NS		Network Service
+ *	NSVC		NS Virtual Connection
+ *	NSEI		NS Entity Identifier
+ *	NSVL		NS Virtual Link
+ *	NSVLI		NS Virtual Link Identifier
+ *	BVC		BSSGP Virtual Connection
+ *	BVCI		BSSGP Virtual Connection Identifier
+ *	NSVCG		NS Virtual Connection Goup
+ *	Blocked		NS-VC cannot be used for user traffic
+ *	Alive		Ability of a NS-VC to provide communication
+ *
+ *  There can be multiple BSSGP virtual connections over one (group of) NSVC's.  BSSGP will
+ * therefore identify the BSSGP virtual connection by a BVCI passed down to NS.
+ * NS then has to firgure out which NSVC's are responsible for this BVCI.
+ * Those mappings are administratively configured.
+ */
+
+/* This implementation has the following limitations:
+ *  o Only one NS-VC for each NSE: No load-sharing function
+ *  o NSVCI 65535 and 65534 are reserved for internal use
+ *  o Only UDP is supported as of now, no frame relay support
+ *  o The IP Sub-Network-Service (SNS) as specified in 48.016 is not implemented
+ *  o There are no BLOCK and UNBLOCK timers (yet?)
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <arpa/inet.h>
+
+#include <openbsc/gsm_data.h>
+#include <osmocore/msgb.h>
+#include <osmocore/tlv.h>
+#include <osmocore/talloc.h>
+#include <osmocore/select.h>
+#include <osmocore/rate_ctr.h>
+#include <openbsc/debug.h>
+#include <openbsc/signal.h>
+#include <openbsc/gprs_ns.h>
+#include <openbsc/gprs_bssgp.h>
+#include <openbsc/gprs_ns_frgre.h>
+#include <openbsc/socket.h>
+
+static const struct tlv_definition ns_att_tlvdef = {
+	.def = {
+		[NS_IE_CAUSE]	= { TLV_TYPE_TvLV, 0 },
+		[NS_IE_VCI]	= { TLV_TYPE_TvLV, 0 },
+		[NS_IE_PDU]	= { TLV_TYPE_TvLV, 0 },
+		[NS_IE_BVCI]	= { TLV_TYPE_TvLV, 0 },
+		[NS_IE_NSEI]	= { TLV_TYPE_TvLV, 0 },
+	},
+};
+
+enum ns_ctr {
+	NS_CTR_PKTS_IN,
+	NS_CTR_PKTS_OUT,
+	NS_CTR_BYTES_IN,
+	NS_CTR_BYTES_OUT,
+	NS_CTR_BLOCKED,
+	NS_CTR_DEAD,
+};
+
+static const struct rate_ctr_desc nsvc_ctr_description[] = {
+	{ "packets.in", "Packets at NS Level ( In)" },
+	{ "packets.out","Packets at NS Level (Out)" },
+	{ "bytes.in",	"Bytes at NS Level   ( In)" },
+	{ "bytes.out",	"Bytes at NS Level   (Out)" },
+	{ "blocked",	"NS-VC Block count        " },
+	{ "dead",	"NS-VC gone dead count    " },
+};
+
+static const struct rate_ctr_group_desc nsvc_ctrg_desc = {
+	.group_name_prefix = "ns.nsvc",
+	.group_description = "NSVC Peer Statistics",
+	.num_ctr = ARRAY_SIZE(nsvc_ctr_description),
+	.ctr_desc = nsvc_ctr_description,
+};
+
+/* Lookup struct gprs_nsvc based on NSVCI */
+struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci)
+{
+	struct gprs_nsvc *nsvc;
+	llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) {
+		if (nsvc->nsvci == nsvci)
+			return nsvc;
+	}
+	return NULL;
+}
+
+/* Lookup struct gprs_nsvc based on NSVCI */
+struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei)
+{
+	struct gprs_nsvc *nsvc;
+	llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) {
+		if (nsvc->nsei == nsei)
+			return nsvc;
+	}
+	return NULL;
+}
+
+/* Lookup struct gprs_nsvc based on remote peer socket addr */
+static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi,
+					  struct sockaddr_in *sin)
+{
+	struct gprs_nsvc *nsvc;
+	llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) {
+		if (nsvc->ip.bts_addr.sin_addr.s_addr ==
+					sin->sin_addr.s_addr &&
+		    nsvc->ip.bts_addr.sin_port == sin->sin_port)
+			return nsvc;
+	}
+	return NULL;
+}
+
+static void gprs_ns_timer_cb(void *data);
+
+struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci)
+{
+	struct gprs_nsvc *nsvc;
+
+	LOGP(DNS, LOGL_INFO, "NSVCI=%u Creating NS-VC\n", nsvci);
+
+	nsvc = talloc_zero(nsi, struct gprs_nsvc);
+	nsvc->nsvci = nsvci;
+	/* before RESET procedure: BLOCKED and DEAD */
+	nsvc->state = NSE_S_BLOCKED;
+	nsvc->nsi = nsi;
+	nsvc->timer.cb = gprs_ns_timer_cb;
+	nsvc->timer.data = nsvc;
+	nsvc->ctrg = rate_ctr_group_alloc(nsvc, &nsvc_ctrg_desc, nsvci);
+
+	llist_add(&nsvc->list, &nsi->gprs_nsvcs);
+
+	return nsvc;
+}
+
+void nsvc_delete(struct gprs_nsvc *nsvc)
+{
+	if (bsc_timer_pending(&nsvc->timer))
+		bsc_del_timer(&nsvc->timer);
+	llist_del(&nsvc->list);
+	talloc_free(nsvc);
+}
+
+static void ns_dispatch_signal(struct gprs_nsvc *nsvc, unsigned int signal,
+			       uint8_t cause)
+{
+	struct ns_signal_data nssd;
+
+	nssd.nsvc = nsvc;
+	nssd.cause = cause;
+
+	dispatch_signal(SS_NS, signal, &nssd);
+}
+
+/* Section 10.3.2, Table 13 */
+static const struct value_string ns_cause_str[] = {
+	{ NS_CAUSE_TRANSIT_FAIL,	"Transit network failure" },
+	{ NS_CAUSE_OM_INTERVENTION, 	"O&M intervention" },
+	{ NS_CAUSE_EQUIP_FAIL,		"Equipment failure" },
+	{ NS_CAUSE_NSVC_BLOCKED,	"NS-VC blocked" },
+	{ NS_CAUSE_NSVC_UNKNOWN,	"NS-VC unknown" },
+	{ NS_CAUSE_BVCI_UNKNOWN,	"BVCI unknown" },
+	{ NS_CAUSE_SEM_INCORR_PDU,	"Semantically incorrect PDU" },
+	{ NS_CAUSE_PDU_INCOMP_PSTATE,	"PDU not compatible with protocol state" },
+	{ NS_CAUSE_PROTO_ERR_UNSPEC,	"Protocol error, unspecified" },
+	{ NS_CAUSE_INVAL_ESSENT_IE,	"Invalid essential IE" },
+	{ NS_CAUSE_MISSING_ESSENT_IE,	"Missing essential IE" },
+	{ 0, NULL }
+};
+
+const char *gprs_ns_cause_str(enum ns_cause cause)
+{
+	return get_value_string(ns_cause_str, cause);
+}
+
+static int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg);
+extern int grps_ns_frgre_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg);
+
+static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg)
+{
+	int ret;
+
+	log_set_context(BSC_CTX_NSVC, nsvc);
+
+	/* Increment number of Uplink bytes */
+	rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_OUT]);
+	rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_OUT], msgb_l2len(msg));
+
+	switch (nsvc->ll) {
+	case GPRS_NS_LL_UDP:
+		ret = nsip_sendmsg(nsvc, msg);
+		break;
+	case GPRS_NS_LL_FR_GRE:
+		ret = gprs_ns_frgre_sendmsg(nsvc, msg);
+		break;
+	default:
+		LOGP(DNS, LOGL_ERROR, "unsupported NS linklayer %u\n", nsvc->ll);
+		msgb_free(msg);
+		ret = -EIO;
+		break;
+	}
+	return ret;
+}
+
+static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type)
+{
+	struct msgb *msg = gprs_ns_msgb_alloc();
+	struct gprs_ns_hdr *nsh;
+
+	log_set_context(BSC_CTX_NSVC, nsvc);
+
+	if (!msg)
+		return -ENOMEM;
+
+	msg->l2h = msgb_put(msg, sizeof(*nsh));
+	nsh = (struct gprs_ns_hdr *) msg->l2h;
+
+	nsh->pdu_type = pdu_type;
+
+	return gprs_ns_tx(nsvc, msg);
+}
+
+int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause)
+{
+	struct msgb *msg = gprs_ns_msgb_alloc();
+	struct gprs_ns_hdr *nsh;
+	uint16_t nsvci = htons(nsvc->nsvci);
+	uint16_t nsei = htons(nsvc->nsei);
+
+	log_set_context(BSC_CTX_NSVC, nsvc);
+
+	if (!msg)
+		return -ENOMEM;
+
+	LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS RESET (NSVCI=%u, cause=%s)\n",
+		nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause));
+
+	msg->l2h = msgb_put(msg, sizeof(*nsh));
+	nsh = (struct gprs_ns_hdr *) msg->l2h;
+	nsh->pdu_type = NS_PDUT_RESET;
+
+	msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
+	msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
+	msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *) &nsei);
+
+	return gprs_ns_tx(nsvc, msg);
+
+}
+
+int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause,
+		      uint16_t bvci, struct msgb *orig_msg)
+{
+	struct msgb *msg = gprs_ns_msgb_alloc();
+	struct gprs_ns_hdr *nsh;
+	uint16_t nsvci = htons(nsvc->nsvci);
+
+	log_set_context(BSC_CTX_NSVC, nsvc);
+
+	bvci = htons(bvci);
+
+	if (!msg)
+		return -ENOMEM;
+
+	LOGP(DNS, LOGL_NOTICE, "NSEI=%u Tx NS STATUS (NSVCI=%u, cause=%s)\n",
+		nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause));
+
+	msg->l2h = msgb_put(msg, sizeof(*nsh));
+	nsh = (struct gprs_ns_hdr *) msg->l2h;
+	nsh->pdu_type = NS_PDUT_STATUS;
+
+	msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
+
+	/* Section 9.2.7.1: Static conditions for NS-VCI */
+	if (cause == NS_CAUSE_NSVC_BLOCKED ||
+	    cause == NS_CAUSE_NSVC_UNKNOWN)
+		msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
+
+	/* Section 9.2.7.2: Static conditions for NS PDU */
+	switch (cause) {
+	case NS_CAUSE_SEM_INCORR_PDU:
+	case NS_CAUSE_PDU_INCOMP_PSTATE:
+	case NS_CAUSE_PROTO_ERR_UNSPEC:
+	case NS_CAUSE_INVAL_ESSENT_IE:
+	case NS_CAUSE_MISSING_ESSENT_IE:
+		msgb_tvlv_put(msg, NS_IE_PDU, msgb_l2len(orig_msg),
+			      orig_msg->l2h);
+		break;
+	default:
+		break;
+	}
+
+	/* Section 9.2.7.3: Static conditions for BVCI */
+	if (cause == NS_CAUSE_BVCI_UNKNOWN)
+		msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&bvci);
+
+	return gprs_ns_tx(nsvc, msg);
+}
+
+int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause)
+{
+	struct msgb *msg = gprs_ns_msgb_alloc();
+	struct gprs_ns_hdr *nsh;
+	uint16_t nsvci = htons(nsvc->nsvci);
+
+	log_set_context(BSC_CTX_NSVC, nsvc);
+
+	if (!msg)
+		return -ENOMEM;
+
+	LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS BLOCK (NSVCI=%u, cause=%s)\n",
+		nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause));
+
+	/* be conservative and mark it as blocked even now! */
+	nsvc->state |= NSE_S_BLOCKED;
+	rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]);
+
+	msg->l2h = msgb_put(msg, sizeof(*nsh));
+	nsh = (struct gprs_ns_hdr *) msg->l2h;
+	nsh->pdu_type = NS_PDUT_BLOCK;
+
+	msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
+	msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
+
+	return gprs_ns_tx(nsvc, msg);
+}
+
+int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc)
+{
+	log_set_context(BSC_CTX_NSVC, nsvc);
+	LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS UNBLOCK (NSVCI=%u)\n",
+		nsvc->nsei, nsvc->nsvci);
+
+	return gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK);
+}
+
+int gprs_ns_tx_alive(struct gprs_nsvc *nsvc)
+{
+	log_set_context(BSC_CTX_NSVC, nsvc);
+	LOGP(DNS, LOGL_DEBUG, "NSEI=%u Tx NS ALIVE (NSVCI=%u)\n",
+		nsvc->nsei, nsvc->nsvci);
+
+	return gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE);
+}
+
+int gprs_ns_tx_alive_ack(struct gprs_nsvc *nsvc)
+{
+	log_set_context(BSC_CTX_NSVC, nsvc);
+	LOGP(DNS, LOGL_DEBUG, "NSEI=%u Tx NS ALIVE_ACK (NSVCI=%u)\n",
+		nsvc->nsei, nsvc->nsvci);
+
+	return gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE_ACK);
+}
+
+static const enum ns_timeout timer_mode_tout[_NSVC_TIMER_NR] = {
+	[NSVC_TIMER_TNS_RESET]	= NS_TOUT_TNS_RESET,
+	[NSVC_TIMER_TNS_ALIVE]	= NS_TOUT_TNS_ALIVE,
+	[NSVC_TIMER_TNS_TEST]	= NS_TOUT_TNS_TEST,
+};
+
+static const struct value_string timer_mode_strs[] = {
+	{ NSVC_TIMER_TNS_RESET, "tns-reset" },
+	{ NSVC_TIMER_TNS_ALIVE, "tns-alive" },
+	{ NSVC_TIMER_TNS_TEST, "tns-test" },
+	{ 0, NULL }
+};
+
+static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode)
+{
+	enum ns_timeout tout = timer_mode_tout[mode];
+	unsigned int seconds = nsvc->nsi->timeout[tout];
+
+	log_set_context(BSC_CTX_NSVC, nsvc);
+	DEBUGP(DNS, "NSEI=%u Starting timer in mode %s (%u seconds)\n",
+		nsvc->nsei, get_value_string(timer_mode_strs, mode),
+		seconds);
+		
+	if (bsc_timer_pending(&nsvc->timer))
+		bsc_del_timer(&nsvc->timer);
+
+	nsvc->timer_mode = mode;
+	bsc_schedule_timer(&nsvc->timer, seconds, 0);
+}
+
+static void gprs_ns_timer_cb(void *data)
+{
+	struct gprs_nsvc *nsvc = data;
+	enum ns_timeout tout = timer_mode_tout[nsvc->timer_mode];
+	unsigned int seconds = nsvc->nsi->timeout[tout];
+
+	log_set_context(BSC_CTX_NSVC, nsvc);
+	DEBUGP(DNS, "NSEI=%u Timer expired in mode %s (%u seconds)\n",
+		nsvc->nsei, get_value_string(timer_mode_strs, nsvc->timer_mode),
+		seconds);
+		
+	switch (nsvc->timer_mode) {
+	case NSVC_TIMER_TNS_ALIVE:
+		/* Tns-alive case: we expired without response ! */
+		nsvc->alive_retries++;
+		if (nsvc->alive_retries >
+			nsvc->nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]) {
+			/* mark as dead and blocked */
+			nsvc->state = NSE_S_BLOCKED;
+			rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]);
+			rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_DEAD]);
+			LOGP(DNS, LOGL_NOTICE,
+				"NSEI=%u Tns-alive expired more then "
+				"%u times, blocking NS-VC\n", nsvc->nsei,
+				nsvc->nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]);
+			ns_dispatch_signal(nsvc, S_NS_ALIVE_EXP, 0);
+			ns_dispatch_signal(nsvc, S_NS_BLOCK, NS_CAUSE_NSVC_BLOCKED);
+			return;
+		}
+		/* Tns-test case: send NS-ALIVE PDU */
+		gprs_ns_tx_alive(nsvc);
+		/* start Tns-alive timer */
+		nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE);
+		break;
+	case NSVC_TIMER_TNS_TEST:
+		/* Tns-test case: send NS-ALIVE PDU */
+		gprs_ns_tx_alive(nsvc);
+		/* start Tns-alive timer (transition into faster
+		 * alive retransmissions) */
+		nsvc->alive_retries = 0;
+		nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE);
+		break;
+	case NSVC_TIMER_TNS_RESET:
+		/* Chapter 7.3: Re-send the RESET */
+		gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION);
+		/* Re-start Tns-reset timer */
+		nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET);
+		break;
+	case _NSVC_TIMER_NR:
+		break;
+	}
+}
+
+/* Section 9.2.6 */
+static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc)
+{
+	struct msgb *msg = gprs_ns_msgb_alloc();
+	struct gprs_ns_hdr *nsh;
+	uint16_t nsvci, nsei;
+
+	log_set_context(BSC_CTX_NSVC, nsvc);
+	if (!msg)
+		return -ENOMEM;
+
+	nsvci = htons(nsvc->nsvci);
+	nsei = htons(nsvc->nsei);
+
+	msg->l2h = msgb_put(msg, sizeof(*nsh));
+	nsh = (struct gprs_ns_hdr *) msg->l2h;
+
+	nsh->pdu_type = NS_PDUT_RESET_ACK;
+
+	LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS RESET ACK (NSVCI=%u)\n",
+		nsvc->nsei, nsvc->nsvci);
+
+	msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
+	msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
+
+	return gprs_ns_tx(nsvc, msg);
+}
+
+/* Section 9.2.10: transmit side / NS-UNITDATA-REQUEST primitive */
+int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg)
+{
+	struct gprs_nsvc *nsvc;
+	struct gprs_ns_hdr *nsh;
+	uint16_t bvci = msgb_bvci(msg);
+
+	nsvc = nsvc_by_nsei(nsi, msgb_nsei(msg));
+	if (!nsvc) {
+		LOGP(DNS, LOGL_ERROR, "Unable to resolve NSEI %u "
+			"to NS-VC!\n", msgb_nsei(msg));
+		return -EINVAL;
+	}
+	log_set_context(BSC_CTX_NSVC, nsvc);
+
+	if (!(nsvc->state & NSE_S_ALIVE)) {
+		LOGP(DNS, LOGL_ERROR, "NSEI=%u is not alive, cannot send\n",
+			nsvc->nsei);
+		return -EBUSY;
+	}
+	if (nsvc->state & NSE_S_BLOCKED) {
+		LOGP(DNS, LOGL_ERROR, "NSEI=%u is blocked, cannot send\n",
+			nsvc->nsei);
+		return -EBUSY;
+	}
+
+	msg->l2h = msgb_push(msg, sizeof(*nsh) + 3);
+	nsh = (struct gprs_ns_hdr *) msg->l2h;
+	if (!nsh) {
+		LOGP(DNS, LOGL_ERROR, "Not enough headroom for NS header\n");
+		return -EIO;
+	}
+
+	nsh->pdu_type = NS_PDUT_UNITDATA;
+	/* spare octet in data[0] */
+	nsh->data[1] = bvci >> 8;
+	nsh->data[2] = bvci & 0xff;
+
+	return gprs_ns_tx(nsvc, msg);
+}
+
+/* Section 9.2.10: receive side */
+static int gprs_ns_rx_unitdata(struct gprs_nsvc *nsvc, struct msgb *msg)
+{
+	struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h;
+	uint16_t bvci;
+
+	if (nsvc->state & NSE_S_BLOCKED)
+		return gprs_ns_tx_status(nsvc, NS_CAUSE_NSVC_BLOCKED,
+					 0, msg);
+
+	/* spare octet in data[0] */
+	bvci = nsh->data[1] << 8 | nsh->data[2];
+	msgb_bssgph(msg) = &nsh->data[3];
+	msgb_bvci(msg) = bvci;
+
+	/* call upper layer (BSSGP) */
+	return nsvc->nsi->cb(GPRS_NS_EVT_UNIT_DATA, nsvc, msg, bvci);
+}
+
+/* Section 9.2.7 */
+static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg)
+{
+	struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
+	struct tlv_parsed tp;
+	uint8_t cause;
+	int rc;
+
+	LOGP(DNS, LOGL_NOTICE, "NSEI=%u Rx NS STATUS ", nsvc->nsei);
+
+	rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data,
+			msgb_l2len(msg) - sizeof(*nsh), 0, 0);
+	if (rc < 0) {
+		LOGPC(DNS, LOGL_NOTICE, "Error during TLV Parse\n");
+		LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx NS STATUS: "
+			"Error during TLV Parse\n", nsvc->nsei);
+		return rc;
+	}
+
+	if (!TLVP_PRESENT(&tp, NS_IE_CAUSE)) {
+		LOGPC(DNS, LOGL_INFO, "missing cause IE\n");
+		return -EINVAL;
+	}
+
+	cause = *TLVP_VAL(&tp, NS_IE_CAUSE);
+	LOGPC(DNS, LOGL_NOTICE, "cause=%s\n", gprs_ns_cause_str(cause));
+
+	return 0;
+}
+
+/* Section 7.3 */
+static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg)
+{
+	struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
+	struct tlv_parsed tp;
+	uint8_t *cause;
+	uint16_t *nsvci, *nsei;
+	int rc;
+
+	rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data,
+			msgb_l2len(msg) - sizeof(*nsh), 0, 0);
+	if (rc < 0) {
+		LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx NS RESET "
+			"Error during TLV Parse\n", nsvc->nsei);
+		return rc;
+	}
+
+	if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) ||
+	    !TLVP_PRESENT(&tp, NS_IE_VCI) ||
+	    !TLVP_PRESENT(&tp, NS_IE_NSEI)) {
+		LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n");
+		gprs_ns_tx_status(nsvc, NS_CAUSE_MISSING_ESSENT_IE, 0, msg);
+		return -EINVAL;
+	}
+
+	cause = (uint8_t *) TLVP_VAL(&tp, NS_IE_CAUSE);
+	nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI);
+	nsei = (uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI);
+
+	LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET (NSVCI=%u, cause=%s)\n",
+		nsvc->nsvci, nsvc->nsei, gprs_ns_cause_str(*cause));
+
+	/* Mark NS-VC as blocked and alive */
+	nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE;
+
+	nsvc->nsei = ntohs(*nsei);
+	nsvc->nsvci = ntohs(*nsvci);
+
+	/* start the test procedure */
+	gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE);
+	nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST);
+
+	/* inform interested parties about the fact that this NSVC
+	 * has received RESET */
+	ns_dispatch_signal(nsvc, S_NS_RESET, *cause);
+
+	return gprs_ns_tx_reset_ack(nsvc);
+}
+
+static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg)
+{
+	struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
+	struct tlv_parsed tp;
+	uint8_t *cause;
+	int rc;
+
+	LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei);
+
+	nsvc->state |= NSE_S_BLOCKED;
+
+	rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data,
+			msgb_l2len(msg) - sizeof(*nsh), 0, 0);
+	if (rc < 0) {
+		LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx NS BLOCK "
+			"Error during TLV Parse\n", nsvc->nsei);
+		return rc;
+	}
+
+	if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) ||
+	    !TLVP_PRESENT(&tp, NS_IE_VCI)) {
+		LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n");
+		gprs_ns_tx_status(nsvc, NS_CAUSE_MISSING_ESSENT_IE, 0, msg);
+		return -EINVAL;
+	}
+
+	cause = (uint8_t *) TLVP_VAL(&tp, NS_IE_CAUSE);
+	//nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI);
+
+	ns_dispatch_signal(nsvc, S_NS_BLOCK, *cause);
+	rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]);
+
+	return gprs_ns_tx_simple(nsvc, NS_PDUT_BLOCK_ACK);
+}
+
+/* main entry point, here incoming NS frames enter */
+int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg,
+		   struct sockaddr_in *saddr, enum gprs_ns_ll ll)
+{
+	struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
+	struct gprs_nsvc *nsvc;
+	int rc = 0;
+
+	/* look up the NSVC based on source address */
+	nsvc = nsvc_by_rem_addr(nsi, saddr);
+	if (!nsvc) {
+		struct tlv_parsed tp;
+		uint16_t nsei;
+		if (nsh->pdu_type == NS_PDUT_STATUS) {
+			LOGP(DNS, LOGL_INFO, "Ignoring NS STATUS from %s:%u "
+			     "for non-existing NS-VC\n",
+			     inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port));
+			return 0;
+		}
+		/* Only the RESET procedure creates a new NSVC */
+		if (nsh->pdu_type != NS_PDUT_RESET) {
+			/* Since we have no NSVC, we have to use a fake */
+			nsvc = nsi->unknown_nsvc;
+			log_set_context(BSC_CTX_NSVC, nsvc);
+			LOGP(DNS, LOGL_INFO, "Rejecting NS PDU type 0x%0x "
+				"from %s:%u for non-existing NS-VC\n",
+				nsh->pdu_type, inet_ntoa(saddr->sin_addr),
+				ntohs(saddr->sin_port));
+			nsvc->nsvci = nsvc->nsei = 0xfffe;
+			nsvc->ip.bts_addr = *saddr;
+			nsvc->state = NSE_S_ALIVE;
+			nsvc->ll = ll;
+#if 0
+			return gprs_ns_tx_reset(nsvc, NS_CAUSE_PDU_INCOMP_PSTATE);
+#else
+			return gprs_ns_tx_status(nsvc,
+						NS_CAUSE_PDU_INCOMP_PSTATE, 0,
+						msg);
+#endif
+		}
+		rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data,
+				msgb_l2len(msg) - sizeof(*nsh), 0, 0);
+		if (rc < 0) {
+			LOGP(DNS, LOGL_ERROR, "Rx NS RESET Error %d during "
+				"TLV Parse\n", rc);
+			return rc;
+		}
+		if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) ||
+		    !TLVP_PRESENT(&tp, NS_IE_VCI) ||
+		    !TLVP_PRESENT(&tp, NS_IE_NSEI)) {
+			LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n");
+			gprs_ns_tx_status(nsvc, NS_CAUSE_MISSING_ESSENT_IE, 0,
+					  msg);
+			return -EINVAL;
+		}
+		nsei = ntohs(*(uint16_t *)TLVP_VAL(&tp, NS_IE_NSEI));
+		/* Check if we already know this NSEI, the remote end might
+		 * simply have changed addresses, or it is a SGSN */
+		nsvc = nsvc_by_nsei(nsi, nsei);
+		if (!nsvc) {
+			nsvc = nsvc_create(nsi, 0xffff);
+			nsvc->ll = ll;
+			log_set_context(BSC_CTX_NSVC, nsvc);
+			LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n",
+				inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port));
+		}
+		/* Update the remote peer IP address/port */
+		nsvc->ip.bts_addr = *saddr;
+	} else
+		msgb_nsei(msg) = nsvc->nsei;
+
+	log_set_context(BSC_CTX_NSVC, nsvc);
+
+	/* Increment number of Incoming bytes */
+	rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_IN]);
+	rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_IN], msgb_l2len(msg));
+
+	switch (nsh->pdu_type) {
+	case NS_PDUT_ALIVE:
+		/* If we're dead and blocked and suddenly receive a
+		 * NS-ALIVE out of the blue, we might have been re-started
+		 * and should send a NS-RESET to make sure everything recovers
+		 * fine. */
+		if (nsvc->state == NSE_S_BLOCKED)
+			rc = gprs_ns_tx_reset(nsvc, NS_CAUSE_PDU_INCOMP_PSTATE);
+		else
+			rc = gprs_ns_tx_alive_ack(nsvc);
+		break;
+	case NS_PDUT_ALIVE_ACK:
+		/* stop Tns-alive and start Tns-test */
+		nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST);
+		if (nsvc->remote_end_is_sgsn) {
+			/* FIXME: this should be one level higher */
+			if (nsvc->state & NSE_S_BLOCKED)
+				rc = gprs_ns_tx_unblock(nsvc);
+		}
+		break;
+	case NS_PDUT_UNITDATA:
+		/* actual user data */
+		rc = gprs_ns_rx_unitdata(nsvc, msg);
+		break;
+	case NS_PDUT_STATUS:
+		rc = gprs_ns_rx_status(nsvc, msg);
+		break;
+	case NS_PDUT_RESET:
+		rc = gprs_ns_rx_reset(nsvc, msg);
+		break;
+	case NS_PDUT_RESET_ACK:
+		LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei);
+		/* mark NS-VC as blocked + active */
+		nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE;
+		nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE;
+		rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]);
+		if (nsvc->persistent || nsvc->remote_end_is_sgsn) {
+			/* stop RESET timer */
+			bsc_del_timer(&nsvc->timer);
+		}
+		/* Initiate TEST proc.: Send ALIVE and start timer */
+		rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE);
+		nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST);
+		break;
+	case NS_PDUT_UNBLOCK:
+		/* Section 7.2: unblocking procedure */
+		LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei);
+		nsvc->state &= ~NSE_S_BLOCKED;
+		ns_dispatch_signal(nsvc, S_NS_UNBLOCK, 0);
+		rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK);
+		break;
+	case NS_PDUT_UNBLOCK_ACK:
+		LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei);
+		/* mark NS-VC as unblocked + active */
+		nsvc->state = NSE_S_ALIVE;
+		nsvc->remote_state = NSE_S_ALIVE;
+		ns_dispatch_signal(nsvc, S_NS_UNBLOCK, 0);
+		break;
+	case NS_PDUT_BLOCK:
+		rc = gprs_ns_rx_block(nsvc, msg);
+		break;
+	case NS_PDUT_BLOCK_ACK:
+		LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei);
+		/* mark remote NS-VC as blocked + active */
+		nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE;
+		break;
+	default:
+		LOGP(DNS, LOGL_NOTICE, "NSEI=%u Rx Unknown NS PDU type 0x%02x\n",
+			nsvc->nsei, nsh->pdu_type);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb)
+{
+	struct gprs_ns_inst *nsi = talloc_zero(tall_bsc_ctx, struct gprs_ns_inst);
+
+	nsi->cb = cb;
+	INIT_LLIST_HEAD(&nsi->gprs_nsvcs);
+	nsi->timeout[NS_TOUT_TNS_BLOCK] = 3;
+	nsi->timeout[NS_TOUT_TNS_BLOCK_RETRIES] = 3;
+	nsi->timeout[NS_TOUT_TNS_RESET] = 3;
+	nsi->timeout[NS_TOUT_TNS_RESET_RETRIES] = 3;
+	nsi->timeout[NS_TOUT_TNS_TEST] = 30;
+	nsi->timeout[NS_TOUT_TNS_ALIVE] = 3;
+	nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES] = 10;
+
+	/* Create the dummy NSVC that we use for sending
+	 * messages to non-existant/unknown NS-VC's */
+	nsi->unknown_nsvc = nsvc_create(nsi, 0xfffe);
+	llist_del(&nsi->unknown_nsvc->list);
+
+	return nsi;
+}
+
+void gprs_ns_destroy(struct gprs_ns_inst *nsi)
+{
+	/* FIXME: clear all timers */
+
+	/* recursively free the NSI and all its NSVCs */
+	talloc_free(nsi);
+}
+
+
+/* NS-over-IP code, according to 3GPP TS 48.016 Chapter 6.2
+ * We don't support Size Procedure, Configuration Procedure, ChangeWeight Procedure */
+
+/* Read a single NS-over-IP message */
+static struct msgb *read_nsip_msg(struct bsc_fd *bfd, int *error,
+				  struct sockaddr_in *saddr)
+{
+	struct msgb *msg = gprs_ns_msgb_alloc();
+	int ret = 0;
+	socklen_t saddr_len = sizeof(*saddr);
+
+	if (!msg) {
+		*error = -ENOMEM;
+		return NULL;
+	}
+
+	ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE - NS_ALLOC_HEADROOM, 0,
+			(struct sockaddr *)saddr, &saddr_len);
+	if (ret < 0) {
+		LOGP(DNS, LOGL_ERROR, "recv error %s during NSIP recv\n",
+			strerror(errno));
+		msgb_free(msg);
+		*error = ret;
+		return NULL;
+	} else if (ret == 0) {
+		msgb_free(msg);
+		*error = ret;
+		return NULL;
+	}
+
+	msg->l2h = msg->data;
+	msgb_put(msg, ret);
+
+	return msg;
+}
+
+static int handle_nsip_read(struct bsc_fd *bfd)
+{
+	int error;
+	struct sockaddr_in saddr;
+	struct gprs_ns_inst *nsi = bfd->data;
+	struct msgb *msg = read_nsip_msg(bfd, &error, &saddr);
+
+	if (!msg)
+		return error;
+
+	error = gprs_ns_rcvmsg(nsi, msg, &saddr, GPRS_NS_LL_UDP);
+
+	msgb_free(msg);
+
+	return error;
+}
+
+static int handle_nsip_write(struct bsc_fd *bfd)
+{
+	/* FIXME: actually send the data here instead of nsip_sendmsg() */
+	return -EIO;
+}
+
+static int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg)
+{
+	int rc;
+	struct gprs_ns_inst *nsi = nsvc->nsi;
+	struct sockaddr_in *daddr = &nsvc->ip.bts_addr;
+
+	rc = sendto(nsi->nsip.fd.fd, msg->data, msg->len, 0,
+		  (struct sockaddr *)daddr, sizeof(*daddr));
+
+	talloc_free(msg);
+
+	return rc;
+}
+
+/* UDP Port 23000 carries the LLC-in-BSSGP-in-NS protocol stack */
+static int nsip_fd_cb(struct bsc_fd *bfd, unsigned int what)
+{
+	int rc = 0;
+
+	if (what & BSC_FD_READ)
+		rc = handle_nsip_read(bfd);
+	if (what & BSC_FD_WRITE)
+		rc = handle_nsip_write(bfd);
+
+	return rc;
+}
+
+/* Listen for incoming GPRS packets */
+int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi)
+{
+	int ret;
+
+	ret = make_sock(&nsi->nsip.fd, IPPROTO_UDP, nsi->nsip.local_ip,
+			nsi->nsip.local_port, nsip_fd_cb);
+	if (ret < 0)
+		return ret;
+
+	nsi->nsip.fd.data = nsi;
+
+	return ret;
+}
+
+/* Initiate a RESET procedure */
+void gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause)
+{
+	LOGP(DNS, LOGL_INFO, "NSEI=%u RESET procedure based on API request\n",
+		nsvc->nsei);
+
+	/* Mark NS-VC locally as blocked and dead */
+	nsvc->state = NSE_S_BLOCKED;
+	/* Send NS-RESET PDU */
+	if (gprs_ns_tx_reset(nsvc, cause) < 0) {
+		LOGP(DNS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n",
+			nsvc->nsei);
+	}
+	/* Start Tns-reset */
+	nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET);
+}
+
+/* Establish a connection (from the BSS) to the SGSN */
+struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi,
+				struct sockaddr_in *dest, uint16_t nsei,
+				uint16_t nsvci)
+{
+	struct gprs_nsvc *nsvc;
+
+	nsvc = nsvc_by_rem_addr(nsi, dest);
+	if (!nsvc)
+		nsvc = nsvc_create(nsi, nsvci);
+	nsvc->ip.bts_addr = *dest;
+	nsvc->nsei = nsei;
+	nsvc->nsvci = nsvci;
+	nsvc->remote_end_is_sgsn = 1;
+
+	gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION);
+	return nsvc;
+}
diff --git a/openbsc/src/gprs/gprs_ns_frgre.c b/openbsc/src/gprs/gprs_ns_frgre.c
new file mode 100644
index 0000000..7436d0d
--- /dev/null
+++ b/openbsc/src/gprs/gprs_ns_frgre.c
@@ -0,0 +1,305 @@
+/* GPRS Networks Service (NS) messages on the Gb interface
+ * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) */
+
+/* NS-over-FR-over-GRE implementation */
+
+/* (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 <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+#include <osmocore/select.h>
+#include <osmocore/msgb.h>
+#include <osmocore/talloc.h>
+
+#include <openbsc/socket.h>
+#include <openbsc/debug.h>
+#include <openbsc/gprs_ns.h>
+
+#define GRE_PTYPE_FR	0x6559
+#define GRE_PTYPE_IPv4	0x0800
+#define GRE_PTYPE_KAR	0x0000	/* keepalive response */
+
+struct gre_hdr {
+	uint16_t flags;
+	uint16_t ptype;
+} __attribute__ ((packed));
+
+/* IPv4 messages inside the GRE tunnel might be GRE keepalives */
+static int handle_rx_gre_ipv4(struct bsc_fd *bfd, struct msgb *msg,
+				struct iphdr *iph, struct gre_hdr *greh)
+{
+	struct gprs_ns_inst *nsi = bfd->data;
+	int gre_payload_len;
+	struct iphdr *inner_iph;
+	struct gre_hdr *inner_greh;
+	struct sockaddr_in daddr;
+	struct in_addr ia;
+
+	gre_payload_len = msg->len - (iph->ihl*4 + sizeof(*greh));
+
+	inner_iph = (struct iphdr *) ((uint8_t *)greh + sizeof(*greh));
+
+	if (gre_payload_len < inner_iph->ihl*4 + sizeof(*inner_greh)) {
+		LOGP(DNS, LOGL_ERROR, "GRE keepalive too short\n");
+		return -EIO;
+	}
+
+	if (inner_iph->saddr != iph->daddr ||
+	    inner_iph->daddr != iph->saddr) {
+		LOGP(DNS, LOGL_ERROR,
+			"GRE keepalive with wrong tunnel addresses\n");
+		return -EIO;
+	}
+
+	if (inner_iph->protocol != IPPROTO_GRE) {
+		LOGP(DNS, LOGL_ERROR, "GRE keepalive with wrong protocol\n");
+		return -EIO;
+	}
+
+	inner_greh = (struct gre_hdr *) ((uint8_t *)inner_iph + iph->ihl*4);
+	if (inner_greh->ptype != htons(GRE_PTYPE_KAR)) {
+		LOGP(DNS, LOGL_ERROR, "GRE keepalive inner GRE type != 0\n");
+		return -EIO;
+	}
+
+	/* Actually send the response back */
+
+	daddr.sin_family = AF_INET;
+	daddr.sin_addr.s_addr = inner_iph->daddr;
+	daddr.sin_port = IPPROTO_GRE;
+
+	ia.s_addr = iph->saddr;
+	LOGP(DNS, LOGL_DEBUG, "GRE keepalive from %s, responding\n",
+		inet_ntoa(ia));
+
+	return sendto(nsi->frgre.fd.fd, inner_greh,
+		      gre_payload_len - inner_iph->ihl*4, 0,
+		      (struct sockaddr *)&daddr, sizeof(daddr));
+}
+
+static struct msgb *read_nsfrgre_msg(struct bsc_fd *bfd, int *error,
+					struct sockaddr_in *saddr)
+{
+	struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR/GRE Rx");
+	int ret = 0;
+	socklen_t saddr_len = sizeof(*saddr);
+	struct iphdr *iph;
+	struct gre_hdr *greh;
+	uint8_t *frh;
+	uint16_t dlci;
+
+	if (!msg) {
+		*error = -ENOMEM;
+		return NULL;
+	}
+
+	ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0,
+			(struct sockaddr *)saddr, &saddr_len);
+	if (ret < 0) {
+		LOGP(DNS, LOGL_ERROR, "recv error %s during NS-FR-GRE recv\n",
+			strerror(errno));
+		*error = ret;
+		goto out_err;
+	} else if (ret == 0) {
+		*error = ret;
+		goto out_err;
+	}
+
+	msgb_put(msg, ret);
+
+	if (msg->len < sizeof(*iph) + sizeof(*greh) + 2) {
+		LOGP(DNS, LOGL_ERROR, "Short IP packet: %u bytes\n", msg->len);
+		*error = -EIO;
+		goto out_err;
+	}
+
+	iph = (struct iphdr *) msg->data;
+	if (msg->len < (iph->ihl*4 + sizeof(*greh) + 2)) {
+		LOGP(DNS, LOGL_ERROR, "Short IP packet: %u bytes\n", msg->len);
+		*error = -EIO;
+		goto out_err;
+	}
+
+	greh = (struct gre_hdr *) (msg->data + iph->ihl*4);
+	if (greh->flags) {
+		LOGP(DNS, LOGL_NOTICE, "Unknown GRE flags 0x%04x\n",
+			ntohs(greh->flags));
+	}
+
+	switch (ntohs(greh->ptype)) {
+	case GRE_PTYPE_IPv4:
+		/* IPv4 messages might be GRE keepalives */
+		*error = handle_rx_gre_ipv4(bfd, msg, iph, greh);
+		goto out_err;
+		break;
+	case GRE_PTYPE_FR:
+		/* continue as usual */
+		break;
+	default:
+		LOGP(DNS, LOGL_NOTICE, "Unknown GRE protocol 0x%04x != FR\n",
+			ntohs(greh->ptype));
+		*error = -EIO;
+		goto out_err;
+		break;
+	}
+
+	if (msg->len < sizeof(*greh) + 2) {
+		LOGP(DNS, LOGL_ERROR, "Short FR header: %u bytes\n", msg->len);
+		*error = -EIO;
+		goto out_err;
+	}
+
+	frh = (uint8_t *)greh + sizeof(*greh);
+	if (frh[0] & 0x01) {
+		LOGP(DNS, LOGL_NOTICE, "Unsupported single-byte FR address\n");
+		*error = -EIO;
+		goto out_err;
+	}
+	dlci = ((frh[0] & 0xfc) << 2);
+	if ((frh[1] & 0x0f) != 0x01) {
+		LOGP(DNS, LOGL_NOTICE, "Unknown second FR octet 0x%02x\n",
+			frh[1]);
+		*error = -EIO;
+		goto out_err;
+	}
+	dlci |= (frh[1] >> 4);
+
+	msg->l2h = frh+2;
+
+	/* Store DLCI in NETWORK BYTEORDER in sockaddr port member */
+	saddr->sin_port = htons(dlci);
+
+	return msg;
+
+out_err:
+	msgb_free(msg);
+	return NULL;
+}
+
+int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg,
+		   struct sockaddr_in *saddr, enum gprs_ns_ll ll);
+
+static int handle_nsfrgre_read(struct bsc_fd *bfd)
+{
+	int rc;
+	struct sockaddr_in saddr;
+	struct gprs_ns_inst *nsi = bfd->data;
+	struct msgb *msg;
+	uint16_t dlci;
+
+	msg = read_nsfrgre_msg(bfd, &rc, &saddr);
+	if (!msg)
+		return rc;
+
+	dlci = ntohs(saddr.sin_port);
+	if (dlci == 0 || dlci == 1023) {
+		LOGP(DNS, LOGL_INFO, "Received FR on LMI DLCI %u - ignoring\n",
+			dlci);
+		rc = 0;
+		goto out;
+	}
+
+	rc = gprs_ns_rcvmsg(nsi, msg, &saddr, GPRS_NS_LL_FR_GRE);
+out:
+	msgb_free(msg);
+
+	return rc;
+}
+
+static int handle_nsfrgre_write(struct bsc_fd *bfd)
+{
+	/* FIXME: actually send the data here instead of nsip_sendmsg() */
+	return -EIO;
+}
+
+int gprs_ns_frgre_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg)
+{
+	int rc;
+	struct gprs_ns_inst *nsi = nsvc->nsi;
+	struct sockaddr_in daddr;
+	uint16_t dlci = ntohs(nsvc->frgre.bts_addr.sin_port);
+	uint8_t *frh;
+	struct gre_hdr *greh;
+
+	/* Build socket address for the packet destionation */
+	daddr.sin_family = AF_INET;
+	daddr.sin_addr = nsvc->frgre.bts_addr.sin_addr;
+	daddr.sin_port = IPPROTO_GRE;
+
+	/* Prepend the FR header */
+	frh = msgb_push(msg, 2);
+	frh[0] = (dlci >> 2) & 0xfc;
+	frh[1] = ((dlci & 0xf)<<4) | 0x01;
+
+	/* Prepend the GRE header */
+	greh = (struct gre_hdr *) msgb_push(msg, sizeof(*greh));
+	greh->flags = 0;
+	greh->ptype = htons(GRE_PTYPE_FR);
+
+	rc = sendto(nsi->frgre.fd.fd, msg->data, msg->len, 0,
+		  (struct sockaddr *)&daddr, sizeof(daddr));
+
+	talloc_free(msg);
+
+	return rc;
+}
+
+static int nsfrgre_fd_cb(struct bsc_fd *bfd, unsigned int what)
+{
+	int rc = 0;
+
+	if (what & BSC_FD_READ)
+		rc = handle_nsfrgre_read(bfd);
+	if (what & BSC_FD_WRITE)
+		rc = handle_nsfrgre_write(bfd);
+
+	return rc;
+}
+
+int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi)
+{
+	int rc;
+
+	/* Make sure we close any existing socket before changing it */
+	if (nsi->frgre.fd.fd)
+		close(nsi->frgre.fd.fd);
+
+	if (!nsi->frgre.enabled)
+		return 0;
+
+	rc = make_sock(&nsi->frgre.fd, IPPROTO_GRE, nsi->frgre.local_ip,
+			0, nsfrgre_fd_cb);
+	if (rc < 0) {
+		LOGP(DNS, LOGL_ERROR, "Error creating GRE socket (%s)\n",
+			strerror(errno));
+		return rc;
+	}
+	nsi->frgre.fd.data = nsi;
+
+	return rc;
+}
diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c
new file mode 100644
index 0000000..e395df7
--- /dev/null
+++ b/openbsc/src/gprs/gprs_ns_vty.c
@@ -0,0 +1,571 @@
+/* VTY interface for our GPRS Networks Service (NS) implementation */
+
+/* (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 <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <arpa/inet.h>
+
+#include <openbsc/gsm_data.h>
+#include <osmocore/msgb.h>
+#include <osmocore/tlv.h>
+#include <osmocore/talloc.h>
+#include <osmocore/select.h>
+#include <osmocore/rate_ctr.h>
+#include <openbsc/debug.h>
+#include <openbsc/signal.h>
+#include <openbsc/gprs_ns.h>
+#include <openbsc/gprs_bssgp.h>
+#include <openbsc/vty.h>
+
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/logging.h>
+#include <osmocom/vty/telnet_interface.h>
+
+static struct gprs_ns_inst *vty_nsi = NULL;
+
+/* FIXME: this should go to some common file as it is copied
+ * in vty_interface.c of the BSC */
+static const struct value_string gprs_ns_timer_strs[] = {
+	{ 0, "tns-block" },
+	{ 1, "tns-block-retries" },
+	{ 2, "tns-reset" },
+	{ 3, "tns-reset-retries" },
+	{ 4, "tns-test" },
+	{ 5, "tns-alive" },
+	{ 6, "tns-alive-retries" },
+	{ 0, NULL }
+};
+
+static struct cmd_node ns_node = {
+	NS_NODE,
+	"%s(ns)#",
+	1,
+};
+
+static int config_write_ns(struct vty *vty)
+{
+	struct gprs_nsvc *nsvc;
+	unsigned int i;
+	struct in_addr ia;
+
+	vty_out(vty, "ns%s", VTY_NEWLINE);
+
+	llist_for_each_entry(nsvc, &vty_nsi->gprs_nsvcs, list) {
+		if (!nsvc->persistent)
+			continue;
+		vty_out(vty, " nse %u nsvci %u%s",
+			nsvc->nsei, nsvc->nsvci, VTY_NEWLINE);
+		vty_out(vty, " nse %u remote-role %s%s",
+			nsvc->nsei, nsvc->remote_end_is_sgsn ? "sgsn" : "bss",
+			VTY_NEWLINE);
+		switch (nsvc->ll) {
+		case GPRS_NS_LL_UDP:
+			vty_out(vty, " nse %u encapsulation udp%s", nsvc->nsei,
+				VTY_NEWLINE);
+			vty_out(vty, " nse %u remote-ip %s%s",
+				nsvc->nsei,
+				inet_ntoa(nsvc->ip.bts_addr.sin_addr),
+				VTY_NEWLINE);
+			vty_out(vty, " nse %u remote-port %u%s",
+				nsvc->nsei, ntohs(nsvc->ip.bts_addr.sin_port),
+				VTY_NEWLINE);
+			break;
+		case GPRS_NS_LL_FR_GRE:
+			vty_out(vty, " nse %u encapsulation framerelay-gre%s",
+				nsvc->nsei, VTY_NEWLINE);
+			vty_out(vty, " nse %u remote-ip %s%s",
+				nsvc->nsei,
+				inet_ntoa(nsvc->frgre.bts_addr.sin_addr),
+				VTY_NEWLINE);
+			vty_out(vty, " nse %u fr-dlci %u%s",
+				nsvc->nsei, ntohs(nsvc->frgre.bts_addr.sin_port),
+				VTY_NEWLINE);
+		default:
+			break;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++)
+		vty_out(vty, " timer %s %u%s",
+			get_value_string(gprs_ns_timer_strs, i),
+			vty_nsi->timeout[i], VTY_NEWLINE);
+
+	if (vty_nsi->nsip.local_ip) {
+		ia.s_addr = htonl(vty_nsi->nsip.local_ip);
+		vty_out(vty, " encapsulation udp local-ip %s%s",
+			inet_ntoa(ia), VTY_NEWLINE);
+	}
+	if (vty_nsi->nsip.local_port)
+		vty_out(vty, " encapsulation udp local-port %u%s",
+			vty_nsi->nsip.local_port, VTY_NEWLINE);
+
+	vty_out(vty, " encapsulation framerelay-gre enabled %u%s",
+		vty_nsi->frgre.enabled ? 1 : 0, VTY_NEWLINE);
+	if (vty_nsi->frgre.local_ip) {
+		ia.s_addr = htonl(vty_nsi->frgre.local_ip);
+		vty_out(vty, " encapsulation framerelay-gre local-ip %s%s",
+			inet_ntoa(ia), VTY_NEWLINE);
+	}
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ns, cfg_ns_cmd,
+      "ns",
+      "Configure the GPRS Network Service")
+{
+	vty->node = NS_NODE;
+	return CMD_SUCCESS;
+}
+
+static void dump_nse(struct vty *vty, struct gprs_nsvc *nsvc, int stats)
+{
+	vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s",
+		nsvc->nsei, nsvc->nsvci,
+		nsvc->remote_end_is_sgsn ? "SGSN" : "BSS",
+		nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD",
+		nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED");
+	if (nsvc->ll == GPRS_NS_LL_UDP || nsvc->ll == GPRS_NS_LL_FR_GRE)
+		vty_out(vty, ", %s %15s:%u",
+			nsvc->ll == GPRS_NS_LL_UDP ? "UDP   " : "FR-GRE",
+			inet_ntoa(nsvc->ip.bts_addr.sin_addr),
+			ntohs(nsvc->ip.bts_addr.sin_port));
+	vty_out(vty, "%s", VTY_NEWLINE);
+	if (stats)
+		vty_out_rate_ctr_group(vty, " ", nsvc->ctrg);
+}
+
+static void dump_ns(struct vty *vty, struct gprs_ns_inst *nsi, int stats)
+{
+	struct gprs_nsvc *nsvc;
+	struct in_addr ia;
+
+	ia.s_addr = htonl(vty_nsi->nsip.local_ip);
+	vty_out(vty, "Encapsulation NS-UDP-IP     Local IP: %s, UDP Port: %u%s",
+		inet_ntoa(ia), vty_nsi->nsip.local_port, VTY_NEWLINE);
+
+	ia.s_addr = htonl(vty_nsi->frgre.local_ip);
+	vty_out(vty, "Encapsulation NS-FR-GRE-IP  Local IP: %s%s",
+		inet_ntoa(ia), VTY_NEWLINE);
+
+	llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) {
+		if (nsvc == nsi->unknown_nsvc)
+			continue;
+		dump_nse(vty, nsvc, stats);
+	}
+}
+
+DEFUN(show_ns, show_ns_cmd, "show ns",
+	SHOW_STR "Display information about the NS protocol")
+{
+	struct gprs_ns_inst *nsi = vty_nsi;
+	dump_ns(vty, nsi, 0);
+	return CMD_SUCCESS;
+}
+
+DEFUN(show_ns_stats, show_ns_stats_cmd, "show ns stats",
+	SHOW_STR
+	"Display information about the NS protocol\n"
+	"Include statistics\n")
+{
+	struct gprs_ns_inst *nsi = vty_nsi;
+	dump_ns(vty, nsi, 1);
+	return CMD_SUCCESS;
+}
+
+DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]",
+	SHOW_STR "Display information about the NS protocol\n"
+	"Select one NSE by its NSE Identifier\n"
+	"Select one NSE by its NS-VC Identifier\n"
+	"The Identifier of selected type\n"
+	"Include Statistics\n")
+{
+	struct gprs_ns_inst *nsi = vty_nsi;
+	struct gprs_nsvc *nsvc;
+	uint16_t id = atoi(argv[1]);
+	int show_stats = 0;
+
+	if (!strcmp(argv[0], "nsei"))
+		nsvc = nsvc_by_nsei(nsi, id);
+	else
+		nsvc = nsvc_by_nsvci(nsi, id);
+
+	if (!nsvc) {
+		vty_out(vty, "No such NS Entity%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (argc >= 3)
+		show_stats = 1;
+
+	dump_nse(vty, nsvc, show_stats);
+	return CMD_SUCCESS;
+}
+
+#define NSE_CMD_STR "Persistent NS Entity\n" "NS Entity ID (NSEI)\n"
+
+DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd,
+	"nse <0-65535> nsvci <0-65534>",
+	NSE_CMD_STR
+	"NS Virtual Connection\n"
+	"NS Virtual Connection ID (NSVCI)\n"
+	)
+{
+	uint16_t nsei = atoi(argv[0]);
+	uint16_t nsvci = atoi(argv[1]);
+	struct gprs_nsvc *nsvc;
+
+	nsvc = nsvc_by_nsei(vty_nsi, nsei);
+	if (!nsvc) {
+		nsvc = nsvc_create(vty_nsi, nsvci);
+		nsvc->nsei = nsei;
+	}
+	nsvc->nsvci = nsvci;
+	/* All NSVCs that are explicitly configured by VTY are
+	 * marked as persistent so we can write them to the config
+	 * file at some later point */
+	nsvc->persistent = 1;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nse_remoteip, cfg_nse_remoteip_cmd,
+	"nse <0-65535> remote-ip A.B.C.D",
+	NSE_CMD_STR
+	"Remote IP Address\n"
+	"Remote IP Address\n")
+{
+	uint16_t nsei = atoi(argv[0]);
+	struct gprs_nsvc *nsvc;
+
+	nsvc = nsvc_by_nsei(vty_nsi, nsei);
+	if (!nsvc) {
+		vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	inet_aton(argv[1], &nsvc->ip.bts_addr.sin_addr);
+
+	return CMD_SUCCESS;
+
+}
+
+DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd,
+	"nse <0-65535> remote-port <0-65535>",
+	NSE_CMD_STR
+	"Remote UDP Port\n"
+	"Remote UDP Port Number\n")
+{
+	uint16_t nsei = atoi(argv[0]);
+	uint16_t port = atoi(argv[1]);
+	struct gprs_nsvc *nsvc;
+
+	nsvc = nsvc_by_nsei(vty_nsi, nsei);
+	if (!nsvc) {
+		vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (nsvc->ll != GPRS_NS_LL_UDP) {
+		vty_out(vty, "Cannot set UDP Port on non-UDP NSE%s",
+			VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	nsvc->ip.bts_addr.sin_port = htons(port);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nse_fr_dlci, cfg_nse_fr_dlci_cmd,
+	"nse <0-65535> fr-dlci <16-1007>",
+	NSE_CMD_STR
+	"Frame Relay DLCI\n"
+	"Frame Relay DLCI Number\n")
+{
+	uint16_t nsei = atoi(argv[0]);
+	uint16_t dlci = atoi(argv[1]);
+	struct gprs_nsvc *nsvc;
+
+	nsvc = nsvc_by_nsei(vty_nsi, nsei);
+	if (!nsvc) {
+		vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (nsvc->ll != GPRS_NS_LL_FR_GRE) {
+		vty_out(vty, "Cannot set FR DLCI on non-FR NSE%s",
+			VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	nsvc->frgre.bts_addr.sin_port = htons(dlci);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nse_encaps, cfg_nse_encaps_cmd,
+	"nse <0-65535> encapsulation (udp|framerelay-gre)",
+	NSE_CMD_STR
+	"Encapsulation for NS\n"
+	"UDP/IP Encapsulation\n" "Frame-Relay/GRE/IP Encapsulation\n")
+{
+	uint16_t nsei = atoi(argv[0]);
+	struct gprs_nsvc *nsvc;
+
+	nsvc = nsvc_by_nsei(vty_nsi, nsei);
+	if (!nsvc) {
+		vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (!strcmp(argv[1], "udp"))
+		nsvc->ll = GPRS_NS_LL_UDP;
+	else
+		nsvc->ll = GPRS_NS_LL_FR_GRE;
+
+	return CMD_SUCCESS;
+}
+
+
+DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd,
+	"nse <0-65535> remote-role (sgsn|bss)",
+	NSE_CMD_STR
+	"Remote NSE Role\n"
+	"Remote Peer is SGSN\n"
+	"Remote Peer is BSS\n")
+{
+	uint16_t nsei = atoi(argv[0]);
+	struct gprs_nsvc *nsvc;
+
+	nsvc = nsvc_by_nsei(vty_nsi, nsei);
+	if (!nsvc) {
+		vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (!strcmp(argv[1], "sgsn"))
+		nsvc->remote_end_is_sgsn = 1;
+	else
+		nsvc->remote_end_is_sgsn = 0;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_nse, cfg_no_nse_cmd,
+	"no nse <0-65535>",
+	"Delete Persistent NS Entity\n"
+	"Delete " NSE_CMD_STR)
+{
+	uint16_t nsei = atoi(argv[0]);
+	struct gprs_nsvc *nsvc;
+
+	nsvc = nsvc_by_nsei(vty_nsi, nsei);
+	if (!nsvc) {
+		vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (!nsvc->persistent) {
+		vty_out(vty, "NSEI %u is not a persistent NSE%s",
+			nsei, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	nsvc->persistent = 0;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ns_timer, cfg_ns_timer_cmd,
+	"timer " NS_TIMERS " <0-65535>",
+	"Network Service Timer\n"
+	NS_TIMERS_HELP "Timer Value\n")
+{
+	int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
+	int val = atoi(argv[1]);
+
+	if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout))
+		return CMD_WARNING;
+
+	vty_nsi->timeout[idx] = val;
+
+	return CMD_SUCCESS;
+}
+
+#define ENCAPS_STR "NS encapsulation options\n"
+
+DEFUN(cfg_nsip_local_ip, cfg_nsip_local_ip_cmd,
+      "encapsulation udp local-ip A.B.C.D",
+	ENCAPS_STR "NS over UDP Encapsulation\n"
+	"Set the IP address on which we listen for NS/UDP\n"
+	"IP Address\n")
+{
+	struct in_addr ia;
+
+	inet_aton(argv[0], &ia);
+	vty_nsi->nsip.local_ip = ntohl(ia.s_addr);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nsip_local_port, cfg_nsip_local_port_cmd,
+      "encapsulation udp local-port <0-65535>",
+	ENCAPS_STR "NS over UDP Encapsulation\n"
+	"Set the UDP port on which we listen for NS/UDP\n"
+	"UDP port number\n")
+{
+	unsigned int port = atoi(argv[0]);
+
+	vty_nsi->nsip.local_port = port;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_frgre_local_ip, cfg_frgre_local_ip_cmd,
+      "encapsulation framerelay-gre local-ip A.B.C.D",
+	ENCAPS_STR "NS over Frame Relay over GRE Encapsulation\n"
+	"Set the IP address on which we listen for NS/FR/GRE\n"
+	"IP Address\n")
+{
+	struct in_addr ia;
+
+	if (!vty_nsi->frgre.enabled) {
+		vty_out(vty, "FR/GRE is not enabled%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	inet_aton(argv[0], &ia);
+	vty_nsi->frgre.local_ip = ntohl(ia.s_addr);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_frgre_enable, cfg_frgre_enable_cmd,
+      "encapsulation framerelay-gre enabled (1|0)",
+	ENCAPS_STR "NS over Frame Relay over GRE Encapsulation\n"
+	"Enable or disable Frame Relay over GRE\n"
+	"Enable\n" "Disable\n")
+{
+	int enabled = atoi(argv[0]);
+
+	vty_nsi->frgre.enabled = enabled;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(nsvc_nsei, nsvc_nsei_cmd,
+	"nsvc nsei <0-65535> (block|unblock|reset)",
+	"Perform an operation on a NSVC\n"
+	"NS-VC Identifier (NS-VCI)\n"
+	"Initiate BLOCK procedure\n"
+	"Initiate UNBLOCK procedure\n"
+	"Initiate RESET procedure\n")
+{
+	uint16_t nsvci = atoi(argv[0]);
+	const char *operation = argv[1];
+	struct gprs_nsvc *nsvc;
+
+	nsvc = nsvc_by_nsei(vty_nsi, nsvci);
+	if (!nsvc) {
+		vty_out(vty, "No such NSVCI (%u)%s", nsvci, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (!strcmp(operation, "block"))
+		gprs_ns_tx_block(nsvc, NS_CAUSE_OM_INTERVENTION);
+	else if (!strcmp(operation, "unblock"))
+		gprs_ns_tx_unblock(nsvc);
+	else if (!strcmp(operation, "reset"))
+		gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION);
+	else
+		return CMD_WARNING;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(logging_fltr_nsvc,
+      logging_fltr_nsvc_cmd,
+      "logging filter nsvc (nsei|nsvci) <0-65535>",
+	LOGGING_STR FILTER_STR
+	"Filter based on NS Virtual Connection\n"
+	"Identify NS-VC by NSEI\n"
+	"Identify NS-VC by NSVCI\n"
+	"Numeric identifier\n")
+{
+	struct telnet_connection *conn;
+	struct gprs_nsvc *nsvc;
+	uint16_t id = atoi(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 (!strcmp(argv[0], "nsei"))
+		nsvc = nsvc_by_nsei(vty_nsi, id);
+	else
+		nsvc = nsvc_by_nsvci(vty_nsi, id);
+
+	if (!nsvc) {
+		vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	log_set_nsvc_filter(conn->dbg, nsvc);
+	return CMD_SUCCESS;
+}
+
+int gprs_ns_vty_init(struct gprs_ns_inst *nsi)
+{
+	vty_nsi = nsi;
+
+	install_element_ve(&show_ns_cmd);
+	install_element_ve(&show_ns_stats_cmd);
+	install_element_ve(&show_nse_cmd);
+	install_element_ve(&logging_fltr_nsvc_cmd);
+
+	install_element(CONFIG_NODE, &cfg_ns_cmd);
+	install_node(&ns_node, config_write_ns);
+	install_default(NS_NODE);
+	install_element(NS_NODE, &ournode_exit_cmd);
+	install_element(NS_NODE, &ournode_end_cmd);
+	install_element(NS_NODE, &cfg_nse_nsvci_cmd);
+	install_element(NS_NODE, &cfg_nse_remoteip_cmd);
+	install_element(NS_NODE, &cfg_nse_remoteport_cmd);
+	install_element(NS_NODE, &cfg_nse_fr_dlci_cmd);
+	install_element(NS_NODE, &cfg_nse_encaps_cmd);
+	install_element(NS_NODE, &cfg_nse_remoterole_cmd);
+	install_element(NS_NODE, &cfg_no_nse_cmd);
+	install_element(NS_NODE, &cfg_ns_timer_cmd);
+	install_element(NS_NODE, &cfg_nsip_local_ip_cmd);
+	install_element(NS_NODE, &cfg_nsip_local_port_cmd);
+	install_element(NS_NODE, &cfg_frgre_enable_cmd);
+	install_element(NS_NODE, &cfg_frgre_local_ip_cmd);
+
+	install_element(ENABLE_NODE, &nsvc_nsei_cmd);
+
+	return 0;
+}
diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c
new file mode 100644
index 0000000..9a76cee
--- /dev/null
+++ b/openbsc/src/gprs/gprs_sgsn.c
@@ -0,0 +1,304 @@
+/* GPRS SGSN functionality */
+
+/* (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 <stdint.h>
+
+#include <osmocore/linuxlist.h>
+#include <osmocore/talloc.h>
+#include <osmocore/timer.h>
+#include <osmocore/rate_ctr.h>
+#include <openbsc/gsm_subscriber.h>
+#include <openbsc/debug.h>
+#include <openbsc/gprs_sgsn.h>
+#include <openbsc/gprs_ns.h>
+#include <openbsc/gprs_bssgp.h>
+#include <openbsc/sgsn.h>
+
+extern struct sgsn_instance *sgsn;
+
+LLIST_HEAD(sgsn_mm_ctxts);
+LLIST_HEAD(sgsn_ggsn_ctxts);
+LLIST_HEAD(sgsn_apn_ctxts);
+LLIST_HEAD(sgsn_pdp_ctxts);
+
+static const struct rate_ctr_desc mmctx_ctr_description[] = {
+	{ "sign.packets.in",	"Signalling Messages ( In)" },
+	{ "sign.packets.out",	"Signalling Messages (Out)" },
+	{ "udata.packets.in",	"User Data  Messages ( In)" },
+	{ "udata.packets.out",	"User Data  Messages (Out)" },
+	{ "udata.bytes.in",	"User Data  Bytes    ( In)" },
+	{ "udata.bytes.out",	"User Data  Bytes    (Out)" },
+	{ "pdp_ctx_act",	"PDP Context Activations  " },
+	{ "suspend",		"SUSPEND Count            " },
+	{ "paging.ps",		"Paging Packet Switched   " },
+	{ "paging.cs",		"Paging Circuit Switched  " },
+	{ "ra_update",		"Routing Area Update      " },
+};
+
+static const struct rate_ctr_group_desc mmctx_ctrg_desc = {
+	.group_name_prefix = "sgsn.mmctx",
+	.group_description = "SGSN MM Context Statistics",
+	.num_ctr = ARRAY_SIZE(mmctx_ctr_description),
+	.ctr_desc = mmctx_ctr_description,
+};
+
+static const struct rate_ctr_desc pdpctx_ctr_description[] = {
+	{ "udata.packets.in",	"User Data  Messages ( In)" },
+	{ "udata.packets.out",	"User Data  Messages (Out)" },
+	{ "udata.bytes.in",	"User Data  Bytes    ( In)" },
+	{ "udata.bytes.out",	"User Data  Bytes    (Out)" },
+};
+
+static const struct rate_ctr_group_desc pdpctx_ctrg_desc = {
+	.group_name_prefix = "sgsn.pdpctx",
+	.group_description = "SGSN PDP Context Statistics",
+	.num_ctr = ARRAY_SIZE(pdpctx_ctr_description),
+	.ctr_desc = pdpctx_ctr_description,
+};
+
+static int ra_id_equals(const struct gprs_ra_id *id1,
+			const struct gprs_ra_id *id2)
+{
+	return (id1->mcc == id2->mcc && id1->mnc == id2->mnc &&
+		id1->lac == id2->lac && id1->rac == id2->rac);
+}
+
+/* look-up a SGSN MM context based on TLLI + RAI */
+struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
+					const struct gprs_ra_id *raid)
+{
+	struct sgsn_mm_ctx *ctx;
+	int tlli_type;
+
+	llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
+		if (tlli == ctx->tlli &&
+		    ra_id_equals(raid, &ctx->ra))
+			return ctx;
+	}
+
+	tlli_type = gprs_tlli_type(tlli);
+	if (tlli_type == TLLI_LOCAL) {
+		llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
+			if ((ctx->p_tmsi | 0xC0000000) == tlli ||
+			     (ctx->p_tmsi_old && (ctx->p_tmsi_old | 0xC0000000) == tlli)) {
+				ctx->tlli = tlli;
+				return ctx;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t p_tmsi)
+{
+	struct sgsn_mm_ctx *ctx;
+
+	llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
+		if (p_tmsi == ctx->p_tmsi ||
+		    (ctx->p_tmsi_old && ctx->p_tmsi_old == p_tmsi))
+			return ctx;
+	}
+	return NULL;
+}
+
+struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi)
+{
+	struct sgsn_mm_ctx *ctx;
+
+	llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
+		if (!strcmp(imsi, ctx->imsi))
+			return ctx;
+	}
+	return NULL;
+
+}
+
+/* Allocate a new SGSN MM context */
+struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
+					const struct gprs_ra_id *raid)
+{
+	struct sgsn_mm_ctx *ctx;
+
+	ctx = talloc_zero(tall_bsc_ctx, struct sgsn_mm_ctx);
+	if (!ctx)
+		return NULL;
+
+	memcpy(&ctx->ra, raid, sizeof(ctx->ra));
+	ctx->tlli = tlli;
+	ctx->mm_state = GMM_DEREGISTERED;
+	ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, tlli);
+	INIT_LLIST_HEAD(&ctx->pdp_list);
+
+	llist_add(&ctx->list, &sgsn_mm_ctxts);
+
+	return ctx;
+}
+
+
+/* look up PDP context by MM context and NSAPI */
+struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm,
+					   uint8_t nsapi)
+{
+	struct sgsn_pdp_ctx *pdp;
+
+	llist_for_each_entry(pdp, &mm->pdp_list, list) {
+		if (pdp->nsapi == nsapi)
+			return pdp;
+	}
+	return NULL;
+}
+
+/* look up PDP context by MM context and transaction ID */
+struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm,
+					 uint8_t tid)
+{
+	struct sgsn_pdp_ctx *pdp;
+
+	llist_for_each_entry(pdp, &mm->pdp_list, list) {
+		if (pdp->ti == tid)
+			return pdp;
+	}
+	return NULL;
+}
+
+struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
+					uint8_t nsapi)
+{
+	struct sgsn_pdp_ctx *pdp;
+
+	pdp = sgsn_pdp_ctx_by_nsapi(mm, nsapi);
+	if (pdp)
+		return NULL;
+
+	pdp = talloc_zero(tall_bsc_ctx, struct sgsn_pdp_ctx);
+	if (!pdp)
+		return NULL;
+
+	pdp->mm = mm;
+	pdp->nsapi = nsapi;
+	pdp->ctrg = rate_ctr_group_alloc(pdp, &pdpctx_ctrg_desc, nsapi);
+	llist_add(&pdp->list, &mm->pdp_list);
+	llist_add(&pdp->g_list, &sgsn_pdp_ctxts);
+
+	return pdp;
+}
+
+void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
+{
+	llist_del(&pdp->list);
+	llist_del(&pdp->g_list);
+	talloc_free(pdp);
+}
+
+/* GGSN contexts */
+
+struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id)
+{
+	struct sgsn_ggsn_ctx *ggc;
+
+	ggc = talloc_zero(tall_bsc_ctx, struct sgsn_ggsn_ctx);
+	if (!ggc)
+		return NULL;
+
+	ggc->id = id;
+	ggc->gtp_version = 1;
+	/* if we are called from config file parse, this gsn doesn't exist yet */
+	ggc->gsn = sgsn->gsn;
+	llist_add(&ggc->list, &sgsn_ggsn_ctxts);
+
+	return ggc;
+}
+
+struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id)
+{
+	struct sgsn_ggsn_ctx *ggc;
+
+	llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) {
+		if (id == ggc->id)
+			return ggc;
+	}
+	return NULL;
+}
+
+struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id)
+{
+	struct sgsn_ggsn_ctx *ggc;
+
+	ggc = sgsn_ggsn_ctx_by_id(id);
+	if (!ggc)
+		ggc = sgsn_ggsn_ctx_alloc(id);
+	return ggc;
+}
+
+/* APN contexts */
+
+#if 0
+struct apn_ctx *apn_ctx_alloc(const char *ap_name)
+{
+	struct apn_ctx *actx;
+
+	actx = talloc_zero(talloc_bsc_ctx, struct apn_ctx);
+	if (!actx)
+		return NULL;
+	actx->name = talloc_strdup(actx, ap_name);
+
+	return actx;
+}
+
+struct apn_ctx *apn_ctx_by_name(const char *name)
+{
+	struct apn_ctx *actx;
+
+	llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
+		if (!strcmp(name, actx->name))
+			return actx;
+	}
+	return NULL;
+}
+
+struct apn_ctx *apn_ctx_find_alloc(const char *name)
+{
+	struct apn_ctx *actx;
+
+	actx = apn_ctx_by_name(name);
+	if (!actx)
+		actx = apn_ctx_alloc(name);
+
+	return actx;
+}
+#endif
+
+uint32_t sgsn_alloc_ptmsi(void)
+{
+	struct sgsn_mm_ctx *mm;
+	uint32_t ptmsi;
+
+restart:
+	ptmsi = rand();
+	llist_for_each_entry(mm, &sgsn_mm_ctxts, list) {
+		if (mm->p_tmsi == ptmsi)
+			goto restart;
+	}
+
+	return ptmsi;
+}
diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c
new file mode 100644
index 0000000..8433326
--- /dev/null
+++ b/openbsc/src/gprs/gprs_sndcp.c
@@ -0,0 +1,635 @@
+/* GPRS SNDCP protocol implementation as per 3GPP TS 04.65 */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (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 <errno.h>
+#include <stdint.h>
+
+#include <osmocore/msgb.h>
+#include <osmocore/linuxlist.h>
+#include <osmocore/timer.h>
+#include <osmocore/talloc.h>
+
+#include <openbsc/gsm_data.h>
+#include <openbsc/debug.h>
+#include <openbsc/gprs_bssgp.h>
+#include <openbsc/gprs_llc.h>
+#include <openbsc/sgsn.h>
+
+/* Chapter 7.2: SN-PDU Formats */
+struct sndcp_common_hdr {
+	/* octet 1 */
+	uint8_t nsapi:4;
+	uint8_t more:1;
+	uint8_t type:1;
+	uint8_t first:1;
+	uint8_t spare:1;
+} __attribute__((packed));
+
+/* PCOMP / DCOMP only exist in first fragment */
+struct sndcp_comp_hdr {
+	/* octet 2 */
+	uint8_t pcomp:4;
+	uint8_t dcomp:4;
+} __attribute__((packed));
+
+struct sndcp_udata_hdr {
+	/* octet 3 */
+	uint8_t npdu_high:4;
+	uint8_t seg_nr:4;
+	/* octet 4 */
+	uint8_t npdu_low;
+} __attribute__((packed));
+
+/* See 6.7.1.2 Reassembly */
+enum sndcp_rx_state {
+	SNDCP_RX_S_FIRST,
+	SNDCP_RX_S_SUBSEQ,
+	SNDCP_RX_S_DISCARD,
+};
+
+
+static void *tall_sndcp_ctx;
+
+/* A fragment queue entry, containing one framgent of a N-PDU */
+struct defrag_queue_entry {
+	struct llist_head list;
+	/* segment number of this fragment */
+	uint32_t seg_nr;
+	/* length of the data area of this fragment */
+	uint32_t data_len;
+	/* pointer to the data of this fragment */
+	uint8_t *data;
+};
+
+/* A fragment queue header, maintaining list of fragments for one N-PDU */
+struct defrag_state {
+	/* PDU number for which the defragmentation state applies */
+	uint16_t npdu;
+	/* highest segment number we have received so far */
+	uint8_t highest_seg;
+	/* bitmask of the segments we already have */
+	uint32_t seg_have;
+	/* do we still expect more segments? */
+	unsigned int no_more;
+	/* total length of all segments together */
+	unsigned int tot_len;
+
+	/* linked list of defrag_queue_entry: one for each fragment  */
+	struct llist_head frag_list;
+
+	struct timer_list timer;
+};
+
+struct sndcp_entity {
+	struct llist_head list;
+
+	/* reference to the LLC Entity below this SNDCP entity */
+	struct gprs_llc_lle *lle;
+	/* The NSAPI we shall use on top of LLC */
+	uint8_t nsapi;
+
+	/* NPDU number for the GTP->SNDCP side */
+	uint16_t tx_npdu_nr;
+	/* SNDCP eeceiver state */
+	enum sndcp_rx_state rx_state;
+	/* The defragmentation queue */
+	struct defrag_state defrag;
+};
+
+LLIST_HEAD(sndcp_entities);
+
+/* Enqueue a fragment into the defragment queue */
+static int defrag_enqueue(struct sndcp_entity *sne, uint8_t seg_nr,
+			  uint32_t data_len, uint8_t *data)
+{
+	struct defrag_queue_entry *dqe;
+
+	dqe = talloc_zero(tall_sndcp_ctx, struct defrag_queue_entry);
+	if (!dqe)
+		return -ENOMEM;
+	dqe->data = talloc_zero_size(dqe, data_len);
+	if (!dqe->data) {
+		talloc_free(dqe);
+		return -ENOMEM;
+	}
+	dqe->seg_nr = seg_nr;
+	dqe->data_len = data_len;
+
+	llist_add(&dqe->list, &sne->defrag.frag_list);
+
+	if (seg_nr > sne->defrag.highest_seg)
+		sne->defrag.highest_seg = seg_nr;
+
+	sne->defrag.seg_have |= (1 << seg_nr);
+	sne->defrag.tot_len += data_len;
+
+	return 0;
+}
+
+/* return if we have all segments of this N-PDU */
+static int defrag_have_all_segments(struct sndcp_entity *sne)
+{
+	uint32_t seg_needed = 0;
+	unsigned int i;
+
+	/* create a bitmask of needed segments */
+	for (i = 0; i < sne->defrag.highest_seg; i++)
+		seg_needed |= (1 << i);
+
+	if (seg_needed == sne->defrag.seg_have)
+		return 1;
+
+	return 0;
+}
+
+static struct defrag_queue_entry *defrag_get_seg(struct sndcp_entity *sne,
+						 uint32_t seg_nr)
+{
+	struct defrag_queue_entry *dqe;
+
+	llist_for_each_entry(dqe, &sne->defrag.frag_list, list) {
+		if (dqe->seg_nr == seg_nr) {
+			llist_del(&dqe->list);
+			return dqe;
+		}
+	}
+	return NULL;
+}
+
+static int defrag_segments(struct sndcp_entity *sne)
+{
+	struct msgb *msg;
+	unsigned int seg_nr;
+	uint8_t *npdu;
+
+	msg = msgb_alloc_headroom(sne->defrag.tot_len+256, 128, "SNDCP Defrag");
+	if (!msg)
+		return -ENOMEM;
+
+	/* FIXME: message headers + identifiers */
+
+	npdu = msg->data;
+
+	for (seg_nr = 0; seg_nr < sne->defrag.highest_seg; seg_nr++) {
+		struct defrag_queue_entry *dqe;
+		uint8_t *data;
+
+		dqe = defrag_get_seg(sne, seg_nr);
+		if (!dqe) {
+			LOGP(DSNDCP, LOGL_ERROR, "Segment %u missing\n", seg_nr);
+			talloc_free(msg);
+			return -EIO;
+		}
+		/* actually append the segment to the N-PDU */
+		data = msgb_put(msg, dqe->data_len);
+		memcpy(data, dqe->data, dqe->data_len);
+
+		/* release memory for the fragment queue entry */
+		talloc_free(dqe);
+	}
+
+	/* actually send the N-PDU to the SGSN core code, which then
+	 * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */
+	return sgsn_rx_sndcp_ud_ind(sne->lle->llme->tlli, sne->nsapi, msg,
+				    sne->defrag.tot_len, npdu);
+}
+
+static int defrag_input(struct sndcp_entity *sne, struct msgb *msg, uint8_t *hdr)
+{
+	struct sndcp_common_hdr *sch;
+	struct sndcp_comp_hdr *scomph = NULL;
+	struct sndcp_udata_hdr *suh;
+	uint16_t npdu_num;
+	uint8_t *data;
+	int rc;
+
+	sch = (struct sndcp_common_hdr *) hdr;
+	if (sch->first) {
+		scomph = (struct sndcp_comp_hdr *) (hdr + 1);
+		suh = (struct sndcp_udata_hdr *) (hdr + 1 + sizeof(struct sndcp_common_hdr));
+	} else
+		suh = (struct sndcp_udata_hdr *) (hdr + sizeof(struct sndcp_common_hdr));
+
+	data = (uint8_t *)suh + sizeof(struct sndcp_udata_hdr);
+
+	npdu_num = (suh->npdu_high << 8) | suh->npdu_low;
+
+	if (sch->first) {
+		/* first segment of a new packet.  Discard all leftover fragments of
+		 * previous packet */
+		if (!llist_empty(&sne->defrag.frag_list)) {
+			struct defrag_queue_entry *dqe;
+			LOGP(DSNDCP, LOGL_INFO, "Dropping SN-PDU due to "
+				"insufficient segments\n");
+			llist_for_each_entry(dqe, &sne->defrag.frag_list, list) {
+				llist_del(&dqe->list);
+				talloc_free(dqe);
+			}
+		}
+		/* store the currently de-fragmented PDU number */
+		sne->defrag.npdu = npdu_num;
+		sne->defrag.no_more = sne->defrag.highest_seg = sne->defrag.seg_have = 0;
+		/* FIXME: Start timer */
+	}
+
+	if (sne->defrag.npdu != npdu_num) {
+		LOGP(DSNDCP, LOGL_INFO, "Segment for different SN-PDU "
+			"(%u != %u)\n", npdu_num, sne->defrag.npdu);
+		/* FIXME */
+	}
+
+	/* FIXME: check if seg_nr already exists */
+	rc = defrag_enqueue(sne, suh->seg_nr, (msg->data + msg->len) - data, data);
+	if (rc < 0)
+		return rc;
+
+	if (!sch->more) {
+		/* this is suppsed to be the last segment of the N-PDU, but it
+		 * might well be not the last to arrive */
+		sne->defrag.no_more = 1;
+	}
+
+	if (sne->defrag.no_more) {
+		/* we have already received the last segment before, let's check
+		 * if all the previous segments exist */
+		if (defrag_have_all_segments(sne))
+			return defrag_segments(sne);
+	}
+
+	return 0;
+}
+
+static struct sndcp_entity *sndcp_entity_by_lle(const struct gprs_llc_lle *lle,
+						uint8_t nsapi)
+{
+	struct sndcp_entity *sne;
+
+	llist_for_each_entry(sne, &sndcp_entities, list) {
+		if (sne->lle == lle && sne->nsapi == nsapi)
+			return sne;
+	}
+	return NULL;
+}
+
+static struct sndcp_entity *sndcp_entity_alloc(struct gprs_llc_lle *lle,
+						uint8_t nsapi)
+{
+	struct sndcp_entity *sne;
+
+	sne = talloc_zero(tall_sndcp_ctx, struct sndcp_entity);
+	if (!sne)
+		return NULL;
+
+	sne->lle = lle;
+	sne->nsapi = nsapi;
+	sne->defrag.timer.data = sne;
+	//sne->fqueue.timer.cb = FIXME;
+	sne->rx_state = SNDCP_RX_S_FIRST;
+
+	llist_add(&sne->list, &sndcp_entities);
+
+	return sne;
+}
+
+/* Entry point for the SNSM-ACTIVATE.indication */
+int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi)
+{
+	LOGP(DSNDCP, LOGL_INFO, "SNSM-ACTIVATE.ind (lle=%p TLLI=%08x, "
+	     "SAPI=%u, NSAPI=%u)\n", lle, lle->llme->tlli, lle->sapi, nsapi);
+
+	if (sndcp_entity_by_lle(lle, nsapi)) {
+		LOGP(DSNDCP, LOGL_ERROR, "Trying to ACTIVATE "
+			"already-existing entity (TLLI=%08x, NSAPI=%u)\n",
+			lle->llme->tlli, nsapi);
+		return -EEXIST;
+	}
+
+	if (!sndcp_entity_alloc(lle, nsapi)) {
+		LOGP(DSNDCP, LOGL_ERROR, "Out of memory during ACTIVATE\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/* Entry point for the SNSM-DEACTIVATE.indication */
+int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi)
+{
+	struct sndcp_entity *sne;
+
+	LOGP(DSNDCP, LOGL_INFO, "SNSM-DEACTIVATE.ind (lle=%p, TLLI=%08x, "
+	     "SAPI=%u, NSAPI=%u)\n", lle, lle->llme->tlli, lle->sapi, nsapi);
+
+	sne = sndcp_entity_by_lle(lle, nsapi);
+	if (!sne) {
+		LOGP(DSNDCP, LOGL_ERROR, "SNSM-DEACTIVATE.ind for non-"
+		     "existing TLLI=%08x SAPI=%u NSAPI=%u\n", lle->llme->tlli,
+		     lle->sapi, nsapi);
+		return -ENOENT;
+	}
+	llist_del(&sne->list);
+	/* frag queue entries are hierarchically allocated, so no need to
+	 * free them explicitly here */
+	talloc_free(sne);
+
+	return 0;
+}
+
+/* Fragmenter state */
+struct sndcp_frag_state {
+	uint8_t frag_nr;
+	struct msgb *msg;	/* original message */
+	uint8_t *next_byte;	/* first byte of next fragment */
+
+	struct sndcp_entity *sne;
+	void *mmcontext;
+};
+
+/* returns '1' if there are more fragments to send, '0' if none */
+static int sndcp_send_ud_frag(struct sndcp_frag_state *fs)
+{
+	struct sndcp_entity *sne = fs->sne;
+	struct gprs_llc_lle *lle = sne->lle;
+	struct sndcp_common_hdr *sch;
+	struct sndcp_comp_hdr *scomph;
+	struct sndcp_udata_hdr *suh;
+	struct msgb *fmsg;
+	unsigned int max_payload_len;
+	unsigned int len;
+	uint8_t *data;
+	int rc, more;
+
+	fmsg = msgb_alloc_headroom(fs->sne->lle->params.n201_u+256, 128,
+				   "SNDCP Frag");
+	if (!fmsg)
+		return -ENOMEM;
+
+	/* make sure lower layers route the fragment like the original */
+	msgb_tlli(fmsg) = msgb_tlli(fs->msg);
+	msgb_bvci(fmsg) = msgb_bvci(fs->msg);
+	msgb_nsei(fmsg) = msgb_nsei(fs->msg);
+
+	/* prepend common SNDCP header */
+	sch = (struct sndcp_common_hdr *) msgb_put(fmsg, sizeof(*sch));
+	sch->nsapi = sne->nsapi;
+	/* Set FIRST bit if we are the first fragment in a series */
+	if (fs->frag_nr == 0)
+		sch->first = 1;
+	sch->type = 1;
+
+	/* append the compression header for first fragment */
+	if (sch->first) {
+		scomph = (struct sndcp_comp_hdr *)
+				msgb_put(fmsg, sizeof(*scomph));
+		scomph->pcomp = 0;
+		scomph->dcomp = 0;
+	}
+
+	/* append the user-data header */
+	suh = (struct sndcp_udata_hdr *) msgb_put(fmsg, sizeof(*suh));
+	suh->npdu_low = sne->tx_npdu_nr & 0xff;
+	suh->npdu_high = (sne->tx_npdu_nr >> 8) & 0xf;
+	suh->seg_nr = fs->frag_nr % 0xf;
+
+	/* calculate remaining length to be sent */
+	len = (fs->msg->data + fs->msg->len) - fs->next_byte;
+	/* how much payload can we actually send via LLC? */
+	max_payload_len = lle->params.n201_u - (sizeof(*sch) + sizeof(*suh));
+	if (sch->first)
+		max_payload_len -= sizeof(*scomph);
+	/* check if we're exceeding the max */
+	if (len > max_payload_len)
+		len = max_payload_len;
+
+	/* copy the actual fragment data into our fmsg */
+	data = msgb_put(fmsg, len);
+	memcpy(data, fs->next_byte, len);
+
+	/* Increment fragment number and data pointer to next fragment */
+	fs->frag_nr++;
+	fs->next_byte += len;
+
+	/* determine if we have more fragemnts to send */
+	if ((fs->msg->data + fs->msg->len) <= fs->next_byte)
+		more = 0;
+	else
+		more = 1;
+
+	/* set the MORE bit of the SNDCP header accordingly */
+	sch->more = more;
+
+	rc = gprs_llc_tx_ui(fmsg, lle->sapi, 0, fs->mmcontext);
+	if (rc < 0) {
+		/* abort in case of error, do not advance frag_nr / next_byte */
+		msgb_free(fmsg);
+		return rc;
+	}
+
+	if (!more) {
+		/* we've sent all fragments */
+		msgb_free(fs->msg);
+		memset(fs, 0, sizeof(*fs));
+		/* increment NPDU number for next frame */
+		sne->tx_npdu_nr = (sne->tx_npdu_nr + 1) % 0xfff;
+		return 0;
+	}
+
+	/* default: more fragments to send */
+	return 1;
+}
+
+/* Request transmission of a SN-PDU over specified LLC Entity + SAPI */
+int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
+			void *mmcontext)
+{
+	struct sndcp_entity *sne;
+	struct sndcp_common_hdr *sch;
+	struct sndcp_comp_hdr *scomph;
+	struct sndcp_udata_hdr *suh;
+	struct sndcp_frag_state fs;
+
+	/* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */
+
+	sne = sndcp_entity_by_lle(lle, nsapi);
+	if (!sne) {
+		LOGP(DSNDCP, LOGL_ERROR, "Cannot find SNDCP Entity\n");
+		return -EIO;
+	}
+
+	/* Check if we need to fragment this N-PDU into multiple SN-PDUs */
+	if (msg->len > lle->params.n201_u - 
+			(sizeof(*sch) + sizeof(*suh) + sizeof(*scomph))) {
+		/* initialize the fragmenter state */
+		fs.msg = msg;
+		fs.frag_nr = 0;
+		fs.next_byte = msg->data;
+		fs.sne = sne;
+		fs.mmcontext = mmcontext;
+
+		/* call function to generate and send fragments until all
+		 * of the N-PDU has been sent */
+		while (1) {
+			int rc = sndcp_send_ud_frag(&fs);
+			if (rc == 0)
+				return 0;
+			if (rc < 0)
+				return rc;
+		}
+		/* not reached */
+		return 0;
+	}
+
+	/* this is the non-fragmenting case where we only build 1 SN-PDU */
+
+	/* prepend the user-data header */
+	suh = (struct sndcp_udata_hdr *) msgb_push(msg, sizeof(*suh));
+	suh->npdu_low = sne->tx_npdu_nr & 0xff;
+	suh->npdu_high = (sne->tx_npdu_nr >> 8) & 0xf;
+	suh->seg_nr = 0;
+	sne->tx_npdu_nr = (sne->tx_npdu_nr + 1) % 0xfff;
+
+	scomph = (struct sndcp_comp_hdr *) msgb_push(msg, sizeof(*scomph));
+	scomph->pcomp = 0;
+	scomph->dcomp = 0;
+
+	/* prepend common SNDCP header */
+	sch = (struct sndcp_common_hdr *) msgb_push(msg, sizeof(*sch));
+	sch->first = 1;
+	sch->type = 1;
+	sch->nsapi = nsapi;
+
+	return gprs_llc_tx_ui(msg, lle->sapi, 0, mmcontext);
+}
+
+/* Section 5.1.2.17 LL-UNITDATA.ind */
+int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t *hdr, uint8_t len)
+{
+	struct sndcp_entity *sne;
+	struct sndcp_common_hdr *sch = (struct sndcp_common_hdr *)hdr;
+	struct sndcp_comp_hdr *scomph = NULL;
+	struct sndcp_udata_hdr *suh;
+	uint8_t *npdu;
+	uint16_t npdu_num;
+	int npdu_len;
+
+	sch = (struct sndcp_common_hdr *) hdr;
+	if (sch->first) {
+		scomph = (struct sndcp_comp_hdr *) (hdr + 1);
+		suh = (struct sndcp_udata_hdr *) (hdr + 1 + sizeof(struct sndcp_common_hdr));
+	} else
+		suh = (struct sndcp_udata_hdr *) (hdr + sizeof(struct sndcp_common_hdr));
+
+	if (sch->type == 0) {
+		LOGP(DSNDCP, LOGL_ERROR, "SN-DATA PDU at unitdata_ind() function\n");
+		return -EINVAL;
+	}
+
+	if (len < sizeof(*sch) + sizeof(*suh)) {
+		LOGP(DSNDCP, LOGL_ERROR, "SN-UNITDATA PDU too short (%u)\n", len);
+		return -EIO;
+	}
+
+	sne = sndcp_entity_by_lle(lle, sch->nsapi);
+	if (!sne) {
+		LOGP(DSNDCP, LOGL_ERROR, "Message for non-existing SNDCP Entity "
+			"(lle=%p, TLLI=%08x, SAPI=%u, NSAPI=%u)\n", lle,
+			lle->llme->tlli, lle->sapi, sch->nsapi);
+		return -EIO;
+	}
+
+	if (!sch->first || sch->more) {
+		/* FIXME: implement fragment re-assembly */
+		LOGP(DSNDCP, LOGL_ERROR, "We don't support reassembly yet\n");
+		return -EIO;
+	}
+
+	if (scomph && (scomph->pcomp || scomph->dcomp)) {
+		LOGP(DSNDCP, LOGL_ERROR, "We don't support compression yet\n");
+		return -EIO;
+	}
+
+	npdu_num = (suh->npdu_high << 8) | suh->npdu_low;
+	npdu = (uint8_t *)suh + sizeof(*suh);
+	npdu_len = (msg->data + msg->len) - npdu;
+	if (npdu_len <= 0) {
+		LOGP(DSNDCP, LOGL_ERROR, "Short SNDCP N-PDU: %d\n", npdu_len);
+		return -EIO;
+	}
+	/* actually send the N-PDU to the SGSN core code, which then
+	 * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */
+	return sgsn_rx_sndcp_ud_ind(lle->llme->tlli, sne->nsapi, msg, npdu_len, npdu);
+}
+
+/* Section 5.1.2.1 LL-RESET.ind */
+static int sndcp_ll_reset_ind(struct sndcp_entity *se)
+{
+	/* treat all outstanding SNDCP-LLC request type primitives as not sent */
+	/* reset all SNDCP XID parameters to default values */
+}
+
+static int sndcp_ll_status_ind()
+{
+	/* inform the SM sub-layer by means of SNSM-STATUS.req */
+}
+
+#if 0
+static struct sndcp_state_list {{
+	uint32_t	states;
+	unsigned int	type;
+	int		(*rout)(struct sndcp_entity *se, struct msgb *msg);
+} sndcp_state_list[] = {
+	{ ALL_STATES,
+	  LL_RESET_IND, sndcp_ll_reset_ind },
+	{ ALL_STATES,
+	  LL_ESTABLISH_IND, sndcp_ll_est_ind },
+	{ SBIT(SNDCP_S_EST_RQD),
+	  LL_ESTABLISH_RESP, sndcp_ll_est_ind },
+	{ SBIT(SNDCP_S_EST_RQD),
+	  LL_ESTABLISH_CONF, sndcp_ll_est_conf },
+	{ SBIT(SNDCP_S_
+};
+
+static int sndcp_rx_llc_prim()
+{
+	case LL_ESTABLISH_REQ:
+	case LL_RELEASE_REQ:
+	case LL_XID_REQ:
+	case LL_DATA_REQ:
+	LL_UNITDATA_REQ,	/* TLLI, SN-PDU, Ref, QoS, Radio Prio, Ciph */
+
+	switch (prim) {
+	case LL_RESET_IND:
+	case LL_ESTABLISH_IND:
+	case LL_ESTABLISH_RESP:
+	case LL_ESTABLISH_CONF:
+	case LL_RELEASE_IND:
+	case LL_RELEASE_CONF:
+	case LL_XID_IND:
+	case LL_XID_RESP:
+	case LL_XID_CONF:
+	case LL_DATA_IND:
+	case LL_DATA_CONF:
+	case LL_UNITDATA_IND:
+	case LL_STATUS_IND:
+}
+#endif
diff --git a/openbsc/src/gprs/osmo_gbproxy.cfg b/openbsc/src/gprs/osmo_gbproxy.cfg
new file mode 100644
index 0000000..d6b5619
--- /dev/null
+++ b/openbsc/src/gprs/osmo_gbproxy.cfg
@@ -0,0 +1,24 @@
+!
+! Osmocom Gb Proxy (0.9.0.404-6463) configuration saved from vty
+!!
+!
+line vty
+ no login
+!
+gbproxy
+ sgsn nsei 101
+ns
+ nse 101 nsvci 101
+ nse 101 remote-role sgsn
+ nse 101 encapsulation udp
+ nse 101 remote-ip 192.168.100.239
+ nse 101 remote-port 7777
+ timer tns-block 3
+ timer tns-block-retries 3
+ timer tns-reset 3
+ timer tns-reset-retries 3
+ timer tns-test 30
+ timer tns-alive 3
+ timer tns-alive-retries 10
+ encapsulation framerelay-gre enabled 1
+ encapsulation framerelay-gre local-ip 0.0.0.0
diff --git a/openbsc/src/gprs/osmo_sgsn.cfg b/openbsc/src/gprs/osmo_sgsn.cfg
new file mode 100644
index 0000000..c4c9ec1
--- /dev/null
+++ b/openbsc/src/gprs/osmo_sgsn.cfg
@@ -0,0 +1,23 @@
+!
+! Osmocom SGSN (0.9.0.474-0ede2) configuration saved from vty
+!!
+!
+line vty
+ no login
+!
+sgsn
+ gtp local-ip 192.168.100.11
+ ggsn 0 remote-ip 192.168.100.239
+ ggsn 0 gtp-version 1
+ns
+ timer tns-block 3
+ timer tns-block-retries 3
+ timer tns-reset 3
+ timer tns-reset-retries 3
+ timer tns-test 30
+ timer tns-alive 3
+ timer tns-alive-retries 10
+ encapsulation udp local-ip 192.168.100.11
+ encapsulation udp local-port 23000
+ encapsulation framerelay-gre enabled 0
+bssgp
diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c
new file mode 100644
index 0000000..0eface3
--- /dev/null
+++ b/openbsc/src/gprs/sgsn_libgtp.c
@@ -0,0 +1,557 @@
+/* GPRS SGSN integration with libgtp of OpenGGSN */
+/* libgtp implements the GPRS Tunelling Protocol GTP per TS 09.60 / 29.060 */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <osmocore/talloc.h>
+#include <osmocore/select.h>
+#include <osmocore/rate_ctr.h>
+#include <openbsc/gsm_04_08_gprs.h>
+
+#include <openbsc/signal.h>
+#include <openbsc/debug.h>
+#include <openbsc/sgsn.h>
+#include <openbsc/gprs_llc.h>
+#include <openbsc/gprs_bssgp.h>
+#include <openbsc/gprs_sgsn.h>
+#include <openbsc/gprs_gmm.h>
+
+#include <gtp.h>
+#include <pdp.h>
+
+const struct value_string gtp_cause_strs[] = {
+	{ GTPCAUSE_REQ_IMSI, "Request IMSI" },
+	{ GTPCAUSE_REQ_IMEI, "Request IMEI" },
+	{ GTPCAUSE_REQ_IMSI_IMEI, "Request IMSI and IMEI" },
+	{ GTPCAUSE_NO_ID_NEEDED, "No identity needed" },
+	{ GTPCAUSE_MS_REFUSES_X, "MS refuses" },
+	{ GTPCAUSE_MS_NOT_RESP_X, "MS is not GPRS responding" },
+	{ GTPCAUSE_ACC_REQ, "Request accepted" },
+	{ GTPCAUSE_NON_EXIST, "Non-existent" },
+	{ GTPCAUSE_INVALID_MESSAGE, "Invalid message format" },
+	{ GTPCAUSE_IMSI_NOT_KNOWN, "IMSI not known" },
+	{ GTPCAUSE_MS_DETACHED, "MS is GPRS detached" },
+	{ GTPCAUSE_MS_NOT_RESP, "MS is not GPRS responding" },
+	{ GTPCAUSE_MS_REFUSES, "MS refuses" },
+	{ GTPCAUSE_NO_RESOURCES, "No resources available" },
+	{ GTPCAUSE_NOT_SUPPORTED, "Service not supported" },
+	{ GTPCAUSE_MAN_IE_INCORRECT, "Mandatory IE incorrect" },
+	{ GTPCAUSE_MAN_IE_MISSING, "Mandatory IE missing" },
+	{ GTPCAUSE_OPT_IE_INCORRECT, "Optional IE incorrect" },
+	{ GTPCAUSE_SYS_FAIL, "System failure" },
+	{ GTPCAUSE_ROAMING_REST, "Roaming restrictions" },
+	{ GTPCAUSE_PTIMSI_MISMATCH, "P-TMSI Signature mismatch" },
+	{ GTPCAUSE_CONN_SUSP, "GPRS connection suspended" },
+	{ GTPCAUSE_AUTH_FAIL, "Authentication failure" },
+	{ GTPCAUSE_USER_AUTH_FAIL, "User authentication failed" },
+	{ GTPCAUSE_CONTEXT_NOT_FOUND, "Context not found" },
+	{ GTPCAUSE_ADDR_OCCUPIED, "All dynamic PDP addresses occupied" },
+	{ GTPCAUSE_NO_MEMORY, "No memory is available" },
+	{ GTPCAUSE_RELOC_FAIL, "Relocation failure" },
+	{ GTPCAUSE_UNKNOWN_MAN_EXTHEADER, "Unknown mandatory ext. header" },
+	{ GTPCAUSE_SEM_ERR_TFT, "Semantic error in TFT operation" },
+	{ GTPCAUSE_SYN_ERR_TFT, "Syntactic error in TFT operation" },
+	{ GTPCAUSE_SEM_ERR_FILTER, "Semantic errors in packet filter" },
+	{ GTPCAUSE_SYN_ERR_FILTER, "Syntactic errors in packet filter" },
+	{ GTPCAUSE_MISSING_APN, "Missing or unknown APN" },
+	{ GTPCAUSE_UNKNOWN_PDP, "Unknown PDP address or PDP type" },
+	{ 0, NULL }
+};
+
+/* generate a PDP context based on the IE's from the 04.08 message,
+ * and send the GTP create pdp context request to the GGSN */
+struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
+					 struct sgsn_mm_ctx *mmctx,
+					 uint16_t nsapi,
+					 struct tlv_parsed *tp)
+{
+	struct sgsn_pdp_ctx *pctx;
+	struct pdp_t *pdp;
+	uint64_t imsi_ui64 = 0;
+	int rc;
+
+	LOGP(DGPRS, LOGL_ERROR, "Create PDP Context\n");
+	pctx = sgsn_pdp_ctx_alloc(mmctx, nsapi);
+	if (!pctx) {
+		LOGP(DGPRS, LOGL_ERROR, "Couldn't allocate PDP Ctx\n");
+		return NULL;
+	}
+
+	rc = pdp_newpdp(&pdp, imsi_ui64, nsapi, NULL);
+	if (rc) {
+		LOGP(DGPRS, LOGL_ERROR, "Out of libgtp PDP Contexts\n");
+		return NULL;
+	}
+	pdp->priv = pctx;
+	pctx->lib = pdp;
+	pctx->ggsn = ggsn;
+
+	//pdp->peer =	/* sockaddr_in of GGSN (receive) */
+	//pdp->ipif =	/* not used by library */
+	pdp->version = ggsn->gtp_version;
+	pdp->hisaddr0 =	ggsn->remote_addr;
+	pdp->hisaddr1 = ggsn->remote_addr;
+	//pdp->cch_pdp = 512;	/* Charging Flat Rate */
+
+	/* MS provided APN, subscription not verified */
+	pdp->selmode = 0x01;
+
+	/* IMSI, TEID/TEIC, FLLU/FLLC, TID, NSAPI set in pdp_newpdp */
+
+	/* FIXME: MSISDN in BCD format from mmctx */
+	//pdp->msisdn.l/.v
+
+	/* End User Address from GMM requested PDP address */
+	pdp->eua.l = TLVP_LEN(tp, OSMO_IE_GSM_REQ_PDP_ADDR);
+	if (pdp->eua.l > sizeof(pdp->eua.v))
+		pdp->eua.l = sizeof(pdp->eua.v);
+	memcpy(pdp->eua.v, TLVP_VAL(tp, OSMO_IE_GSM_REQ_PDP_ADDR),
+		pdp->eua.l);
+	/* Highest 4 bits of first byte need to be set to 1, otherwise
+	 * the IE is identical with the 04.08 PDP Address IE */
+	pdp->eua.v[0] |= 0xf0;
+
+	/* APN name from GMM */
+	pdp->apn_use.l = TLVP_LEN(tp, GSM48_IE_GSM_APN);
+	if (pdp->apn_use.l > sizeof(pdp->apn_use.v))
+		pdp->apn_use.l = sizeof(pdp->apn_use.v);
+	memcpy(pdp->apn_use.v, TLVP_VAL(tp, GSM48_IE_GSM_APN),
+		pdp->apn_use.l);
+
+	/* Protocol Configuration Options from GMM */
+	pdp->pco_req.l = TLVP_LEN(tp, GSM48_IE_GSM_PROTO_CONF_OPT);
+	if (pdp->pco_req.l > sizeof(pdp->pco_req.v))
+		pdp->pco_req.l = sizeof(pdp->pco_req.v);
+	memcpy(pdp->pco_req.v, TLVP_VAL(tp, GSM48_IE_GSM_PROTO_CONF_OPT),
+		pdp->pco_req.l);
+
+	/* QoS options from GMM */
+	pdp->qos_req.l = TLVP_LEN(tp, OSMO_IE_GSM_REQ_QOS);
+	if (pdp->qos_req.l > sizeof(pdp->qos_req.v))
+		pdp->qos_req.l = sizeof(pdp->qos_req.v);
+	memcpy(pdp->qos_req.v, TLVP_VAL(tp, OSMO_IE_GSM_REQ_QOS),
+		pdp->qos_req.l);
+
+	/* SGSN address for control plane */
+	pdp->gsnlc.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr);
+	memcpy(pdp->gsnlc.v, &sgsn->cfg.gtp_listenaddr.sin_addr,
+		sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
+
+	/* SGSN address for user plane */
+	pdp->gsnlu.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr);
+	memcpy(pdp->gsnlu.v, &sgsn->cfg.gtp_listenaddr.sin_addr,
+		sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
+
+	/* change pdp state to 'requested' */
+	pctx->state = PDP_STATE_CR_REQ;
+
+	rc = gtp_create_context_req(ggsn->gsn, pdp, pctx);
+	/* FIXME */
+
+	return pctx;
+}
+
+int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx)
+{
+	LOGP(DGPRS, LOGL_ERROR, "Delete PDP Context\n");
+
+	/* FIXME: decide if we need teardown or not ! */
+	return gtp_delete_context_req(pctx->ggsn->gsn, pctx->lib, pctx, 1);
+}
+
+struct cause_map {
+	uint8_t cause_in;
+	uint8_t cause_out;
+};
+
+static uint8_t cause_map(const struct cause_map *map, uint8_t in, uint8_t deflt)
+{
+	const struct cause_map *m;
+
+	for (m = map; m->cause_in && m->cause_out; m++) {
+		if (m->cause_in == in)
+			return m->cause_out;
+	}
+	return deflt;
+}
+
+/* how do we map from gtp cause to SM cause */
+static const struct cause_map gtp2sm_cause_map[] = {
+	{ GTPCAUSE_NO_RESOURCES, 	GSM_CAUSE_INSUFF_RSRC },
+	{ GTPCAUSE_NOT_SUPPORTED,	GSM_CAUSE_SERV_OPT_NOTSUPP },
+	{ GTPCAUSE_MAN_IE_INCORRECT,	GSM_CAUSE_INV_MAND_INFO },
+	{ GTPCAUSE_MAN_IE_MISSING,	GSM_CAUSE_INV_MAND_INFO },
+	{ GTPCAUSE_OPT_IE_INCORRECT,	GSM_CAUSE_PROTO_ERR_UNSPEC },
+	{ GTPCAUSE_SYS_FAIL,		GSM_CAUSE_NET_FAIL },
+	{ GTPCAUSE_ROAMING_REST,	GSM_CAUSE_REQ_SERV_OPT_NOTSUB },
+	{ GTPCAUSE_PTIMSI_MISMATCH,	GSM_CAUSE_PROTO_ERR_UNSPEC },
+	{ GTPCAUSE_CONN_SUSP,		GSM_CAUSE_PROTO_ERR_UNSPEC },
+	{ GTPCAUSE_AUTH_FAIL,		GSM_CAUSE_AUTH_FAILED },
+	{ GTPCAUSE_USER_AUTH_FAIL,	GSM_CAUSE_ACT_REJ_GGSN },
+	{ GTPCAUSE_CONTEXT_NOT_FOUND,	GSM_CAUSE_PROTO_ERR_UNSPEC },
+	{ GTPCAUSE_ADDR_OCCUPIED,	GSM_CAUSE_INSUFF_RSRC },
+	{ GTPCAUSE_NO_MEMORY,		GSM_CAUSE_INSUFF_RSRC },
+	{ GTPCAUSE_RELOC_FAIL,		GSM_CAUSE_PROTO_ERR_UNSPEC },
+	{ GTPCAUSE_UNKNOWN_MAN_EXTHEADER, GSM_CAUSE_PROTO_ERR_UNSPEC },
+	{ GTPCAUSE_MISSING_APN,		GSM_CAUSE_MISSING_APN },
+	{ GTPCAUSE_UNKNOWN_PDP,		GSM_CAUSE_UNKNOWN_PDP },
+	{ 0, 0 }
+};
+
+/* The GGSN has confirmed the creation of a PDP Context */
+static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
+{
+	struct sgsn_pdp_ctx *pctx = cbp;
+	uint8_t reject_cause;
+	int rc;
+
+	DEBUGP(DGPRS, "Received CREATE PDP CTX CONF, cause=%d(%s)\n",
+		cause, get_value_string(gtp_cause_strs, cause));
+
+	/* Check for cause value if it was really successful */
+	if (cause < 0) {
+		LOGP(DGPRS, LOGL_NOTICE, "Create PDP ctx req timed out\n");
+		if (pdp && pdp->version == 1) {
+			pdp->version = 0;
+			gtp_create_context_req(sgsn->gsn, pdp, cbp);
+			return 0;
+		} else {
+			reject_cause = GSM_CAUSE_NET_FAIL;
+			goto reject;
+		}
+	}
+
+	/* Check for cause value if it was really successful */
+	if (cause != GTPCAUSE_ACC_REQ) {
+		reject_cause = cause_map(gtp2sm_cause_map, cause,
+					 GSM_CAUSE_ACT_REJ_GGSN);
+		goto reject;
+	}
+
+	/* Activate the SNDCP layer */
+	sndcp_sm_activate_ind(&pctx->mm->llme->lle[pctx->sapi], pctx->nsapi);
+
+	/* Send PDP CTX ACT to MS */
+	return gsm48_tx_gsm_act_pdp_acc(pctx);
+
+reject:
+	pctx->state = PDP_STATE_NONE;
+	if (pdp)
+		pdp_freepdp(pdp);
+	/* Send PDP CTX ACT REJ to MS */
+	rc = gsm48_tx_gsm_act_pdp_rej(pctx->mm, pctx->ti, reject_cause,
+					0, NULL);
+	sgsn_pdp_ctx_free(pctx);
+
+	return EOF;
+}
+
+/* Confirmation of a PDP Context Delete */
+static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
+{
+	struct sgsn_pdp_ctx *pctx = cbp;
+	int rc;
+
+	DEBUGP(DGPRS, "Received DELETE PDP CTX CONF, cause=%d(%s)\n",
+		cause, get_value_string(gtp_cause_strs, cause));
+
+	/* Confirm deactivation of PDP context to MS */
+	rc = gsm48_tx_gsm_deact_pdp_acc(pctx);
+
+	sgsn_pdp_ctx_free(pctx);
+
+	return rc;
+}
+
+/* Confirmation of an GTP ECHO request */
+static int echo_conf(int recovery)
+{
+	if (recovery < 0) {
+		DEBUGP(DGPRS, "GTP Echo Request timed out\n");
+		/* FIXME: if version == 1, retry with version 0 */
+	} else {
+		DEBUGP(DGPRS, "GTP Rx Echo Response\n");
+	}
+	return 0;
+}
+
+/* libgtp callback for confirmations */
+static int cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
+{
+	DEBUGP(DGPRS, "libgtp cb_conf(type=%d, cause=%d, pdp=%p, cbp=%p)\n",
+		type, cause, pdp, cbp);
+
+	if (cause == EOF)
+		LOGP(DGPRS, LOGL_ERROR, "libgtp EOF (type=%u, pdp=%p, cbp=%p)\n",
+			type, pdp, cbp);
+
+	switch (type) {
+	case GTP_ECHO_REQ:
+		return echo_conf(cause);
+	case GTP_CREATE_PDP_REQ:
+		return create_pdp_conf(pdp, cbp, cause);
+	case GTP_DELETE_PDP_REQ:
+		return delete_pdp_conf(pdp, cbp, cause);
+	default:
+		break;
+	}
+	return 0;
+}
+
+/* Called whenever a PDP context is deleted for any reason */
+static int cb_delete_context(struct pdp_t *pdp)
+{
+	LOGP(DGPRS, LOGL_INFO, "PDP Context was deleted\n");
+	return 0;
+}
+
+/* Called when we receive a Version Not Supported message */
+static int cb_unsup_ind(struct sockaddr_in *peer)
+{
+	LOGP(DGPRS, LOGL_INFO, "GTP Version not supported Indication "
+		"from %s:%u\n", inet_ntoa(peer->sin_addr),
+		ntohs(peer->sin_port));
+	return 0;
+}
+
+/* Called when we receive a Supported Ext Headers Notification */
+static int cb_extheader_ind(struct sockaddr_in *peer)
+{
+	LOGP(DGPRS, LOGL_INFO, "GTP Supported Ext Headers Noficiation "
+		"from %s:%u\n", inet_ntoa(peer->sin_addr),
+		ntohs(peer->sin_port));
+	return 0;
+}
+
+/* Called whenever we recive a DATA packet */
+static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
+{
+	struct bssgp_paging_info pinfo;
+	struct sgsn_pdp_ctx *pdp;
+	struct sgsn_mm_ctx *mm;
+	struct msgb *msg;
+	uint8_t *ud;
+	int rc;
+
+	DEBUGP(DGPRS, "GTP DATA IND from GGSN, length=%u\n", len);
+
+	pdp = lib->priv;
+	if (!pdp) {
+		DEBUGP(DGPRS, "GTP DATA IND from GGSN for unknown PDP\n");
+		return -EIO;
+	}
+	mm = pdp->mm;
+
+	msg = msgb_alloc_headroom(len+256, 128, "GTP->SNDCP");
+	ud = msgb_put(msg, len);
+	memcpy(ud, packet, len);
+
+	msgb_tlli(msg) = mm->tlli;
+	msgb_bvci(msg) = mm->bvci;
+	msgb_nsei(msg) = mm->nsei;
+
+	switch (mm->mm_state) {
+	case GMM_REGISTERED_SUSPENDED:
+		/* initiate PS PAGING procedure */
+		memset(&pinfo, 0, sizeof(pinfo));
+		pinfo.mode = BSSGP_PAGING_PS;
+		pinfo.scope = BSSGP_PAGING_BVCI;
+		pinfo.bvci = mm->bvci;
+		pinfo.imsi = mm->imsi;
+		pinfo.ptmsi = mm->p_tmsi;
+		pinfo.drx_params = mm->drx_parms;
+		pinfo.qos[0] = 0; // FIXME
+		rc = gprs_bssgp_tx_paging(mm->nsei, 0, &pinfo);
+		rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PAGING_PS]);
+		/* FIXME: queue the packet we received from GTP */
+		break;
+	case GMM_REGISTERED_NORMAL:
+		break;
+	default:
+		LOGP(DGPRS, LOGL_ERROR, "GTP DATA IND for TLLI %08X in state "
+			"%u\n", mm->tlli, mm->mm_state);
+		msgb_free(msg);
+		return -1;
+	}
+
+	rate_ctr_inc(&pdp->ctrg->ctr[PDP_CTR_PKTS_UDATA_OUT]);
+	rate_ctr_add(&pdp->ctrg->ctr[PDP_CTR_BYTES_UDATA_OUT], len);
+	rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_UDATA_OUT]);
+	rate_ctr_add(&mm->ctrg->ctr[GMM_CTR_BYTES_UDATA_OUT], len);
+
+	return sndcp_unitdata_req(msg, &mm->llme->lle[pdp->sapi],
+				  pdp->nsapi, mm);
+}
+
+/* Called by SNDCP when it has received/re-assembled a N-PDU */
+int sgsn_rx_sndcp_ud_ind(uint32_t tlli, uint8_t nsapi, struct msgb *msg,
+			 uint32_t npdu_len, uint8_t *npdu)
+{
+	struct sgsn_mm_ctx *mmctx;
+	struct sgsn_pdp_ctx *pdp;
+	struct gprs_ra_id ra_id;
+
+	/* look-up the MM context for this message */
+	bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
+	mmctx = sgsn_mm_ctx_by_tlli(tlli, &ra_id);
+	if (!mmctx) {
+		LOGP(DGPRS, LOGL_ERROR,
+			"Cannot find MM CTX for TLLI %08x\n", tlli);
+		return -EIO;
+	}
+	/* look-up the PDP context for this message */
+	pdp = sgsn_pdp_ctx_by_nsapi(mmctx, nsapi);
+	if (!pdp) {
+		LOGP(DGPRS, LOGL_ERROR, "Cannot find PDP CTX for "
+			"TLLI=%08x, NSAPI=%u\n", tlli, nsapi);
+		return -EIO;
+	}
+	if (!pdp->lib) {
+		LOGP(DGPRS, LOGL_ERROR, "PDP CTX without libgtp\n");
+		return -EIO;
+	}
+
+	rate_ctr_inc(&pdp->ctrg->ctr[PDP_CTR_PKTS_UDATA_IN]);
+	rate_ctr_add(&pdp->ctrg->ctr[PDP_CTR_BYTES_UDATA_IN], npdu_len);
+	rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_UDATA_IN]);
+	rate_ctr_add(&mmctx->ctrg->ctr[GMM_CTR_BYTES_UDATA_IN], npdu_len);
+
+	return gtp_data_req(pdp->ggsn->gsn, pdp->lib, npdu, npdu_len);
+
+	return gtp_data_req(pdp->ggsn->gsn, pdp->lib, npdu, npdu_len);
+}
+
+/* libgtp select loop integration */
+static int sgsn_gtp_fd_cb(struct bsc_fd *fd, unsigned int what)
+{
+	struct sgsn_instance *sgi = fd->data;
+	int rc;
+
+	if (!(what & BSC_FD_READ))
+		return 0;
+
+	switch (fd->priv_nr) {
+	case 0:
+		rc = gtp_decaps0(sgi->gsn);
+		break;
+	case 1:
+		rc = gtp_decaps1c(sgi->gsn);
+		break;
+	case 2:
+		rc = gtp_decaps1u(sgi->gsn);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static void sgsn_gtp_tmr_start(struct sgsn_instance *sgi)
+{
+	struct timeval next;
+
+	/* Retrieve next retransmission as struct timeval */
+	gtp_retranstimeout(sgi->gsn, &next);
+
+	/* re-schedule the timer */
+	bsc_schedule_timer(&sgi->gtp_timer, next.tv_sec, next.tv_usec/1000);
+}
+
+/* timer callback for libgtp retransmissions and ping */
+static void sgsn_gtp_tmr_cb(void *data)
+{
+	struct sgsn_instance *sgi = data;
+
+	/* Do all the retransmissions as needed */
+	gtp_retrans(sgi->gsn);
+
+	sgsn_gtp_tmr_start(sgi);
+}
+
+int sgsn_gtp_init(struct sgsn_instance *sgi)
+{
+	int rc;
+	struct gsn_t *gsn;
+
+	rc = gtp_new(&sgi->gsn, sgi->cfg.gtp_statedir,
+		     &sgi->cfg.gtp_listenaddr.sin_addr, GTP_MODE_SGSN);
+	if (rc) {
+		LOGP(DGPRS, LOGL_ERROR, "Failed to create GTP: %d\n", rc);
+		return rc;
+	}
+	gsn = sgi->gsn;
+
+	sgi->gtp_fd0.fd = gsn->fd0;
+	sgi->gtp_fd0.priv_nr = 0;
+	sgi->gtp_fd0.data = sgi;
+	sgi->gtp_fd0.when = BSC_FD_READ;
+	sgi->gtp_fd0.cb = sgsn_gtp_fd_cb;
+	rc = bsc_register_fd(&sgi->gtp_fd0);
+	if (rc < 0)
+		return rc;
+
+	sgi->gtp_fd1c.fd = gsn->fd1c;
+	sgi->gtp_fd1c.priv_nr = 1;
+	sgi->gtp_fd1c.data = sgi;
+	sgi->gtp_fd1c.when = BSC_FD_READ;
+	sgi->gtp_fd1c.cb = sgsn_gtp_fd_cb;
+	bsc_register_fd(&sgi->gtp_fd1c);
+	if (rc < 0)
+		return rc;
+
+	sgi->gtp_fd1u.fd = gsn->fd1u;
+	sgi->gtp_fd1u.priv_nr = 2;
+	sgi->gtp_fd1u.data = sgi;
+	sgi->gtp_fd1u.when = BSC_FD_READ;
+	sgi->gtp_fd1u.cb = sgsn_gtp_fd_cb;
+	bsc_register_fd(&sgi->gtp_fd1u);
+	if (rc < 0)
+		return rc;
+
+	/* Start GTP re-transmission timer */
+	sgi->gtp_timer.cb = sgsn_gtp_tmr_cb;
+	sgi->gtp_timer.data = sgi;
+	sgsn_gtp_tmr_start(sgi);
+
+	/* Register callbackcs with libgtp */
+	gtp_set_cb_delete_context(gsn, cb_delete_context);
+	gtp_set_cb_conf(gsn, cb_conf);
+	gtp_set_cb_data_ind(gsn, cb_data_ind);
+	gtp_set_cb_unsup_ind(gsn, cb_unsup_ind);
+	gtp_set_cb_extheader_ind(gsn, cb_extheader_ind);
+
+	return 0;
+}
diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c
new file mode 100644
index 0000000..27d156a
--- /dev/null
+++ b/openbsc/src/gprs/sgsn_main.c
@@ -0,0 +1,210 @@
+/* GPRS SGSN Implementation */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <osmocore/talloc.h>
+#include <osmocore/select.h>
+#include <osmocore/rate_ctr.h>
+
+#include <osmocom/vty/telnet_interface.h>
+
+#include <openbsc/signal.h>
+#include <openbsc/debug.h>
+#include <openbsc/vty.h>
+#include <openbsc/sgsn.h>
+#include <openbsc/gprs_ns.h>
+#include <openbsc/gprs_bssgp.h>
+#include <openbsc/gprs_llc.h>
+
+#include <gtp.h>
+
+#include "../../bscconfig.h"
+
+/* this is here for the vty... it will never be called */
+void subscr_put() { abort(); }
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+void *tall_bsc_ctx;
+
+struct gprs_ns_inst *sgsn_nsi;
+const char *openbsc_copyright =
+	"Copyright (C) 2010 Harald Welte and On-Waves\n"
+	"License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\n"
+	"This is free software: you are free to change and redistribute it.\n"
+	"There is NO WARRANTY, to the extent permitted by law.\n";
+
+static struct sgsn_instance sgsn_inst = {
+	.config_file = "osmo_sgsn.cfg",
+	.cfg = {
+		.gtp_statedir = "./",
+	},
+};
+struct sgsn_instance *sgsn = &sgsn_inst;
+
+/* call-back function for the NS protocol */
+static int sgsn_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
+		      struct msgb *msg, u_int16_t bvci)
+{
+	int rc = 0;
+
+	switch (event) {
+	case GPRS_NS_EVT_UNIT_DATA:
+		/* hand the message into the BSSGP implementation */
+		rc = gprs_bssgp_rcvmsg(msg);
+		break;
+	default:
+		LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event);
+		if (msg)
+			talloc_free(msg);
+		rc = -EIO;
+		break;
+	}
+	return rc;
+}
+
+static void signal_handler(int signal)
+{
+	fprintf(stdout, "signal %u received\n", signal);
+
+	switch (signal) {
+	case SIGINT:
+		dispatch_signal(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL);
+		sleep(1);
+		exit(0);
+		break;
+	case SIGABRT:
+		/* in case of abort, we want to obtain a talloc report
+		 * and then return to the caller, who will abort the process */
+	case SIGUSR1:
+		talloc_report(tall_vty_ctx, stderr);
+		talloc_report_full(tall_bsc_ctx, stderr);
+		break;
+	case SIGUSR2:
+		talloc_report_full(tall_vty_ctx, stderr);
+		break;
+	default:
+		break;
+	}
+}
+
+/* NSI that BSSGP uses when transmitting on NS */
+extern struct gprs_ns_inst *bssgp_nsi;
+extern void *tall_msgb_ctx;
+
+extern enum node_type bsc_vty_go_parent(struct vty *vty);
+
+static struct vty_app_info vty_info = {
+	.name 		= "Osmocom SGSN",
+	.version	= PACKAGE_VERSION,
+	.go_parent_cb	= bsc_vty_go_parent,
+};
+
+int main(int argc, char **argv)
+{
+	struct gsm_network dummy_network;
+	struct log_target *stderr_target;
+	struct sockaddr_in sin;
+	int rc;
+
+	tall_bsc_ctx = talloc_named_const(NULL, 0, "osmo_sgsn");
+	tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb");
+
+	signal(SIGINT, &signal_handler);
+	signal(SIGABRT, &signal_handler);
+	signal(SIGUSR1, &signal_handler);
+	signal(SIGUSR2, &signal_handler);
+	signal(SIGPIPE, SIG_IGN);
+
+	log_init(&log_info);
+	stderr_target = log_target_create_stderr();
+	log_add_target(stderr_target);
+	log_set_all_filter(stderr_target, 1);
+
+	vty_info.copyright = openbsc_copyright;
+	vty_init(&vty_info);
+	logging_vty_add_cmds();
+        sgsn_vty_init();
+
+	rate_ctr_init(tall_bsc_ctx);
+	rc = telnet_init(tall_bsc_ctx, &dummy_network, 4245);
+	if (rc < 0)
+		exit(1);
+
+	sgsn_nsi = gprs_ns_instantiate(&sgsn_ns_cb);
+	if (!sgsn_nsi) {
+		LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
+		exit(1);
+	}
+	bssgp_nsi = sgsn_inst.cfg.nsi = sgsn_nsi;
+	gprs_ns_vty_init(bssgp_nsi);
+	gprs_bssgp_vty_init();
+	gprs_llc_vty_init();
+	/* FIXME: register signal handler for SS_NS */
+
+	rc = sgsn_parse_config(sgsn_inst.config_file, &sgsn_inst.cfg);
+	if (rc < 0) {
+		LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n");
+		exit(2);
+	}
+
+	rc = sgsn_gtp_init(&sgsn_inst);
+	if (rc) {
+		LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen on GTP socket\n");
+		exit(2);
+	}
+
+	rc = gprs_ns_nsip_listen(sgsn_nsi);
+	if (rc < 0) {
+		LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen on NSIP socket\n");
+		exit(2);
+	}
+
+	rc = gprs_ns_frgre_listen(sgsn_nsi);
+	if (rc < 0) {
+		LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen GRE "
+			"socket. Do you have CAP_NET_RAW?\n");
+		exit(2);
+	}
+
+	while (1) {
+		rc = bsc_select_main(0);
+		if (rc < 0)
+			exit(3);
+	}
+
+	exit(0);
+}
diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c
new file mode 100644
index 0000000..873fa20
--- /dev/null
+++ b/openbsc/src/gprs/sgsn_vty.c
@@ -0,0 +1,289 @@
+/*
+ * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (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 <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <osmocore/talloc.h>
+#include <osmocore/utils.h>
+#include <osmocore/rate_ctr.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/sgsn.h>
+#include <openbsc/gprs_ns.h>
+#include <openbsc/gprs_sgsn.h>
+#include <openbsc/vty.h>
+
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/vty.h>
+
+#include <pdp.h>
+
+static struct sgsn_config *g_cfg = NULL;
+
+static struct cmd_node sgsn_node = {
+	SGSN_NODE,
+	"%s(sgsn)#",
+	1,
+};
+
+static int config_write_sgsn(struct vty *vty)
+{
+	struct sgsn_ggsn_ctx *gctx;
+
+	vty_out(vty, "sgsn%s", VTY_NEWLINE);
+
+	vty_out(vty, " gtp local-ip %s%s",
+		inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
+
+	llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
+		vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id,
+			inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
+		vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
+			gctx->gtp_version, VTY_NEWLINE);
+	}
+
+	return CMD_SUCCESS;
+}
+
+#define SGSN_STR	"Configure the SGSN"
+
+DEFUN(cfg_sgsn, cfg_sgsn_cmd,
+	"sgsn",
+	SGSN_STR)
+{
+	vty->node = SGSN_NODE;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
+	"gtp local-ip A.B.C.D",
+	"GTP Parameters\n"
+	"Set the IP address for the local GTP bind\n")
+{
+	inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
+	"ggsn <0-255> remote-ip A.B.C.D",
+	"")
+{
+	uint32_t id = atoi(argv[0]);
+	struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
+
+	inet_aton(argv[1], &ggc->remote_addr);
+
+	return CMD_SUCCESS;
+}
+
+#if 0
+DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
+	"ggsn <0-255> remote-port <0-65535>",
+	"")
+{
+	uint32_t id = atoi(argv[0]);
+	struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
+	uint16_t port = atoi(argv[1]);
+
+}
+#endif
+
+DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
+	"ggsn <0-255> gtp-version (0|1)",
+	"")
+{
+	uint32_t id = atoi(argv[0]);
+	struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
+
+	if (atoi(argv[1]))
+		ggc->gtp_version = 1;
+	else
+		ggc->gtp_version = 0;
+
+	return CMD_SUCCESS;
+}
+
+#if 0
+DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd,
+	"apn APNAME ggsn <0-255>",
+	"")
+{
+	struct apn_ctx **
+}
+#endif
+
+const struct value_string gprs_mm_st_strs[] = {
+	{ GMM_DEREGISTERED, "DEREGISTERED" },
+	{ GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
+	{ GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
+	{ GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
+	{ GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
+	{ 0, NULL }
+};
+
+static void vty_dump_pdp(struct vty *vty, const char *pfx,
+			 struct sgsn_pdp_ctx *pdp)
+{
+	vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u%s",
+		pfx, pdp->mm->imsi, pdp->sapi, pdp->nsapi, VTY_NEWLINE);
+	vty_out(vty, "%s  APN: %s\n", pfx, pdp->lib->apn_use.v);
+	vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
+}
+
+static void vty_dump_mmctx(struct vty *vty, const char *pfx,
+			   struct sgsn_mm_ctx *mm, int pdp)
+{
+	vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
+		pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
+	vty_out(vty, "%s  MSISDN: %s, TLLI: %08x%s", pfx, mm->msisdn,
+		mm->tlli, VTY_NEWLINE);
+	vty_out(vty, "%s  MM State: %s, Routeing Area: %u-%u-%u-%u, "
+		"Cell ID: %u%s", pfx,
+		get_value_string(gprs_mm_st_strs, mm->mm_state),
+		mm->ra.mcc, mm->ra.mnc, mm->ra.lac, mm->ra.rac,
+		mm->cell_id, VTY_NEWLINE);
+
+	vty_out_rate_ctr_group(vty, " ", mm->ctrg);
+
+	if (pdp) {
+		struct sgsn_pdp_ctx *pdp;
+
+		llist_for_each_entry(pdp, &mm->pdp_list, list)
+			vty_dump_pdp(vty, "  ", pdp);
+	}
+}
+
+DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
+      SHOW_STR "Display information about the SGSN")
+{
+	/* FIXME: statistics */
+	return CMD_SUCCESS;
+}
+
+#define MMCTX_STR "MM Context\n"
+#define INCLUDE_PDP_STR "Include PDP Context Information\n"
+
+#if 0
+DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd,
+	"show mm-context tlli HEX [pdp]",
+	SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR)
+{
+	uint32_t tlli;
+	struct sgsn_mm_ctx *mm;
+
+	tlli = strtoul(argv[0], NULL, 16);
+	mm = sgsn_mm_ctx_by_tlli(tlli);
+	if (!mm) {
+		vty_out(vty, "No MM context for TLLI %08x%s",
+			tlli, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
+	return CMD_SUCCESS;
+}
+#endif
+
+DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
+	"show mm-context imsi IMSI [pdp]",
+	SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n"
+	INCLUDE_PDP_STR)
+{
+	struct sgsn_mm_ctx *mm;
+
+	mm = sgsn_mm_ctx_by_imsi(argv[0]);
+	if (!mm) {
+		vty_out(vty, "No MM context for IMSI %s%s",
+			argv[0], VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
+	return CMD_SUCCESS;
+}
+
+DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
+	"show mm-context all [pdp]",
+	SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
+{
+	struct sgsn_mm_ctx *mm;
+
+	llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
+		vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(show_ggsn, show_ggsn_cmd,
+	"show ggsn",
+	"")
+{
+
+}
+
+DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
+	"show pdp-context all",
+	SHOW_STR "Display information on PDP Context\n")
+{
+	struct sgsn_pdp_ctx *pdp;
+
+	llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
+		vty_dump_pdp(vty, "", pdp);
+
+	return CMD_SUCCESS;
+}
+
+int sgsn_vty_init(void)
+{
+	install_element_ve(&show_sgsn_cmd);
+	//install_element_ve(&show_mmctx_tlli_cmd);
+	install_element_ve(&show_mmctx_imsi_cmd);
+	install_element_ve(&show_mmctx_all_cmd);
+	install_element_ve(&show_pdpctx_all_cmd);
+
+	install_element(CONFIG_NODE, &cfg_sgsn_cmd);
+	install_node(&sgsn_node, config_write_sgsn);
+	install_default(SGSN_NODE);
+	install_element(SGSN_NODE, &ournode_exit_cmd);
+	install_element(SGSN_NODE, &ournode_end_cmd);
+	install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
+	install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
+	//install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
+	install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
+
+	return 0;
+}
+
+int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg)
+{
+	int rc;
+
+	g_cfg = cfg;
+	rc = vty_read_config_file(config_file, NULL);
+	if (rc < 0) {
+		fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
+		return rc;
+	}
+
+	return 0;
+}
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index 2eda0bd..e3eafe6 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -1,4 +1,4 @@
-/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface 
+/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
  * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
 
 /* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
@@ -30,6 +30,7 @@
 #include <time.h>
 #include <netinet/in.h>
 
+#include <openbsc/auth.h>
 #include <openbsc/db.h>
 #include <osmocore/msgb.h>
 #include <osmocore/bitvec.h>
@@ -52,13 +53,15 @@
 #include <openbsc/transaction.h>
 #include <openbsc/ussd.h>
 #include <openbsc/silent_call.h>
+#include <openbsc/bsc_api.h>
 
 void *tall_locop_ctx;
+void *tall_authciphop_ctx;
 
-int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi);
+int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn, u_int32_t tmsi);
 static int gsm48_tx_simple(struct gsm_lchan *lchan,
 			   u_int8_t pdisc, u_int8_t msg_type);
-static void schedule_reject(struct gsm_lchan *lchan);
+static void schedule_reject(struct gsm_subscriber_connection *conn);
 
 struct gsm_lai {
 	u_int16_t mcc;
@@ -68,6 +71,122 @@
 
 static u_int32_t new_callref = 0x80000001;
 
+static int gsm48_conn_sendmsg(struct msgb *msg, struct gsm_subscriber_connection *conn,
+			      struct gsm_trans *trans)
+{
+	struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data;
+
+	/* if we get passed a transaction reference, do some common
+	 * work that the caller no longer has to do */
+	if (trans) {
+		gh->proto_discr = trans->protocol | (trans->transaction_id << 4);
+		msg->lchan = trans->conn->lchan;
+	}
+
+
+	if (msg->lchan) {
+		msg->trx = msg->lchan->ts->trx;
+		if ((gh->proto_discr & GSM48_PDISC_MASK) == GSM48_PDISC_CC)
+			DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x) "
+				"Sending '%s' to MS.\n", msg->trx->bts->nr,
+				msg->trx->nr, msg->lchan->ts->nr,
+				gh->proto_discr & 0xf0,
+				gsm48_cc_msg_name(gh->msg_type));
+		else
+			DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) "
+				"Sending 0x%02x to MS.\n", msg->trx->bts->nr,
+				msg->trx->nr, msg->lchan->ts->nr,
+				gh->proto_discr, gh->msg_type);
+	}
+
+	msg->l3h = msg->data;
+	return gsm0808_submit_dtap(conn, msg, 0);
+}
+
+static void release_security_operation(struct gsm_subscriber_connection *conn)
+{
+	if (!conn->sec_operation)
+		return;
+
+	talloc_free(conn->sec_operation);
+	conn->sec_operation = NULL;
+	put_subscr_con(conn);
+}
+
+static void allocate_security_operation(struct gsm_subscriber_connection *conn)
+{
+	use_subscr_con(conn)
+
+	conn->sec_operation = talloc_zero(tall_authciphop_ctx,
+	                                  struct gsm_security_operation);
+}
+
+int gsm48_secure_channel(struct gsm_lchan *lchan, int key_seq,
+                         gsm_cbfn *cb, void *cb_data)
+{
+	struct gsm_network *net = lchan->ts->trx->bts->network;
+	struct gsm_subscriber *subscr = lchan->conn.subscr;
+	struct gsm_security_operation *op;
+	struct gsm_auth_tuple atuple;
+	int status = -1, rc;
+
+	/* Check if we _can_ enable encryption. Cases where we can't:
+	 *  - Encryption disabled in config
+	 *  - Channel already secured (nothing to do)
+	 *  - Subscriber equipment doesn't support configured encryption
+	 */
+	if (!net->a5_encryption) {
+		status = GSM_SECURITY_NOAVAIL;
+	} else if (lchan->encr.alg_id > RSL_ENC_ALG_A5(0)) {
+		DEBUGP(DMM, "Requesting to secure an already secure channel");
+		status = GSM_SECURITY_SUCCEEDED;
+	} else if (!ms_cm2_a5n_support(subscr->equipment.classmark2,
+	                               net->a5_encryption)) {
+		DEBUGP(DMM, "Subscriber equipment doesn't support requested encryption");
+		status = GSM_SECURITY_NOAVAIL;
+	}
+
+	/* If not done yet, try to get info for this user */
+	if (status < 0) {
+		rc = auth_get_tuple_for_subscr(&atuple, subscr, key_seq);
+		if (rc <= 0)
+			status = GSM_SECURITY_NOAVAIL;
+	}
+
+	/* Are we done yet ? */
+	if (status >= 0)
+		return cb ?
+			cb(GSM_HOOK_RR_SECURITY, status, NULL, lchan, cb_data) :
+			0;
+
+	/* Start an operation (can't have more than one pending !!!) */
+	if (lchan->conn.sec_operation)
+		return -EBUSY;
+
+	allocate_security_operation(&lchan->conn);
+	op = lchan->conn.sec_operation;
+	op->cb = cb;
+	op->cb_data = cb_data;
+	memcpy(&op->atuple, &atuple, sizeof(struct gsm_auth_tuple));
+
+		/* FIXME: Should start a timer for completion ... */
+
+	/* Then do whatever is needed ... */
+	if (rc == 1) {
+		/* Start authentication */
+		return gsm48_tx_mm_auth_req(lchan, op->atuple.rand, op->atuple.key_seq);
+	} else if (rc == 2) {
+		/* Start ciphering directly */
+		lchan->encr.alg_id = RSL_ENC_ALG_A5(net->a5_encryption);
+		lchan->encr.key_len = 8;
+		memcpy(lchan->encr.key, op->atuple.kc, 8);
+
+		return gsm48_send_rr_ciph_mode(lchan, 0);
+	}
+
+	return -EINVAL; /* not reached */
+}
+
 static int authorize_subscriber(struct gsm_loc_updating_operation *loc,
 				struct gsm_subscriber *subscriber)
 {
@@ -96,90 +215,104 @@
 	}
 }
 
-static void release_loc_updating_req(struct gsm_lchan *lchan)
+static void release_loc_updating_req(struct gsm_subscriber_connection *conn)
 {
-	if (!lchan->loc_operation)
+	if (!conn->loc_operation)
 		return;
 
-	bsc_del_timer(&lchan->loc_operation->updating_timer);
-	talloc_free(lchan->loc_operation);
-	lchan->loc_operation = 0;
-	put_lchan(lchan);
+	bsc_del_timer(&conn->loc_operation->updating_timer);
+	talloc_free(conn->loc_operation);
+	conn->loc_operation = 0;
+	put_subscr_con(conn);
 }
 
-static void allocate_loc_updating_req(struct gsm_lchan *lchan)
+static void allocate_loc_updating_req(struct gsm_subscriber_connection *conn)
 {
-	use_lchan(lchan);
-	release_loc_updating_req(lchan);
+	use_subscr_con(conn)
+	release_loc_updating_req(conn);
 
-	lchan->loc_operation = talloc_zero(tall_locop_ctx,
+	conn->loc_operation = talloc_zero(tall_locop_ctx,
 					   struct gsm_loc_updating_operation);
 }
 
-static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg)
+static int _gsm0408_authorize_sec_cb(unsigned int hooknum, unsigned int event,
+                                     struct msgb *msg, void *data, void *param)
 {
-	if (authorize_subscriber(lchan->loc_operation, lchan->subscr)) {
-		int rc;
+	struct gsm_lchan *lchan = data;
+	struct gsm_subscriber_connection *conn = &lchan->conn;
+	int rc = 0;
 
-		db_subscriber_alloc_tmsi(lchan->subscr);
-		release_loc_updating_req(lchan);
-		rc = gsm0408_loc_upd_acc(msg->lchan, lchan->subscr->tmsi);
-		if (lchan->ts->trx->bts->network->send_mm_info) {
-			/* send MM INFO with network name */
-			rc = gsm48_tx_mm_info(msg->lchan);
-		}
+	switch (event) {
+		case GSM_SECURITY_AUTH_FAILED:
+			release_loc_updating_req(conn);
+			break;
 
-		/* call subscr_update after putting the loc_upd_acc
-		 * in the transmit queue, since S_SUBSCR_ATTACHED might
-		 * trigger further action like SMS delivery */
-		subscr_update(lchan->subscr, msg->trx->bts,
-			      GSM_SUBSCRIBER_UPDATE_ATTACHED);
-		/* try to close channel ASAP */
-		lchan_auto_release(lchan);
-		return rc;
-	}
+		case GSM_SECURITY_NOAVAIL:
+		case GSM_SECURITY_SUCCEEDED:
+			/* We're all good */
+			db_subscriber_alloc_tmsi(conn->subscr);
+			release_loc_updating_req(conn);
+			rc = gsm0408_loc_upd_acc(conn, conn->subscr->tmsi);
+			if (lchan->ts->trx->bts->network->send_mm_info) {
+				/* send MM INFO with network name */
+				rc = gsm48_tx_mm_info(conn);
+			}
 
+			/* call subscr_update after putting the loc_upd_acc
+			 * in the transmit queue, since S_SUBSCR_ATTACHED might
+			 * trigger further action like SMS delivery */
+			subscr_update(conn->subscr, lchan->ts->trx->bts,
+				      GSM_SUBSCRIBER_UPDATE_ATTACHED);
+
+			/* try to close channel ASAP */
+			lchan_auto_release(lchan);
+
+			break;
+
+		default:
+			rc = -EINVAL;
+	};
+
+	return rc;
+}
+
+static int gsm0408_authorize(struct gsm_subscriber_connection *conn, struct msgb *msg)
+{
+	if (authorize_subscriber(conn->loc_operation, conn->subscr))
+		return gsm48_secure_channel(conn->lchan,
+			conn->loc_operation->key_seq,
+			_gsm0408_authorize_sec_cb, NULL);
 	return 0;
 }
 
-static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal,
-					void *handler_data, void *signal_data)
+void gsm0408_clear_request(struct gsm_subscriber_connection* conn, uint32_t cause)
 {
 	struct gsm_trans *trans, *temp;
-
-	if (subsys != SS_LCHAN || signal != S_LCHAN_UNEXPECTED_RELEASE)
-		return 0;
-
 	/*
 	 * Cancel any outstanding location updating request
-	 * operation taking place on the lchan.
+	 * operation taking place on the subscriber connection.
 	 */
-	struct gsm_lchan *lchan = (struct gsm_lchan *)signal_data;
-	if (!lchan)
-		return 0;
-
-	release_loc_updating_req(lchan);
+	release_loc_updating_req(conn);
+	release_security_operation(conn);
 
 	/* Free all transactions that are associated with the released lchan */
 	/* FIXME: this is not neccessarily the right thing to do, we should
 	 * only set trans->lchan to NULL and wait for another lchan to be
 	 * established to the same MM entity (phone/subscriber) */
-	llist_for_each_entry_safe(trans, temp, &lchan->ts->trx->bts->network->trans_list, entry) {
-		if (trans->lchan == lchan)
+	llist_for_each_entry_safe(trans, temp, &conn->bts->network->trans_list, entry) {
+		if (trans->conn == conn)
 			trans_free(trans);
 	}
-
-	return 0;
 }
 
 /* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */
-int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause)
+int gsm0408_loc_upd_rej(struct gsm_subscriber_connection *conn, u_int8_t cause)
 {
-	struct gsm_bts *bts = lchan->ts->trx->bts;
+	struct gsm_bts *bts = conn->bts;
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
 	
-	msg->lchan = lchan;
+	msg->lchan = conn->lchan;
 
 	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
 	gh->proto_discr = GSM48_PDISC_MM;
@@ -187,25 +320,25 @@
 	gh->data[0] = cause;
 
 	LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT "
-	     "LAC=%u BTS=%u\n", lchan->subscr ?
-	     			subscr_name(lchan->subscr) : "unknown",
-	     lchan->ts->trx->bts->location_area_code, lchan->ts->trx->bts->nr);
+	     "LAC=%u BTS=%u\n", conn->subscr ?
+	     			subscr_name(conn->subscr) : "unknown",
+	     bts->location_area_code, bts->nr);
 
 	counter_inc(bts->network->stats.loc_upd_resp.reject);
 	
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_conn_sendmsg(msg, conn, NULL);
 }
 
 /* Chapter 9.2.13 : Send LOCATION UPDATE ACCEPT */
-int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi)
+int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn, u_int32_t tmsi)
 {
-	struct gsm_bts *bts = lchan->ts->trx->bts;
+	struct gsm_bts *bts = conn->bts;
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
 	struct gsm48_loc_area_id *lai;
 	u_int8_t *mid;
 	
-	msg->lchan = lchan;
+	msg->lchan = conn->lchan;
 
 	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
 	gh->proto_discr = GSM48_PDISC_MM;
@@ -222,29 +355,30 @@
 
 	counter_inc(bts->network->stats.loc_upd_resp.accept);
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_conn_sendmsg(msg, conn, NULL);
 }
 
 /* Transmit Chapter 9.2.10 Identity Request */
-static int mm_tx_identity_req(struct gsm_lchan *lchan, u_int8_t id_type)
+static int mm_tx_identity_req(struct gsm_subscriber_connection *conn, u_int8_t id_type)
 {
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
 
-	msg->lchan = lchan;
+	msg->lchan = conn->lchan;
 
 	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
 	gh->proto_discr = GSM48_PDISC_MM;
 	gh->msg_type = GSM48_MT_MM_ID_REQ;
 	gh->data[0] = id_type;
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_conn_sendmsg(msg, conn, NULL);
 }
 
 
 /* Parse Chapter 9.2.11 Identity Response */
 static int mm_rx_id_resp(struct msgb *msg)
 {
+	struct gsm_subscriber_connection *conn;
 	struct gsm48_hdr *gh = msgb_l3(msg);
 	struct gsm_lchan *lchan = msg->lchan;
 	struct gsm_bts *bts = lchan->ts->trx->bts;
@@ -256,51 +390,54 @@
 	DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n",
 		mi_type, mi_string);
 
+	conn = &lchan->conn;
+
 	dispatch_signal(SS_SUBSCR, S_SUBSCR_IDENTITY, gh->data);
 
 	switch (mi_type) {
 	case GSM_MI_TYPE_IMSI:
 		/* look up subscriber based on IMSI, create if not found */
-		if (!lchan->subscr) {
-			lchan->subscr = subscr_get_by_imsi(net, mi_string);
-			if (!lchan->subscr)
-				lchan->subscr = db_create_subscriber(net, mi_string);
+		if (!conn->subscr) {
+			conn->subscr = subscr_get_by_imsi(net, mi_string);
+			if (!conn->subscr)
+				conn->subscr = db_create_subscriber(net, mi_string);
 		}
-		if (lchan->loc_operation)
-			lchan->loc_operation->waiting_for_imsi = 0;
+		if (conn->loc_operation)
+			conn->loc_operation->waiting_for_imsi = 0;
 		break;
 	case GSM_MI_TYPE_IMEI:
 	case GSM_MI_TYPE_IMEISV:
 		/* update subscribe <-> IMEI mapping */
-		if (lchan->subscr) {
-			db_subscriber_assoc_imei(lchan->subscr, mi_string);
-			db_sync_equipment(&lchan->subscr->equipment);
+		if (conn->subscr) {
+			db_subscriber_assoc_imei(conn->subscr, mi_string);
+			db_sync_equipment(&conn->subscr->equipment);
 		}
-		if (lchan->loc_operation)
-			lchan->loc_operation->waiting_for_imei = 0;
+		if (conn->loc_operation)
+			conn->loc_operation->waiting_for_imei = 0;
 		break;
 	}
 
 	/* Check if we can let the mobile station enter */
-	return gsm0408_authorize(lchan, msg);
+	return gsm0408_authorize(conn, msg);
 }
 
 
 static void loc_upd_rej_cb(void *data)
 {
-	struct gsm_lchan *lchan = data;
+	struct gsm_subscriber_connection *conn = data;
+	struct gsm_lchan *lchan = conn->lchan;
 	struct gsm_bts *bts = lchan->ts->trx->bts;
 
-	release_loc_updating_req(lchan);
-	gsm0408_loc_upd_rej(lchan, bts->network->reject_cause);
+	release_loc_updating_req(conn);
+	gsm0408_loc_upd_rej(conn, bts->network->reject_cause);
 	lchan_auto_release(lchan);
 }
 
-static void schedule_reject(struct gsm_lchan *lchan)
+static void schedule_reject(struct gsm_subscriber_connection *conn)
 {
-	lchan->loc_operation->updating_timer.cb = loc_upd_rej_cb;
-	lchan->loc_operation->updating_timer.data = lchan;
-	bsc_schedule_timer(&lchan->loc_operation->updating_timer, 5, 0);
+	conn->loc_operation->updating_timer.cb = loc_upd_rej_cb;
+	conn->loc_operation->updating_timer.data = conn;
+	bsc_schedule_timer(&conn->loc_operation->updating_timer, 5, 0);
 }
 
 static const char *lupd_name(u_int8_t type)
@@ -320,6 +457,7 @@
 /* Chapter 9.2.15: Receive Location Updating Request */
 static int mm_rx_loc_upd_req(struct msgb *msg)
 {
+	struct gsm_subscriber_connection *conn;
 	struct gsm48_hdr *gh = msgb_l3(msg);
 	struct gsm48_loc_upd_req *lu;
 	struct gsm_subscriber *subscr = NULL;
@@ -330,6 +468,7 @@
 	int rc;
 
  	lu = (struct gsm48_loc_upd_req *) gh->data;
+	conn = &lchan->conn;
 
 	mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
 
@@ -356,21 +495,23 @@
 	 * Pseudo Spoof detection: Just drop a second/concurrent
 	 * location updating request.
 	 */
-	if (lchan->loc_operation) {
+	if (conn->loc_operation) {
 		DEBUGPC(DMM, "ignoring request due an existing one: %p.\n",
-			lchan->loc_operation);
-		gsm0408_loc_upd_rej(lchan, GSM48_REJECT_PROTOCOL_ERROR);
+			conn->loc_operation);
+		gsm0408_loc_upd_rej(conn, GSM48_REJECT_PROTOCOL_ERROR);
 		return 0;
 	}
 
-	allocate_loc_updating_req(lchan);
+	allocate_loc_updating_req(&lchan->conn);
+
+	conn->loc_operation->key_seq = lu->key_seq;
 
 	switch (mi_type) {
 	case GSM_MI_TYPE_IMSI:
 		DEBUGPC(DMM, "\n");
 		/* we always want the IMEI, too */
-		rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
-		lchan->loc_operation->waiting_for_imei = 1;
+		rc = mm_tx_identity_req(conn, GSM_MI_TYPE_IMEI);
+		conn->loc_operation->waiting_for_imei = 1;
 
 		/* look up subscriber based on IMSI, create if not found */
 		subscr = subscr_get_by_imsi(bts->network, mi_string);
@@ -380,18 +521,17 @@
 		break;
 	case GSM_MI_TYPE_TMSI:
 		DEBUGPC(DMM, "\n");
-		/* we always want the IMEI, too */
-		rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
-		lchan->loc_operation->waiting_for_imei = 1;
-
 		/* look up the subscriber based on TMSI, request IMSI if it fails */
 		subscr = subscr_get_by_tmsi(bts->network,
 					    tmsi_from_string(mi_string));
 		if (!subscr) {
 			/* send IDENTITY REQUEST message to get IMSI */
-			rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI);
-			lchan->loc_operation->waiting_for_imsi = 1;
+			rc = mm_tx_identity_req(conn, GSM_MI_TYPE_IMSI);
+			conn->loc_operation->waiting_for_imsi = 1;
 		}
+		/* we always want the IMEI, too */
+		rc = mm_tx_identity_req(conn, GSM_MI_TYPE_IMEI);
+		conn->loc_operation->waiting_for_imei = 1;
 		break;
 	case GSM_MI_TYPE_IMEI:
 	case GSM_MI_TYPE_IMEISV:
@@ -404,7 +544,7 @@
 	}
 
 	/* schedule the reject timer */
-	schedule_reject(lchan);
+	schedule_reject(conn);
 
 	if (!subscr) {
 		DEBUGPC(DRR, "<- Can't find any subscriber for this ID\n");
@@ -412,12 +552,12 @@
 		return -EINVAL;
 	}
 
-	lchan->subscr = subscr;
-	lchan->subscr->equipment.classmark1 = lu->classmark1;
+	conn->subscr = subscr;
+	conn->subscr->equipment.classmark1 = lu->classmark1;
 
 	/* check if we can let the subscriber into our network immediately
 	 * or if we need to wait for identity responses. */
-	return gsm0408_authorize(lchan, msg);
+	return gsm0408_authorize(conn, msg);
 }
 
 #if 0
@@ -428,11 +568,11 @@
 #endif
 
 /* Section 9.2.15a */
-int gsm48_tx_mm_info(struct gsm_lchan *lchan)
+int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
 {
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
-	struct gsm_network *net = lchan->ts->trx->bts->network;
+	struct gsm_network *net = conn->bts->network;
 	u_int8_t *ptr8;
 	int name_len, name_pad;
 #if 0
@@ -441,7 +581,7 @@
 	int tz15min;
 #endif
 
-	msg->lchan = lchan;
+	msg->lchan = conn->lchan;
 
 	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
 	gh->proto_discr = GSM48_PDISC_MM;
@@ -527,7 +667,7 @@
 
 	DEBUGP(DMM, "-> MM INFO\n");
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_conn_sendmsg(msg, conn, NULL);
 }
 
 /* Section 9.2.2 */
@@ -549,7 +689,7 @@
 	if (rand)
 		memcpy(ar->rand, rand, 16);
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_conn_sendmsg(msg, &lchan->conn, NULL);
 }
 
 /* Section 9.2.1 */
@@ -566,7 +706,7 @@
 }
 
 /* 9.2.6 CM service reject */
-static int gsm48_tx_mm_serv_rej(struct gsm_lchan *lchan,
+static int gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
 				enum gsm48_reject_value value)
 {
 	struct msgb *msg = gsm48_msgb_alloc();
@@ -574,15 +714,43 @@
 
 	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
 
-	msg->lchan = lchan;
-	use_lchan(lchan);
+	msg->lchan = conn->lchan;
+	use_subscr_con(conn);
 
 	gh->proto_discr = GSM48_PDISC_MM;
 	gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
 	gh->data[0] = value;
 	DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_conn_sendmsg(msg, conn, NULL);
+}
+
+static int _gsm48_rx_mm_serv_req_sec_cb(
+	unsigned int hooknum, unsigned int event,
+	struct msgb *msg, void *data, void *param)
+{
+	struct gsm_lchan *lchan = data;
+	int rc = 0;
+
+	switch (event) {
+		case GSM_SECURITY_AUTH_FAILED:
+			/* Nothing to do */
+			break;
+
+		case GSM_SECURITY_NOAVAIL:
+			rc = gsm48_tx_mm_serv_ack(lchan);
+			break;
+
+		case GSM_SECURITY_SUCCEEDED:
+			/* nothing to do. CIPHER MODE COMMAND is
+			 * implicit CM SERV ACK */
+			break;
+
+		default:
+			rc = -EINVAL;
+	};
+
+	return rc;
 }
 
 /*
@@ -604,7 +772,7 @@
 	struct gsm48_hdr *gh = msgb_l3(msg);
 	struct gsm48_service_request *req =
 			(struct gsm48_service_request *)gh->data;
-	/* unfortunately in Phase1 the classmar2 length is variable */
+	/* unfortunately in Phase1 the classmark2 length is variable */
 	u_int8_t classmark2_len = gh->data[1];
 	u_int8_t *classmark2 = gh->data+2;
 	u_int8_t mi_len = *(classmark2 + classmark2_len);
@@ -613,20 +781,20 @@
 	DEBUGP(DMM, "<- CM SERVICE REQUEST ");
 	if (msg->data_len < sizeof(struct gsm48_service_request*)) {
 		DEBUGPC(DMM, "wrong sized message\n");
-		return gsm48_tx_mm_serv_rej(msg->lchan,
+		return gsm48_tx_mm_serv_rej(&msg->lchan->conn,
 					    GSM48_REJECT_INCORRECT_MESSAGE);
 	}
 
 	if (msg->data_len < req->mi_len + 6) {
 		DEBUGPC(DMM, "does not fit in packet\n");
-		return gsm48_tx_mm_serv_rej(msg->lchan,
+		return gsm48_tx_mm_serv_rej(&msg->lchan->conn,
 					    GSM48_REJECT_INCORRECT_MESSAGE);
 	}
 
 	mi_type = mi[0] & GSM_MI_TYPE_MASK;
 	if (mi_type != GSM_MI_TYPE_TMSI) {
 		DEBUGPC(DMM, "mi_type is not TMSI: %d\n", mi_type);
-		return gsm48_tx_mm_serv_rej(msg->lchan,
+		return gsm48_tx_mm_serv_rej(&msg->lchan->conn,
 					    GSM48_REJECT_INCORRECT_MESSAGE);
 	}
 
@@ -644,12 +812,12 @@
 
 	/* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */
 	if (!subscr)
-		return gsm48_tx_mm_serv_rej(msg->lchan,
+		return gsm48_tx_mm_serv_rej(&msg->lchan->conn,
 					    GSM48_REJECT_IMSI_UNKNOWN_IN_HLR);
 
-	if (!msg->lchan->subscr)
-		msg->lchan->subscr = subscr;
-	else if (msg->lchan->subscr == subscr)
+	if (!msg->lchan->conn.subscr)
+		msg->lchan->conn.subscr = subscr;
+	else if (msg->lchan->conn.subscr == subscr)
 		subscr_put(subscr); /* lchan already has a ref, don't need another one */
 	else {
 		DEBUGP(DMM, "<- CM Channel already owned by someone else?\n");
@@ -660,7 +828,8 @@
 	memcpy(subscr->equipment.classmark2, classmark2, classmark2_len);
 	db_sync_equipment(&subscr->equipment);
 
-	return gsm48_tx_mm_serv_ack(msg->lchan);
+	return gsm48_secure_channel(msg->lchan, req->cipher_key_seq,
+			_gsm48_rx_mm_serv_req_sec_cb, NULL);
 }
 
 static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
@@ -727,6 +896,49 @@
 	return 0;
 }
 
+/* Chapter 9.2.3: Authentication Response */
+static int gsm48_rx_mm_auth_resp(struct msgb *msg)
+{
+	struct gsm48_hdr *gh = msgb_l3(msg);
+	struct gsm48_auth_resp *ar = (struct gsm48_auth_resp*) gh->data;
+	struct gsm_lchan *lchan = msg->lchan;
+	struct gsm_subscriber_connection *conn = &msg->lchan->conn;
+	struct gsm_network *net = lchan->ts->trx->bts->network;
+
+	DEBUGP(DMM, "MM AUTHENTICATION RESPONSE (sres = %s): ",
+		hexdump(ar->sres, 4));
+
+	/* Safety check */
+	if (!conn->sec_operation) {
+		DEBUGP(DMM, "No authentication/cipher operation in progress !!!\n");
+		return -EIO;
+	}
+
+	/* Validate SRES */
+	if (memcmp(conn->sec_operation->atuple.sres, ar->sres,4)) {
+		gsm_cbfn *cb = conn->sec_operation->cb;
+
+		DEBUGPC(DMM, "Invalid (expected %s)\n",
+			hexdump(conn->sec_operation->atuple.sres, 4));
+
+		if (cb)
+			cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_AUTH_FAILED,
+			   NULL, lchan, conn->sec_operation->cb_data);
+
+		release_security_operation(conn);
+		return gsm48_tx_mm_auth_rej(lchan);
+	}
+
+	DEBUGPC(DMM, "OK\n");
+
+	/* Start ciphering */
+	lchan->encr.alg_id = RSL_ENC_ALG_A5(net->a5_encryption);
+	lchan->encr.key_len = 8;
+	memcpy(msg->lchan->encr.key, conn->sec_operation->atuple.kc, 8);
+
+	return gsm48_send_rr_ciph_mode(msg->lchan, 0);
+}
+
 /* Receive a GSM 04.08 Mobility Management (MM) message */
 static int gsm0408_rcv_mm(struct msgb *msg)
 {
@@ -749,8 +961,8 @@
 		break;
 	case GSM48_MT_MM_TMSI_REALL_COMPL:
 		DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n",
-		       msg->lchan->subscr ?
-				subscr_name(msg->lchan->subscr) :
+		       msg->lchan->conn.subscr ?
+				subscr_name(msg->lchan->conn.subscr) :
 				"unknown subscriber");
 		break;
 	case GSM48_MT_MM_IMSI_DETACH_IND:
@@ -760,7 +972,7 @@
 		DEBUGP(DMM, "CM REESTABLISH REQUEST: Not implemented\n");
 		break;
 	case GSM48_MT_MM_AUTH_RESP:
-		DEBUGP(DMM, "AUTHENTICATION RESPONSE: Not implemented\n");
+		rc = gsm48_rx_mm_auth_resp(msg);
 		break;
 	default:
 		LOGP(DMM, LOGL_NOTICE, "Unknown GSM 04.08 MM msg type 0x%02x\n",
@@ -776,13 +988,16 @@
 {
 	struct gsm_bts *bts = msg->lchan->ts->trx->bts;
 	struct gsm48_hdr *gh = msgb_l3(msg);
+	struct gsm48_pag_resp *resp;
 	u_int8_t *classmark2_lv = gh->data + 1;
 	u_int8_t mi_type;
 	char mi_string[GSM48_MI_SIZE];
 	struct gsm_subscriber *subscr = NULL;
 	int rc = 0;
 
-	gsm48_paging_extract_mi(msg, mi_string, &mi_type);
+	resp = (struct gsm48_pag_resp *) &gh->data[0];
+	gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*gh),
+				mi_string, &mi_type);
 	DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
 		mi_type, mi_string);
 
@@ -815,7 +1030,7 @@
 static int gsm48_rx_rr_classmark(struct msgb *msg)
 {
 	struct gsm48_hdr *gh = msgb_l3(msg);
-	struct gsm_subscriber *subscr = msg->lchan->subscr;
+	struct gsm_subscriber *subscr = msg->lchan->conn.subscr;
 	unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
 	u_int8_t cm2_len, cm3_len = 0;
 	u_int8_t *cm2, *cm3 = NULL;
@@ -863,7 +1078,7 @@
 {
 	struct gsm48_hdr *gh = msgb_l3(msg);
 
-	DEBUGP(DRR, "STATUS rr_cause = %s\n", 
+	DEBUGP(DRR, "STATUS rr_cause = %s\n",
 		rr_cause_name(gh->data[0]));
 
 	return 0;
@@ -896,7 +1111,38 @@
 	DEBUGP(DNM, "RX APPLICATION INFO id/flags=0x%02x apdu_len=%u apdu=%s",
 		apdu_id_flags, apdu_len, hexdump(apdu_data, apdu_len));
 
-	return db_apdu_blob_store(msg->lchan->subscr, apdu_id_flags, apdu_len, apdu_data);
+	return db_apdu_blob_store(msg->lchan->conn.subscr, apdu_id_flags, apdu_len, apdu_data);
+}
+
+/* Chapter 9.1.10 Ciphering Mode Complete */
+static int gsm48_rx_rr_ciph_m_compl(struct msgb *msg)
+{
+	struct gsm_lchan *lchan = msg->lchan;
+	struct gsm_subscriber_connection *conn = &lchan->conn;
+	gsm_cbfn *cb;
+	int rc = 0;
+
+	DEBUGP(DRR, "CIPHERING MODE COMPLETE\n");
+
+	/* Safety check */
+	if (!conn->sec_operation) {
+		DEBUGP(DRR, "No authentication/cipher operation in progress !!!\n");
+		return -EIO;
+	}
+
+	/* FIXME: check for MI (if any) */
+
+	/* Call back whatever was in progress (if anything) ... */
+	cb = conn->sec_operation->cb;
+	if (cb) {
+		rc = cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_SUCCEEDED,
+			NULL, lchan, conn->sec_operation->cb_data);
+	}
+
+	/* Complete the operation */
+	release_security_operation(conn);
+
+	return rc;
 }
 
 /* Chapter 9.1.16 Handover complete */
@@ -956,8 +1202,7 @@
 		rc = gsm48_rx_rr_app_info(msg);
 		break;
 	case GSM48_MT_RR_CIPH_M_COMPL:
-		DEBUGP(DRR, "CIPHERING MODE COMPLETE\n");
-		/* FIXME: check for MI (if any) */
+		rc = gsm48_rx_rr_ciph_m_compl(msg);
 		break;
 	case GSM48_MT_RR_HANDO_COMPL:
 		rc = gsm48_rx_rr_ho_compl(msg);
@@ -992,7 +1237,7 @@
 	gh->data[1] = apdu_len;
 	memcpy(gh->data+2, apdu, apdu_len);
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_conn_sendmsg(msg, &lchan->conn, NULL);
 }
 
 /* Call Control */
@@ -1030,7 +1275,7 @@
 	call_state = msgb_put(msg, 1);
 	call_state[0] = 0xc0 | 0x00;
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_tx_simple(struct gsm_lchan *lchan,
@@ -1044,7 +1289,7 @@
 	gh->proto_discr = pdisc;
 	gh->msg_type = msg_type;
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_conn_sendmsg(msg, &lchan->conn, NULL);
 }
 
 static void gsm48_stop_cc_timer(struct gsm_trans *trans)
@@ -1055,19 +1300,19 @@
 		trans->cc.Tcurrent = 0;
 	}
 }
- 
+
 static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
 			int msg_type, struct gsm_mncc *mncc)
 {
 	struct msgb *msg;
 
 	if (trans)
-		if (trans->lchan)
+		if (trans->conn)
 			DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
 				"Sending '%s' to MNCC.\n",
-				trans->lchan->ts->trx->bts->nr,
-				trans->lchan->ts->trx->nr,
-				trans->lchan->ts->nr, trans->transaction_id,
+				trans->conn->lchan->ts->trx->bts->nr,
+				trans->conn->lchan->ts->trx->nr,
+				trans->conn->lchan->ts->nr, trans->transaction_id,
 				(trans->subscr)?(trans->subscr->extension):"-",
 				get_mncc_name(msg_type));
 		else
@@ -1116,12 +1361,12 @@
 	}
 	if (trans->cc.state != GSM_CSTATE_NULL)
 		new_cc_state(trans, GSM_CSTATE_NULL);
-	if (trans->lchan)
-		trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref);
+	if (trans->conn)
+		trau_mux_unmap(&trans->conn->lchan->ts->e1_link, trans->callref);
 }
 
 static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
- 
+
 /* call-back from paging the B-end of the connection */
 static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
 			      struct msgb *msg, void *_lchan, void *param)
@@ -1133,7 +1378,7 @@
 
 	if (hooknum != GSM_HOOK_RR_PAGING)
 		return -EINVAL;
-  
+
 	if (!subscr)
 		return -EINVAL;
 	net = subscr->net;
@@ -1144,7 +1389,7 @@
 
 	/* check all tranactions (without lchan) for subscriber */
 	llist_for_each_entry_safe(transt, tmp, &net->trans_list, entry) {
-		if (transt->subscr != subscr || transt->lchan)
+		if (transt->subscr != subscr || transt->conn)
 			continue;
 		switch (event) {
 		case GSM_PAGING_SUCCEEDED:
@@ -1153,9 +1398,9 @@
 			DEBUGP(DCC, "Paging subscr %s succeeded!\n",
 				subscr->extension);
 			/* Assign lchan */
-			if (!transt->lchan) {
-				transt->lchan = lchan;
-				use_lchan(lchan);
+			if (!transt->conn) {
+				transt->conn = &lchan->conn;
+				use_subscr_con(transt->conn);
 			}
 			/* send SETUP request to called party */
 			gsm48_cc_tx_setup(transt, &transt->cc.msg);
@@ -1200,7 +1445,7 @@
 		 * a tch_recv_mncc request pending */
 		net = lchan->ts->trx->bts->network;
 		llist_for_each_entry(trans, &net->trans_list, entry) {
-			if (trans->lchan == lchan && trans->tch_recv) {
+			if (trans->conn && trans->conn->lchan == lchan && trans->tch_recv) {
 				DEBUGP(DCC, "pending tch_recv_mncc request\n");
 				tch_recv_mncc(net, trans->callref, 1);
 			}
@@ -1273,11 +1518,11 @@
 	if (!trans1 || !trans2)
 		return -EIO;
 
-	if (!trans1->lchan || !trans2->lchan)
+	if (!trans1->conn || !trans2->conn)
 		return -EIO;
 
 	/* through-connect channel */
-	return tch_map(trans1->lchan, trans2->lchan);
+	return tch_map(trans1->conn->lchan, trans2->conn->lchan);
 }
 
 /* enable receive of channels to MNCC upqueue */
@@ -1292,9 +1537,9 @@
 	trans = trans_find_by_callref(net, callref);
 	if (!trans)
 		return -EIO;
-	if (!trans->lchan)
+	if (!trans->conn)
 		return 0;
-	lchan = trans->lchan;
+	lchan = trans->conn->lchan;
 	bts = lchan->ts->trx->bts;
 
 	switch (bts->type) {
@@ -1586,7 +1831,7 @@
 	
 	new_cc_state(trans, GSM_CSTATE_CALL_PRESENT);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
@@ -1654,7 +1899,7 @@
 	if (proceeding->fields & MNCC_F_PROGRESS)
 		gsm48_encode_progress(msg, 0, &proceeding->progress);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
@@ -1716,7 +1961,7 @@
 
 	new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED);
 	
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg)
@@ -1733,7 +1978,7 @@
 	if (progress->fields & MNCC_F_USERUSER)
 		gsm48_encode_useruser(msg, 0, &progress->useruser);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg)
@@ -1762,7 +2007,7 @@
 
 	new_cc_state(trans, GSM_CSTATE_CONNECT_IND);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg)
@@ -1833,7 +2078,7 @@
 
 	new_cc_state(trans, GSM_CSTATE_ACTIVE);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg)
@@ -1921,7 +2166,7 @@
 
 	new_cc_state(trans, GSM_CSTATE_DISCONNECT_IND);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
@@ -2009,7 +2254,7 @@
 	if (trans->cc.state != GSM_CSTATE_RELEASE_REQ)
 		new_cc_state(trans, GSM_CSTATE_RELEASE_REQ);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
@@ -2099,7 +2344,7 @@
 
 	trans_free(trans);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg)
@@ -2139,7 +2384,7 @@
 	/* facility */
 	gsm48_encode_facility(msg, 1, &fac->facility);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_hold(struct gsm_trans *trans, struct msgb *msg)
@@ -2158,7 +2403,7 @@
 
 	gh->msg_type = GSM48_MT_CC_HOLD_ACK;
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg)
@@ -2175,7 +2420,7 @@
 	else
 		gsm48_encode_cause(msg, 1, &default_cause);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_retrieve(struct gsm_trans *trans, struct msgb *msg)
@@ -2195,7 +2440,7 @@
 
 	gh->msg_type = GSM48_MT_CC_RETR_ACK;
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg)
@@ -2212,7 +2457,7 @@
 	else
 		gsm48_encode_cause(msg, 1, &default_cause);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_start_dtmf(struct gsm_trans *trans, struct msgb *msg)
@@ -2247,7 +2492,7 @@
 	if (dtmf->fields & MNCC_F_KEYPAD)
 		gsm48_encode_keypad(msg, dtmf->keypad);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg)
@@ -2264,7 +2509,7 @@
 	else
 		gsm48_encode_cause(msg, 1, &default_cause);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_tx_stop_dtmf_ack(struct gsm_trans *trans, void *arg)
@@ -2274,7 +2519,7 @@
 
 	gh->msg_type = GSM48_MT_CC_STOP_DTMF_ACK;
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_stop_dtmf(struct gsm_trans *trans, struct msgb *msg)
@@ -2324,7 +2569,7 @@
 
 	new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg)
@@ -2364,7 +2609,7 @@
 
 	new_cc_state(trans, GSM_CSTATE_ACTIVE);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg)
@@ -2412,7 +2657,7 @@
 
 	new_cc_state(trans, GSM_CSTATE_ACTIVE);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg)
@@ -2426,7 +2671,7 @@
 	/* notify */
 	gsm48_encode_notify(msg, notify->notify);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg)
@@ -2460,7 +2705,7 @@
 	if (user->more)
 		gsm48_encode_more(msg);
 
-	return gsm48_sendmsg(msg, trans);
+	return gsm48_conn_sendmsg(msg, trans->conn, trans);
 }
 
 static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
@@ -2490,7 +2735,7 @@
 {
 	struct gsm_mncc *mode = arg;
 
-	return gsm48_lchan_modify(trans->lchan, mode->lchan_mode);
+	return gsm48_lchan_modify(trans->conn->lchan, mode->lchan_mode);
 }
 
 static struct downstate {
@@ -2576,18 +2821,18 @@
 		trans = trans_find_by_callref(net, data->callref);
 		if (!trans)
 			return -EIO;
-		if (!trans->lchan)
+		if (!trans->conn)
 			return 0;
-		if (trans->lchan->type != GSM_LCHAN_TCH_F)
+		if (trans->conn->lchan->type != GSM_LCHAN_TCH_F)
 			return 0;
-		bts = trans->lchan->ts->trx->bts;
+		bts = trans->conn->lchan->ts->trx->bts;
 		switch (bts->type) {
 		case GSM_BTS_TYPE_NANOBTS:
-			if (!trans->lchan->abis_ip.rtp_socket)
+			if (!trans->conn->lchan->abis_ip.rtp_socket)
 				return 0;
-			return rtp_send_frame(trans->lchan->abis_ip.rtp_socket, arg);
+			return rtp_send_frame(trans->conn->lchan->abis_ip.rtp_socket, arg);
 		case GSM_BTS_TYPE_BS11:
-			return trau_send_frame(trans->lchan, arg);
+			return trau_send_frame(trans->conn->lchan, arg);
 		default:
 			DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
 		}
@@ -2665,6 +2910,7 @@
 		}
 		/* Find lchan */
 		lchan = lchan_for_subscr(subscr);
+
 		/* If subscriber has no lchan */
 		if (!lchan) {
 			/* find transaction with this subscriber already paging */
@@ -2692,16 +2938,18 @@
 			return 0;
 		}
 		/* Assign lchan */
-		trans->lchan = lchan;
-		use_lchan(lchan);
+		trans->conn = &lchan->conn;
+		use_subscr_con(trans->conn);
 		subscr_put(subscr);
 	}
-	lchan = trans->lchan;
+
+	if (trans->conn)
+		lchan = trans->conn->lchan;
 
 	/* if paging did not respond yet */
 	if (!lchan) {
 		DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
-			"Received '%s' from MNCC in paging state\n", 
+			"Received '%s' from MNCC in paging state\n",
 			(trans->subscr)?(trans->subscr->extension):"-",
 			get_mncc_name(msg_type));
 		mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
@@ -2719,7 +2967,7 @@
 		"Received '%s' from MNCC in state %d (%s)\n",
 		lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
 		trans->transaction_id,
-		(lchan->subscr)?(lchan->subscr->extension):"-",
+		(trans->conn->subscr)?(trans->conn->subscr->extension):"-",
 		get_mncc_name(msg_type), trans->cc.state,
 		gsm48_cc_state_name(trans->cc.state));
 
@@ -2756,7 +3004,7 @@
 	 GSM48_MT_CC_CALL_CONF, gsm48_cc_rx_call_conf},
 	{SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* ???? | 5.2.2.3.2 */
 	 GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
-	{SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF) | SBIT(GSM_CSTATE_CALL_RECEIVED), /* (5.2.2.6) | 5.2.2.6 | 5.2.2.6 */  
+	{SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF) | SBIT(GSM_CSTATE_CALL_RECEIVED), /* (5.2.2.6) | 5.2.2.6 | 5.2.2.6 */
 	 GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
 	 /* signalling during call */
 	{ALL_STATES - SBIT(GSM_CSTATE_NULL),
@@ -2795,6 +3043,7 @@
 
 static int gsm0408_rcv_cc(struct msgb *msg)
 {
+	struct gsm_subscriber_connection *conn;
 	struct gsm48_hdr *gh = msgb_l3(msg);
 	u_int8_t msg_type = gh->msg_type & 0xbf;
 	u_int8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */
@@ -2806,14 +3055,16 @@
 		DEBUGP(DCC, "MSG 0x%2x not defined for PD error\n", msg_type);
 		return -EINVAL;
 	}
-	
+
+	conn = &lchan->conn;
+
 	/* Find transaction */
-	trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_CC, transaction_id);
+	trans = trans_find_by_id(conn->subscr, GSM48_PDISC_CC, transaction_id);
 
 	DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
 		"Received '%s' from MS in state %d (%s)\n",
 		lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
-		transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-",
+		transaction_id, (conn->subscr)?(conn->subscr->extension):"-",
 		gsm48_cc_msg_name(msg_type), trans?(trans->cc.state):0,
 		gsm48_cc_state_name(trans?(trans->cc.state):0));
 
@@ -2822,7 +3073,7 @@
 		DEBUGP(DCC, "Unknown transaction ID %x, "
 			"creating new trans.\n", transaction_id);
 		/* Create transaction */
-		trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC,
+		trans = trans_alloc(conn->subscr, GSM48_PDISC_CC,
 				    transaction_id, new_callref++);
 		if (!trans) {
 			DEBUGP(DCC, "No memory for trans.\n");
@@ -2832,8 +3083,8 @@
 			return -ENOMEM;
 		}
 		/* Assign transaction */
-		trans->lchan = lchan;
-		use_lchan(lchan);
+		trans->conn = &lchan->conn;
+		use_subscr_con(trans->conn);
 	}
 
 	/* find function for current state and message */
@@ -2891,31 +3142,11 @@
 	return rc;
 }
 
-/* dequeue messages to layer 4 */
-int bsc_upqueue(struct gsm_network *net)
-{
-	struct gsm_mncc *mncc;
-	struct msgb *msg;
-	int work = 0;
-
-	if (net)
-		while ((msg = msgb_dequeue(&net->upqueue))) {
-			mncc = (struct gsm_mncc *)msg->data;
-			if (net->mncc_recv)
-				net->mncc_recv(net, mncc->msg_type, mncc);
-			work = 1; /* work done */
-			talloc_free(msg);
-		}
-
-	return work;
-}
-
 /*
  * This will be ran by the linker when loading the DSO. We use it to
  * do system initialization, e.g. registration of signal handlers.
  */
 static __attribute__((constructor)) void on_dso_load_0408(void)
 {
-	register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
 	register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
 }
diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c
index 2472f12..5a8ded7 100644
--- a/openbsc/src/gsm_04_08_utils.c
+++ b/openbsc/src/gsm_04_08_utils.c
@@ -36,48 +36,16 @@
 #include <openbsc/paging.h>
 #include <openbsc/signal.h>
 
-#define GSM48_ALLOC_SIZE	1024
-#define GSM48_ALLOC_HEADROOM	128
-
 /* should ip.access BTS use direct RTP streams between each other (1),
  * or should OpenBSC always act as RTP relay/proxy in between (0) ? */
 int ipacc_rtp_direct = 1;
 
-struct msgb *gsm48_msgb_alloc(void)
+static int gsm48_sendmsg(struct msgb *msg)
 {
-	return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM,
-				   "GSM 04.08");
-}
-
-int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans)
-{
-	struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data;
-
-	/* if we get passed a transaction reference, do some common
-	 * work that the caller no longer has to do */
-	if (trans) {
-		gh->proto_discr = trans->protocol | (trans->transaction_id << 4);
-		msg->lchan = trans->lchan;
-	}
-
-	if (msg->lchan) {
+	if (msg->lchan)
 		msg->trx = msg->lchan->ts->trx;
 
-		if ((gh->proto_discr & GSM48_PDISC_MASK) == GSM48_PDISC_CC)
-			DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x) "
-				"Sending '%s' to MS.\n", msg->trx->bts->nr,
-				msg->trx->nr, msg->lchan->ts->nr,
-				gh->proto_discr & 0xf0,
-				gsm48_cc_msg_name(gh->msg_type));
-		else
-			DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) "
-				"Sending 0x%02x to MS.\n", msg->trx->bts->nr,
-				msg->trx->nr, msg->lchan->ts->nr,
-				gh->proto_discr, gh->msg_type);
-	}
-
 	msg->l3h = msg->data;
-
 	return rsl_data_request(msg, 0);
 }
 
@@ -229,57 +197,13 @@
 		lchan->nr, lchan->type);
 
 	/* Send actual release request to MS */
-	gsm48_sendmsg(msg, NULL);
+	gsm48_sendmsg(msg);
 	/* FIXME: Start Timer T3109 */
 
 	/* Deactivate the SACCH on the BTS side */
 	return rsl_deact_sacch(lchan);
 }
 
-/* Convert Mobile Identity (10.5.1.4) to string */
-int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len)
-{
-	int i;
-	u_int8_t mi_type;
-	char *str_cur = string;
-	u_int32_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;
-}
-
-
 int send_siemens_mrpci(struct gsm_lchan *lchan,
 		       u_int8_t *classmark2_lv)
 {
@@ -296,16 +220,30 @@
 	return rsl_siemens_mrpci(lchan, &mrpci);
 }
 
-int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type)
+int gsm48_extract_mi(uint8_t *classmark2_lv, int length, char *mi_string, uint8_t *mi_type)
 {
-	struct gsm48_hdr *gh = msgb_l3(msg);
-	u_int8_t *classmark2_lv = gh->data + 1;
-	u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
-	*mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
+	/* Check the size for the classmark */
+	if (length < 1 + *classmark2_lv)
+		return -1;
 
+	u_int8_t *mi_lv = classmark2_lv + *classmark2_lv + 1;
+	if (length < 2 + *classmark2_lv + mi_lv[0])
+		return -2;
+
+	*mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
 	return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv);
 }
 
+int gsm48_paging_extract_mi(struct gsm48_pag_resp *resp, int length,
+			    char *mi_string, u_int8_t *mi_type)
+{
+	static const uint32_t classmark_offset =
+		offsetof(struct gsm48_pag_resp, classmark2);
+	u_int8_t *classmark2_lv = (uint8_t *) &resp->classmark2;
+	return gsm48_extract_mi(classmark2_lv, length - classmark_offset,
+				mi_string, mi_type);
+}
+
 int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr)
 {
 	struct gsm_bts *bts = msg->lchan->ts->trx->bts;
@@ -316,23 +254,23 @@
 	if (is_siemens_bts(bts))
 		send_siemens_mrpci(msg->lchan, classmark2_lv);
 
-	if (!msg->lchan->subscr) {
-		msg->lchan->subscr = subscr;
-	} else if (msg->lchan->subscr != subscr) {
+	if (!msg->lchan->conn.subscr) {
+		msg->lchan->conn.subscr = subscr;
+	} else if (msg->lchan->conn.subscr != subscr) {
 		LOGP(DRR, LOGL_ERROR, "<- Channel already owned by someone else?\n");
 		subscr_put(subscr);
 		return -EINVAL;
 	} else {
 		DEBUGP(DRR, "<- Channel already owned by us\n");
 		subscr_put(subscr);
-		subscr = msg->lchan->subscr;
+		subscr = msg->lchan->conn.subscr;
 	}
 
 	sig_data.subscr = subscr;
 	sig_data.bts	= msg->lchan->ts->trx->bts;
 	sig_data.lchan	= msg->lchan;
 
-	bts->network->stats.paging.completed++;
+	counter_inc(bts->network->stats.paging.completed);
 
 	dispatch_signal(SS_PAGING, S_PAGING_SUCCEEDED, &sig_data);
 
@@ -407,7 +345,7 @@
 
 	/* FIXME: optional bits for type of synchronization? */
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_sendmsg(msg);
 }
 
 /* Chapter 9.1.2: Assignment Command */
@@ -450,7 +388,7 @@
 		}
 	}
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_sendmsg(msg);
 }
 
 /* 9.1.5 Channel mode modify: Modify the mode on the MS side */
@@ -491,7 +429,7 @@
 		}
 	}
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_sendmsg(msg);
 }
 
 int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode)
@@ -626,4 +564,3 @@
 
 	return 0;
 }
-
diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c
index 881c375..8a85933 100644
--- a/openbsc/src/gsm_04_11.c
+++ b/openbsc/src/gsm_04_11.c
@@ -4,6 +4,8 @@
 
 /* (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
  * (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2010 by On Waves
  *
  * All Rights Reserved
  *
@@ -24,6 +26,7 @@
  */
 
 
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -47,12 +50,11 @@
 #include <openbsc/paging.h>
 #include <openbsc/bsc_rll.h>
 #include <openbsc/chan_alloc.h>
+#include <openbsc/bsc_api.h>
 
 #define GSM411_ALLOC_SIZE	1024
 #define GSM411_ALLOC_HEADROOM	128
 
-#define UM_SAPI_SMS 3	/* See GSM 04.05/04.06 */
-
 void *tall_gsms_ctx;
 static u_int32_t new_callref = 0x40000001;
 
@@ -63,7 +65,7 @@
 	{ GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
 	{ GSM411_CP_CAUSE_INV_MAND_INF,	"Invalid Mandatory Information" },
 	{ GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" },
-	{ GSM411_CP_CAUSE_MSG_INCOMP_STATE, 
+	{ GSM411_CP_CAUSE_MSG_INCOMP_STATE,
 				"Message incompatible with protocol state" },
 	{ GSM411_CP_CAUSE_IE_NOTEXIST,	"IE does not exist" },
 	{ GSM411_CP_CAUSE_PROTOCOL_ERR,	"Protocol Error" },
@@ -115,22 +117,30 @@
 	talloc_free(sms);
 }
 
+/*
+ * This should be called whenever all SMS to a given subscriber
+ * on a given connection has been sent. This will inform the higher
+ * layers that a channel can be given up.
+ */
+static void gsm411_release_conn(struct gsm_subscriber_connection *conn)
+{
+	if (!conn->lchan)
+		return;
+
+	subscr_put_channel(conn->lchan);
+}
+
 struct msgb *gsm411_msgb_alloc(void)
 {
 	return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM,
 				   "GSM 04.11");
 }
 
-static int gsm411_sendmsg(struct msgb *msg, u_int8_t link_id)
+static int gsm411_sendmsg(struct gsm_subscriber_connection *conn, struct msgb *msg, u_int8_t link_id)
 {
-	if (msg->lchan)
-		msg->trx = msg->lchan->ts->trx;
-
-	msg->l3h = msg->data;
-
 	DEBUGP(DSMS, "GSM4.11 TX %s\n", hexdump(msg->data, msg->len));
-
-	return rsl_data_request(msg, link_id);
+	msg->l3h = msg->data;
+	return gsm0808_submit_dtap(conn, msg, link_id);
 }
 
 /* SMC TC1* is expired */
@@ -154,9 +164,6 @@
 	gh->proto_discr = trans->protocol | (trans->transaction_id<<4);
 	gh->msg_type = msg_type;
 
-	/* assign the outgoing lchan */
-	msg->lchan = trans->lchan;
-
 	/* mobile originating */
 	switch (gh->msg_type) {
 	case GSM411_MT_CP_DATA:
@@ -179,7 +186,7 @@
 
 	DEBUGPC(DSMS, "trans=%x\n", trans->transaction_id);
 
-	return gsm411_sendmsg(msg, trans->sms.link_id);
+	return gsm411_sendmsg(trans->conn, msg, trans->sms.link_id);
 }
 
 /* Prefix msg with a RP-DATA header and send as CP-DATA */
@@ -215,7 +222,7 @@
 	u_int8_t ret;
 
 	if ((value & 0x0F) > 9 || (value >> 4) > 9)
-		LOGP(DSMS, LOGL_ERROR, 
+		LOGP(DSMS, LOGL_ERROR,
 		     "unbcdify got too big nibble: 0x%02X\n", value);
 
 	ret = (value&0x0F)*10;
@@ -375,9 +382,11 @@
 	enum sms_alphabet alpha = DCS_NONE;
 
 	if ((cgbits & 0xc) == 0) {
-		if (cgbits & 2)
+		if (cgbits & 2) {
 			LOGP(DSMS, LOGL_NOTICE,
 			     "Compressed SMS not supported yet\n");
+			return 0xffffffff;
+		}
 
 		switch ((dcs >> 2)&0x03) {
 		case 0:
@@ -412,8 +421,6 @@
 	}
 	/* dispatch a signal to tell higher level about it */
 	dispatch_signal(SS_SMS, S_SMS_SUBMITTED, gsms);
-	/* try delivering the SMS right now */
-	//gsm411_send_sms_subscr(gsms->receiver, gsms);
 
 	return 0;
 }
@@ -457,11 +464,6 @@
 	/* TP-UDHI (indicating TP-UD contains a header) */
 	if (sms->ud_hdr_ind)
 		*smsp |= 0x40;
-#if 0
-	/* TP-RP (indicating that a reply path exists) */
-	if (sms->
-		*smsp |= 0x80;
-#endif
 	
 	/* generate originator address */
 	oa_len = gsm340_gen_oa(oa, sizeof(oa), sms->sender);
@@ -509,11 +511,10 @@
 	return msg->len - old_msg_len;
 }
 
-/* process an incoming TPDU (called from RP-DATA) 
- * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */ 
-static int gsm340_rx_tpdu(struct msgb *msg)
+/* process an incoming TPDU (called from RP-DATA)
+ * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
+static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *msg)
 {
-	struct gsm_bts *bts = msg->lchan->ts->trx->bts;
 	u_int8_t *smsp = msgb_sms(msg);
 	struct gsm_sms *gsms;
 	u_int8_t sms_mti, sms_mms, sms_vpf, sms_alphabet, sms_rp;
@@ -522,7 +523,7 @@
 	u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
 	int rc = 0;
 
-	counter_inc(bts->network->stats.sms.submitted);
+	counter_inc(conn->bts->network->stats.sms.submitted);
 
 	gsms = sms_alloc();
 	if (!gsms)
@@ -558,6 +559,10 @@
 	gsms->data_coding_scheme = *smsp++;
 
 	sms_alphabet = gsm338_get_sms_alphabet(gsms->data_coding_scheme);
+	if (sms_alphabet == 0xffffffff) {
+		sms_free(gsms);
+		return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
+	}
 
 	switch (sms_vpf) {
 	case GSM340_TP_VPF_RELATIVE:
@@ -575,7 +580,7 @@
 		sms_vp = 0;
 		break;
 	default:
-		LOGP(DSMS, LOGL_NOTICE, 
+		LOGP(DSMS, LOGL_NOTICE,
 		     "SMS Validity period not implemented: 0x%02x\n", sms_vpf);
 		return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
 	}
@@ -594,7 +599,7 @@
 		}
 	}
 
-	gsms->sender = subscr_get(msg->lchan->subscr);
+	gsms->sender = subscr_get(msg->lchan->conn.subscr);
 
 	LOGP(DSMS, LOGL_INFO, "RX SMS: Sender: %s, MTI: 0x%02x, VPF: 0x%02x, "
 	     "MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, DA: %s, "
@@ -602,7 +607,7 @@
 	     subscr_name(gsms->sender), sms_mti, sms_vpf, gsms->msg_ref,
 	     gsms->protocol_id, gsms->data_coding_scheme, gsms->dest_addr,
 	     gsms->user_data_len,
-			sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text : 
+			sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
 				hexdump(gsms->user_data, gsms->user_data_len));
 
 	gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp);
@@ -610,10 +615,10 @@
 	dispatch_signal(SS_SMS, 0, gsms);
 
 	/* determine gsms->receiver based on dialled number */
-	gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr);
+	gsms->receiver = subscr_get_by_extension(conn->bts->network, gsms->dest_addr);
 	if (!gsms->receiver) {
 		rc = 1; /* cause 1: unknown subscriber */
-		counter_inc(bts->network->stats.sms.no_receiver);
+		counter_inc(conn->bts->network->stats.sms.no_receiver);
 		goto out;
 	}
 
@@ -683,11 +688,11 @@
 				     GSM411_RP_CAUSE_INV_MAND_INF);
 		return -EIO;
 	}
-	msg->smsh = tpdu;
+	msg->l4h = tpdu;
 
 	DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));
 
-	rc = gsm340_rx_tpdu(msg);
+	rc = gsm340_rx_tpdu(trans->conn, msg);
 	if (rc == 0)
 		return gsm411_send_rp_ack(trans, rph->msg_ref);
 	else if (rc > 0)
@@ -753,24 +758,23 @@
 	trans->sms.sms = NULL;
 
 	/* check for more messages for this subscriber */
-	sms = db_sms_get_unsent_for_subscr(msg->lchan->subscr);
+	assert(msg->lchan->conn.subscr == trans->subscr);
+
+	sms = db_sms_get_unsent_for_subscr(trans->subscr);
 	if (sms)
-		gsm411_send_sms_lchan(msg->lchan, sms);
+		gsm411_send_sms_lchan(trans->conn, sms);
+	else
+		gsm411_release_conn(trans->conn);
 
 	/* free the transaction here */
 	trans_free(trans);
-
-	/* release channel if done */
-	if (!sms)
-		rsl_release_request(msg->lchan, trans->sms.link_id);
-
 	return 0;
 }
 
 static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
 			      struct gsm411_rp_hdr *rph)
 {
-	struct gsm_network *net = trans->lchan->ts->trx->bts->network;
+	struct gsm_network *net = trans->conn->bts->network;
 	struct gsm_sms *sms = trans->sms.sms;
 	u_int8_t cause_len = rph->data[0];
 	u_int8_t cause = rph->data[1];
@@ -780,7 +784,7 @@
 	 * the cause and take action depending on it */
 
 	LOGP(DSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n",
-	     subscr_name(msg->lchan->subscr), cause_len, cause,
+	     subscr_name(trans->conn->subscr), cause_len, cause,
 	     get_value_string(rp_cause_strs, cause));
 
 	if (!trans->sms.is_mt) {
@@ -813,8 +817,6 @@
 	sms_free(sms);
 	trans->sms.sms = NULL;
 
-	//trans_free(trans);
-
 	return 0;
 }
 
@@ -833,11 +835,12 @@
 	dispatch_signal(SS_SMS, S_SMS_SMMA, trans->subscr);
 
 	/* check for more messages for this subscriber */
-	sms = db_sms_get_unsent_for_subscr(msg->lchan->subscr);
+	assert(msg->lchan->conn.subscr == trans->subscr);
+	sms = db_sms_get_unsent_for_subscr(trans->subscr);
 	if (sms)
-		gsm411_send_sms_lchan(msg->lchan, sms);
+		gsm411_send_sms_lchan(trans->conn, sms);
 	else
-		rsl_release_request(msg->lchan, trans->sms.link_id);
+		gsm411_release_conn(trans->conn);
 
 	return rc;
 }
@@ -920,16 +923,16 @@
 	struct gsm_trans *trans;
 	int rc = 0;
 
-	if (!lchan->subscr)
+	if (!lchan->conn.subscr)
 		return -EIO;
 		/* FIXME: send some error message */
 
 	DEBUGP(DSMS, "trans_id=%x ", transaction_id);
-	trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_SMS,
+	trans = trans_find_by_id(lchan->conn.subscr, GSM48_PDISC_SMS,
 				 transaction_id);
 	if (!trans) {
 		DEBUGPC(DSMS, "(new) ");
-		trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
+		trans = trans_alloc(lchan->conn.subscr, GSM48_PDISC_SMS,
 				    transaction_id, new_callref++);
 		if (!trans) {
 			DEBUGPC(DSMS, "No memory for trans\n");
@@ -941,8 +944,8 @@
 		trans->sms.is_mt = 0;
 		trans->sms.link_id = link_id;
 
-		trans->lchan = lchan;
-		use_lchan(lchan);
+		trans->conn = &lchan->conn;
+		use_subscr_con(trans->conn);
 	}
 
 	switch(msg_type) {
@@ -961,7 +964,7 @@
 				if (i == transaction_id)
 					continue;
 
-				ptrans = trans_find_by_id(lchan->subscr,
+				ptrans = trans_find_by_id(lchan->conn.subscr,
 				                          GSM48_PDISC_SMS, i);
 				if (!ptrans)
 					continue;
@@ -1003,7 +1006,7 @@
 		bsc_del_timer(&trans->sms.cp_timer);
 
 		if (!trans->sms.is_mt) {
-			/* FIXME: we have sont one CP-DATA, which was now
+			/* FIXME: we have sent one CP-DATA, which was now
 			 * acknowledged.  Check if we want to transfer more,
 			 * i.e. multi-part message */
 			trans->sms.cp_state = GSM411_CPS_IDLE;
@@ -1028,20 +1031,10 @@
 	return rc;
 }
 
-#if 0
-/* Test TPDU - ALL YOUR */
-static u_int8_t tpdu_test[] = {
-	0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x03, 0x41, 0x24,
-	0x32, 0x40, 0x1F, 0x41, 0x26, 0x13, 0x94, 0x7D, 0x56, 0xA5, 0x20, 0x28,
-	0xF2, 0xE9, 0x2C, 0x82, 0x82, 0xD2, 0x22, 0x48, 0x58, 0x64, 0x3E, 0x9D,
-	0x47, 0x10, 0xF5, 0x09, 0xAA, 0x4E, 0x01
-};
-#endif
-
 /* Take a SMS in gsm_sms structure and send it through an already
  * existing lchan. We also assume that the caller ensured this lchan already
  * has a SAPI3 RLL connection! */
-int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms)
+int gsm411_send_sms_lchan(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
 {
 	struct msgb *msg = gsm411_msgb_alloc();
 	struct gsm_trans *trans;
@@ -1050,21 +1043,21 @@
 	int transaction_id;
 	int rc;
 
-	transaction_id = trans_assign_trans_id(lchan->subscr, GSM48_PDISC_SMS, 0);
+	transaction_id = trans_assign_trans_id(conn->subscr, GSM48_PDISC_SMS, 0);
 	if (transaction_id == -1) {
 		LOGP(DSMS, LOGL_ERROR, "No available transaction ids\n");
+		sms_free(sms);
 		return -EBUSY;
 	}
 
-	msg->lchan = lchan;
-
 	DEBUGP(DSMS, "send_sms_lchan()\n");
 
 	/* FIXME: allocate transaction with message reference */
-	trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
+	trans = trans_alloc(conn->subscr, GSM48_PDISC_SMS,
 			    transaction_id, new_callref++);
 	if (!trans) {
 		LOGP(DSMS, LOGL_ERROR, "No memory for trans\n");
+		sms_free(sms);
 		/* FIXME: send some error message */
 		return -ENOMEM;
 	}
@@ -1074,8 +1067,8 @@
 	trans->sms.sms = sms;
 	trans->sms.link_id = UM_SAPI_SMS;	/* FIXME: main or SACCH ? */
 
-	trans->lchan = lchan;
-	use_lchan(lchan);
+	trans->conn = conn;
+	use_subscr_con(trans->conn);
 
 	/* Hardcode SMSC Originating Address for now */
 	data = (u_int8_t *)msgb_put(msg, 8);
@@ -1095,51 +1088,25 @@
 	/* obtain a pointer for the rp_ud_len, so we can fill it later */
 	rp_ud_len = (u_int8_t *)msgb_put(msg, 1);
 
-#if 1
 	/* generate the 03.40 TPDU */
 	rc = gsm340_gen_tpdu(msg, sms);
 	if (rc < 0) {
+		trans_free(trans);
+		sms_free(sms);
 		msgb_free(msg);
 		return rc;
 	}
 
 	*rp_ud_len = rc;
-#else
-	data = msgb_put(msg, sizeof(tpdu_test));
-	memcpy(data, tpdu_test, sizeof(tpdu_test));
-	*rp_ud_len = sizeof(tpdu_test);
-#endif
 
 	DEBUGP(DSMS, "TX: SMS DELIVER\n");
 
-	counter_inc(lchan->ts->trx->bts->network->stats.sms.delivered);
+	counter_inc(conn->bts->network->stats.sms.delivered);
 
 	return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
 	/* FIXME: enter 'wait for RP-ACK' state, start TR1N */
 }
 
-/* RLL SAPI3 establish callback. Now we have a RLL connection and
- * can deliver the actual message */
-static void rll_ind_cb(struct gsm_lchan *lchan, u_int8_t link_id,
-			void *_sms, enum bsc_rllr_ind type)
-{
-	struct gsm_sms *sms = _sms;
-
-	DEBUGP(DSMS, "rll_ind_cb(lchan=%p, link_id=%u, sms=%p, type=%u\n",
-		lchan, link_id, sms, type);
-
-	switch (type) {
-	case BSC_RLLR_IND_EST_CONF:
-		gsm411_send_sms_lchan(lchan, sms);
-		break;
-	case BSC_RLLR_IND_REL_IND:
-	case BSC_RLLR_IND_ERR_IND:
-	case BSC_RLLR_IND_TIMEOUT:
-		sms_free(sms);
-		break;
-	}
-}
-
 /* paging callback. Here we get called if paging a subscriber has
  * succeeded or failed. */
 static int paging_cb_send_sms(unsigned int hooknum, unsigned int event,
@@ -1147,7 +1114,7 @@
 {
 	struct gsm_lchan *lchan = _lchan;
 	struct gsm_sms *sms = _sms;
-	int rc;
+	int rc = 0;
 
 	DEBUGP(DSMS, "paging_cb_send_sms(hooknum=%u, event=%u, msg=%p,"
 		"lchan=%p, sms=%p)\n", hooknum, event, msg, lchan, sms);
@@ -1157,22 +1124,14 @@
 
 	switch (event) {
 	case GSM_PAGING_SUCCEEDED:
-		/* Paging aborted without lchan ?!? */
-		if (!lchan) {
-			sms_free(sms);
-			rc = -EIO;
-			break;
-		}
-		/* Establish a SAPI3 RLL connection for SMS */
-		rc = rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
+		use_subscr_con(&lchan->conn);
+		gsm411_send_sms_lchan(&lchan->conn, sms);
 		break;
 	case GSM_PAGING_EXPIRED:
+	case GSM_PAGING_OOM:
 		sms_free(sms);
 		rc = -ETIMEDOUT;
 		break;
-	default:
-		rc = -EINVAL;
-		break;
 	}
 
 	return rc;
@@ -1185,21 +1144,17 @@
 			   struct gsm_sms *sms)
 {
 	struct gsm_lchan *lchan;
-	int rc;
 
 	/* check if we already have an open lchan to the subscriber.
 	 * if yes, send the SMS this way */
 	lchan = lchan_for_subscr(subscr);
-	if (lchan)
-		return rll_establish(lchan, UM_SAPI_SMS,
-				     rll_ind_cb, sms);
+	if (lchan) {
+		use_subscr_con(&lchan->conn);
+		gsm411_send_sms_lchan(&lchan->conn, sms);
+	}
 
 	/* if not, we have to start paging */
-	rc = paging_request(subscr->net, subscr, RSL_CHANNEED_SDCCH,
-			    paging_cb_send_sms, sms);
-	if (rc <= 0)
-		sms_free(sms);
-
+	subscr_get_channel(subscr, RSL_CHANNEED_SDCCH, paging_cb_send_sms, sms);
 	return 0;
 }
 
@@ -1221,8 +1176,8 @@
 		sms = db_sms_get_unsent_for_subscr(subscr);
 		if (!sms)
 			break;
-		/* Establish a SAPI3 RLL connection for SMS */
-		rll_establish(lchan, UM_SAPI_SMS, rll_ind_cb, sms);
+		use_subscr_con(&lchan->conn);
+		gsm411_send_sms_lchan(&lchan->conn, sms);
 		break;
 	default:
 		break;
@@ -1232,9 +1187,35 @@
 
 void _gsm411_sms_trans_free(struct gsm_trans *trans)
 {
+	if (trans->sms.sms) {
+		LOGP(DSMS, LOGL_ERROR, "Transaction contains SMS.\n");
+		sms_free(trans->sms.sms);
+		trans->sms.sms = NULL;
+	}
+
 	bsc_del_timer(&trans->sms.cp_timer);
 }
 
+void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn)
+{
+	struct gsm_trans *trans, *tmp;
+
+	llist_for_each_entry_safe(trans, tmp, &conn->bts->network->trans_list, entry)
+		if (trans->conn == conn) {
+			struct gsm_sms *sms = trans->sms.sms;
+			if (!sms) {
+				LOGP(DSMS, LOGL_ERROR, "SAPI Reject but no SMS.\n");
+				continue;
+			}
+
+			sms_free(sms);
+			trans->sms.sms = NULL;
+			trans_free(trans);
+		}
+
+	gsm411_release_conn(conn);
+}
+
 static __attribute__((constructor)) void on_dso_load_sms(void)
 {
 	register_signal_handler(SS_SUBSCR, subscr_sig_cb, NULL);
diff --git a/openbsc/src/gsm_04_80.c b/openbsc/src/gsm_04_80.c
index 8271274..7d6679b 100644
--- a/openbsc/src/gsm_04_80.c
+++ b/openbsc/src/gsm_04_80.c
@@ -36,6 +36,7 @@
 #include <osmocore/gsm_utils.h>
 #include <openbsc/gsm_04_08.h>
 #include <openbsc/gsm_04_80.h>
+#include <openbsc/bsc_api.h>
 
 /* Forward declarations */
 static int parse_ussd(u_int8_t *ussd, struct ussd_request *req);
@@ -236,7 +237,7 @@
 				gsm_7bit_decode(req->text,
 						&(uss_req_data[7]), num_chars);
 				/* append null-terminator */
-				req->text[num_chars+1] = 0;  
+				req->text[num_chars+1] = 0;
 				rc = 1;
 			}
 		}
@@ -257,7 +258,6 @@
 	if (((strlen(response_text) * 7) % 8) != 0)
 		response_len += 1;
 
-	msg->bts_link = in_msg->bts_link;
 	msg->lchan = in_msg->lchan;
 
 	/* First put the payload text into the message */
@@ -295,7 +295,7 @@
 					| (1<<7);  /* TI direction = 1 */
 	gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm0808_submit_dtap(&msg->lchan->conn, msg, 0);
 }
 
 int gsm0480_send_ussd_reject(const struct msgb *in_msg,
@@ -304,7 +304,6 @@
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
 
-	msg->bts_link = in_msg->bts_link;
 	msg->lchan = in_msg->lchan;
 
 	/* First insert the problem code */
@@ -326,5 +325,5 @@
 	gh->proto_discr |= req->transaction_id | (1<<7);  /* TI direction = 1 */
 	gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm0808_submit_dtap(&msg->lchan->conn, msg, 0);
 }
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index 176367d..9de4c1f 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -88,6 +88,7 @@
 	{ LCHAN_S_ACTIVE,	"ACTIVE" },
 	{ LCHAN_S_INACTIVE,	"INACTIVE" },
 	{ LCHAN_S_REL_REQ,	"RELEASE REQUESTED" },
+	{ LCHAN_S_REL_ERR,	"RELEASE DUE ERROR" },
 	{ 0,			NULL }
 };
 
@@ -171,6 +172,10 @@
 	return trx;
 }
 
+static const uint8_t bts_nse_timer_default[] = { 3, 3, 3, 3, 30, 3, 10 };
+static const uint8_t bts_cell_timer_default[] =
+				{ 3, 3, 3, 3, 3, 10, 3, 10, 3, 10, 3 };
+
 struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type,
 			      u_int8_t tsc, u_int8_t bsic)
 {
@@ -212,6 +217,10 @@
 		bts->gprs.nsvc[i].bts = bts;
 		bts->gprs.nsvc[i].id = i;
 	}
+	memcpy(&bts->gprs.nse.timer, bts_nse_timer_default,
+		sizeof(bts->gprs.nse.timer));
+	memcpy(&bts->gprs.cell.timer, bts_cell_timer_default,
+		sizeof(bts->gprs.cell.timer));
 
 	/* create our primary TRX */
 	bts->c0 = gsm_bts_trx_alloc(bts);
@@ -221,6 +230,8 @@
 	}
 	bts->c0->ts[0].pchan = GSM_PCHAN_CCCH_SDCCH4;
 
+	bts->rach_b_thresh = -1;
+	bts->rach_ldavg_slots = -1;
 	llist_add_tail(&bts->list, &net->bts_list);
 
 	return bts;
@@ -280,6 +291,10 @@
 	net->stats.call.dialled = counter_alloc("net.call.dialled");
 	net->stats.call.alerted = counter_alloc("net.call.alerted");
 	net->stats.call.connected = counter_alloc("net.call.connected");
+	net->stats.chan.rf_fail = counter_alloc("net.chan.rf_fail");
+	net->stats.chan.rll_err = counter_alloc("net.chan.rll_err");
+	net->stats.bts.oml_fail = counter_alloc("net.bts.oml_fail");
+	net->stats.bts.rsl_fail = counter_alloc("net.bts.rsl_fail");
 
 	net->mncc_recv = mncc_recv;
 
@@ -436,33 +451,6 @@
 	return get_value_string(auth_policy_names, policy);
 }
 
-/* this should not be here but in gsm_04_08... but that creates
-   in turn a dependency nightmare (abis_nm depending on 04_08, ...) */
-static int gsm48_construct_ra(u_int8_t *buf, const struct gprs_ra_id *raid)
-{
-	u_int16_t mcc = raid->mcc;
-	u_int16_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);
-	}
-
-	*(u_int16_t *)(buf+3) = htons(raid->lac);
-
-	buf[5] = raid->rac;
-
-	return 6;
-}
-
 void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts)
 {
 	raid->mcc = bts->network->country_code;
@@ -498,6 +486,23 @@
 	return get_value_string(rrlp_mode_names, mode);
 }
 
+static const struct value_string bts_gprs_mode_names[] = {
+	{ BTS_GPRS_NONE,	"none" },
+	{ BTS_GPRS_GPRS,	"gprs" },
+	{ BTS_GPRS_EGPRS,	"egprs" },
+	{ 0,			NULL }
+};
+
+enum bts_gprs_mode bts_gprs_mode_parse(const char *arg)
+{
+	return get_string_value(bts_gprs_mode_names, arg);
+}
+
+const char *bts_gprs_mode_name(enum bts_gprs_mode mode)
+{
+	return get_value_string(bts_gprs_mode_names, mode);
+}
+
 struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan)
 {
 	struct gsm_meas_rep *meas_rep;
@@ -530,6 +535,8 @@
 		break;
 	case GSM_BTS_TYPE_BS11:
 		break;
+	case GSM_BTS_TYPE_UNKNOWN:
+		break;
 	}
 
 	return 0;
diff --git a/openbsc/src/gsm_subscriber_base.c b/openbsc/src/gsm_subscriber_base.c
index dee89c0..40c3bbd 100644
--- a/openbsc/src/gsm_subscriber_base.c
+++ b/openbsc/src/gsm_subscriber_base.c
@@ -187,6 +187,7 @@
 
 void subscr_put_channel(struct gsm_lchan *lchan)
 {
+	struct gsm_subscriber_connection *conn = &lchan->conn;
 	/*
 	 * FIXME: Continue with other requests now... by checking
 	 * the gsm_subscriber inside the gsm_lchan. Drop the ref count
@@ -205,9 +206,9 @@
 	 * will listen to the paging requests before we timeout
 	 */
 
-	put_lchan(lchan);
+	put_subscr_con(conn);
 
-	if (lchan->subscr && !llist_empty(&lchan->subscr->requests))
-		subscr_send_paging_request(lchan->subscr);
+	if (lchan->conn.subscr && !llist_empty(&lchan->conn.subscr->requests))
+		subscr_send_paging_request(lchan->conn.subscr);
 }
 
diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c
index bd4c563..b2ffe46 100644
--- a/openbsc/src/handover_logic.c
+++ b/openbsc/src/handover_logic.c
@@ -122,7 +122,7 @@
 	new_lchan->bs_power = old_lchan->bs_power;
 	new_lchan->rsl_cmode = old_lchan->rsl_cmode;
 	new_lchan->tch_mode = old_lchan->tch_mode;
-	new_lchan->subscr = subscr_get(old_lchan->subscr);
+	new_lchan->conn.subscr = subscr_get(old_lchan->conn.subscr);
 
 	/* FIXME: do we have a better idea of the timing advance? */
 	rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0,
@@ -134,6 +134,7 @@
 		return rc;
 	}
 
+	rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ);
 	llist_add(&ho->list, &bsc_handovers);
 	/* we continue in the SS_LCHAN handler / ho_chan_activ_ack */
 
@@ -218,7 +219,7 @@
 	}
 
 	LOGP(DHO, LOGL_INFO, "Subscriber %s HO from BTS %u->%u on ARFCN "
-	     "%u->%u\n", subscr_name(ho->old_lchan->subscr),
+	     "%u->%u\n", subscr_name(ho->old_lchan->conn.subscr),
 	     ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr,
 	     ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn);
 
@@ -227,9 +228,9 @@
 	bsc_del_timer(&ho->T3103);
 
 	/* update lchan pointer of transaction */
-	trans_lchan_change(ho->old_lchan, new_lchan);
+	trans_lchan_change(&ho->old_lchan->conn, &new_lchan->conn);
 
-	ho->old_lchan->state = LCHAN_S_INACTIVE;
+	rsl_lchan_set_state(ho->old_lchan, LCHAN_S_INACTIVE);
 	lchan_auto_release(ho->old_lchan);
 
 	/* do something to re-route the actual speech frames ! */
@@ -243,6 +244,7 @@
 /* GSM 04.08 HANDOVER FAIL has been received */
 static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan)
 {
+	struct gsm_subscriber_connection *conn;
 	struct gsm_network *net = old_lchan->ts->trx->bts->network;
 	struct bsc_handover *ho;
 
@@ -256,7 +258,8 @@
 
 	bsc_del_timer(&ho->T3103);
 	llist_del(&ho->list);
-	put_lchan(ho->new_lchan);
+	conn = &ho->new_lchan->conn;
+	put_subscr_con(conn);
 	talloc_free(ho);
 
 	return 0;
diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c
index 91d7563..4968e80 100644
--- a/openbsc/src/input/ipaccess.c
+++ b/openbsc/src/input/ipaccess.c
@@ -1,6 +1,8 @@
 /* OpenBSC Abis input driver for ip.access */
 
 /* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by Holger Hans Peter Freyther
+ * (C) 2010 by On-Waves
  *
  * All Rights Reserved
  *
@@ -42,6 +44,7 @@
 #include <openbsc/subchan_demux.h>
 #include <openbsc/e1_input.h>
 #include <openbsc/ipaccess.h>
+#include <openbsc/socket.h>
 #include <osmocore/talloc.h>
 
 #define PRIV_OML 1
@@ -57,12 +60,12 @@
 static struct ia_e1_handle *e1h;
 
 
-#define TS1_ALLOC_SIZE	300
+#define TS1_ALLOC_SIZE	900
 
 static const u_int8_t pong[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG };
 static const u_int8_t id_ack[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK };
 static const u_int8_t id_req[] = { 0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET,
-					0x01, IPAC_IDTAG_UNIT, 
+					0x01, IPAC_IDTAG_UNIT,
 					0x01, IPAC_IDTAG_MACADDR,
 					0x01, IPAC_IDTAG_LOCATION1,
 					0x01, IPAC_IDTAG_LOCATION2,
@@ -234,6 +237,8 @@
 		}
 		DEBUGP(DINP, "Identified BTS %u/%u/%u\n", site_id, bts_id, trx_id);
 		if (bfd->priv_nr == PRIV_OML) {
+			/* drop any old oml connection */
+			ipaccess_drop_oml(bts);
 			bts->oml_link = e1inp_sign_link_create(&line->ts[PRIV_OML - 1],
 						  E1INP_SIGN_OML, bts->c0,
 						  bts->oml_tei, 0);
@@ -241,7 +246,18 @@
 			struct e1inp_ts *e1i_ts;
 			struct bsc_fd *newbfd;
 			struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, trx_id);
-			
+
+			/* drop any old rsl connection */
+			ipaccess_drop_rsl(trx);
+
+			if (!bts->oml_link) {
+				bsc_unregister_fd(bfd);
+				close(bfd->fd);
+				bfd->fd = -1;
+				talloc_free(bfd);
+				return 0;
+			}
+
 			bfd->data = line = bts->oml_link->ts->line;
 			e1i_ts = &line->ts[PRIV_RSL + trx_id - 1];
 			newbfd = &e1i_ts->driver.ipaccess.fd;
@@ -251,19 +267,13 @@
 							E1INP_SIGN_RSL, trx,
 							trx->rsl_tei, 0);
 
-			if (newbfd->fd >= 0) {
-				LOGP(DINP, LOGL_ERROR, "BTS is still registered. Closing old connection.\n");
-				bsc_unregister_fd(newbfd);
-				close(newbfd->fd);
-				newbfd->fd = -1;
-			}
-
 			/* get rid of our old temporary bfd */
 			memcpy(newbfd, bfd, sizeof(*newbfd));
 			newbfd->priv_nr = PRIV_RSL + trx_id;
 			bsc_unregister_fd(bfd);
-			bsc_register_fd(newbfd);
+			bfd->fd = -1;
 			talloc_free(bfd);
+			bsc_register_fd(newbfd);
 		}
 		break;
 	}
@@ -328,6 +338,103 @@
 	return msg;
 }
 
+int ipaccess_drop_oml(struct gsm_bts *bts)
+{
+	struct gsm_bts_trx *trx;
+	struct e1inp_ts *ts;
+	struct e1inp_line *line;
+	struct bsc_fd *bfd;
+
+	if (!bts || !bts->oml_link)
+		return -1;
+
+	/* send OML down */
+	ts = bts->oml_link->ts;
+	line = ts->line;
+	e1inp_event(ts, EVT_E1_TEI_DN, bts->oml_link->tei, bts->oml_link->sapi);
+
+	bfd = &ts->driver.ipaccess.fd;
+	bsc_unregister_fd(bfd);
+	close(bfd->fd);
+	bfd->fd = -1;
+
+	/* clean up OML and RSL */
+	e1inp_sign_link_destroy(bts->oml_link);
+	bts->oml_link = NULL;
+	bts->ip_access.flags = 0;
+
+	/* drop all RSL connections too */
+	llist_for_each_entry(trx, &bts->trx_list, list)
+		ipaccess_drop_rsl(trx);
+
+	/* kill the E1 line now... as we have no one left to use it */
+	talloc_free(line);
+
+	return -1;
+}
+
+static int ipaccess_drop(struct e1inp_ts *ts, struct bsc_fd *bfd)
+{
+	struct e1inp_sign_link *link;
+	int bts_nr;
+
+	if (!ts) {
+		/*
+		 * If we don't have a TS this means that this is a RSL
+		 * connection but we are not past the authentication
+		 * handling yet. So we can safely delete this bfd and
+		 * wait for a reconnect.
+		 */
+		bsc_unregister_fd(bfd);
+		close(bfd->fd);
+		bfd->fd = -1;
+		talloc_free(bfd);
+		return -1;
+	}
+
+	/* attempt to find a signalling link */
+	if (ts->type == E1INP_TS_TYPE_SIGN) {
+		llist_for_each_entry(link, &ts->sign.sign_links, list) {
+			bts_nr = link->trx->bts->bts_nr;
+			/* we have issues just reconnecting RLS so we drop OML */
+			ipaccess_drop_oml(link->trx->bts);
+			return bts_nr;
+		}
+	}
+
+	/* error case */
+	LOGP(DINP, LOGL_ERROR, "Failed to find a signalling link for ts: %p\n", ts);
+	bsc_unregister_fd(bfd);
+	close(bfd->fd);
+	bfd->fd = -1;
+	return -1;
+}
+
+int ipaccess_drop_rsl(struct gsm_bts_trx *trx)
+{
+	struct bsc_fd *bfd;
+	struct e1inp_ts *ts;
+
+	if (!trx || !trx->rsl_link)
+		return -1;
+
+	/* send RSL down */
+	ts = trx->rsl_link->ts;
+	e1inp_event(ts, EVT_E1_TEI_DN, trx->rsl_link->tei, trx->rsl_link->sapi);
+
+	/* close the socket */
+	bfd = &ts->driver.ipaccess.fd;
+	bsc_unregister_fd(bfd);
+	close(bfd->fd);
+	bfd->fd = -1;
+
+	/* destroy */
+	e1inp_sign_link_destroy(trx->rsl_link);
+	trx->rsl_link = NULL;
+
+	return -1;
+}
+
 static int handle_ts1_read(struct bsc_fd *bfd)
 {
 	struct e1inp_line *line = bfd->data;
@@ -341,18 +448,12 @@
 	msg = ipaccess_read_msg(bfd, &error);
 	if (!msg) {
 		if (error == 0) {
-			link = e1inp_lookup_sign_link(e1i_ts, IPAC_PROTO_OML, 0);
-			if (link) {
-				link->trx->bts->ip_access.flags = 0;
+			int ret = ipaccess_drop(e1i_ts, bfd);
+			if (ret >= 0)
 				LOGP(DINP, LOGL_NOTICE, "BTS %u disappeared, dead socket\n",
-					link->trx->bts->nr);
-			} else
+					ret);
+			else
 				LOGP(DINP, LOGL_NOTICE, "unknown BTS disappeared, dead socket\n");
-			e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL);
-			e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML);
-			bsc_unregister_fd(bfd);
-			close(bfd->fd);
-			bfd->fd = -1;
 		}
 		return error;
 	}
@@ -362,13 +463,8 @@
 	hh = (struct ipaccess_head *) msg->data;
 	if (hh->proto == IPAC_PROTO_IPACCESS) {
 		ret = ipaccess_rcvmsg(line, msg, bfd);
-		if (ret < 0) {
-			e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL);
-			e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML);
-			bsc_unregister_fd(bfd);
-			close(bfd->fd);
-			bfd->fd = -1;
-		}
+		if (ret < 0)
+			ipaccess_drop(e1i_ts, bfd);
 		msgb_free(msg);
 		return ret;
 	}
@@ -475,7 +571,9 @@
 	/* set tx delay timer for next event */
 	e1i_ts->sign.tx_timer.cb = timeout_ts1_write;
 	e1i_ts->sign.tx_timer.data = e1i_ts;
-	bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 100);
+
+	/* Reducing this might break the nanoBTS 900 init. */
+	bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 100000);
 
 	return ret;
 }
@@ -505,7 +603,6 @@
 	return rc;
 }
 
-
 struct e1inp_driver ipaccess_driver = {
 	.name = "ip.access",
 	.want_write = ts_want_write,
@@ -611,53 +708,6 @@
 	return 0;
 }
 
-static int make_sock(struct bsc_fd *bfd, u_int16_t port,
-		     int (*cb)(struct bsc_fd *fd, unsigned int what))
-{
-	struct sockaddr_in addr;
-	int ret, on = 1;
-	
-	bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-	bfd->cb = cb;
-	bfd->when = BSC_FD_READ;
-	//bfd->data = line;
-
-	if (bfd->fd < 0) {
-		LOGP(DINP, LOGL_ERROR, "could not create TCP socket.\n");
-		return -EIO;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.sin_family = AF_INET;
-	addr.sin_port = htons(port);
-	addr.sin_addr.s_addr = INADDR_ANY;
-
-	setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-
-	ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
-	if (ret < 0) {
-		LOGP(DINP, LOGL_ERROR, "could not bind l2 socket %s\n",
-			strerror(errno));
-		close(bfd->fd);
-		return -EIO;
-	}
-
-	ret = listen(bfd->fd, 1);
-	if (ret < 0) {
-		perror("listen");
-		close(bfd->fd);
-		return ret;
-	}
-	
-	ret = bsc_register_fd(bfd);
-	if (ret < 0) {
-		perror("register_listen_fd");
-		close(bfd->fd);
-		return ret;
-	}
-	return 0;
-}
-
 /* Actively connect to a BTS.  Currently used by ipaccess-config.c */
 int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa)
 {
@@ -714,12 +764,16 @@
 	e1h->gsmnet = gsmnet;
 
 	/* Listen for OML connections */
-	ret = make_sock(&e1h->listen_fd, IPA_TCP_PORT_OML, listen_fd_cb);
+	ret = make_sock(&e1h->listen_fd, IPPROTO_TCP, 0, IPA_TCP_PORT_OML,
+			listen_fd_cb);
 	if (ret < 0)
 		return ret;
 
 	/* Listen for RSL connections */
-	ret = make_sock(&e1h->rsl_listen_fd, IPA_TCP_PORT_RSL, rsl_listen_fd_cb);
+	ret = make_sock(&e1h->rsl_listen_fd, IPPROTO_TCP, 0,
+			IPA_TCP_PORT_RSL, rsl_listen_fd_cb);
+	if (ret < 0)
+		return ret;
 
 	return ret;
 }
diff --git a/openbsc/src/input/misdn.c b/openbsc/src/input/misdn.c
index 56930d4..83b01f2 100644
--- a/openbsc/src/input/misdn.c
+++ b/openbsc/src/input/misdn.c
@@ -262,7 +262,7 @@
 
 	ret = send(bfd->fd, tx_buf, sizeof(*hh) + BCHAN_TX_GRAN, 0);
 	if (ret < sizeof(*hh) + BCHAN_TX_GRAN)
-		DEBUGP(DMIB, "send returns %d instead of %lu\n", ret,
+		DEBUGP(DMIB, "send returns %d instead of %zu\n", ret,
 			sizeof(*hh) + BCHAN_TX_GRAN);
 
 	return ret;
diff --git a/openbsc/src/ipaccess/Makefile.am b/openbsc/src/ipaccess/Makefile.am
new file mode 100644
index 0000000..5339321
--- /dev/null
+++ b/openbsc/src/ipaccess/Makefile.am
@@ -0,0 +1,13 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
+AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS)
+AM_LDFLAGS = $(LIBOSMOCORE_LIBS)
+
+sbin_PROGRAMS = ipaccess-find ipaccess-config ipaccess-proxy
+
+ipaccess_find_SOURCES = ipaccess-find.c
+
+ipaccess_config_SOURCES = ipaccess-config.c ipaccess-firmware.c
+ipaccess_config_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libmsc.a \
+			$(top_builddir)/src/libbsc.a $(top_builddir)/src/libvty.a -ldl -ldbi $(LIBCRYPT)
+
+ipaccess_proxy_SOURCES = ipaccess-proxy.c ../debug.c
diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c
index 870950d..52b18e2 100644
--- a/openbsc/src/ipaccess/ipaccess-config.c
+++ b/openbsc/src/ipaccess/ipaccess-config.c
@@ -1,8 +1,8 @@
 /* ip.access nanoBTS configuration tool */
 
 /* (C) 2009 by Harald Welte <laforge@gnumonks.org>
- * (C) 2009 by Holger Hans Peter Freyther
- * (C) 2009 by On Waves
+ * (C) 2009,2010 by Holger Hans Peter Freyther
+ * (C) 2009,2010 by On Waves
  * All Rights Reserved
  *
  * This program is free software; you can redistribute it and/or modify
@@ -59,6 +59,7 @@
 static int oml_state = 0;
 static int dump_files = 0;
 static char *firmware_analysis = NULL;
+static int found_trx = 0;
 
 struct sw_load {
 	u_int8_t file_id[255];
@@ -91,23 +92,23 @@
 	return 0;
 }
 
-static int ipacc_msg_ack(u_int8_t mt, struct gsm_bts *bts)
+static void check_restart_or_exit(struct gsm_bts_trx *trx)
+{
+	if (restart) {
+		abis_nm_ipaccess_restart(trx);
+	} else {
+		exit(0);
+	}
+}
+
+static int ipacc_msg_ack(u_int8_t mt, struct gsm_bts_trx *trx)
 {
 	if (sw_load_state == 1) {
 		fprintf(stderr, "The new software is activaed.\n");
-
-		if (restart) {
-			abis_nm_ipaccess_restart(bts);
-		} else {
-			exit(0);
-		}
+		check_restart_or_exit(trx);
 	} else if (oml_state == 1) {
 		fprintf(stderr, "Set the primary OML IP.\n");
-		if (restart) {
-			abis_nm_ipaccess_restart(bts);
-		} else {
-			exit(0);
-		}
+		check_restart_or_exit(trx);
 	}
 
 	return 0;
@@ -202,7 +203,7 @@
 		return ipacc_msg_nack(ipacc_data->msg_type);
 	case S_NM_IPACC_ACK:
 		ipacc_data = signal_data;
-		return ipacc_msg_ack(ipacc_data->msg_type, ipacc_data->bts);
+		return ipacc_msg_ack(ipacc_data->msg_type, ipacc_data->trx);
 	case S_NM_TEST_REP:
 		return test_rep(signal_data);
 	case S_NM_IPACC_RESTART_ACK:
@@ -227,12 +228,12 @@
 		       void *data, void *param)
 {
 	struct msgb *msg;
-	struct gsm_bts *bts;
+	struct gsm_bts_trx *trx;
 
 	if (hook != GSM_HOOK_NM_SWLOAD)
 		return 0;
 
-	bts = (struct gsm_bts *) data;
+	trx = (struct gsm_bts_trx *) data;
 
 	switch (event) {
 	case NM_MT_LOAD_INIT_ACK:
@@ -271,7 +272,7 @@
 		msg->l2h[1] = msgb_l3len(msg) >> 8;
 		msg->l2h[2] = msgb_l3len(msg) & 0xff;
 		printf("Foo l2h: %p l3h: %p... length l2: %u  l3: %u\n", msg->l2h, msg->l3h, msgb_l2len(msg), msgb_l3len(msg));
-		abis_nm_ipaccess_set_nvattr(bts->c0, msg->l2h, msgb_l2len(msg));
+		abis_nm_ipaccess_set_nvattr(trx, msg->l2h, msgb_l2len(msg));
 		msgb_free(msg);
 		break;
 	case NM_MT_LOAD_END_NACK:
@@ -285,7 +286,7 @@
 	case NM_MT_ACTIVATE_SW_ACK:
 		break;
 	case NM_MT_LOAD_SEG_ACK:
-		percent = abis_nm_software_load_status(bts);
+		percent = abis_nm_software_load_status(trx->bts);
 		if (percent > percent_old)
 			printf("Software Download Progress: %d%%\n", percent);
 		percent_old = percent;
@@ -298,13 +299,13 @@
 	return 0;
 }
 
-static void bootstrap_om(struct gsm_bts *bts)
+static void bootstrap_om(struct gsm_bts_trx *trx)
 {
 	int len;
 	static u_int8_t buf[1024];
 	u_int8_t *cur = buf;
 
-	printf("OML link established\n");
+	printf("OML link established using TRX %d\n", trx->nr);
 
 	if (unit_id) {
 		len = strlen(unit_id);
@@ -316,7 +317,7 @@
 		memcpy(buf+3, unit_id, len);
 		buf[3+len] = 0;
 		printf("setting Unit ID to '%s'\n", unit_id);
-		abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len+1);
+		abis_nm_ipaccess_set_nvattr(trx, buf, 3+len+1);
 	}
 	if (prim_oml_ip) {
 		struct in_addr ia;
@@ -340,7 +341,7 @@
 		*cur++ = 0;
 		printf("setting primary OML link IP to '%s'\n", inet_ntoa(ia));
 		oml_state = 1;
-		abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len);
+		abis_nm_ipaccess_set_nvattr(trx, buf, 3+len);
 	}
 	if (nv_mask) {
 		len = 4;
@@ -354,12 +355,12 @@
 		*cur++ = nv_mask >> 8;
 		printf("setting NV Flags/Mask to 0x%04x/0x%04x\n",
 			nv_flags, nv_mask);
-		abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len);
+		abis_nm_ipaccess_set_nvattr(trx, buf, 3+len);
 	}
 
 	if (restart && !prim_oml_ip && !software) {
 		printf("restarting BTS\n");
-		abis_nm_ipaccess_restart(bts);
+		abis_nm_ipaccess_restart(trx);
 	}
 
 }
@@ -370,7 +371,6 @@
 	case EVT_E1_TEI_UP:
 		switch (type) {
 		case E1INP_SIGN_OML:
-			bootstrap_om(trx->bts);
 			break;
 		case E1INP_SIGN_RSL:
 			/* FIXME */
@@ -389,22 +389,29 @@
 }
 
 int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
-		   struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
+		   struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
+		   struct abis_om_obj_inst *obj_inst)
 {
-	if (evt == EVT_STATECHG_OPER &&
+	if (obj_class == NM_OC_BASEB_TRANSC) {
+		if (!found_trx && obj_inst->trx_nr != 0xff) {
+			struct gsm_bts_trx *trx = container_of(obj, struct gsm_bts_trx, bb_transc);
+			bootstrap_om(trx);
+			found_trx = 1;
+		}
+	} else if (evt == EVT_STATECHG_OPER &&
 	    obj_class == NM_OC_RADIO_CARRIER &&
 	    new_state->availability == 3) {
 		struct gsm_bts_trx *trx = obj;
 
 		if (net_listen_testnr) {
 			u_int8_t phys_config[] = { 0x02, 0x0a, 0x00, 0x01, 0x02 };
-			abis_nm_perform_test(trx->bts, 2, 0, 0, 0xff,
+			abis_nm_perform_test(trx->bts, 2, 0, trx->nr, 0xff,
 					     net_listen_testnr, 1,
 					     phys_config, sizeof(phys_config));
 		} else if (software) {
 			int rc;
 			printf("Attempting software upload with '%s'\n", software);
-			rc = abis_nm_software_load(trx->bts, software, 19, 0, swload_cbfn, trx->bts);
+			rc = abis_nm_software_load(trx->bts, trx->nr, software, 19, 0, swload_cbfn, trx);
 			if (rc < 0) {
 				fprintf(stderr, "Failed to start software load\n");
 				exit(-3);
@@ -595,31 +602,33 @@
 
 static void print_help(void)
 {
-	printf("  -u --unit-id UNIT_ID\n");
-	printf("  -o --oml-ip ip\n");
-	printf("  -r --restart\n");
-	printf("  -n flags/mask\tSet NVRAM attributes.\n");
-	printf("  -l --listen testnr \tPerform specified test number\n");
-	printf("  -h --help this text\n");
-	printf("  -s --stream-id ID\n");
-	printf("  -d --software firmware\n");
+	printf("  -u --unit-id UNIT_ID\tSet the Unit ID of the BTS\n");
+	printf("  -o --oml-ip IP\tSet primary OML IP (IP of your BSC)\n");
+	printf("  -r --restart\t\tRestart the BTS (after other operations)\n");
+	printf("  -n flags/mask\t\tSet NVRAM attributes.\n");
+	printf("  -l --listen testnr\tPerform specified test number\n");
+	printf("  -h --help\t\tthis text\n");
+	printf("  -s --stream-id ID\tSet the IPA Stream Identifier for OML\n");
+	printf("  -d --software firmware Download firmware into BTS\n");
 	printf("  -f --firmware firmware Provide firmware information\n");
-	printf("  -w --write-firmware. This will dump the firmware parts to the filesystem. Use with -f.\n");
+	printf("  -w --write-firmware    This will dump the firmware parts to the filesystem. Use with -f.\n");
 }
 
+extern void bts_model_nanobts_init();
+
 int main(int argc, char **argv)
 {
 	struct gsm_bts *bts;
 	struct sockaddr_in sin;
 	int rc, option_index = 0, stream_id = 0xff;
-	struct debug_target *stderr_target;
+	struct log_target *stderr_target;
 
-	debug_init();
-	stderr_target = debug_target_create_stderr();
-	debug_add_target(stderr_target);
-	debug_set_all_filter(stderr_target, 1);
-	debug_set_log_level(stderr_target, 0);
-	debug_parse_category_mask(stderr_target, "DNM,0");
+	log_init(&log_info);
+	stderr_target = log_target_create_stderr();
+	log_add_target(stderr_target);
+	log_set_all_filter(stderr_target, 1);
+	log_set_log_level(stderr_target, 0);
+	log_parse_category_mask(stderr_target, "DNM,0");
 	bts_model_nanobts_init();
 
 	printf("ipaccess-config (C) 2009 by Harald Welte\n");
@@ -639,6 +648,7 @@
 			{ "software", 1, 0, 'd' },
 			{ "firmware", 1, 0, 'f' },
 			{ "write-firmware", 0, 0, 'w' },
+			{ 0, 0, 0, 0 },
 		};
 
 		c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:w", long_options,
diff --git a/openbsc/src/ipaccess/ipaccess-find.c b/openbsc/src/ipaccess/ipaccess-find.c
index 01f8a2d..ec4a0b7 100644
--- a/openbsc/src/ipaccess/ipaccess-find.c
+++ b/openbsc/src/ipaccess/ipaccess-find.c
@@ -71,7 +71,7 @@
 	rc = connect(fd, (struct sockaddr *)&sa, sizeof(sa));
 	if (rc < 0)
 		goto err;
-#endif		
+#endif
 	return fd;
 
 err:
@@ -79,7 +79,7 @@
 	return rc;
 }
 
-const unsigned char find_pkt[] = { 0x00, 0x0b+8, IPAC_PROTO_IPACCESS, 0x00, 
+const unsigned char find_pkt[] = { 0x00, 0x0b+8, IPAC_PROTO_IPACCESS, 0x00,
 				IPAC_MSGT_ID_GET,
 					0x01, IPAC_IDTAG_MACADDR,
 					0x01, IPAC_IDTAG_IPADDR,
diff --git a/openbsc/src/ipaccess/ipaccess-proxy.c b/openbsc/src/ipaccess/ipaccess-proxy.c
index 217e0bd..0310749 100644
--- a/openbsc/src/ipaccess/ipaccess-proxy.c
+++ b/openbsc/src/ipaccess/ipaccess-proxy.c
@@ -1,6 +1,8 @@
 /* OpenBSC Abis/IP proxy ip.access nanoBTS */
 
 /* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by On Waves
+ * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
  *
  * All Rights Reserved
  *
@@ -34,6 +36,9 @@
 #include <arpa/inet.h>
 #include <netinet/in.h>
 
+#define _GNU_SOURCE
+#include <getopt.h>
+
 #include <openbsc/gsm_data.h>
 #include <osmocore/select.h>
 #include <osmocore/tlv.h>
@@ -42,7 +47,7 @@
 #include <openbsc/ipaccess.h>
 #include <osmocore/talloc.h>
 
-static struct debug_target *stderr_target;
+static struct log_target *stderr_target;
 
 /* one instance of an ip.access protocol proxy */
 struct ipa_proxy {
@@ -54,6 +59,9 @@
 	struct llist_head bts_list;
 	/* the BSC reconnect timer */
 	struct timer_list reconn_timer;
+	/* global GPRS NS data */
+	struct in_addr gprs_addr;
+	struct in_addr listen_addr;
 };
 
 /* global pointer to the proxy structure */
@@ -64,7 +72,6 @@
 	struct llist_head tx_queue;
 	struct ipa_bts_conn *bts_conn;
 };
-
 #define MAX_TRX 4
 
 /* represents a particular BTS in our proxy */
@@ -91,6 +98,13 @@
 	struct bsc_fd udp_bts_fd;
 	struct bsc_fd udp_bsc_fd;
 
+	/* NS data */
+	struct in_addr bts_addr;
+	struct bsc_fd gprs_ns_fd;
+	int gprs_local_port;
+	uint16_t gprs_orig_port;
+	uint32_t gprs_orig_ip;
+
 	char *id_tags[0xff];
 	u_int8_t *id_resp;
 	unsigned int id_resp_len;
@@ -110,8 +124,12 @@
 
 static char *listen_ipaddr;
 static char *bsc_ipaddr;
+static char *gprs_ns_ipaddr;
 
-#define PROXY_ALLOC_SIZE	300
+static int make_gprs_sock(struct bsc_fd *bfd, int (*cb)(struct bsc_fd*,unsigned int), void *);
+static int gprs_ns_cb(struct bsc_fd *bfd, unsigned int what);
+
+#define PROXY_ALLOC_SIZE	1200
 
 static const u_int8_t pong[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG };
 static const u_int8_t id_ack[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK };
@@ -265,10 +283,10 @@
 			   struct ipa_bts_conn *ipbc, u_int8_t trx_id)
 {
 	if (ipbc)
-		debugp2(ss, lvl, file, line, 0, "(%u/%u/%u) ", ipbc->unit_id.site_id,
+		logp2(ss, lvl, file, line, 0, "(%u/%u/%u) ", ipbc->unit_id.site_id,
 		     ipbc->unit_id.bts_id, trx_id);
 	else
-		debugp2(ss, lvl, file, line, 0, "unknown ");
+		logp2(ss, lvl, file, line, 0, "unknown ");
 }
 
 /* UDP socket handling */
@@ -492,6 +510,28 @@
 		goto err_udp_bsc;
 	DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection "
 		"towards BSC at port %u\n", site_id, bts_id, trx_id, udp_port);
+
+
+	/* GPRS NS related code */
+	if (gprs_ns_ipaddr) {
+		struct sockaddr_in sock;
+		socklen_t len = sizeof(sock);
+		ret = make_gprs_sock(&ipbc->gprs_ns_fd, gprs_ns_cb, ipbc);
+		if (ret < 0) {
+			LOGP(DINP, LOGL_ERROR, "Creating the GPRS socket failed.\n");
+			goto err_udp_bsc;
+		}
+
+		ret = getsockname(ipbc->gprs_ns_fd.fd, (struct sockaddr* ) &sock, &len);
+		ipbc->gprs_local_port = ntohs(sock.sin_port);
+		LOGP(DINP, LOGL_NOTICE,
+			"Created GPRS NS Socket. Listening on: %s:%d\n",
+			inet_ntoa(sock.sin_addr), ipbc->gprs_local_port);
+
+		ret = getpeername(bfd->fd, (struct sockaddr* ) &sock, &len);
+		ipbc->bts_addr = sock.sin_addr;
+	}
+
 	llist_add(&ipbc->list, &ipp->bts_list);
 
 	return 0;
@@ -550,6 +590,7 @@
 		}
 
 		/* lookup BTS, create sign_link, ... */
+		site_id = bts_id = trx_id = 0;
 		parse_unitid((char *)TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT),
 			     &site_id, &bts_id, &trx_id);
 		ipbc = find_bts_by_unitid(ipp, site_id, bts_id);
@@ -616,6 +657,10 @@
 		DEBUGP(DMI, "ID_ACK? -> ACK!\n");
 		ret = write(bfd->fd, id_ack, sizeof(id_ack));
 		break;
+	default:
+		LOGP(DMI, LOGL_ERROR, "Unhandled IPA type; %d\n", msg_type);
+		return 1;
+		break;
 	}
 	return 0;
 }
@@ -804,6 +849,42 @@
 	talloc_free(ipc);
 }
 
+static void patch_gprs_msg(struct ipa_bts_conn *ipbc, int priv_nr, struct msgb *msg)
+{
+	uint8_t *nsvci;
+
+	if ((priv_nr & 0xff) != OML_FROM_BTS && (priv_nr & 0xff) != OML_TO_BSC)
+		return;
+
+	if (msgb_l2len(msg) != 39)
+		return;
+
+	/*
+	 * Check if this is a IPA Set Attribute or IPA Set Attribute ACK
+	 * and if the FOM Class is GPRS NSVC0 and then we will patch it.
+	 *
+	 * The patch assumes the message looks like the one from the trace
+	 * but we only match messages with a specific size anyway... So
+	 * this hack should work just fine.
+	 */
+
+	if (msg->l2h[0] == 0x10 && msg->l2h[1] == 0x80 &&
+	    msg->l2h[2] == 0x00 && msg->l2h[3] == 0x15 &&
+	    msg->l2h[18] == 0xf5 && msg->l2h[19] == 0xf2) {
+		nsvci = &msg->l2h[23];
+		ipbc->gprs_orig_port =  *(u_int16_t *)(nsvci+8);
+		ipbc->gprs_orig_ip = *(u_int32_t *)(nsvci+10);
+		*(u_int16_t *)(nsvci+8) = htons(ipbc->gprs_local_port);
+		*(u_int32_t *)(nsvci+10) = ipbc->ipp->listen_addr.s_addr;
+	} else if (msg->l2h[0] == 0x10 && msg->l2h[1] == 0x80 &&
+	    msg->l2h[2] == 0x00 && msg->l2h[3] == 0x15 &&
+	    msg->l2h[18] == 0xf6 && msg->l2h[19] == 0xf2) {
+		nsvci = &msg->l2h[23];
+		*(u_int16_t *)(nsvci+8) = ipbc->gprs_orig_port;
+		*(u_int32_t *)(nsvci+10) = ipbc->gprs_orig_ip;
+	}
+}
+
 static int handle_tcp_read(struct bsc_fd *bfd)
 {
 	struct ipa_proxy_conn *ipc = bfd->data;
@@ -842,11 +923,14 @@
 			close(bfd->fd);
 			bfd->fd = -1;
 			talloc_free(bfd);
+			msgb_free(msg);
+			return ret;
+		} else if (ret == 0) {
+			/* we do not forward parts of the CCM protocol
+			 * through the proxy but rather terminate it ourselves. */
+			msgb_free(msg);
+			return ret;
 		}
-		/* we do not forward the CCM protocol through the
-		 * proxy but rather terminate it ourselves */
-		msgb_free(msg);
-		return ret;
 	}
 
 	if (!ipbc) {
@@ -858,6 +942,8 @@
 
 	bsc_conn = ipc_by_priv_nr(ipbc, bfd->priv_nr);
 	if (bsc_conn) {
+		if (gprs_ns_ipaddr)
+			patch_gprs_msg(ipbc, bfd->priv_nr, msg);
 		/* enqueue packet towards BSC */
 		msgb_enqueue(&bsc_conn->tx_queue, msg);
 		/* mark respective filedescriptor as 'we want to write' */
@@ -946,7 +1032,7 @@
 		perror("accept");
 		return ret;
 	}
-	DEBUGP(DINP, "accept()ed new %s link from %s\n", 
+	DEBUGP(DINP, "accept()ed new %s link from %s\n",
 		(listen_bfd->priv_nr & 0xff) == OML_FROM_BTS ? "OML" : "RSL",
 		inet_ntoa(sa.sin_addr));
 
@@ -976,6 +1062,54 @@
 	return 0;
 }
 
+static void send_ns(int fd, const char *buf, int size, struct in_addr ip, int port)
+{
+	int ret;
+	struct sockaddr_in addr;
+	socklen_t len = sizeof(addr);
+	memset(&addr, 0, sizeof(addr));
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	addr.sin_addr = ip;
+
+	ret = sendto(fd, buf, size, 0, (struct sockaddr *) &addr, len);
+	if (ret < 0) {
+		LOGP(DINP, LOGL_ERROR, "Failed to forward GPRS message.\n");
+	}
+}
+
+static int gprs_ns_cb(struct bsc_fd *bfd, unsigned int what)
+{
+	struct ipa_bts_conn *bts;
+	char buf[4096];
+	int ret;
+	struct sockaddr_in sock;
+	socklen_t len = sizeof(sock);
+
+	/* 1. get the data... */
+	ret = recvfrom(bfd->fd, buf, sizeof(buf), 0, (struct sockaddr *) &sock, &len);
+	if (ret < 0) {
+		LOGP(DINP, LOGL_ERROR, "Failed to recv GPRS NS msg: %s.\n", strerror(errno));
+		return -1;
+	}
+
+	bts = bfd->data;
+
+	/* 2. figure out where to send it to */
+	if (memcmp(&sock.sin_addr, &ipp->gprs_addr, sizeof(sock.sin_addr)) == 0) {
+		LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from network.\n");
+		send_ns(bfd->fd, buf, ret, bts->bts_addr, 23000);
+	} else if (memcmp(&sock.sin_addr, &bts->bts_addr, sizeof(sock.sin_addr)) == 0) {
+		LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from BTS.\n");
+		send_ns(bfd->fd, buf, ret, ipp->gprs_addr, 23000);
+	} else {
+		LOGP(DINP, LOGL_ERROR, "Unknown GPRS source: %s\n", inet_ntoa(sock.sin_addr));
+	}
+
+	return 0;
+}
+
 static int make_listen_sock(struct bsc_fd *bfd, u_int16_t port, int priv_nr,
 		     int (*cb)(struct bsc_fd *fd, unsigned int what))
 {
@@ -999,8 +1133,9 @@
 
 	ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
 	if (ret < 0) {
-		LOGP(DINP, LOGL_ERROR, "could not bind listen socket %s\n",
-			strerror(errno));
+		LOGP(DINP, LOGL_ERROR,
+			"Could not bind listen socket for IP %s with error: %s.\n",
+			listen_ipaddr, strerror(errno));
 		return -EIO;
 	}
 
@@ -1018,6 +1153,37 @@
 	return 0;
 }
 
+static int make_gprs_sock(struct bsc_fd *bfd, int (*cb)(struct bsc_fd*,unsigned int), void *data)
+{
+	struct sockaddr_in addr;
+	int ret;
+
+	bfd->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	bfd->cb = cb;
+	bfd->data = data;
+	bfd->when = BSC_FD_READ;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_port = 0;
+	inet_aton(listen_ipaddr, &addr.sin_addr);
+
+	ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
+	if (ret < 0) {
+		LOGP(DINP, LOGL_ERROR,
+			"Could not bind n socket for IP %s with error: %s.\n",
+			listen_ipaddr, strerror(errno));
+		return -EIO;
+	}
+
+	ret = bsc_register_fd(bfd);
+	if (ret < 0) {
+		perror("register_listen_fd");
+		return ret;
+	}
+	return 0;
+}
+
 /* Actively connect to a BSC.  */
 static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data)
 {
@@ -1042,7 +1208,8 @@
 
 	ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa));
 	if (ret < 0) {
-		LOGP(DINP, LOGL_ERROR, "could not connect socket\n");
+		LOGP(DINP, LOGL_ERROR, "Could not connect socket: %s\n",
+		     inet_ntoa(sa->sin_addr));
 		close(bfd->fd);
 		talloc_free(ipc);
 		return NULL;
@@ -1080,6 +1247,15 @@
 	ret = make_listen_sock(&ipp->rsl_listen_fd, IPA_TCP_PORT_RSL,
 				RSL_FROM_BTS, listen_fd_cb);
 
+	if (ret < 0)
+		return ret;
+
+	/* Connect the GPRS NS Socket */
+	if (gprs_ns_ipaddr) {
+		inet_aton(gprs_ns_ipaddr, &ipp->gprs_addr);
+		inet_aton(listen_ipaddr, &ipp->listen_addr);
+	}
+
 	return ret;
 }
 
@@ -1099,6 +1275,75 @@
 	}
 }
 
+static void print_help()
+{
+	printf(" ipaccess-proxy is a proxy BTS.\n");
+	printf(" -h --help. This help text.\n");
+	printf(" -l --listen IP. The ip to listen to.\n");
+	printf(" -b --bsc IP. The BSC IP address.\n");
+	printf(" -g --gprs IP. Take GPRS NS from that IP.\n");
+	printf("\n");
+	printf(" -s --disable-color. Disable the color inside the logging message.\n");
+	printf(" -e --log-level number. Set the global loglevel.\n");
+	printf(" -T --timestamp. Prefix every log message with a timestamp.\n");
+	printf(" -V --version. Print the version of OpenBSC.\n");
+}
+
+static void print_usage()
+{
+	printf("Usage: ipaccess-proxy\n");
+}
+
+static void handle_options(int argc, char** argv)
+{
+	while (1) {
+		int option_index = 0, c;
+		static struct option long_options[] = {
+			{"help", 0, 0, 'h'},
+			{"disable-color", 0, 0, 's'},
+			{"timestamp", 0, 0, 'T'},
+			{"log-level", 1, 0, 'e'},
+			{"listen", 1, 0, 'l'},
+			{"bsc", 1, 0, 'b'},
+			{"udp", 1, 0, 'u'},
+			{0, 0, 0, 0}
+		};
+
+		c = getopt_long(argc, argv, "hsTe:l:b:g:",
+				long_options, &option_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'h':
+			print_usage();
+			print_help();
+			exit(0);
+		case 'l':
+			listen_ipaddr = optarg;
+			break;
+		case 'b':
+			bsc_ipaddr = optarg;
+			break;
+		case 'g':
+			gprs_ns_ipaddr = optarg;
+			break;
+		case 's':
+			log_set_use_color(stderr_target, 0);
+			break;
+		case 'T':
+			log_set_print_timestamp(stderr_target, 1);
+			break;
+		case 'e':
+			log_set_log_level(stderr_target, atoi(optarg));
+			break;
+		default:
+			/* ignore */
+			break;
+		}
+	}
+}
+
 int main(int argc, char **argv)
 {
 	int rc;
@@ -1108,11 +1353,13 @@
 
 	tall_bsc_ctx = talloc_named_const(NULL, 1, "ipaccess-proxy");
 
-	debug_init();
-	stderr_target = debug_target_create_stderr();
-	debug_add_target(stderr_target);
-	debug_set_all_filter(stderr_target, 1);
-	debug_parse_category_mask(stderr_target, "DINP:DMI");
+	log_init(&log_info);
+	stderr_target = log_target_create_stderr();
+	log_add_target(stderr_target);
+	log_set_all_filter(stderr_target, 1);
+	log_parse_category_mask(stderr_target, "DINP:DMI");
+
+	handle_options(argc, argv);
 
 	rc = ipaccess_proxy_setup();
 	if (rc < 0)
diff --git a/openbsc/src/mgcp/mgcp_main.c b/openbsc/src/mgcp/mgcp_main.c
index e45a1e9..d5b6502 100644
--- a/openbsc/src/mgcp/mgcp_main.c
+++ b/openbsc/src/mgcp/mgcp_main.c
@@ -38,7 +38,11 @@
 #include <openbsc/gsm_data.h>
 #include <osmocore/select.h>
 #include <openbsc/mgcp.h>
-#include <openbsc/telnet_interface.h>
+#include <openbsc/mgcp_internal.h>
+#include <osmocom/vty//telnet_interface.h>
+#include <openbsc/vty.h>
+
+#include <osmocom/vty/command.h>
 
 #include "../../bscconfig.h"
 
@@ -51,10 +55,10 @@
 #warning "Make use of the rtp proxy code"
 
 static struct bsc_fd bfd;
-static int first_request = 1;
 static struct mgcp_config *cfg;
-const char *openbsc_version = "OpenBSC MGCP " PACKAGE_VERSION;
-const char *openbsc_copyright = 
+static int reset_endpoints = 0;
+
+const char *openbsc_copyright =
 	"Copyright (C) 2009-2010 Holger Freyther and On-Waves\n"
 	"Contributions by Daniel Willmann, Jan Lübbe,Stefan Schmidt\n"
 	"Dieter Spaar, Andreas Eversberg, Harald Welte\n\n"
@@ -74,12 +78,6 @@
 	printf(" -c --config-file filename The config file to use.\n");
 }
 
-static void print_version()
-{
-	printf("%s\n\n", openbsc_version);
-	printf(openbsc_copyright);
-}
-
 static void handle_options(int argc, char** argv)
 {
 	while (1) {
@@ -105,7 +103,7 @@
 			config_file = talloc_strdup(tall_bsc_ctx, optarg);
 			break;
 		case 'V':
-			print_version();
+			print_version(1);
 			exit(0);
 			break;
 		default:
@@ -115,12 +113,30 @@
 	}
 }
 
+/* simply remember this */
+static int mgcp_rsip_cb(struct mgcp_config *cfg)
+{
+	reset_endpoints = 1;
+
+	return 0;
+}
+
+static int mgcp_change_cb(struct mgcp_config *cfg, int endpoint, int state, int local_rtp)
+{
+	if (state != MGCP_ENDP_MDCX)
+		return 0;
+
+	mgcp_send_dummy(&cfg->endpoints[endpoint]);
+	return 0;
+}
+
 static int read_call_agent(struct bsc_fd *fd, unsigned int what)
 {
 	struct sockaddr_in addr;
 	socklen_t slen = sizeof(addr);
 	struct msgb *msg;
 	struct msgb *resp;
+	int i;
 
 	msg = (struct msgb *) fd->data;
 
@@ -136,18 +152,6 @@
 		return -1;
 	}
 
-	if (first_request) {
-		first_request = 0;
-		resp = mgcp_create_rsip();
-
-		if (resp) {
-			sendto(bfd.fd, resp->l2h, msgb_l2len(resp), 0,
-				(struct sockaddr *) &addr, sizeof(addr));
-			msgb_free(resp);
-		}
-		return 0;
-        }
-
 	/* handle message now */
 	msg->l2h = msgb_put(msg, rc);
 	resp = mgcp_handle_message(cfg, msg);
@@ -157,35 +161,63 @@
 		sendto(bfd.fd, resp->l2h, msgb_l2len(resp), 0, (struct sockaddr *) &addr, sizeof(addr));
 		msgb_free(resp);
 	}
+
+	if (reset_endpoints) {
+		LOGP(DMGCP, LOGL_NOTICE, "Asked to reset endpoints.\n");
+		reset_endpoints = 0;
+
+		/* is checking in_addr.s_addr == INADDR_LOOPBACK making it more secure? */
+		for (i = 1; i < cfg->number_endpoints; ++i)
+			mgcp_free_endp(&cfg->endpoints[i]);
+	}
+
 	return 0;
 }
 
+extern enum node_type bsc_vty_go_parent(struct vty *vty);
+
+static struct vty_app_info vty_info = {
+	.name 		= "OpenBSC MGCP",
+	.version	= PACKAGE_VERSION,
+	.go_parent_cb	= bsc_vty_go_parent,
+};
 
 int main(int argc, char** argv)
 {
 	struct gsm_network dummy_network;
 	struct sockaddr_in addr;
 	int on = 1, rc;
-	struct debug_target *stderr_target;
+	struct log_target *stderr_target;
 
 	tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
 
-	debug_init();
-	stderr_target = debug_target_create_stderr();
-	debug_add_target(stderr_target);
-	debug_set_all_filter(stderr_target, 1);
+	log_init(&log_info);
+	stderr_target = log_target_create_stderr();
+	log_add_target(stderr_target);
+	log_set_all_filter(stderr_target, 1);
 
 	cfg = mgcp_config_alloc();
 	if (!cfg)
 		return -1;
 
+	vty_info.copyright = openbsc_copyright;
+	vty_init(&vty_info);
+	logging_vty_add_cmds();
+	mgcp_vty_init();
+
 	handle_options(argc, argv);
 
-	telnet_init(&dummy_network, 4243);
         rc = mgcp_parse_config(config_file, cfg);
 	if (rc < 0)
 		return rc;
 
+	rc = telnet_init(tall_bsc_ctx, &dummy_network, 4243);
+	if (rc < 0)
+		return rc;
+
+	/* set some callbacks */
+	cfg->reset_cb = mgcp_rsip_cb;
+	cfg->change_cb = mgcp_change_cb;
 
         /* we need to bind a socket */
         if (rc == 0) {
@@ -217,11 +249,11 @@
 
 
 		if (bsc_register_fd(&bfd) != 0) {
-			DEBUGP(DMGCP, "Failed to register the fd\n");
+			LOGP(DMGCP, LOGL_FATAL, "Failed to register the fd\n");
 			return -1;
 		}
 
-		DEBUGP(DMGCP, "Configured for MGCP.\n");
+		LOGP(DMGCP, LOGL_NOTICE, "Configured for MGCP.\n");
 	}
 
 	/* initialisation */
diff --git a/openbsc/src/mgcp/mgcp_network.c b/openbsc/src/mgcp/mgcp_network.c
index b76ca47..1f51233 100644
--- a/openbsc/src/mgcp/mgcp_network.c
+++ b/openbsc/src/mgcp/mgcp_network.c
@@ -23,14 +23,15 @@
  */
 
 #include <string.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <endian.h>
+#include <errno.h>
 
 #include <sys/socket.h>
 #include <arpa/inet.h>
 
 #include <osmocore/msgb.h>
-#include <osmocore/talloc.h>
 #include <osmocore/select.h>
 
 #include <openbsc/debug.h>
@@ -72,6 +73,8 @@
 	PROTO_RTCP,
 };
 
+#define DUMMY_LOAD 0x23
+
 
 static int udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
 {
@@ -83,6 +86,14 @@
 	return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
 }
 
+int mgcp_send_dummy(struct mgcp_endpoint *endp)
+{
+	static char buf[] = { DUMMY_LOAD };
+
+	return udp_send(endp->local_rtp.fd, &endp->remote,
+			endp->net_rtp, buf, 1);
+}
+
 static void patch_payload(int payload, char *data, int len)
 {
 	struct rtp_hdr *rtp_hdr;
@@ -90,6 +101,9 @@
 	if (len < sizeof(*rtp_hdr))
 		return;
 
+	if (payload < 0)
+		return;
+
 	rtp_hdr = (struct rtp_hdr *) data;
 	rtp_hdr->payload_type = payload;
 }
@@ -119,16 +133,14 @@
 	rc = recvfrom(fd->fd, &buf, sizeof(buf), 0,
 			    (struct sockaddr *) &addr, &slen);
 	if (rc < 0) {
-		LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x\n",
-			ENDPOINT_NUMBER(endp));
+		LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x errno: %d/%s\n",
+			ENDPOINT_NUMBER(endp), errno, strerror(errno));
 		return -1;
 	}
 
 	/* do not forward aynthing... maybe there is a packet from the bts */
-	if (endp->ci == CI_UNUSED) {
-		LOGP(DMGCP, LOGL_ERROR, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp));
+	if (endp->ci == CI_UNUSED)
 		return -1;
-	}
 
 	/*
 	 * Figure out where to forward it to. This code assumes that we
@@ -139,14 +151,16 @@
 	 */
 	#warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
 	dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 &&
-                    (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port)
+		    (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port)
 			? DEST_BTS : DEST_NETWORK;
 	proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
 
 	/* We have no idea who called us, maybe it is the BTS. */
 	if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || cfg->forward_ip)) {
 		/* it was the BTS... */
-		if (!cfg->bts_ip || memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0) {
+		if (!cfg->bts_ip
+		    || memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0
+		    || memcmp(&addr.sin_addr, &endp->bts, sizeof(endp->bts)) == 0) {
 			if (fd == &endp->local_rtp) {
 				endp->bts_rtp = addr.sin_port;
 			} else {
@@ -154,12 +168,27 @@
 			}
 
 			endp->bts = addr.sin_addr;
-			LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d\n",
-				ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp));
+			LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d of %s\n",
+				ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp),
+				inet_ntoa(addr.sin_addr));
+
 		}
 	}
 
-	/* dispatch */
+	/* throw away the dummy message */
+	if (rc == 1 && buf[0] == DUMMY_LOAD) {
+		LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy on 0x%x\n",
+			ENDPOINT_NUMBER(endp));
+		return 0;
+	}
+
+	/* do this before the loop handling */
+	if (dest == DEST_NETWORK)
+		++endp->in_bts;
+	else
+		++endp->in_remote;
+
+	/* For loop toggle the destination and then dispatch. */
 	if (cfg->audio_loop)
 		dest = !dest;
 
diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c
index f7ef547..d82bd68 100644
--- a/openbsc/src/mgcp/mgcp_protocol.c
+++ b/openbsc/src/mgcp/mgcp_protocol.c
@@ -80,11 +80,6 @@
 	}
 
 
-struct mgcp_msg_ptr {
-	unsigned int start;
-	unsigned int length;
-};
-
 struct mgcp_request {
 	char *name;
 	struct msgb *(*handle_request) (struct mgcp_config *cfg, struct msgb *msg);
@@ -98,6 +93,7 @@
 static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg);
 static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg);
 static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg);
+static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg);
 
 static int generate_call_id(struct mgcp_config *cfg)
 {
@@ -119,12 +115,6 @@
 	return cfg->last_call_id;
 }
 
-/* FIXIME/TODO: need to have a list of pending transactions and check that */
-static unsigned int generate_transaction_id()
-{
-	return abs(rand());
-}
-
 /*
  * array of function pointers for handling various
  * messages. In the future this might be binary sorted
@@ -135,6 +125,9 @@
 	MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
 	MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
 	MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
+
+	/* SPEC extension */
+	MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
 };
 
 static struct msgb *mgcp_msgb_alloc(void)
@@ -194,23 +187,6 @@
 	return mgcp_create_response_with_data(200, msg, trans_id, sdp_record);
 }
 
-/* send a static record */
-struct msgb *mgcp_create_rsip(void)
-{
-	struct msgb *msg;
-	int len;
-
-	msg = mgcp_msgb_alloc();
-	if (!msg)
-		return NULL;
-
-	len = snprintf((char *) msg->data, 2048,
-			"RSIP %u *@mgw MGCP 1.0\n"
-			"RM: restart\n", generate_transaction_id());
-	msg->l2h = msgb_put(msg, len);
-	return msg;
-}
-
 /*
  * handle incoming messages:
  *   - this can be a command (four letters, space, transaction id)
@@ -221,25 +197,25 @@
         int code;
 	struct msgb *resp = NULL;
 
-	if (msg->len < 4) {
+	if (msgb_l2len(msg) < 4) {
 		LOGP(DMGCP, LOGL_ERROR, "mgs too short: %d\n", msg->len);
 		return NULL;
 	}
 
         /* attempt to treat it as a response */
-        if (sscanf((const char *)&msg->data[0], "%3d %*s", &code) == 1) {
+        if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
 		LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
 	} else {
 		int i, handled = 0;
 		msg->l3h = &msg->l2h[4];
 		for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i)
-			if (strncmp(mgcp_requests[i].name, (const char *) &msg->data[0], 4) == 0) {
+			if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
 				handled = 1;
 				resp = mgcp_requests[i].handle_request(cfg, msg);
 				break;
 			}
 		if (!handled) {
-			LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->data[0]);
+			LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
 		}
 	}
 
@@ -296,9 +272,9 @@
 	return &cfg->endpoints[gw];
 }
 
-static int analyze_header(struct mgcp_config *cfg, struct msgb *msg,
-			  struct mgcp_msg_ptr *ptr, int size,
-			  const char **transaction_id, struct mgcp_endpoint **endp)
+int mgcp_analyze_header(struct mgcp_config *cfg, struct msgb *msg,
+			struct mgcp_msg_ptr *ptr, int size,
+			const char **transaction_id, struct mgcp_endpoint **endp)
 {
 	int found;
 
@@ -334,8 +310,11 @@
 	}
 
 	*transaction_id = (const char *)&msg->l3h[ptr[0].start];
-	*endp = find_endpoint(cfg, (const char *)&msg->l3h[ptr[1].start]);
-	return *endp == NULL;
+	if (endp) {
+		*endp = find_endpoint(cfg, (const char *)&msg->l3h[ptr[1].start]);
+		return *endp == NULL;
+	}
+	return 0;
 }
 
 static int verify_call_id(const struct mgcp_endpoint *endp,
@@ -369,7 +348,7 @@
 	const char *trans_id;
 	struct mgcp_endpoint *endp;
 
-	found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+	found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
 	if (found != 0)
 	    response = 500;
 	else
@@ -402,13 +381,20 @@
 	int error_code = 500;
 	int port;
 
-	found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+	found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
 	if (found != 0)
 		return create_response(500, "CRCX", trans_id);
 
 	if (endp->ci != CI_UNUSED) {
-		LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp));
-		return create_response(500, "CRCX", trans_id);
+		if (cfg->force_realloc) {
+			LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
+			    ENDPOINT_NUMBER(endp));
+			mgcp_free_endp(endp);
+		} else {
+			LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
+			     ENDPOINT_NUMBER(endp));
+			return create_response(500, "CRCX", trans_id);
+		}
 	}
 
 	/* parse CallID C: and LocalParameters L: */
@@ -500,8 +486,9 @@
 	const char *trans_id;
 	struct mgcp_endpoint *endp;
 	int error_code = 500;
+	int silent = 0;
 
-	found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+	found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
 	if (found != 0)
 		return create_response(error_code, "MDCX", trans_id);
 
@@ -532,6 +519,9 @@
 		    goto error3;
 		}
 		break;
+	case 'Z':
+		silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0;
+		break;
 	case '\0':
 		/* SDP file begins */
 		break;
@@ -577,6 +567,8 @@
 		case MGCP_POLICY_REJECT:
 			LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
 			     ENDPOINT_NUMBER(endp));
+			if (silent)
+				goto out_silent;
 			return create_response(500, "MDCX", trans_id);
 			break;
 		case MGCP_POLICY_DEFER:
@@ -594,6 +586,9 @@
 		ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), ntohs(endp->net_rtp));
 	if (cfg->change_cb)
 		cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, endp->rtp_port);
+	if (silent)
+		goto out_silent;
+
 	return create_response_with_sdp(endp, "MDCX", trans_id);
 
 error:
@@ -604,6 +599,10 @@
 
 error3:
 	return create_response(error_code, "MDCX", trans_id);
+
+
+out_silent:
+	return NULL;
 }
 
 static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
@@ -613,8 +612,9 @@
 	const char *trans_id;
 	struct mgcp_endpoint *endp;
 	int error_code = 500;
+	int silent = 0;
 
-	found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+	found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
 	if (found != 0)
 		return create_response(error_code, "DLCX", trans_id);
 
@@ -634,6 +634,9 @@
 		if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
 			goto error3;
 		break;
+	case 'Z':
+		silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0;
+		break;
 	}
 	default:
 		LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
@@ -649,6 +652,8 @@
 		case MGCP_POLICY_REJECT:
 			LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
 			     ENDPOINT_NUMBER(endp));
+			if (silent)
+				goto out_silent;
 			return create_response(500, "DLCX", trans_id);
 			break;
 		case MGCP_POLICY_DEFER:
@@ -662,10 +667,14 @@
 	}
 
 	/* free the connection */
+	LOGP(DMGCP, LOGL_NOTICE, "Deleted endpoint on: 0x%x Server: %s:%u\n",
+		ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), ntohs(endp->net_rtp));
 	mgcp_free_endp(endp);
 	if (cfg->change_cb)
 		cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, endp->rtp_port);
 
+	if (silent)
+		goto out_silent;
 	return create_response(250, "DLCX", trans_id);
 
 error:
@@ -676,6 +685,16 @@
 
 error3:
 	return create_response(error_code, "DLCX", trans_id);
+
+out_silent:
+	return NULL;
+}
+
+static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg)
+{
+	if (cfg->reset_cb)
+		cfg->reset_cb(cfg);
+	return NULL;
 }
 
 struct mgcp_config *mgcp_config_alloc(void)
@@ -722,7 +741,7 @@
 
 void mgcp_free_endp(struct mgcp_endpoint *endp)
 {
-	LOGP(DMGCP, LOGL_NOTICE, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
+	LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
 	endp->ci= CI_UNUSED;
 
 	if (endp->callid) {
@@ -732,7 +751,7 @@
 
 	if (endp->local_options) {
 		talloc_free(endp->local_options);
-		endp->callid = NULL;
+		endp->local_options = NULL;
 	}
 
 	if (!endp->cfg->early_bind) {
@@ -742,4 +761,7 @@
 
 	endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
 	endp->net_payload_type = endp->bts_payload_type = -1;
+	endp->in_bts = endp->in_remote = 0;
+	memset(&endp->remote, 0, sizeof(endp->remote));
+	memset(&endp->bts, 0, sizeof(endp->bts));
 }
diff --git a/openbsc/src/mgcp/mgcp_vty.c b/openbsc/src/mgcp/mgcp_vty.c
index f13b3cf..ea59abf 100644
--- a/openbsc/src/mgcp/mgcp_vty.c
+++ b/openbsc/src/mgcp/mgcp_vty.c
@@ -29,9 +29,12 @@
 #include <openbsc/debug.h>
 #include <openbsc/mgcp.h>
 #include <openbsc/mgcp_internal.h>
+#include <openbsc/vty.h>
 
-#include <vty/command.h>
-#include <vty/vty.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/vty.h>
+
+#include <string.h>
 
 static struct mgcp_config *g_cfg = NULL;
 
@@ -48,21 +51,25 @@
 {
 	vty_out(vty, "mgcp%s", VTY_NEWLINE);
 	if (g_cfg->local_ip)
-		vty_out(vty, " local ip %s%s", g_cfg->local_ip, VTY_NEWLINE);
-	if (g_cfg->bts_ip)
+		vty_out(vty, "  local ip %s%s", g_cfg->local_ip, VTY_NEWLINE);
+	if (g_cfg->bts_ip && strlen(g_cfg->bts_ip) != 0)
 		vty_out(vty, "  bts ip %s%s", g_cfg->bts_ip, VTY_NEWLINE);
 	vty_out(vty, "  bind ip %s%s", g_cfg->source_addr, VTY_NEWLINE);
 	vty_out(vty, "  bind port %u%s", g_cfg->source_port, VTY_NEWLINE);
 	vty_out(vty, "  bind early %u%s", !!g_cfg->early_bind, VTY_NEWLINE);
 	vty_out(vty, "  rtp base %u%s", g_cfg->rtp_base_port, VTY_NEWLINE);
-	vty_out(vty, "  sdp audio payload number %u%s", g_cfg->audio_payload, VTY_NEWLINE);
-	vty_out(vty, "  sdp audio payload name %s%s", g_cfg->audio_name, VTY_NEWLINE);
+	if (g_cfg->audio_payload != -1)
+		vty_out(vty, "  sdp audio payload number %d%s", g_cfg->audio_payload, VTY_NEWLINE);
+	if (g_cfg->audio_name)
+		vty_out(vty, "  sdp audio payload name %s%s", g_cfg->audio_name, VTY_NEWLINE);
 	vty_out(vty, "  loop %u%s", !!g_cfg->audio_loop, VTY_NEWLINE);
-	vty_out(vty, "  endpoints %u%s", g_cfg->number_endpoints, VTY_NEWLINE);
+	vty_out(vty, "  number endpoints %u%s", g_cfg->number_endpoints - 1, VTY_NEWLINE);
 	if (g_cfg->forward_ip)
-		vty_out(vty, " forward audio ip %s%s", g_cfg->forward_ip, VTY_NEWLINE);
+		vty_out(vty, "  forward audio ip %s%s", g_cfg->forward_ip, VTY_NEWLINE);
 	if (g_cfg->forward_port != 0)
-		vty_out(vty, " forward audio port %d%s", g_cfg->forward_port, VTY_NEWLINE);
+		vty_out(vty, "  forward audio port %d%s", g_cfg->forward_port, VTY_NEWLINE);
+	if (g_cfg->call_agent_addr)
+		vty_out(vty, "  call agent ip %s%s", g_cfg->call_agent_addr, VTY_NEWLINE);
 
 	return CMD_SUCCESS;
 }
@@ -75,10 +82,12 @@
 	vty_out(vty, "MGCP is up and running with %u endpoints:%s", g_cfg->number_endpoints - 1, VTY_NEWLINE);
 	for (i = 1; i < g_cfg->number_endpoints; ++i) {
 		struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
-		vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s",
+		vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u on %s traffic received bts: %u  remote: %u%s",
 			i, endp->ci,
 			ntohs(endp->net_rtp), ntohs(endp->net_rtcp),
-			ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE);
+			ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp),
+			inet_ntoa(endp->bts), endp->in_bts, endp->in_remote,
+			VTY_NEWLINE);
 	}
 
 	return CMD_SUCCESS;
@@ -95,7 +104,7 @@
 
 DEFUN(cfg_mgcp_local_ip,
       cfg_mgcp_local_ip_cmd,
-      "local ip IP",
+      "local ip A.B.C.D",
       "Set the IP to be used in SDP records")
 {
 	if (g_cfg->local_ip)
@@ -106,7 +115,7 @@
 
 DEFUN(cfg_mgcp_bts_ip,
       cfg_mgcp_bts_ip_cmd,
-      "bts ip IP",
+      "bts ip A.B.C.D",
       "Set the IP of the BTS for RTP forwarding")
 {
 	if (g_cfg->bts_ip)
@@ -118,7 +127,7 @@
 
 DEFUN(cfg_mgcp_bind_ip,
       cfg_mgcp_bind_ip_cmd,
-      "bind ip IP",
+      "bind ip A.B.C.D",
       "Bind the MGCP to this local addr")
 {
 	if (g_cfg->source_addr)
@@ -133,11 +142,6 @@
       "Bind the MGCP to this port")
 {
 	unsigned int port = atoi(argv[0]);
-	if (port > 65534) {
-		vty_out(vty, "%% wrong bind port '%s'%s", argv[0], VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
 	g_cfg->source_port = port;
 	return CMD_SUCCESS;
 }
@@ -148,11 +152,6 @@
       "Bind all RTP ports early")
 {
 	unsigned int bind = atoi(argv[0]);
-	if (bind != 0 && bind != 1) {
-		vty_out(vty, "%% param must be 0 or 1.%s", VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
 	g_cfg->early_bind = bind == 1;
 	return CMD_SUCCESS;
 }
@@ -163,11 +162,6 @@
       "Base port to use")
 {
 	unsigned int port = atoi(argv[0]);
-	if (port > 65534) {
-		vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
 	g_cfg->rtp_base_port = port;
 	return CMD_SUCCESS;
 }
@@ -178,11 +172,6 @@
       "Set the audio codec to use")
 {
 	unsigned int payload = atoi(argv[0]);
-	if (payload > 255) {
-		vty_out(vty, "%% wrong payload number '%s'%s", argv[0], VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
 	g_cfg->audio_payload = payload;
 	return CMD_SUCCESS;
 }
@@ -219,7 +208,7 @@
 
 DEFUN(cfg_mgcp_forward_ip,
       cfg_mgcp_forward_ip_cmd,
-      "forward audio ip IP",
+      "forward audio ip A.B.C.D",
       "Forward packets from and to the IP. This disables most of the MGCP feature.")
 {
 	if (g_cfg->forward_ip)
@@ -237,13 +226,26 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_mgcp_agent_addr,
+      cfg_mgcp_agent_addr_cmd,
+      "call agent ip IP",
+      "Set the address of the call agent.")
+{
+	if (g_cfg->call_agent_addr)
+		talloc_free(g_cfg->call_agent_addr);
+	g_cfg->call_agent_addr = talloc_strdup(g_cfg, argv[0]);
+	return CMD_SUCCESS;
+}
+
 int mgcp_vty_init(void)
 {
-	install_element(VIEW_NODE, &show_mgcp_cmd);
+	install_element_ve(&show_mgcp_cmd);
 
 	install_element(CONFIG_NODE, &cfg_mgcp_cmd);
 	install_node(&mgcp_node, config_write_mgcp);
 	install_default(MGCP_NODE);
+	install_element(MGCP_NODE, &ournode_exit_cmd);
+	install_element(MGCP_NODE, &ournode_end_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd);
@@ -256,6 +258,7 @@
 	install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_forward_ip_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_forward_port_cmd);
+	install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd);
 	return 0;
 }
 
@@ -264,7 +267,7 @@
 	int i, rc;
 
 	g_cfg = cfg;
-	rc = vty_read_config_file(config_file);
+	rc = vty_read_config_file(config_file, NULL);
 	if (rc < 0) {
 		fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
 		return rc;
@@ -274,6 +277,11 @@
 	if (!g_cfg->bts_ip)
 		fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n");
 
+	if (!g_cfg->source_addr) {
+		fprintf(stderr, "You need to specify a bind address.\n");
+		return -1;
+	}
+
 	if (mgcp_endpoints_allocate(g_cfg) != 0) {
 		fprintf(stderr, "Failed to allocate endpoints: %d. Quitting.\n", g_cfg->number_endpoints);
 		return -1;
@@ -281,8 +289,8 @@
 
 	/*
 	 * This application supports two modes.
-         *    1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX
-         *    2.) plain forwarding of RTP packets on the endpoints.
+	 *    1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX
+	 *    2.) plain forwarding of RTP packets on the endpoints.
 	 * both modes are mutual exclusive
 	 */
 	if (g_cfg->forward_ip) {
@@ -327,13 +335,3 @@
 	return !!g_cfg->forward_ip;
 }
 
-struct gsm_network;
-int bsc_vty_init(struct gsm_network *dummy)
-{
-	cmd_init(1);
-	vty_init();
-
-        mgcp_vty_init();
-	return 0;
-}
-
diff --git a/openbsc/src/mncc.c b/openbsc/src/mncc.c
index 01d59aa..afd5364 100644
--- a/openbsc/src/mncc.c
+++ b/openbsc/src/mncc.c
@@ -332,16 +332,16 @@
 	remote_trans = trans_find_by_callref(call->net, call->remote_ref);
 
 	/* this shouldn't really happen */
-	if (!remote_trans || !remote_trans->lchan) {
+	if (!remote_trans || !remote_trans->conn) {
 		LOGP(DMNCC, LOGL_ERROR, "No transaction or transaction without lchan?!?\n");
 		return -EIO;
 	}
 
 	/* RTP socket of remote end has meanwhile died */
-	if (!remote_trans->lchan->abis_ip.rtp_socket)
+	if (!remote_trans->conn->lchan->abis_ip.rtp_socket)
 		return -EIO;
 
-	return rtp_send_frame(remote_trans->lchan->abis_ip.rtp_socket, dfr);
+	return rtp_send_frame(remote_trans->conn->lchan->abis_ip.rtp_socket, dfr);
 }
 
 
diff --git a/openbsc/src/openbsc.cfg.nanobts b/openbsc/src/openbsc.cfg.nanobts
index a1ceaec..da0ba74 100644
--- a/openbsc/src/openbsc.cfg.nanobts
+++ b/openbsc/src/openbsc.cfg.nanobts
@@ -1,6 +1,6 @@
 !
 ! OpenBSC configuration saved from vty
-!
+!   !
 password foo
 !
 line vty
@@ -11,17 +11,52 @@
  mobile network code 1
  short name OpenBSC
  long name OpenBSC
+ auth policy closed
+ location updating reject cause 13
+ encryption a5 0
+ neci 0
+ rrlp mode none
+ mm info 1
+ handover 0
+ handover window rxlev averaging 10
+ handover window rxqual averaging 1
+ handover window rxlev neighbor averaging 10
+ handover power budget interval 6
+ handover power budget hysteresis 3
+ handover maximum distance 9999
  timer t3101 10
+ timer t3103 0
+ timer t3105 0
+ timer t3107 0
+ timer t3109 0
+ timer t3111 0
  timer t3113 60
+ timer t3115 0
+ timer t3117 0
+ timer t3119 0
+ timer t3141 0
  bts 0
   type nanobts
-  ip.access unit_id 1801 0
-  band GSM1800
+  band DCS1800
+  cell_identity 0
   location_area_code 1
   training_sequence_code 7
   base_station_id_code 63
+  ms max power 15
+  cell reselection hysteresis 4
+  rxlev access min 0
+  channel allocator ascending
+  rach tx integer 9
+  rach max transmission 7
+  ip.access unit_id 1801 0
+  oml ip.access stream_id 255
+  gprs mode none
   trx 0
+   rf_locked 0
    arfcn 514
+   nominal power 23
+   max_power_red 20
+   rsl e1 tei 0
     timeslot 0
      phys_chan_config CCCH+SDCCH4
     timeslot 1
diff --git a/openbsc/src/openbsc.cfg.nanobts.multitrx b/openbsc/src/openbsc.cfg.nanobts.multitrx
new file mode 100644
index 0000000..6e27ff5
--- /dev/null
+++ b/openbsc/src/openbsc.cfg.nanobts.multitrx
@@ -0,0 +1,97 @@
+!
+! OpenBSC configuration saved from vty
+!   !
+password foo
+!
+line vty
+ no login
+!
+network
+ network country code 1
+ mobile network code 1
+ short name OpenBSC
+ long name OpenBSC
+ auth policy closed
+ location updating reject cause 13
+ encryption a5 0
+ neci 0
+ rrlp mode none
+ mm info 0
+ handover 0
+ handover window rxlev averaging 10
+ handover window rxqual averaging 1
+ handover window rxlev neighbor averaging 10
+ handover power budget interval 6
+ handover power budget hysteresis 3
+ handover maximum distance 9999
+ timer t3101 10
+ timer t3103 0
+ timer t3105 0
+ timer t3107 0
+ timer t3109 0
+ timer t3111 0
+ timer t3113 60
+ timer t3115 0
+ timer t3117 0
+ timer t3119 0
+ timer t3141 0
+ bts 0
+  type nanobts
+  band DCS1800
+  cell_identity 0
+  location_area_code 1
+  training_sequence_code 7
+  base_station_id_code 63
+  ms max power 15
+  cell reselection hysteresis 4
+  rxlev access min 0
+  channel allocator ascending
+  rach tx integer 9
+  rach max transmission 7
+  ip.access unit_id 1800 0
+  oml ip.access stream_id 255
+  gprs mode none
+  trx 0
+   rf_locked 0
+   arfcn 871
+   nominal power 23
+   max_power_red 0
+   rsl e1 tei 0
+    timeslot 0
+     phys_chan_config CCCH+SDCCH4
+    timeslot 1
+     phys_chan_config SDCCH8
+    timeslot 2
+     phys_chan_config TCH/F
+    timeslot 3
+     phys_chan_config TCH/F
+    timeslot 4
+     phys_chan_config TCH/F
+    timeslot 5
+     phys_chan_config TCH/F
+    timeslot 6
+     phys_chan_config TCH/F
+    timeslot 7
+     phys_chan_config TCH/F
+  trx 1
+   rf_locked 0
+   arfcn 873
+   nominal power 23
+   max_power_red 0
+   rsl e1 tei 0
+    timeslot 0
+     phys_chan_config SDCCH8
+    timeslot 1
+     phys_chan_config TCH/F
+    timeslot 2
+     phys_chan_config TCH/F
+    timeslot 3
+     phys_chan_config TCH/F
+    timeslot 4
+     phys_chan_config TCH/F
+    timeslot 5
+     phys_chan_config TCH/F
+    timeslot 6
+     phys_chan_config TCH/F
+    timeslot 7
+     phys_chan_config TCH/F
diff --git a/openbsc/src/osmo_msc.c b/openbsc/src/osmo_msc.c
new file mode 100644
index 0000000..b647a81
--- /dev/null
+++ b/openbsc/src/osmo_msc.c
@@ -0,0 +1,50 @@
+/* main MSC management code... */
+
+/*
+ * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (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 <openbsc/bsc_api.h>
+#include <openbsc/debug.h>
+
+#include <openbsc/gsm_04_11.h>
+
+static void msc_sapi_n_reject(struct gsm_subscriber_connection* conn, int dlci)
+{
+	int sapi = dlci & 0x7;
+
+	if (sapi == UM_SAPI_SMS)
+		gsm411_sapi_n_reject(conn);
+}
+
+static void msc_clear_request(struct gsm_subscriber_connection* conn, uint32_t cause)
+{
+	gsm0408_clear_request(conn, cause);
+}
+
+static struct bsc_api msc_handler = {
+	.sapi_n_reject = msc_sapi_n_reject,
+	.clear_request = msc_clear_request,
+};
+
+struct bsc_api *msc_bsc_api() {
+	return &msc_handler;
+}
diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c
index 7c3750d..12ed903 100644
--- a/openbsc/src/paging.c
+++ b/openbsc/src/paging.c
@@ -45,6 +45,7 @@
 #include <openbsc/signal.h>
 #include <openbsc/abis_rsl.h>
 #include <openbsc/gsm_data.h>
+#include <openbsc/chan_alloc.h>
 
 void *tall_paging_ctx;
 
@@ -70,14 +71,6 @@
 static void paging_remove_request(struct gsm_bts_paging_state *paging_bts,
 				struct gsm_paging_request *to_be_deleted)
 {
-	/* Update the last_request if that is necessary */
-	if (to_be_deleted == paging_bts->last_request) {
-		paging_bts->last_request =
-			(struct gsm_paging_request *)paging_bts->last_request->entry.next;
-		if (&to_be_deleted->entry == &paging_bts->pending_requests)
-			paging_bts->last_request = NULL;
-	}
-
 	bsc_del_timer(&to_be_deleted->T3113);
 	llist_del(&to_be_deleted->entry);
 	subscr_put(to_be_deleted->subscr);
@@ -90,7 +83,7 @@
 	unsigned int mi_len;
 	unsigned int page_group;
 
-	DEBUGP(DPAG, "Going to send paging commands: imsi: '%s' tmsi: '0x%x'\n",
+	LOGP(DPAG, LOGL_INFO, "Going to send paging commands: imsi: '%s' tmsi: '0x%x'\n",
 		request->subscr->imsi, request->subscr->tmsi);
 
 	if (request->subscr->tmsi == GSM_RESERVED_TMSI)
@@ -103,14 +96,6 @@
 			request->chan_type);
 }
 
-static void paging_move_to_next(struct gsm_bts_paging_state *paging_bts)
-{
-	paging_bts->last_request =
-		(struct gsm_paging_request *)paging_bts->last_request->entry.next;
-	if (&paging_bts->last_request->entry == &paging_bts->pending_requests)
-		paging_bts->last_request = NULL;
-}
-
 /*
  * This is kicked by the periodic PAGING LOAD Indicator
  * coming from abis_rsl.c
@@ -128,17 +113,26 @@
 	 * return then.
 	 */
 	if (llist_empty(&paging_bts->pending_requests)) {
-		paging_bts->last_request = NULL;
 		/* since the list is empty, no need to reschedule the timer */
 		return;
 	}
 
-	if (!paging_bts->last_request)
-		paging_bts->last_request =
-			(struct gsm_paging_request *)paging_bts->pending_requests.next;
+	/*
+	 * In case the BTS does not provide us with load indication just fill
+	 * up our slots for this round. We should be able to page 20 subscribers
+	 * every two seconds. So we will just give the BTS some extra credit.
+	 * We will have to see how often we run out of this credit, so we might
+	 * need a low watermark and then add credit or give 20 every run when
+	 * the bts sets an option for that.
+	 */
+	if (paging_bts->available_slots == 0) {
+		LOGP(DPAG, LOGL_NOTICE, "No slots available on bts nr %d\n",
+		     paging_bts->bts->nr);
+		paging_bts->available_slots = 20;
+	}
 
-	assert(paging_bts->last_request);
-	initial_request = paging_bts->last_request;
+	initial_request = llist_entry(paging_bts->pending_requests.next,
+				      struct gsm_paging_request, entry);
 	current_request = initial_request;
 
 	do {
@@ -146,21 +140,17 @@
 		page_ms(current_request);
 		paging_bts->available_slots--;
 
-		/*
-		 * move to the next item. We might wrap around
-		 * this means last_request will be NULL and we just
-		 * call paging_page_to_next again. It it guranteed
-		 * that the list is not empty.
-		 */
-		paging_move_to_next(paging_bts);
-		if (!paging_bts->last_request)
-			paging_bts->last_request =
-				(struct gsm_paging_request *)paging_bts->pending_requests.next;
-		current_request = paging_bts->last_request;
+		/* take the current and add it to the back */
+		llist_del(&current_request->entry);
+		llist_add_tail(&current_request->entry, &paging_bts->pending_requests);
+
+		/* take the next request */
+		current_request = llist_entry(paging_bts->pending_requests.next,
+					      struct gsm_paging_request, entry);
 	} while (paging_bts->available_slots > 0
 		    &&  initial_request != current_request);
 
-	bsc_schedule_timer(&paging_bts->work_timer, 1, 0);
+	bsc_schedule_timer(&paging_bts->work_timer, 2, 0);
 }
 
 static void paging_worker(void *data)
@@ -178,7 +168,7 @@
 	bts->paging.work_timer.data = &bts->paging;
 
 	/* Large number, until we get a proper message */
-	bts->paging.available_slots = 100;
+	bts->paging.available_slots = 20;
 }
 
 static int paging_pending_request(struct gsm_bts_paging_state *bts,
@@ -200,7 +190,7 @@
 	void *cbfn_param;
 	gsm_cbfn *cbfn;
 
-	DEBUGP(DPAG, "T3113 expired for request %p (%s)\n",
+	LOGP(DPAG, LOGL_INFO, "T3113 expired for request %p (%s)\n",
 		req, req->subscr->imsi);
 	
 	sig_data.subscr = req->subscr;
@@ -208,11 +198,11 @@
 	sig_data.lchan	= NULL;
 
 	/* must be destroyed before calling cbfn, to prevent double free */
+	counter_inc(req->bts->network->stats.paging.expired);
 	cbfn_param = req->cbfn_param;
 	cbfn = req->cbfn;
 	paging_remove_request(&req->bts->paging, req);
 
-	counter_inc(req->bts->network->stats.paging.expired);
 
 	dispatch_signal(SS_PAGING, S_PAGING_EXPIRED, &sig_data);
 	if (cbfn)
@@ -227,11 +217,11 @@
 	struct gsm_paging_request *req;
 
 	if (paging_pending_request(bts_entry, subscr)) {
-		DEBUGP(DPAG, "Paging request already pending\n");
+		LOGP(DPAG, LOGL_INFO, "Paging request already pending for %s\n", subscr->imsi);
 		return -EEXIST;
 	}
 
-	DEBUGP(DPAG, "Start paging of subscriber %llu on bts %d.\n",
+	LOGP(DPAG, LOGL_DEBUG, "Start paging of subscriber %llu on bts %d.\n",
 		subscr->id, bts->nr);
 	req = talloc_zero(tall_paging_ctx, struct gsm_paging_request);
 	req->subscr = subscr_get(subscr);
@@ -245,7 +235,7 @@
 	llist_add_tail(&req->entry, &bts_entry->pending_requests);
 
 	if (!bsc_timer_pending(&bts_entry->work_timer))
-		bsc_schedule_timer(&bts_entry->work_timer, 1, 0);
+		bsc_schedule_timer(&bts_entry->work_timer, 2, 0);
 
 	return 0;
 }
@@ -296,11 +286,11 @@
 				 entry) {
 		if (req->subscr == subscr) {
 			if (lchan && req->cbfn) {
-				DEBUGP(DPAG, "Stop paging on bts %d, calling cbfn.\n", bts->nr);
+				LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d, calling cbfn.\n", bts->nr);
 				req->cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
 					  NULL, lchan, req->cbfn_param);
 			} else
-				DEBUGP(DPAG, "Stop paging on bts %d silently.\n", bts->nr);
+				LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d silently.\n", bts->nr);
 			paging_remove_request(&bts->paging, req);
 			break;
 		}
@@ -328,7 +318,7 @@
 			break;
 
 		/* Stop paging */
-                if (bts != _bts)
+		if (bts != _bts)
 			_paging_request_stop(bts, subscr, NULL);
 	} while (1);
 }
diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c
index 16996ce..d9f5da5 100644
--- a/openbsc/src/rest_octets.c
+++ b/openbsc/src/rest_octets.c
@@ -133,6 +133,7 @@
 			     const struct gsm48_lsa_params *lsa_params)
 {
 	/* FIXME */
+	return -1;
 }
 
 /* Generate SI4 Rest Octets (Chapter 10.5.2.35) */
@@ -315,11 +316,42 @@
 	bitvec_set_bit(bv, 1);
 	bitvec_set_uint(bv, gco->bs_cv_max, 4);
 
-	/* hard-code no PAN_{DEC,INC,MAX} */
-	bitvec_set_bit(bv, 0);
+	if (0) {
+		/* hard-code no PAN_{DEC,INC,MAX} */
+		bitvec_set_bit(bv, 0);
+	} else {
+		/* copied from ip.access BSC protocol trace */
+		bitvec_set_bit(bv, 1);
+		bitvec_set_uint(bv, 1, 3);	/* DEC */
+		bitvec_set_uint(bv, 1, 3);	/* INC */
+		bitvec_set_uint(bv, 15, 3);	/* MAX */
+	}
 
-	/* no extension information (EDGE) */
-	bitvec_set_bit(bv, 0);
+	if (!gco->ext_info_present) {
+		/* no extension information */
+		bitvec_set_bit(bv, 0);
+	} else {
+		/* extension information */
+		bitvec_set_bit(bv, 1);
+		if (!gco->ext_info.egprs_supported) {
+			/* 6bit length of extension */
+			bitvec_set_uint(bv, (1 + 3)-1, 6);
+			/* EGPRS supported in the cell */
+			bitvec_set_bit(bv, 0);
+		} else {
+			/* 6bit length of extension */
+			bitvec_set_uint(bv, (1 + 5 + 3)-1, 6);
+			/* EGPRS supported in the cell */
+			bitvec_set_bit(bv, 1);
+			/* 1bit EGPRS PACKET CHANNEL REQUEST */
+			bitvec_set_bit(bv, gco->ext_info.use_egprs_p_ch_req);
+			/* 4bit BEP PERIOD */
+			bitvec_set_uint(bv, gco->ext_info.bep_period, 4);
+		}
+		bitvec_set_bit(bv, gco->ext_info.pfc_supported);
+		bitvec_set_bit(bv, gco->ext_info.dtm_supported);
+		bitvec_set_bit(bv, gco->ext_info.bss_paging_coordination);
+	}
 
 	return 0;
 }
@@ -334,7 +366,7 @@
 	bitvec_set_uint(bv, pcp->n_avg_i, 4);
 }
 
-/* Generate SI13 Rest Octests (Chapter 10.5.2.37b) */
+/* Generate SI13 Rest Octests (04.08 Chapter 10.5.2.37b) */
 int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13)
 {
 	struct bitvec bv;
@@ -390,6 +422,11 @@
 				break;
 			}
 		}
+		/* 3GPP TS 44.018 Release 6 / 10.5.2.37b */
+		bitvec_set_bit(&bv, H);	/* added Release 99 */
+		/* claim our SGSN is compatible with Release 99, as EDGE and EGPRS
+		 * was only added in this Release */
+		bitvec_set_bit(&bv, 1);
 	}
 	bitvec_spare_padding(&bv, (bv.data_len*8)-1);
 	return bv.data_len;
diff --git a/openbsc/src/rs232.c b/openbsc/src/rs232.c
index 36af59c..22adf56 100644
--- a/openbsc/src/rs232.c
+++ b/openbsc/src/rs232.c
@@ -156,7 +156,7 @@
 				fprintf(stderr, "Invalid length in hdr: %u\n",
 					sh->rxmsg_bytes_missing);
 		}
-	} else { 
+	} else {
 		/* try to read as many of the missing bytes as are available */
 		rc = read(sh->fd.fd, msg->tail, sh->rxmsg_bytes_missing);
 		if (rc < 0) {
diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c
index 9f2e2fd..924173d 100644
--- a/openbsc/src/rtp_proxy.c
+++ b/openbsc/src/rtp_proxy.c
@@ -91,9 +91,6 @@
 
 #define RTP_VERSION	2
 
-#define RTP_PT_GSM_FULL	3
-#define RTP_PT_GSM_EFR	97
-
 /* decode an rtp frame and create a new buffer with payload */
 static int rtp_decode(struct msgb *msg, u_int32_t callref, struct msgb **data)
 {
@@ -504,7 +501,7 @@
 	return 0;
 }
 
-static void init_rss(struct rtp_sub_socket *rss, 
+static void init_rss(struct rtp_sub_socket *rss,
 		     struct rtp_socket *rs, int fd, int priv_nr)
 {
 	/* initialize bfd */
diff --git a/openbsc/src/silent_call.c b/openbsc/src/silent_call.c
index cada24e..8bd5341 100644
--- a/openbsc/src/silent_call.c
+++ b/openbsc/src/silent_call.c
@@ -38,6 +38,7 @@
 static int paging_cb_silent(unsigned int hooknum, unsigned int event,
 			    struct msgb *msg, void *_lchan, void *_data)
 {
+	struct gsm_subscriber_connection *conn;
 	struct gsm_lchan *lchan = _lchan;
 	struct scall_signal_data sigdata;
 	int rc;
@@ -47,6 +48,8 @@
 
 	DEBUGP(DSMS, "paging_cb_silent: ");
 
+	conn = &lchan->conn;
+
 	sigdata.lchan = lchan;
 	sigdata.data = _data;
 
@@ -54,10 +57,10 @@
 	case GSM_PAGING_SUCCEEDED:
 		DEBUGPC(DSMS, "success, using Timeslot %u on ARFCN %u\n",
 			lchan->ts->nr, lchan->ts->trx->arfcn);
-		lchan->silent_call = 1;
+		conn->silent_call = 1;
 		/* increment lchan reference count */
 		dispatch_signal(SS_SCALL, S_SCALL_SUCCESS, &sigdata);
-		use_lchan(lchan);
+		use_subscr_con(conn);
 		break;
 	case GSM_PAGING_EXPIRED:
 		DEBUGP(DSMS, "expired\n");
@@ -97,7 +100,7 @@
 	int i;
 
 	/* if we're not part of a silent call, never reroute */
-	if (!msg->lchan->silent_call)
+	if (!msg->lchan->conn.silent_call)
 		return 0;
 
 	/* check if we are a special message that is handled in openbsc */
@@ -126,16 +129,18 @@
 int gsm_silent_call_stop(struct gsm_subscriber *subscr)
 {
 	struct gsm_lchan *lchan;
+	struct gsm_subscriber_connection *conn;
 
 	lchan = lchan_for_subscr(subscr);
 	if (!lchan)
 		return -EINVAL;
 
 	/* did we actually establish a silent call for this guy? */
-	if (!lchan->silent_call)
+	conn = &lchan->conn;
+	if (!conn->silent_call)
 		return -EINVAL;
 
-	put_lchan(lchan);
+	put_subscr_con(conn);
 
 	return 0;
 }
diff --git a/openbsc/src/socket.c b/openbsc/src/socket.c
new file mode 100644
index 0000000..d60c43e
--- /dev/null
+++ b/openbsc/src/socket.c
@@ -0,0 +1,108 @@
+/* OpenBSC sokcet code, taken from Abis input driver for ip.access */
+
+/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ * (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 <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+
+#include <osmocore/select.h>
+#include <osmocore/tlv.h>
+#include <osmocore/msgb.h>
+#include <openbsc/debug.h>
+#include <openbsc/gsm_data.h>
+#include <osmocore/talloc.h>
+
+int make_sock(struct bsc_fd *bfd, int proto, u_int32_t ip, u_int16_t port,
+	      int (*cb)(struct bsc_fd *fd, unsigned int what))
+{
+	struct sockaddr_in addr;
+	int ret, on = 1;
+	int type = SOCK_STREAM;
+
+	switch (proto) {
+	case IPPROTO_TCP:
+		type = SOCK_STREAM;
+		break;
+	case IPPROTO_UDP:
+		type = SOCK_DGRAM;
+		break;
+	case IPPROTO_GRE:
+		type = SOCK_RAW;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	bfd->fd = socket(AF_INET, type, proto);
+	bfd->cb = cb;
+	bfd->when = BSC_FD_READ;
+	//bfd->data = line;
+
+	if (bfd->fd < 0) {
+		LOGP(DINP, LOGL_ERROR, "could not create socket.\n");
+		return -EIO;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	if (ip)
+		addr.sin_addr.s_addr = htonl(ip);
+	else
+		addr.sin_addr.s_addr = INADDR_ANY;
+
+	setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+	ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
+	if (ret < 0) {
+		LOGP(DINP, LOGL_ERROR, "could not bind socket %s\n",
+			strerror(errno));
+		close(bfd->fd);
+		return -EIO;
+	}
+
+	if (proto == IPPROTO_TCP) {
+		ret = listen(bfd->fd, 1);
+		if (ret < 0) {
+			perror("listen");
+			return ret;
+		}
+	}
+
+	ret = bsc_register_fd(bfd);
+	if (ret < 0) {
+		perror("register_listen_fd");
+		close(bfd->fd);
+		return ret;
+	}
+	return 0;
+}
diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c
index 3f9d609..eb4ac7c 100644
--- a/openbsc/src/system_information.c
+++ b/openbsc/src/system_information.c
@@ -397,18 +397,28 @@
 
 static struct gsm48_si13_info si13_default = {
 	.cell_opts = {
-		.nmo 		= GPRS_NMO_III,
-		.t3168		= 1500,
-		.t3192		= 500,
+		.nmo 		= GPRS_NMO_II,
+		.t3168		= 2000,
+		.t3192		= 200,
 		.drx_timer_max	= 3,
 		.bs_cv_max	= 15,
+		.ext_info_present = 1,
+		.ext_info = {
+			/* The values below are just guesses ! */
+			.egprs_supported = 0,
+			.use_egprs_p_ch_req = 1,
+			.bep_period = 5,
+			.pfc_supported = 0,
+			.dtm_supported = 0,
+			.bss_paging_coordination = 0,
+		},
 	},
 	.pwr_ctrl_pars = {
 		.alpha		= 10,	/* a = 1.0 */
-		.t_avg_w	= 25,
-		.t_avg_t	= 25,
+		.t_avg_w	= 16,
+		.t_avg_t	= 16,
 		.pc_meas_chan	= 0, 	/* downling measured on CCCH */
-		.n_avg_i	= 15,
+		.n_avg_i	= 8,
 	},
 	.bcch_change_mark	= 1,
 	.si_change_field	= 0,
@@ -448,7 +458,18 @@
 
 int gsm_generate_si(u_int8_t *output, struct gsm_bts *bts, int type)
 {
-	si_info.gprs_ind.present = bts->gprs.enabled;
+	switch (bts->gprs.mode) {
+	case BTS_GPRS_EGPRS:
+		si13_default.cell_opts.ext_info_present = 1;
+		si13_default.cell_opts.ext_info.egprs_supported = 1;
+		/* fallthrough */
+	case BTS_GPRS_GPRS:
+		si_info.gprs_ind.present = 1;
+		break;
+	case BTS_GPRS_NONE:
+		si_info.gprs_ind.present = 0;
+		break;
+	}
 
 	switch (type) {
 	case RSL_SYSTEM_INFO_1:
diff --git a/openbsc/src/talloc_ctx.c b/openbsc/src/talloc_ctx.c
index 6379e13..8e7ec23 100644
--- a/openbsc/src/talloc_ctx.c
+++ b/openbsc/src/talloc_ctx.c
@@ -4,6 +4,7 @@
 extern void *tall_msgb_ctx;
 extern void *tall_fle_ctx;
 extern void *tall_locop_ctx;
+extern void *tall_authciphop_ctx;
 extern void *tall_gsms_ctx;
 extern void *tall_subscr_ctx;
 extern void *tall_sub_req_ctx;
@@ -19,9 +20,10 @@
 void talloc_ctx_init(void)
 {
 	tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb");
-	tall_fle_ctx = talloc_named_const(tall_bsc_ctx, 0, 
+	tall_fle_ctx = talloc_named_const(tall_bsc_ctx, 0,
 					  "bs11_file_list_entry");
 	tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 0, "loc_updating_oper");
+	tall_authciphop_ctx = talloc_named_const(tall_bsc_ctx, 0, "auth_ciph_oper");
 	tall_gsms_ctx = talloc_named_const(tall_bsc_ctx, 0, "sms");
 	tall_subscr_ctx = talloc_named_const(tall_bsc_ctx, 0, "subscriber");
 	tall_sub_req_ctx = talloc_named_const(tall_bsc_ctx, 0, "subscr_request");
diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c
deleted file mode 100644
index aa119b4..0000000
--- a/openbsc/src/telnet_interface.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/* 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 <openbsc/telnet_interface.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/gsm_04_11.h>
-#include <osmocore/msgb.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/paging.h>
-#include <openbsc/signal.h>
-#include <osmocore/talloc.h>
-#include <openbsc/debug.h>
-
-#include <vty/buffer.h>
-
-#define WRITE_CONNECTION(fd, msg...) \
-	int ret; \
-	char buf[4096]; \
-	snprintf(buf, sizeof(buf), msg); \
-	ret = write(fd, buf, strlen(buf));
-
-
-/* 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,
-};
-
-void telnet_init(struct gsm_network *network, int port) {
-	struct sockaddr_in sock_addr;
-	int fd, on = 1;
-
-	tall_telnet_ctx = talloc_named_const(tall_bsc_ctx, 1,
-					     "telnet_connection");
-
-	bsc_vty_init(network);
-
-	fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-
-	if (fd < 0) {
-		LOGP(DNM, LOGL_ERROR, "Telnet interface socket creation failed\n");
-		return;
-	}
-
-	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);
-
-	if (bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) {
-		LOGP(DNM, LOGL_ERROR, "Telnet interface failed to bind\n");
-		return;
-	}
-
-	if (listen(fd, 0) < 0) {
-		LOGP(DNM, LOGL_ERROR, "Telnet interface failed to listen\n");
-		return;
-	}
-
-	server_socket.data = network;
-	server_socket.fd = fd;
-	bsc_register_fd(&server_socket);
-}
-
-extern const char *openbsc_copyright;
-extern const char *openbsc_version;
-
-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) {
-		debug_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(DNM, LOGL_ERROR, "telnet accept failed\n");
-		return -1;
-	}
-
-
-	connection = talloc_zero(tall_telnet_ctx, struct telnet_connection);
-	connection->network = (struct gsm_network*)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(DNM, LOGL_ERROR, "couldn't create VTY\n");
-		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;
-	}
-}
-
diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c
index 75a279d..5e0d507 100644
--- a/openbsc/src/transaction.c
+++ b/openbsc/src/transaction.c
@@ -95,10 +95,10 @@
 		break;
 	}
 
-	if (trans->lchan)
-		put_lchan(trans->lchan);
+	if (trans->conn)
+		put_subscr_con(trans->conn);
 
-	if (!trans->lchan && trans->subscr && trans->subscr->net) {
+	if (!trans->conn && trans->subscr && trans->subscr->net) {
 		/* Stop paging on all bts' */
 		paging_request_stop(NULL, trans->subscr, NULL);
 	}
@@ -148,21 +148,22 @@
 
 /* update all transactions to use a different LCHAN, e.g.
  * after handover has succeeded */
-int trans_lchan_change(struct gsm_lchan *lchan_old,
-		       struct gsm_lchan *lchan_new)
+int trans_lchan_change(struct gsm_subscriber_connection *conn_old,
+		       struct gsm_subscriber_connection *conn_new)
 {
-	struct gsm_network *net = lchan_old->ts->trx->bts->network;
+	struct gsm_network *net = conn_old->lchan->ts->trx->bts->network;
 	struct gsm_trans *trans;
 	int num = 0;
 
 	llist_for_each_entry(trans, &net->trans_list, entry) {
-		if (trans->lchan == lchan_old) {
-			/* drop old channel use cound */
-			put_lchan(trans->lchan);
+		if (trans->conn == conn_old) {
+
+			/* drop old channel use count */
+			put_subscr_con(conn_old);
 			/* assign new channel */
-			trans->lchan = lchan_new;
+			trans->conn = conn_new;
 			/* bump new channel use count */
-			use_lchan(trans->lchan);
+			use_subscr_con(conn_new);
 			num++;
 		}
 	}
diff --git a/openbsc/src/ussd.c b/openbsc/src/ussd.c
index a3d11f0..5476919 100644
--- a/openbsc/src/ussd.c
+++ b/openbsc/src/ussd.c
@@ -62,7 +62,7 @@
 /* A network-specific handler function */
 static int send_own_number(const struct msgb *msg, const struct ussd_request *req)
 {
-	char *own_number = msg->lchan->subscr->extension;
+	char *own_number = msg->lchan->conn.subscr->extension;
 	char response_string[GSM_EXTENSION_LENGTH + 20];
 
 	/* Need trailing CR as EOT character */
diff --git a/openbsc/src/vty/buffer.c b/openbsc/src/vty/buffer.c
deleted file mode 100644
index 195d062..0000000
--- a/openbsc/src/vty/buffer.c
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * 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 <vty/buffer.h>
-#include <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(size_t size)
-{
-	struct buffer *b;
-
-	b = talloc_zero(tall_vty_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(tall_vty_ctx,
-			 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;
-}
diff --git a/openbsc/src/vty/cardshell.h b/openbsc/src/vty/cardshell.h
deleted file mode 100644
index 85164d2..0000000
--- a/openbsc/src/vty/cardshell.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "../../bscconfig.h"
-#define QUAGGA_PROGNAME	PACKAGE_NAME
-#define QUAGGA_VERSION	PACKAGE_VERSION
-#define QUAGGA_COPYRIGHT "Harald Welte <laforge@gnumonks.org>"
-#define CONFIGFILE_MASK 022
-#define SYSCONFDIR "/usr/local/etc"
diff --git a/openbsc/src/vty/command.c b/openbsc/src/vty/command.c
deleted file mode 100644
index 2faed35..0000000
--- a/openbsc/src/vty/command.c
+++ /dev/null
@@ -1,3411 +0,0 @@
-/*
-   $Id: command.c,v 1.47 2005/04/25 16:26:42 paul Exp $
-
-   Command interpreter routine for virtual terminal [aka TeletYpe]
-   Copyright (C) 1997, 98, 99 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 "cardshell.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <errno.h>
-#define _XOPEN_SOURCE
-#include <unistd.h>
-#include <assert.h>
-#include <ctype.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-
-//#include "memory.h"
-//#include "log.h"
-//#include <lib/version.h>
-//#include "thread.h"
-#include <vty/vector.h>
-#include <vty/vty.h>
-#include <vty/command.h>
-//#include "workqueue.h"
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_subscriber.h>
-#include <osmocore/talloc.h>
-
-void *tall_vty_cmd_ctx;
-
-/* Command vector which includes some level of command lists. Normally
-   each daemon maintains each own cmdvec. */
-vector cmdvec;
-
-/* Host information structure. */
-struct host host;
-
-/* Standard command node structures. */
-struct cmd_node auth_node = {
-	AUTH_NODE,
-	"Password: ",
-};
-
-struct cmd_node view_node = {
-	VIEW_NODE,
-	"%s> ",
-};
-
-struct cmd_node auth_enable_node = {
-	AUTH_ENABLE_NODE,
-	"Password: ",
-};
-
-struct cmd_node enable_node = {
-	ENABLE_NODE,
-	"%s# ",
-};
-
-struct cmd_node config_node = {
-	CONFIG_NODE,
-	"%s(config)# ",
-	1
-};
-
-/* Default motd string. */
-const char *default_motd = "\r\n\
-Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
-" QUAGGA_COPYRIGHT "\r\n\
-\r\n";
-
-#if 0
-static struct facility_map {
-	int facility;
-	const char *name;
-	size_t match;
-} syslog_facilities[] = {
-	{
-	LOG_KERN, "kern", 1}, {
-	LOG_USER, "user", 2}, {
-	LOG_MAIL, "mail", 1}, {
-	LOG_DAEMON, "daemon", 1}, {
-	LOG_AUTH, "auth", 1}, {
-	LOG_SYSLOG, "syslog", 1}, {
-	LOG_LPR, "lpr", 2}, {
-	LOG_NEWS, "news", 1}, {
-	LOG_UUCP, "uucp", 2}, {
-	LOG_CRON, "cron", 1},
-#ifdef LOG_FTP
-	{
-	LOG_FTP, "ftp", 1},
-#endif
-	{
-	LOG_LOCAL0, "local0", 6}, {
-	LOG_LOCAL1, "local1", 6}, {
-	LOG_LOCAL2, "local2", 6}, {
-	LOG_LOCAL3, "local3", 6}, {
-	LOG_LOCAL4, "local4", 6}, {
-	LOG_LOCAL5, "local5", 6}, {
-	LOG_LOCAL6, "local6", 6}, {
-	LOG_LOCAL7, "local7", 6}, {
-0, NULL, 0},};
-
-static const char *facility_name(int facility)
-{
-	struct facility_map *fm;
-
-	for (fm = syslog_facilities; fm->name; fm++)
-		if (fm->facility == facility)
-			return fm->name;
-	return "";
-}
-
-static int facility_match(const char *str)
-{
-	struct facility_map *fm;
-
-	for (fm = syslog_facilities; fm->name; fm++)
-		if (!strncmp(str, fm->name, fm->match))
-			return fm->facility;
-	return -1;
-}
-
-static int level_match(const char *s)
-{
-	int level;
-
-	for (level = 0; zlog_priority[level] != NULL; level++)
-		if (!strncmp(s, zlog_priority[level], 2))
-			return level;
-	return ZLOG_DISABLED;
-}
-#endif
-
-/* This is called from main when a daemon is invoked with -v or --version. */
-void print_version(const char *progname)
-{
-	printf("%s version %s\n", progname, QUAGGA_VERSION);
-	printf("%s\n", QUAGGA_COPYRIGHT);
-}
-
-/* Utility function to concatenate argv argument into a single string
-   with inserting ' ' character between each argument.  */
-char *argv_concat(const char **argv, int argc, int shift)
-{
-	int i;
-	size_t len;
-	char *str;
-	char *p;
-
-	len = 0;
-	for (i = shift; i < argc; i++)
-		len += strlen(argv[i]) + 1;
-	if (!len)
-		return NULL;
-	p = str = _talloc_zero(tall_vty_cmd_ctx, len, "arvg_concat");
-	for (i = shift; i < argc; i++) {
-		size_t arglen;
-		memcpy(p, argv[i], (arglen = strlen(argv[i])));
-		p += arglen;
-		*p++ = ' ';
-	}
-	*(p - 1) = '\0';
-	return str;
-}
-
-/* Install top node of command vector. */
-void install_node(struct cmd_node *node, int (*func) (struct vty *))
-{
-	vector_set_index(cmdvec, node->node, node);
-	node->func = func;
-	node->cmd_vector = vector_init(VECTOR_MIN_SIZE);
-}
-
-/* Compare two command's string.  Used in sort_node (). */
-static int cmp_node(const void *p, const void *q)
-{
-	struct cmd_element *a = *(struct cmd_element **)p;
-	struct cmd_element *b = *(struct cmd_element **)q;
-
-	return strcmp(a->string, b->string);
-}
-
-static int cmp_desc(const void *p, const void *q)
-{
-	struct desc *a = *(struct desc **)p;
-	struct desc *b = *(struct desc **)q;
-
-	return strcmp(a->cmd, b->cmd);
-}
-
-/* Sort each node's command element according to command string. */
-void sort_node()
-{
-	unsigned int i, j;
-	struct cmd_node *cnode;
-	vector descvec;
-	struct cmd_element *cmd_element;
-
-	for (i = 0; i < vector_active(cmdvec); i++)
-		if ((cnode = vector_slot(cmdvec, i)) != NULL) {
-			vector cmd_vector = cnode->cmd_vector;
-			qsort(cmd_vector->index, vector_active(cmd_vector),
-			      sizeof(void *), cmp_node);
-
-			for (j = 0; j < vector_active(cmd_vector); j++)
-				if ((cmd_element =
-				     vector_slot(cmd_vector, j)) != NULL
-				    && vector_active(cmd_element->strvec)) {
-					descvec =
-					    vector_slot(cmd_element->strvec,
-							vector_active
-							(cmd_element->strvec) -
-							1);
-					qsort(descvec->index,
-					      vector_active(descvec),
-					      sizeof(void *), cmp_desc);
-				}
-		}
-}
-
-/* Breaking up string into each command piece. I assume given
-   character is separated by a space character. Return value is a
-   vector which includes char ** data element. */
-vector cmd_make_strvec(const char *string)
-{
-	const char *cp, *start;
-	char *token;
-	int strlen;
-	vector strvec;
-
-	if (string == NULL)
-		return NULL;
-
-	cp = string;
-
-	/* Skip white spaces. */
-	while (isspace((int)*cp) && *cp != '\0')
-		cp++;
-
-	/* Return if there is only white spaces */
-	if (*cp == '\0')
-		return NULL;
-
-	if (*cp == '!' || *cp == '#')
-		return NULL;
-
-	/* Prepare return vector. */
-	strvec = vector_init(VECTOR_MIN_SIZE);
-
-	/* Copy each command piece and set into vector. */
-	while (1) {
-		start = cp;
-		while (!(isspace((int)*cp) || *cp == '\r' || *cp == '\n') &&
-		       *cp != '\0')
-			cp++;
-		strlen = cp - start;
-		token = _talloc_zero(tall_vty_cmd_ctx, strlen + 1, "make_strvec");
-		memcpy(token, start, strlen);
-		*(token + strlen) = '\0';
-		vector_set(strvec, token);
-
-		while ((isspace((int)*cp) || *cp == '\n' || *cp == '\r') &&
-		       *cp != '\0')
-			cp++;
-
-		if (*cp == '\0')
-			return strvec;
-	}
-}
-
-/* Free allocated string vector. */
-void cmd_free_strvec(vector v)
-{
-	unsigned int i;
-	char *cp;
-
-	if (!v)
-		return;
-
-	for (i = 0; i < vector_active(v); i++)
-		if ((cp = vector_slot(v, i)) != NULL)
-			talloc_free(cp);
-
-	vector_free(v);
-}
-
-/* Fetch next description.  Used in cmd_make_descvec(). */
-static char *cmd_desc_str(const char **string)
-{
-	const char *cp, *start;
-	char *token;
-	int strlen;
-
-	cp = *string;
-
-	if (cp == NULL)
-		return NULL;
-
-	/* Skip white spaces. */
-	while (isspace((int)*cp) && *cp != '\0')
-		cp++;
-
-	/* Return if there is only white spaces */
-	if (*cp == '\0')
-		return NULL;
-
-	start = cp;
-
-	while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
-		cp++;
-
-	strlen = cp - start;
-	token = _talloc_zero(tall_vty_cmd_ctx, strlen + 1, "cmd_desc_str");
-	memcpy(token, start, strlen);
-	*(token + strlen) = '\0';
-
-	*string = cp;
-
-	return token;
-}
-
-/* New string vector. */
-static vector cmd_make_descvec(const char *string, const char *descstr)
-{
-	int multiple = 0;
-	const char *sp;
-	char *token;
-	int len;
-	const char *cp;
-	const char *dp;
-	vector allvec;
-	vector strvec = NULL;
-	struct desc *desc;
-
-	cp = string;
-	dp = descstr;
-
-	if (cp == NULL)
-		return NULL;
-
-	allvec = vector_init(VECTOR_MIN_SIZE);
-
-	while (1) {
-		while (isspace((int)*cp) && *cp != '\0')
-			cp++;
-
-		if (*cp == '(') {
-			multiple = 1;
-			cp++;
-		}
-		if (*cp == ')') {
-			multiple = 0;
-			cp++;
-		}
-		if (*cp == '|') {
-			if (!multiple) {
-				fprintf(stderr, "Command parse error!: %s\n",
-					string);
-				exit(1);
-			}
-			cp++;
-		}
-
-		while (isspace((int)*cp) && *cp != '\0')
-			cp++;
-
-		if (*cp == '(') {
-			multiple = 1;
-			cp++;
-		}
-
-		if (*cp == '\0')
-			return allvec;
-
-		sp = cp;
-
-		while (!
-		       (isspace((int)*cp) || *cp == '\r' || *cp == '\n'
-			|| *cp == ')' || *cp == '|') && *cp != '\0')
-			cp++;
-
-		len = cp - sp;
-
-		token = _talloc_zero(tall_vty_cmd_ctx, len + 1, "cmd_make_descvec");
-		memcpy(token, sp, len);
-		*(token + len) = '\0';
-
-		desc = talloc_zero(tall_vty_cmd_ctx, struct desc);
-		desc->cmd = token;
-		desc->str = cmd_desc_str(&dp);
-
-		if (multiple) {
-			if (multiple == 1) {
-				strvec = vector_init(VECTOR_MIN_SIZE);
-				vector_set(allvec, strvec);
-			}
-			multiple++;
-		} else {
-			strvec = vector_init(VECTOR_MIN_SIZE);
-			vector_set(allvec, strvec);
-		}
-		vector_set(strvec, desc);
-	}
-}
-
-/* Count mandantory string vector size.  This is to determine inputed
-   command has enough command length. */
-static int cmd_cmdsize(vector strvec)
-{
-	unsigned int i;
-	int size = 0;
-	vector descvec;
-	struct desc *desc;
-
-	for (i = 0; i < vector_active(strvec); i++)
-		if ((descvec = vector_slot(strvec, i)) != NULL) {
-			if ((vector_active(descvec)) == 1
-			    && (desc = vector_slot(descvec, 0)) != NULL) {
-				if (desc->cmd == NULL || CMD_OPTION(desc->cmd))
-					return size;
-				else
-					size++;
-			} else
-				size++;
-		}
-	return size;
-}
-
-/* Return prompt character of specified node. */
-const char *cmd_prompt(enum node_type node)
-{
-	struct cmd_node *cnode;
-
-	cnode = vector_slot(cmdvec, node);
-	return cnode->prompt;
-}
-
-/* Install a command into a node. */
-void install_element(enum node_type ntype, struct cmd_element *cmd)
-{
-	struct cmd_node *cnode;
-
-	cnode = vector_slot(cmdvec, ntype);
-
-	if (cnode == NULL) {
-		fprintf(stderr,
-			"Command node %d doesn't exist, please check it\n",
-			ntype);
-		exit(1);
-	}
-
-	vector_set(cnode->cmd_vector, cmd);
-
-	cmd->strvec = cmd_make_descvec(cmd->string, cmd->doc);
-	cmd->cmdsize = cmd_cmdsize(cmd->strvec);
-}
-
-#ifdef VTY_CRYPT_PW
-static unsigned char itoa64[] =
-    "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-
-static void to64(char *s, long v, int n)
-{
-	while (--n >= 0) {
-		*s++ = itoa64[v & 0x3f];
-		v >>= 6;
-	}
-}
-
-static char *zencrypt(const char *passwd)
-{
-	char salt[6];
-	struct timeval tv;
-	char *crypt(const char *, const char *);
-
-	gettimeofday(&tv, 0);
-
-	to64(&salt[0], random(), 3);
-	to64(&salt[3], tv.tv_usec, 3);
-	salt[5] = '\0';
-
-	return crypt(passwd, salt);
-}
-#endif
-
-/* This function write configuration of this host. */
-static int config_write_host(struct vty *vty)
-{
-	if (host.name)
-		vty_out(vty, "hostname %s%s", host.name, VTY_NEWLINE);
-
-	if (host.encrypt) {
-		if (host.password_encrypt)
-			vty_out(vty, "password 8 %s%s", host.password_encrypt,
-				VTY_NEWLINE);
-		if (host.enable_encrypt)
-			vty_out(vty, "enable password 8 %s%s",
-				host.enable_encrypt, VTY_NEWLINE);
-	} else {
-		if (host.password)
-			vty_out(vty, "password %s%s", host.password,
-				VTY_NEWLINE);
-		if (host.enable)
-			vty_out(vty, "enable password %s%s", host.enable,
-				VTY_NEWLINE);
-	}
-
-#if 0
-	if (zlog_default->default_lvl != LOG_DEBUG) {
-		vty_out(vty, "! N.B. The 'log trap' command is deprecated.%s",
-			VTY_NEWLINE);
-		vty_out(vty, "log trap %s%s",
-			zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
-	}
-
-	if (host.logfile
-	    && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED)) {
-		vty_out(vty, "log file %s", host.logfile);
-		if (zlog_default->maxlvl[ZLOG_DEST_FILE] !=
-		    zlog_default->default_lvl)
-			vty_out(vty, " %s",
-				zlog_priority[zlog_default->
-					      maxlvl[ZLOG_DEST_FILE]]);
-		vty_out(vty, "%s", VTY_NEWLINE);
-	}
-
-	if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED) {
-		vty_out(vty, "log stdout");
-		if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] !=
-		    zlog_default->default_lvl)
-			vty_out(vty, " %s",
-				zlog_priority[zlog_default->
-					      maxlvl[ZLOG_DEST_STDOUT]]);
-		vty_out(vty, "%s", VTY_NEWLINE);
-	}
-
-	if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
-		vty_out(vty, "no log monitor%s", VTY_NEWLINE);
-	else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] !=
-		 zlog_default->default_lvl)
-		vty_out(vty, "log monitor %s%s",
-			zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],
-			VTY_NEWLINE);
-
-	if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED) {
-		vty_out(vty, "log syslog");
-		if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] !=
-		    zlog_default->default_lvl)
-			vty_out(vty, " %s",
-				zlog_priority[zlog_default->
-					      maxlvl[ZLOG_DEST_SYSLOG]]);
-		vty_out(vty, "%s", VTY_NEWLINE);
-	}
-
-	if (zlog_default->facility != LOG_DAEMON)
-		vty_out(vty, "log facility %s%s",
-			facility_name(zlog_default->facility), VTY_NEWLINE);
-
-	if (zlog_default->record_priority == 1)
-		vty_out(vty, "log record-priority%s", VTY_NEWLINE);
-#endif
-	if (host.advanced)
-		vty_out(vty, "service advanced-vty%s", VTY_NEWLINE);
-
-	if (host.encrypt)
-		vty_out(vty, "service password-encryption%s", VTY_NEWLINE);
-
-	if (host.lines >= 0)
-		vty_out(vty, "service terminal-length %d%s", host.lines,
-			VTY_NEWLINE);
-
-	if (host.motdfile)
-		vty_out(vty, "banner motd file %s%s", host.motdfile,
-			VTY_NEWLINE);
-	else if (!host.motd)
-		vty_out(vty, "no banner motd%s", VTY_NEWLINE);
-
-	return 1;
-}
-
-/* Utility function for getting command vector. */
-static vector cmd_node_vector(vector v, enum node_type ntype)
-{
-	struct cmd_node *cnode = vector_slot(v, ntype);
-	return cnode->cmd_vector;
-}
-
-#if 0
-/* Filter command vector by symbol.  This function is not actually used;
- * should it be deleted? */
-static int cmd_filter_by_symbol(char *command, char *symbol)
-{
-	int i, lim;
-
-	if (strcmp(symbol, "IPV4_ADDRESS") == 0) {
-		i = 0;
-		lim = strlen(command);
-		while (i < lim) {
-			if (!
-			    (isdigit((int)command[i]) || command[i] == '.'
-			     || command[i] == '/'))
-				return 1;
-			i++;
-		}
-		return 0;
-	}
-	if (strcmp(symbol, "STRING") == 0) {
-		i = 0;
-		lim = strlen(command);
-		while (i < lim) {
-			if (!
-			    (isalpha((int)command[i]) || command[i] == '_'
-			     || command[i] == '-'))
-				return 1;
-			i++;
-		}
-		return 0;
-	}
-	if (strcmp(symbol, "IFNAME") == 0) {
-		i = 0;
-		lim = strlen(command);
-		while (i < lim) {
-			if (!isalnum((int)command[i]))
-				return 1;
-			i++;
-		}
-		return 0;
-	}
-	return 0;
-}
-#endif
-
-/* Completion match types. */
-enum match_type {
-	no_match,
-	extend_match,
-	ipv4_prefix_match,
-	ipv4_match,
-	ipv6_prefix_match,
-	ipv6_match,
-	range_match,
-	vararg_match,
-	partly_match,
-	exact_match
-};
-
-static enum match_type cmd_ipv4_match(const char *str)
-{
-	const char *sp;
-	int dots = 0, nums = 0;
-	char buf[4];
-
-	if (str == NULL)
-		return partly_match;
-
-	for (;;) {
-		memset(buf, 0, sizeof(buf));
-		sp = str;
-		while (*str != '\0') {
-			if (*str == '.') {
-				if (dots >= 3)
-					return no_match;
-
-				if (*(str + 1) == '.')
-					return no_match;
-
-				if (*(str + 1) == '\0')
-					return partly_match;
-
-				dots++;
-				break;
-			}
-			if (!isdigit((int)*str))
-				return no_match;
-
-			str++;
-		}
-
-		if (str - sp > 3)
-			return no_match;
-
-		strncpy(buf, sp, str - sp);
-		if (atoi(buf) > 255)
-			return no_match;
-
-		nums++;
-
-		if (*str == '\0')
-			break;
-
-		str++;
-	}
-
-	if (nums < 4)
-		return partly_match;
-
-	return exact_match;
-}
-
-static enum match_type cmd_ipv4_prefix_match(const char *str)
-{
-	const char *sp;
-	int dots = 0;
-	char buf[4];
-
-	if (str == NULL)
-		return partly_match;
-
-	for (;;) {
-		memset(buf, 0, sizeof(buf));
-		sp = str;
-		while (*str != '\0' && *str != '/') {
-			if (*str == '.') {
-				if (dots == 3)
-					return no_match;
-
-				if (*(str + 1) == '.' || *(str + 1) == '/')
-					return no_match;
-
-				if (*(str + 1) == '\0')
-					return partly_match;
-
-				dots++;
-				break;
-			}
-
-			if (!isdigit((int)*str))
-				return no_match;
-
-			str++;
-		}
-
-		if (str - sp > 3)
-			return no_match;
-
-		strncpy(buf, sp, str - sp);
-		if (atoi(buf) > 255)
-			return no_match;
-
-		if (dots == 3) {
-			if (*str == '/') {
-				if (*(str + 1) == '\0')
-					return partly_match;
-
-				str++;
-				break;
-			} else if (*str == '\0')
-				return partly_match;
-		}
-
-		if (*str == '\0')
-			return partly_match;
-
-		str++;
-	}
-
-	sp = str;
-	while (*str != '\0') {
-		if (!isdigit((int)*str))
-			return no_match;
-
-		str++;
-	}
-
-	if (atoi(sp) > 32)
-		return no_match;
-
-	return exact_match;
-}
-
-#define IPV6_ADDR_STR		"0123456789abcdefABCDEF:.%"
-#define IPV6_PREFIX_STR		"0123456789abcdefABCDEF:.%/"
-#define STATE_START		1
-#define STATE_COLON		2
-#define STATE_DOUBLE		3
-#define STATE_ADDR		4
-#define STATE_DOT               5
-#define STATE_SLASH		6
-#define STATE_MASK		7
-
-#ifdef HAVE_IPV6
-
-static enum match_type cmd_ipv6_match(const char *str)
-{
-	int state = STATE_START;
-	int colons = 0, nums = 0, double_colon = 0;
-	const char *sp = NULL;
-	struct sockaddr_in6 sin6_dummy;
-	int ret;
-
-	if (str == NULL)
-		return partly_match;
-
-	if (strspn(str, IPV6_ADDR_STR) != strlen(str))
-		return no_match;
-
-	/* use inet_pton that has a better support,
-	 * for example inet_pton can support the automatic addresses:
-	 *  ::1.2.3.4
-	 */
-	ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
-
-	if (ret == 1)
-		return exact_match;
-
-	while (*str != '\0') {
-		switch (state) {
-		case STATE_START:
-			if (*str == ':') {
-				if (*(str + 1) != ':' && *(str + 1) != '\0')
-					return no_match;
-				colons--;
-				state = STATE_COLON;
-			} else {
-				sp = str;
-				state = STATE_ADDR;
-			}
-
-			continue;
-		case STATE_COLON:
-			colons++;
-			if (*(str + 1) == ':')
-				state = STATE_DOUBLE;
-			else {
-				sp = str + 1;
-				state = STATE_ADDR;
-			}
-			break;
-		case STATE_DOUBLE:
-			if (double_colon)
-				return no_match;
-
-			if (*(str + 1) == ':')
-				return no_match;
-			else {
-				if (*(str + 1) != '\0')
-					colons++;
-				sp = str + 1;
-				state = STATE_ADDR;
-			}
-
-			double_colon++;
-			nums++;
-			break;
-		case STATE_ADDR:
-			if (*(str + 1) == ':' || *(str + 1) == '\0') {
-				if (str - sp > 3)
-					return no_match;
-
-				nums++;
-				state = STATE_COLON;
-			}
-			if (*(str + 1) == '.')
-				state = STATE_DOT;
-			break;
-		case STATE_DOT:
-			state = STATE_ADDR;
-			break;
-		default:
-			break;
-		}
-
-		if (nums > 8)
-			return no_match;
-
-		if (colons > 7)
-			return no_match;
-
-		str++;
-	}
-
-#if 0
-	if (nums < 11)
-		return partly_match;
-#endif				/* 0 */
-
-	return exact_match;
-}
-
-static enum match_type cmd_ipv6_prefix_match(const char *str)
-{
-	int state = STATE_START;
-	int colons = 0, nums = 0, double_colon = 0;
-	int mask;
-	const char *sp = NULL;
-	char *endptr = NULL;
-
-	if (str == NULL)
-		return partly_match;
-
-	if (strspn(str, IPV6_PREFIX_STR) != strlen(str))
-		return no_match;
-
-	while (*str != '\0' && state != STATE_MASK) {
-		switch (state) {
-		case STATE_START:
-			if (*str == ':') {
-				if (*(str + 1) != ':' && *(str + 1) != '\0')
-					return no_match;
-				colons--;
-				state = STATE_COLON;
-			} else {
-				sp = str;
-				state = STATE_ADDR;
-			}
-
-			continue;
-		case STATE_COLON:
-			colons++;
-			if (*(str + 1) == '/')
-				return no_match;
-			else if (*(str + 1) == ':')
-				state = STATE_DOUBLE;
-			else {
-				sp = str + 1;
-				state = STATE_ADDR;
-			}
-			break;
-		case STATE_DOUBLE:
-			if (double_colon)
-				return no_match;
-
-			if (*(str + 1) == ':')
-				return no_match;
-			else {
-				if (*(str + 1) != '\0' && *(str + 1) != '/')
-					colons++;
-				sp = str + 1;
-
-				if (*(str + 1) == '/')
-					state = STATE_SLASH;
-				else
-					state = STATE_ADDR;
-			}
-
-			double_colon++;
-			nums += 1;
-			break;
-		case STATE_ADDR:
-			if (*(str + 1) == ':' || *(str + 1) == '.'
-			    || *(str + 1) == '\0' || *(str + 1) == '/') {
-				if (str - sp > 3)
-					return no_match;
-
-				for (; sp <= str; sp++)
-					if (*sp == '/')
-						return no_match;
-
-				nums++;
-
-				if (*(str + 1) == ':')
-					state = STATE_COLON;
-				else if (*(str + 1) == '.')
-					state = STATE_DOT;
-				else if (*(str + 1) == '/')
-					state = STATE_SLASH;
-			}
-			break;
-		case STATE_DOT:
-			state = STATE_ADDR;
-			break;
-		case STATE_SLASH:
-			if (*(str + 1) == '\0')
-				return partly_match;
-
-			state = STATE_MASK;
-			break;
-		default:
-			break;
-		}
-
-		if (nums > 11)
-			return no_match;
-
-		if (colons > 7)
-			return no_match;
-
-		str++;
-	}
-
-	if (state < STATE_MASK)
-		return partly_match;
-
-	mask = strtol(str, &endptr, 10);
-	if (*endptr != '\0')
-		return no_match;
-
-	if (mask < 0 || mask > 128)
-		return no_match;
-
-/* I don't know why mask < 13 makes command match partly.
-   Forgive me to make this comments. I Want to set static default route
-   because of lack of function to originate default in ospf6d; sorry
-       yasu
-  if (mask < 13)
-    return partly_match;
-*/
-
-	return exact_match;
-}
-
-#endif				/* HAVE_IPV6  */
-
-#define DECIMAL_STRLEN_MAX 10
-
-static int cmd_range_match(const char *range, const char *str)
-{
-	char *p;
-	char buf[DECIMAL_STRLEN_MAX + 1];
-	char *endptr = NULL;
-	unsigned long min, max, val;
-
-	if (str == NULL)
-		return 1;
-
-	val = strtoul(str, &endptr, 10);
-	if (*endptr != '\0')
-		return 0;
-
-	range++;
-	p = strchr(range, '-');
-	if (p == NULL)
-		return 0;
-	if (p - range > DECIMAL_STRLEN_MAX)
-		return 0;
-	strncpy(buf, range, p - range);
-	buf[p - range] = '\0';
-	min = strtoul(buf, &endptr, 10);
-	if (*endptr != '\0')
-		return 0;
-
-	range = p + 1;
-	p = strchr(range, '>');
-	if (p == NULL)
-		return 0;
-	if (p - range > DECIMAL_STRLEN_MAX)
-		return 0;
-	strncpy(buf, range, p - range);
-	buf[p - range] = '\0';
-	max = strtoul(buf, &endptr, 10);
-	if (*endptr != '\0')
-		return 0;
-
-	if (val < min || val > max)
-		return 0;
-
-	return 1;
-}
-
-/* Make completion match and return match type flag. */
-static enum match_type
-cmd_filter_by_completion(char *command, vector v, unsigned int index)
-{
-	unsigned int i;
-	const char *str;
-	struct cmd_element *cmd_element;
-	enum match_type match_type;
-	vector descvec;
-	struct desc *desc;
-
-	match_type = no_match;
-
-	/* If command and cmd_element string does not match set NULL to vector */
-	for (i = 0; i < vector_active(v); i++)
-		if ((cmd_element = vector_slot(v, i)) != NULL) {
-			if (index >= vector_active(cmd_element->strvec))
-				vector_slot(v, i) = NULL;
-			else {
-				unsigned int j;
-				int matched = 0;
-
-				descvec =
-				    vector_slot(cmd_element->strvec, index);
-
-				for (j = 0; j < vector_active(descvec); j++)
-					if ((desc = vector_slot(descvec, j))) {
-						str = desc->cmd;
-
-						if (CMD_VARARG(str)) {
-							if (match_type <
-							    vararg_match)
-								match_type =
-								    vararg_match;
-							matched++;
-						} else if (CMD_RANGE(str)) {
-							if (cmd_range_match
-							    (str, command)) {
-								if (match_type <
-								    range_match)
-									match_type
-									    =
-									    range_match;
-
-								matched++;
-							}
-						}
-#ifdef HAVE_IPV6
-						else if (CMD_IPV6(str)) {
-							if (cmd_ipv6_match
-							    (command)) {
-								if (match_type <
-								    ipv6_match)
-									match_type
-									    =
-									    ipv6_match;
-
-								matched++;
-							}
-						} else if (CMD_IPV6_PREFIX(str)) {
-							if (cmd_ipv6_prefix_match(command)) {
-								if (match_type <
-								    ipv6_prefix_match)
-									match_type
-									    =
-									    ipv6_prefix_match;
-
-								matched++;
-							}
-						}
-#endif				/* HAVE_IPV6  */
-						else if (CMD_IPV4(str)) {
-							if (cmd_ipv4_match
-							    (command)) {
-								if (match_type <
-								    ipv4_match)
-									match_type
-									    =
-									    ipv4_match;
-
-								matched++;
-							}
-						} else if (CMD_IPV4_PREFIX(str)) {
-							if (cmd_ipv4_prefix_match(command)) {
-								if (match_type <
-								    ipv4_prefix_match)
-									match_type
-									    =
-									    ipv4_prefix_match;
-								matched++;
-							}
-						} else
-							/* Check is this point's argument optional ? */
-						if (CMD_OPTION(str)
-							    ||
-							    CMD_VARIABLE(str)) {
-							if (match_type <
-							    extend_match)
-								match_type =
-								    extend_match;
-							matched++;
-						} else
-						    if (strncmp
-							(command, str,
-							 strlen(command)) ==
-							0) {
-							if (strcmp(command, str)
-							    == 0)
-								match_type =
-								    exact_match;
-							else {
-								if (match_type <
-								    partly_match)
-									match_type
-									    =
-									    partly_match;
-							}
-							matched++;
-						}
-					}
-				if (!matched)
-					vector_slot(v, i) = NULL;
-			}
-		}
-	return match_type;
-}
-
-/* Filter vector by command character with index. */
-static enum match_type
-cmd_filter_by_string(char *command, vector v, unsigned int index)
-{
-	unsigned int i;
-	const char *str;
-	struct cmd_element *cmd_element;
-	enum match_type match_type;
-	vector descvec;
-	struct desc *desc;
-
-	match_type = no_match;
-
-	/* If command and cmd_element string does not match set NULL to vector */
-	for (i = 0; i < vector_active(v); i++)
-		if ((cmd_element = vector_slot(v, i)) != NULL) {
-			/* If given index is bigger than max string vector of command,
-			   set NULL */
-			if (index >= vector_active(cmd_element->strvec))
-				vector_slot(v, i) = NULL;
-			else {
-				unsigned int j;
-				int matched = 0;
-
-				descvec =
-				    vector_slot(cmd_element->strvec, index);
-
-				for (j = 0; j < vector_active(descvec); j++)
-					if ((desc = vector_slot(descvec, j))) {
-						str = desc->cmd;
-
-						if (CMD_VARARG(str)) {
-							if (match_type <
-							    vararg_match)
-								match_type =
-								    vararg_match;
-							matched++;
-						} else if (CMD_RANGE(str)) {
-							if (cmd_range_match
-							    (str, command)) {
-								if (match_type <
-								    range_match)
-									match_type
-									    =
-									    range_match;
-								matched++;
-							}
-						}
-#ifdef HAVE_IPV6
-						else if (CMD_IPV6(str)) {
-							if (cmd_ipv6_match
-							    (command) ==
-							    exact_match) {
-								if (match_type <
-								    ipv6_match)
-									match_type
-									    =
-									    ipv6_match;
-								matched++;
-							}
-						} else if (CMD_IPV6_PREFIX(str)) {
-							if (cmd_ipv6_prefix_match(command) == exact_match) {
-								if (match_type <
-								    ipv6_prefix_match)
-									match_type
-									    =
-									    ipv6_prefix_match;
-								matched++;
-							}
-						}
-#endif				/* HAVE_IPV6  */
-						else if (CMD_IPV4(str)) {
-							if (cmd_ipv4_match
-							    (command) ==
-							    exact_match) {
-								if (match_type <
-								    ipv4_match)
-									match_type
-									    =
-									    ipv4_match;
-								matched++;
-							}
-						} else if (CMD_IPV4_PREFIX(str)) {
-							if (cmd_ipv4_prefix_match(command) == exact_match) {
-								if (match_type <
-								    ipv4_prefix_match)
-									match_type
-									    =
-									    ipv4_prefix_match;
-								matched++;
-							}
-						} else if (CMD_OPTION(str)
-							   || CMD_VARIABLE(str))
-						{
-							if (match_type <
-							    extend_match)
-								match_type =
-								    extend_match;
-							matched++;
-						} else {
-							if (strcmp(command, str)
-							    == 0) {
-								match_type =
-								    exact_match;
-								matched++;
-							}
-						}
-					}
-				if (!matched)
-					vector_slot(v, i) = NULL;
-			}
-		}
-	return match_type;
-}
-
-/* Check ambiguous match */
-static int
-is_cmd_ambiguous(char *command, vector v, int index, enum match_type type)
-{
-	unsigned int i;
-	unsigned int j;
-	const char *str = NULL;
-	struct cmd_element *cmd_element;
-	const char *matched = NULL;
-	vector descvec;
-	struct desc *desc;
-
-	for (i = 0; i < vector_active(v); i++)
-		if ((cmd_element = vector_slot(v, i)) != NULL) {
-			int match = 0;
-
-			descvec = vector_slot(cmd_element->strvec, index);
-
-			for (j = 0; j < vector_active(descvec); j++)
-				if ((desc = vector_slot(descvec, j))) {
-					enum match_type ret;
-
-					str = desc->cmd;
-
-					switch (type) {
-					case exact_match:
-						if (!
-						    (CMD_OPTION(str)
-						     || CMD_VARIABLE(str))
-&& strcmp(command, str) == 0)
-							match++;
-						break;
-					case partly_match:
-						if (!
-						    (CMD_OPTION(str)
-						     || CMD_VARIABLE(str))
-&& strncmp(command, str, strlen(command)) == 0) {
-							if (matched
-							    && strcmp(matched,
-								      str) != 0)
-								return 1;	/* There is ambiguous match. */
-							else
-								matched = str;
-							match++;
-						}
-						break;
-					case range_match:
-						if (cmd_range_match
-						    (str, command)) {
-							if (matched
-							    && strcmp(matched,
-								      str) != 0)
-								return 1;
-							else
-								matched = str;
-							match++;
-						}
-						break;
-#ifdef HAVE_IPV6
-					case ipv6_match:
-						if (CMD_IPV6(str))
-							match++;
-						break;
-					case ipv6_prefix_match:
-						if ((ret =
-						     cmd_ipv6_prefix_match
-						     (command)) != no_match) {
-							if (ret == partly_match)
-								return 2;	/* There is incomplete match. */
-
-							match++;
-						}
-						break;
-#endif				/* HAVE_IPV6 */
-					case ipv4_match:
-						if (CMD_IPV4(str))
-							match++;
-						break;
-					case ipv4_prefix_match:
-						if ((ret =
-						     cmd_ipv4_prefix_match
-						     (command)) != no_match) {
-							if (ret == partly_match)
-								return 2;	/* There is incomplete match. */
-
-							match++;
-						}
-						break;
-					case extend_match:
-						if (CMD_OPTION(str)
-						    || CMD_VARIABLE(str))
-							match++;
-						break;
-					case no_match:
-					default:
-						break;
-					}
-				}
-			if (!match)
-				vector_slot(v, i) = NULL;
-		}
-	return 0;
-}
-
-/* If src matches dst return dst string, otherwise return NULL */
-static const char *cmd_entry_function(const char *src, const char *dst)
-{
-	/* Skip variable arguments. */
-	if (CMD_OPTION(dst) || CMD_VARIABLE(dst) || CMD_VARARG(dst) ||
-	    CMD_IPV4(dst) || CMD_IPV4_PREFIX(dst) || CMD_RANGE(dst))
-		return NULL;
-
-	/* In case of 'command \t', given src is NULL string. */
-	if (src == NULL)
-		return dst;
-
-	/* Matched with input string. */
-	if (strncmp(src, dst, strlen(src)) == 0)
-		return dst;
-
-	return NULL;
-}
-
-/* If src matches dst return dst string, otherwise return NULL */
-/* This version will return the dst string always if it is
-   CMD_VARIABLE for '?' key processing */
-static const char *cmd_entry_function_desc(const char *src, const char *dst)
-{
-	if (CMD_VARARG(dst))
-		return dst;
-
-	if (CMD_RANGE(dst)) {
-		if (cmd_range_match(dst, src))
-			return dst;
-		else
-			return NULL;
-	}
-#ifdef HAVE_IPV6
-	if (CMD_IPV6(dst)) {
-		if (cmd_ipv6_match(src))
-			return dst;
-		else
-			return NULL;
-	}
-
-	if (CMD_IPV6_PREFIX(dst)) {
-		if (cmd_ipv6_prefix_match(src))
-			return dst;
-		else
-			return NULL;
-	}
-#endif				/* HAVE_IPV6 */
-
-	if (CMD_IPV4(dst)) {
-		if (cmd_ipv4_match(src))
-			return dst;
-		else
-			return NULL;
-	}
-
-	if (CMD_IPV4_PREFIX(dst)) {
-		if (cmd_ipv4_prefix_match(src))
-			return dst;
-		else
-			return NULL;
-	}
-
-	/* Optional or variable commands always match on '?' */
-	if (CMD_OPTION(dst) || CMD_VARIABLE(dst))
-		return dst;
-
-	/* In case of 'command \t', given src is NULL string. */
-	if (src == NULL)
-		return dst;
-
-	if (strncmp(src, dst, strlen(src)) == 0)
-		return dst;
-	else
-		return NULL;
-}
-
-/* Check same string element existence.  If it isn't there return
-    1. */
-static int cmd_unique_string(vector v, const char *str)
-{
-	unsigned int i;
-	char *match;
-
-	for (i = 0; i < vector_active(v); i++)
-		if ((match = vector_slot(v, i)) != NULL)
-			if (strcmp(match, str) == 0)
-				return 0;
-	return 1;
-}
-
-/* Compare string to description vector.  If there is same string
-   return 1 else return 0. */
-static int desc_unique_string(vector v, const char *str)
-{
-	unsigned int i;
-	struct desc *desc;
-
-	for (i = 0; i < vector_active(v); i++)
-		if ((desc = vector_slot(v, i)) != NULL)
-			if (strcmp(desc->cmd, str) == 0)
-				return 1;
-	return 0;
-}
-
-static int cmd_try_do_shortcut(enum node_type node, char *first_word)
-{
-	if (first_word != NULL &&
-	    node != AUTH_NODE &&
-	    node != VIEW_NODE &&
-	    node != AUTH_ENABLE_NODE &&
-	    node != ENABLE_NODE && 0 == strcmp("do", first_word))
-		return 1;
-	return 0;
-}
-
-/* '?' describe command support. */
-static vector
-cmd_describe_command_real(vector vline, struct vty *vty, int *status)
-{
-	unsigned int i;
-	vector cmd_vector;
-#define INIT_MATCHVEC_SIZE 10
-	vector matchvec;
-	struct cmd_element *cmd_element;
-	unsigned int index;
-	int ret;
-	enum match_type match;
-	char *command;
-	static struct desc desc_cr = { "<cr>", "" };
-
-	/* Set index. */
-	if (vector_active(vline) == 0) {
-		*status = CMD_ERR_NO_MATCH;
-		return NULL;
-	} else
-		index = vector_active(vline) - 1;
-
-	/* Make copy vector of current node's command vector. */
-	cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
-
-	/* Prepare match vector */
-	matchvec = vector_init(INIT_MATCHVEC_SIZE);
-
-	/* Filter commands. */
-	/* Only words precedes current word will be checked in this loop. */
-	for (i = 0; i < index; i++)
-		if ((command = vector_slot(vline, i))) {
-			match =
-			    cmd_filter_by_completion(command, cmd_vector, i);
-
-			if (match == vararg_match) {
-				struct cmd_element *cmd_element;
-				vector descvec;
-				unsigned int j, k;
-
-				for (j = 0; j < vector_active(cmd_vector); j++)
-					if ((cmd_element =
-					     vector_slot(cmd_vector, j)) != NULL
-					    &&
-					    (vector_active
-					     (cmd_element->strvec))) {
-						descvec =
-						    vector_slot(cmd_element->
-								strvec,
-								vector_active
-								(cmd_element->
-								 strvec) - 1);
-						for (k = 0;
-						     k < vector_active(descvec);
-						     k++) {
-							struct desc *desc =
-							    vector_slot(descvec,
-									k);
-							vector_set(matchvec,
-								   desc);
-						}
-					}
-
-				vector_set(matchvec, &desc_cr);
-				vector_free(cmd_vector);
-
-				return matchvec;
-			}
-
-			if ((ret =
-			     is_cmd_ambiguous(command, cmd_vector, i,
-					      match)) == 1) {
-				vector_free(cmd_vector);
-				*status = CMD_ERR_AMBIGUOUS;
-				return NULL;
-			} else if (ret == 2) {
-				vector_free(cmd_vector);
-				*status = CMD_ERR_NO_MATCH;
-				return NULL;
-			}
-		}
-
-	/* Prepare match vector */
-	/*  matchvec = vector_init (INIT_MATCHVEC_SIZE); */
-
-	/* Make sure that cmd_vector is filtered based on current word */
-	command = vector_slot(vline, index);
-	if (command)
-		match = cmd_filter_by_completion(command, cmd_vector, index);
-
-	/* Make description vector. */
-	for (i = 0; i < vector_active(cmd_vector); i++)
-		if ((cmd_element = vector_slot(cmd_vector, i)) != NULL) {
-			const char *string = NULL;
-			vector strvec = cmd_element->strvec;
-
-			/* if command is NULL, index may be equal to vector_active */
-			if (command && index >= vector_active(strvec))
-				vector_slot(cmd_vector, i) = NULL;
-			else {
-				/* Check if command is completed. */
-				if (command == NULL
-				    && index == vector_active(strvec)) {
-					string = "<cr>";
-					if (!desc_unique_string
-					    (matchvec, string))
-						vector_set(matchvec, &desc_cr);
-				} else {
-					unsigned int j;
-					vector descvec =
-					    vector_slot(strvec, index);
-					struct desc *desc;
-
-					for (j = 0; j < vector_active(descvec);
-					     j++)
-						if ((desc =
-						     vector_slot(descvec, j))) {
-							string =
-							    cmd_entry_function_desc
-							    (command,
-							     desc->cmd);
-							if (string) {
-								/* Uniqueness check */
-								if (!desc_unique_string(matchvec, string))
-									vector_set
-									    (matchvec,
-									     desc);
-							}
-						}
-				}
-			}
-		}
-	vector_free(cmd_vector);
-
-	if (vector_slot(matchvec, 0) == NULL) {
-		vector_free(matchvec);
-		*status = CMD_ERR_NO_MATCH;
-	} else
-		*status = CMD_SUCCESS;
-
-	return matchvec;
-}
-
-vector cmd_describe_command(vector vline, struct vty * vty, int *status)
-{
-	vector ret;
-
-	if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
-		enum node_type onode;
-		vector shifted_vline;
-		unsigned int index;
-
-		onode = vty->node;
-		vty->node = ENABLE_NODE;
-		/* We can try it on enable node, cos' the vty is authenticated */
-
-		shifted_vline = vector_init(vector_count(vline));
-		/* use memcpy? */
-		for (index = 1; index < vector_active(vline); index++) {
-			vector_set_index(shifted_vline, index - 1,
-					 vector_lookup(vline, index));
-		}
-
-		ret = cmd_describe_command_real(shifted_vline, vty, status);
-
-		vector_free(shifted_vline);
-		vty->node = onode;
-		return ret;
-	}
-
-	return cmd_describe_command_real(vline, vty, status);
-}
-
-/* Check LCD of matched command. */
-static int cmd_lcd(char **matched)
-{
-	int i;
-	int j;
-	int lcd = -1;
-	char *s1, *s2;
-	char c1, c2;
-
-	if (matched[0] == NULL || matched[1] == NULL)
-		return 0;
-
-	for (i = 1; matched[i] != NULL; i++) {
-		s1 = matched[i - 1];
-		s2 = matched[i];
-
-		for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
-			if (c1 != c2)
-				break;
-
-		if (lcd < 0)
-			lcd = j;
-		else {
-			if (lcd > j)
-				lcd = j;
-		}
-	}
-	return lcd;
-}
-
-/* Command line completion support. */
-static char **cmd_complete_command_real(vector vline, struct vty *vty,
-					int *status)
-{
-	unsigned int i;
-	vector cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
-#define INIT_MATCHVEC_SIZE 10
-	vector matchvec;
-	struct cmd_element *cmd_element;
-	unsigned int index;
-	char **match_str;
-	struct desc *desc;
-	vector descvec;
-	char *command;
-	int lcd;
-
-	if (vector_active(vline) == 0) {
-		*status = CMD_ERR_NO_MATCH;
-		return NULL;
-	} else
-		index = vector_active(vline) - 1;
-
-	/* First, filter by preceeding command string */
-	for (i = 0; i < index; i++)
-		if ((command = vector_slot(vline, i))) {
-			enum match_type match;
-			int ret;
-
-			/* First try completion match, if there is exactly match return 1 */
-			match =
-			    cmd_filter_by_completion(command, cmd_vector, i);
-
-			/* If there is exact match then filter ambiguous match else check
-			   ambiguousness. */
-			if ((ret =
-			     is_cmd_ambiguous(command, cmd_vector, i,
-					      match)) == 1) {
-				vector_free(cmd_vector);
-				*status = CMD_ERR_AMBIGUOUS;
-				return NULL;
-			}
-			/*
-			   else if (ret == 2)
-			   {
-			   vector_free (cmd_vector);
-			   *status = CMD_ERR_NO_MATCH;
-			   return NULL;
-			   }
-			 */
-		}
-
-	/* Prepare match vector. */
-	matchvec = vector_init(INIT_MATCHVEC_SIZE);
-
-	/* Now we got into completion */
-	for (i = 0; i < vector_active(cmd_vector); i++)
-		if ((cmd_element = vector_slot(cmd_vector, i))) {
-			const char *string;
-			vector strvec = cmd_element->strvec;
-
-			/* Check field length */
-			if (index >= vector_active(strvec))
-				vector_slot(cmd_vector, i) = NULL;
-			else {
-				unsigned int j;
-
-				descvec = vector_slot(strvec, index);
-				for (j = 0; j < vector_active(descvec); j++)
-					if ((desc = vector_slot(descvec, j))) {
-						if ((string = cmd_entry_function(vector_slot(vline, index), desc->cmd)))
-							if (cmd_unique_string (matchvec, string))
-								vector_set (matchvec, talloc_strdup(tall_vty_cmd_ctx, string));
-					}
-			}
-		}
-
-	/* We don't need cmd_vector any more. */
-	vector_free(cmd_vector);
-
-	/* No matched command */
-	if (vector_slot(matchvec, 0) == NULL) {
-		vector_free(matchvec);
-
-		/* In case of 'command \t' pattern.  Do you need '?' command at
-		   the end of the line. */
-		if (vector_slot(vline, index) == '\0')
-			*status = CMD_ERR_NOTHING_TODO;
-		else
-			*status = CMD_ERR_NO_MATCH;
-		return NULL;
-	}
-
-	/* Only one matched */
-	if (vector_slot(matchvec, 1) == NULL) {
-		match_str = (char **)matchvec->index;
-		vector_only_wrapper_free(matchvec);
-		*status = CMD_COMPLETE_FULL_MATCH;
-		return match_str;
-	}
-	/* Make it sure last element is NULL. */
-	vector_set(matchvec, NULL);
-
-	/* Check LCD of matched strings. */
-	if (vector_slot(vline, index) != NULL) {
-		lcd = cmd_lcd((char **)matchvec->index);
-
-		if (lcd) {
-			int len = strlen(vector_slot(vline, index));
-
-			if (len < lcd) {
-				char *lcdstr;
-
-				lcdstr = _talloc_zero(tall_vty_cmd_ctx, lcd + 1,
-						      "complete-lcdstr");
-				memcpy(lcdstr, matchvec->index[0], lcd);
-				lcdstr[lcd] = '\0';
-
-				/* match_str = (char **) &lcdstr; */
-
-				/* Free matchvec. */
-				for (i = 0; i < vector_active(matchvec); i++) {
-					if (vector_slot(matchvec, i))
-						talloc_free(vector_slot(matchvec, i));
-				}
-				vector_free(matchvec);
-
-				/* Make new matchvec. */
-				matchvec = vector_init(INIT_MATCHVEC_SIZE);
-				vector_set(matchvec, lcdstr);
-				match_str = (char **)matchvec->index;
-				vector_only_wrapper_free(matchvec);
-
-				*status = CMD_COMPLETE_MATCH;
-				return match_str;
-			}
-		}
-	}
-
-	match_str = (char **)matchvec->index;
-	vector_only_wrapper_free(matchvec);
-	*status = CMD_COMPLETE_LIST_MATCH;
-	return match_str;
-}
-
-char **cmd_complete_command(vector vline, struct vty *vty, int *status)
-{
-	char **ret;
-
-	if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
-		enum node_type onode;
-		vector shifted_vline;
-		unsigned int index;
-
-		onode = vty->node;
-		vty->node = ENABLE_NODE;
-		/* We can try it on enable node, cos' the vty is authenticated */
-
-		shifted_vline = vector_init(vector_count(vline));
-		/* use memcpy? */
-		for (index = 1; index < vector_active(vline); index++) {
-			vector_set_index(shifted_vline, index - 1,
-					 vector_lookup(vline, index));
-		}
-
-		ret = cmd_complete_command_real(shifted_vline, vty, status);
-
-		vector_free(shifted_vline);
-		vty->node = onode;
-		return ret;
-	}
-
-	return cmd_complete_command_real(vline, vty, status);
-}
-
-/* return parent node */
-/* MUST eventually converge on CONFIG_NODE */
-enum node_type vty_go_parent(struct vty *vty)
-{
-	assert(vty->node > CONFIG_NODE);
-
-	switch (vty->node) {
-	case GSMNET_NODE:
-		vty->node = CONFIG_NODE;
-		vty->index = NULL;
-		break;
-	case BTS_NODE:
-		vty->node = GSMNET_NODE;
-		{
-			/* set vty->index correctly ! */
-			struct gsm_bts *bts = vty->index;
-			vty->index = bts->network;
-		}
-		break;
-	case TRX_NODE:
-		vty->node = BTS_NODE;
-		{
-			/* set vty->index correctly ! */
-			struct gsm_bts_trx *trx = vty->index;
-			vty->index = trx->bts;
-		}
-		break;
-	case TS_NODE:
-		vty->node = TRX_NODE;
-		{
-			/* set vty->index correctly ! */
-			struct gsm_bts_trx_ts *ts = vty->index;
-			vty->index = ts->trx;
-		}
-		break;
-	case SUBSCR_NODE:
-		vty->node = VIEW_NODE;
-		subscr_put(vty->index);
-		vty->index = NULL;
-		break;
-	default:
-		vty->node = CONFIG_NODE;
-	}
-
-	return vty->node;
-}
-
-/* Execute command by argument vline vector. */
-static int
-cmd_execute_command_real(vector vline, struct vty *vty,
-			 struct cmd_element **cmd)
-{
-	unsigned int i;
-	unsigned int index;
-	vector cmd_vector;
-	struct cmd_element *cmd_element;
-	struct cmd_element *matched_element;
-	unsigned int matched_count, incomplete_count;
-	int argc;
-	const char *argv[CMD_ARGC_MAX];
-	enum match_type match = 0;
-	int varflag;
-	char *command;
-
-	/* Make copy of command elements. */
-	cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
-
-	for (index = 0; index < vector_active(vline); index++)
-		if ((command = vector_slot(vline, index))) {
-			int ret;
-
-			match =
-			    cmd_filter_by_completion(command, cmd_vector,
-						     index);
-
-			if (match == vararg_match)
-				break;
-
-			ret =
-			    is_cmd_ambiguous(command, cmd_vector, index, match);
-
-			if (ret == 1) {
-				vector_free(cmd_vector);
-				return CMD_ERR_AMBIGUOUS;
-			} else if (ret == 2) {
-				vector_free(cmd_vector);
-				return CMD_ERR_NO_MATCH;
-			}
-		}
-
-	/* Check matched count. */
-	matched_element = NULL;
-	matched_count = 0;
-	incomplete_count = 0;
-
-	for (i = 0; i < vector_active(cmd_vector); i++)
-		if ((cmd_element = vector_slot(cmd_vector, i))) {
-			if (match == vararg_match
-			    || index >= cmd_element->cmdsize) {
-				matched_element = cmd_element;
-#if 0
-				printf("DEBUG: %s\n", cmd_element->string);
-#endif
-				matched_count++;
-			} else {
-				incomplete_count++;
-			}
-		}
-
-	/* Finish of using cmd_vector. */
-	vector_free(cmd_vector);
-
-	/* To execute command, matched_count must be 1. */
-	if (matched_count == 0) {
-		if (incomplete_count)
-			return CMD_ERR_INCOMPLETE;
-		else
-			return CMD_ERR_NO_MATCH;
-	}
-
-	if (matched_count > 1)
-		return CMD_ERR_AMBIGUOUS;
-
-	/* Argument treatment */
-	varflag = 0;
-	argc = 0;
-
-	for (i = 0; i < vector_active(vline); i++) {
-		if (varflag)
-			argv[argc++] = vector_slot(vline, i);
-		else {
-			vector descvec =
-			    vector_slot(matched_element->strvec, i);
-
-			if (vector_active(descvec) == 1) {
-				struct desc *desc = vector_slot(descvec, 0);
-
-				if (CMD_VARARG(desc->cmd))
-					varflag = 1;
-
-				if (varflag || CMD_VARIABLE(desc->cmd)
-				    || CMD_OPTION(desc->cmd))
-					argv[argc++] = vector_slot(vline, i);
-			} else
-				argv[argc++] = vector_slot(vline, i);
-		}
-
-		if (argc >= CMD_ARGC_MAX)
-			return CMD_ERR_EXEED_ARGC_MAX;
-	}
-
-	/* For vtysh execution. */
-	if (cmd)
-		*cmd = matched_element;
-
-	if (matched_element->daemon)
-		return CMD_SUCCESS_DAEMON;
-
-	/* Execute matched command. */
-	return (*matched_element->func) (matched_element, vty, argc, argv);
-}
-
-int
-cmd_execute_command(vector vline, struct vty *vty, struct cmd_element **cmd,
-		    int vtysh)
-{
-	int ret, saved_ret, tried = 0;
-	enum node_type onode;
-	void *oindex;
-
-	onode = vty->node;
-	oindex = vty->index;
-
-	if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
-		vector shifted_vline;
-		unsigned int index;
-
-		vty->node = ENABLE_NODE;
-		/* We can try it on enable node, cos' the vty is authenticated */
-
-		shifted_vline = vector_init(vector_count(vline));
-		/* use memcpy? */
-		for (index = 1; index < vector_active(vline); index++) {
-			vector_set_index(shifted_vline, index - 1,
-					 vector_lookup(vline, index));
-		}
-
-		ret = cmd_execute_command_real(shifted_vline, vty, cmd);
-
-		vector_free(shifted_vline);
-		vty->node = onode;
-		return ret;
-	}
-
-	saved_ret = ret = cmd_execute_command_real(vline, vty, cmd);
-
-	if (vtysh)
-		return saved_ret;
-
-	/* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
-	while (ret != CMD_SUCCESS && ret != CMD_WARNING
-	       && vty->node > CONFIG_NODE) {
-		vty_go_parent(vty);
-		ret = cmd_execute_command_real(vline, vty, cmd);
-		tried = 1;
-		if (ret == CMD_SUCCESS || ret == CMD_WARNING) {
-			/* succesfull command, leave the node as is */
-			return ret;
-		}
-	}
-	/* no command succeeded, reset the vty to the original node and
-	   return the error for this node */
-	if (tried) {
-		vty->node = onode;
-		vty->index = oindex;
-	}
-	return saved_ret;
-}
-
-/* Execute command by argument readline. */
-int
-cmd_execute_command_strict(vector vline, struct vty *vty,
-			   struct cmd_element **cmd)
-{
-	unsigned int i;
-	unsigned int index;
-	vector cmd_vector;
-	struct cmd_element *cmd_element;
-	struct cmd_element *matched_element;
-	unsigned int matched_count, incomplete_count;
-	int argc;
-	const char *argv[CMD_ARGC_MAX];
-	int varflag;
-	enum match_type match = 0;
-	char *command;
-
-	/* Make copy of command element */
-	cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
-
-	for (index = 0; index < vector_active(vline); index++)
-		if ((command = vector_slot(vline, index))) {
-			int ret;
-
-			match = cmd_filter_by_string(vector_slot(vline, index),
-						     cmd_vector, index);
-
-			/* If command meets '.VARARG' then finish matching. */
-			if (match == vararg_match)
-				break;
-
-			ret =
-			    is_cmd_ambiguous(command, cmd_vector, index, match);
-			if (ret == 1) {
-				vector_free(cmd_vector);
-				return CMD_ERR_AMBIGUOUS;
-			}
-			if (ret == 2) {
-				vector_free(cmd_vector);
-				return CMD_ERR_NO_MATCH;
-			}
-		}
-
-	/* Check matched count. */
-	matched_element = NULL;
-	matched_count = 0;
-	incomplete_count = 0;
-	for (i = 0; i < vector_active(cmd_vector); i++)
-		if (vector_slot(cmd_vector, i) != NULL) {
-			cmd_element = vector_slot(cmd_vector, i);
-
-			if (match == vararg_match
-			    || index >= cmd_element->cmdsize) {
-				matched_element = cmd_element;
-				matched_count++;
-			} else
-				incomplete_count++;
-		}
-
-	/* Finish of using cmd_vector. */
-	vector_free(cmd_vector);
-
-	/* To execute command, matched_count must be 1. */
-	if (matched_count == 0) {
-		if (incomplete_count)
-			return CMD_ERR_INCOMPLETE;
-		else
-			return CMD_ERR_NO_MATCH;
-	}
-
-	if (matched_count > 1)
-		return CMD_ERR_AMBIGUOUS;
-
-	/* Argument treatment */
-	varflag = 0;
-	argc = 0;
-
-	for (i = 0; i < vector_active(vline); i++) {
-		if (varflag)
-			argv[argc++] = vector_slot(vline, i);
-		else {
-			vector descvec =
-			    vector_slot(matched_element->strvec, i);
-
-			if (vector_active(descvec) == 1) {
-				struct desc *desc = vector_slot(descvec, 0);
-
-				if (CMD_VARARG(desc->cmd))
-					varflag = 1;
-
-				if (varflag || CMD_VARIABLE(desc->cmd)
-				    || CMD_OPTION(desc->cmd))
-					argv[argc++] = vector_slot(vline, i);
-			} else
-				argv[argc++] = vector_slot(vline, i);
-		}
-
-		if (argc >= CMD_ARGC_MAX)
-			return CMD_ERR_EXEED_ARGC_MAX;
-	}
-
-	/* For vtysh execution. */
-	if (cmd)
-		*cmd = matched_element;
-
-	if (matched_element->daemon)
-		return CMD_SUCCESS_DAEMON;
-
-	/* Now execute matched command */
-	return (*matched_element->func) (matched_element, vty, argc, argv);
-}
-
-/* Configration make from file. */
-int config_from_file(struct vty *vty, FILE * fp)
-{
-	int ret;
-	vector vline;
-
-	while (fgets(vty->buf, VTY_BUFSIZ, fp)) {
-		vline = cmd_make_strvec(vty->buf);
-
-		/* In case of comment line */
-		if (vline == NULL)
-			continue;
-		/* Execute configuration command : this is strict match */
-		ret = cmd_execute_command_strict(vline, vty, NULL);
-
-		/* Try again with setting node to CONFIG_NODE */
-		while (ret != CMD_SUCCESS && ret != CMD_WARNING
-		       && ret != CMD_ERR_NOTHING_TODO
-		       && vty->node != CONFIG_NODE) {
-			vty_go_parent(vty);
-			ret = cmd_execute_command_strict(vline, vty, NULL);
-		}
-
-		cmd_free_strvec(vline);
-
-		if (ret != CMD_SUCCESS && ret != CMD_WARNING
-		    && ret != CMD_ERR_NOTHING_TODO)
-			return ret;
-	}
-	return CMD_SUCCESS;
-}
-
-/* Configration from terminal */
-DEFUN(config_terminal,
-      config_terminal_cmd,
-      "configure terminal",
-      "Configuration from vty interface\n" "Configuration terminal\n")
-{
-	if (vty_config_lock(vty))
-		vty->node = CONFIG_NODE;
-	else {
-		vty_out(vty, "VTY configuration is locked by other VTY%s",
-			VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-	return CMD_SUCCESS;
-}
-
-/* Enable command */
-DEFUN(enable, config_enable_cmd, "enable", "Turn on privileged mode command\n")
-{
-	/* If enable password is NULL, change to ENABLE_NODE */
-	if ((host.enable == NULL && host.enable_encrypt == NULL) ||
-	    vty->type == VTY_SHELL_SERV)
-		vty->node = ENABLE_NODE;
-	else
-		vty->node = AUTH_ENABLE_NODE;
-
-	return CMD_SUCCESS;
-}
-
-/* Disable command */
-DEFUN(disable,
-      config_disable_cmd, "disable", "Turn off privileged mode command\n")
-{
-	if (vty->node == ENABLE_NODE)
-		vty->node = VIEW_NODE;
-	return CMD_SUCCESS;
-}
-
-/* Down vty node level. */
-DEFUN(config_exit,
-      config_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
-{
-	switch (vty->node) {
-	case GSMNET_NODE:
-		vty->node = CONFIG_NODE;
-		vty->index = NULL;
-		break;
-	case BTS_NODE:
-		vty->node = GSMNET_NODE;
-		{
-			/* set vty->index correctly ! */
-			struct gsm_bts *bts = vty->index;
-			vty->index = bts->network;
-		}
-		break;
-	case TRX_NODE:
-		vty->node = BTS_NODE;
-		{
-			/* set vty->index correctly ! */
-			struct gsm_bts_trx *trx = vty->index;
-			vty->index = trx->bts;
-		}
-		break;
-	case TS_NODE:
-		vty->node = TRX_NODE;
-		{
-			/* set vty->index correctly ! */
-			struct gsm_bts_trx_ts *ts = vty->index;
-			vty->index = ts->trx;
-		}
-		break;
-	case SUBSCR_NODE:
-		vty->node = VIEW_NODE;
-		subscr_put(vty->index);
-		vty->index = NULL;
-		break;
-	case VIEW_NODE:
-	case ENABLE_NODE:
-		if (0)		//vty_shell (vty))
-			exit(0);
-		else
-			vty->status = VTY_CLOSE;
-		break;
-	case CONFIG_NODE:
-		vty->node = ENABLE_NODE;
-		vty_config_unlock(vty);
-		break;
-	case VTY_NODE:
-		vty->node = CONFIG_NODE;
-		break;
-	default:
-		break;
-	}
-	return CMD_SUCCESS;
-}
-
-/* quit is alias of exit. */
-ALIAS(config_exit,
-      config_quit_cmd, "quit", "Exit current mode and down to previous mode\n")
-
-/* End of configuration. */
-    DEFUN(config_end,
-      config_end_cmd, "end", "End current mode and change to enable mode.")
-{
-	switch (vty->node) {
-	case VIEW_NODE:
-	case ENABLE_NODE:
-		/* Nothing to do. */
-		break;
-	case CONFIG_NODE:
-	case VTY_NODE:
-		vty_config_unlock(vty);
-		vty->node = ENABLE_NODE;
-		break;
-	default:
-		break;
-	}
-	return CMD_SUCCESS;
-}
-
-/* Show version. */
-DEFUN(show_version,
-      show_version_cmd, "show version", SHOW_STR "Displays program version\n")
-{
-	vty_out(vty, "%s %s (%s).%s", QUAGGA_PROGNAME, QUAGGA_VERSION,
-		host.name ? host.name : "", VTY_NEWLINE);
-	vty_out(vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
-
-	return CMD_SUCCESS;
-}
-
-/* Help display function for all node. */
-DEFUN(config_help,
-      config_help_cmd, "help", "Description of the interactive help system\n")
-{
-	vty_out(vty,
-		"This VTY provides advanced help features.  When you need help,%s\
-anytime at the command line please press '?'.%s\
-%s\
-If nothing matches, the help list will be empty and you must backup%s\
- until entering a '?' shows the available options.%s\
-Two styles of help are provided:%s\
-1. Full help is available when you are ready to enter a%s\
-command argument (e.g. 'show ?') and describes each possible%s\
-argument.%s\
-2. Partial help is provided when an abbreviated argument is entered%s\
-   and you want to know what arguments match the input%s\
-   (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
-		VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
-	return CMD_SUCCESS;
-}
-
-/* Help display function for all node. */
-DEFUN(config_list, config_list_cmd, "list", "Print command list\n")
-{
-	unsigned int i;
-	struct cmd_node *cnode = vector_slot(cmdvec, vty->node);
-	struct cmd_element *cmd;
-
-	for (i = 0; i < vector_active(cnode->cmd_vector); i++)
-		if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL
-		    && !(cmd->attr == CMD_ATTR_DEPRECATED
-			 || cmd->attr == CMD_ATTR_HIDDEN))
-			vty_out(vty, "  %s%s", cmd->string, VTY_NEWLINE);
-	return CMD_SUCCESS;
-}
-
-/* Write current configuration into file. */
-DEFUN(config_write_file,
-      config_write_file_cmd,
-      "write file",
-      "Write running configuration to memory, network, or terminal\n"
-      "Write to configuration file\n")
-{
-	unsigned int i;
-	int fd;
-	struct cmd_node *node;
-	char *config_file;
-	char *config_file_tmp = NULL;
-	char *config_file_sav = NULL;
-	struct vty *file_vty;
-
-	/* Check and see if we are operating under vtysh configuration */
-	if (host.config == NULL) {
-		vty_out(vty, "Can't save to configuration file, using vtysh.%s",
-			VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	/* Get filename. */
-	config_file = host.config;
-
-	config_file_sav =
-	    _talloc_zero(tall_vty_cmd_ctx,
-			 strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1,
-			 "config_file_sav");
-	strcpy(config_file_sav, config_file);
-	strcat(config_file_sav, CONF_BACKUP_EXT);
-
-	config_file_tmp = _talloc_zero(tall_vty_cmd_ctx, strlen(config_file) + 8,
-					"config_file_tmp");
-	sprintf(config_file_tmp, "%s.XXXXXX", config_file);
-
-	/* Open file to configuration write. */
-	fd = mkstemp(config_file_tmp);
-	if (fd < 0) {
-		vty_out(vty, "Can't open configuration file %s.%s",
-			config_file_tmp, VTY_NEWLINE);
-		talloc_free(config_file_tmp);
-		talloc_free(config_file_sav);
-		return CMD_WARNING;
-	}
-
-	/* Make vty for configuration file. */
-	file_vty = vty_new();
-	file_vty->fd = fd;
-	file_vty->type = VTY_FILE;
-
-	/* Config file header print. */
-	vty_out(file_vty, "!\n! OpenBSC configuration saved from vty\n!   ");
-	//vty_time_print (file_vty, 1);
-	vty_out(file_vty, "!\n");
-
-	for (i = 0; i < vector_active(cmdvec); i++)
-		if ((node = vector_slot(cmdvec, i)) && node->func) {
-			if ((*node->func) (file_vty))
-				vty_out(file_vty, "!\n");
-		}
-	vty_close(file_vty);
-
-	if (unlink(config_file_sav) != 0)
-		if (errno != ENOENT) {
-			vty_out(vty,
-				"Can't unlink backup configuration file %s.%s",
-				config_file_sav, VTY_NEWLINE);
-			talloc_free(config_file_sav);
-			talloc_free(config_file_tmp);
-			unlink(config_file_tmp);
-			return CMD_WARNING;
-		}
-	if (link(config_file, config_file_sav) != 0) {
-		vty_out(vty, "Can't backup old configuration file %s.%s",
-			config_file_sav, VTY_NEWLINE);
-		talloc_free(config_file_sav);
-		talloc_free(config_file_tmp);
-		unlink(config_file_tmp);
-		return CMD_WARNING;
-	}
-	sync();
-	if (unlink(config_file) != 0) {
-		vty_out(vty, "Can't unlink configuration file %s.%s",
-			config_file, VTY_NEWLINE);
-		talloc_free(config_file_sav);
-		talloc_free(config_file_tmp);
-		unlink(config_file_tmp);
-		return CMD_WARNING;
-	}
-	if (link(config_file_tmp, config_file) != 0) {
-		vty_out(vty, "Can't save configuration file %s.%s", config_file,
-			VTY_NEWLINE);
-		talloc_free(config_file_sav);
-		talloc_free(config_file_tmp);
-		unlink(config_file_tmp);
-		return CMD_WARNING;
-	}
-	unlink(config_file_tmp);
-	sync();
-
-	talloc_free(config_file_sav);
-	talloc_free(config_file_tmp);
-
-	if (chmod(config_file, 0666 & ~CONFIGFILE_MASK) != 0) {
-		vty_out(vty, "Can't chmod configuration file %s: %s (%d).%s",
-			config_file, strerror(errno), errno, VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	vty_out(vty, "Configuration saved to %s%s", config_file, VTY_NEWLINE);
-	return CMD_SUCCESS;
-}
-
-ALIAS(config_write_file,
-      config_write_cmd,
-      "write", "Write running configuration to memory, network, or terminal\n")
-
-    ALIAS(config_write_file,
-      config_write_memory_cmd,
-      "write memory",
-      "Write running configuration to memory, network, or terminal\n"
-      "Write configuration to the file (same as write file)\n")
-
-    ALIAS(config_write_file,
-      copy_runningconfig_startupconfig_cmd,
-      "copy running-config startup-config",
-      "Copy configuration\n"
-      "Copy running config to... \n"
-      "Copy running config to startup config (same as write file)\n")
-
-/* Write current configuration into the terminal. */
-    DEFUN(config_write_terminal,
-      config_write_terminal_cmd,
-      "write terminal",
-      "Write running configuration to memory, network, or terminal\n"
-      "Write to terminal\n")
-{
-	unsigned int i;
-	struct cmd_node *node;
-
-	if (vty->type == VTY_SHELL_SERV) {
-		for (i = 0; i < vector_active(cmdvec); i++)
-			if ((node = vector_slot(cmdvec, i)) && node->func
-			    && node->vtysh) {
-				if ((*node->func) (vty))
-					vty_out(vty, "!%s", VTY_NEWLINE);
-			}
-	} else {
-		vty_out(vty, "%sCurrent configuration:%s", VTY_NEWLINE,
-			VTY_NEWLINE);
-		vty_out(vty, "!%s", VTY_NEWLINE);
-
-		for (i = 0; i < vector_active(cmdvec); i++)
-			if ((node = vector_slot(cmdvec, i)) && node->func) {
-				if ((*node->func) (vty))
-					vty_out(vty, "!%s", VTY_NEWLINE);
-			}
-		vty_out(vty, "end%s", VTY_NEWLINE);
-	}
-	return CMD_SUCCESS;
-}
-
-/* Write current configuration into the terminal. */
-ALIAS(config_write_terminal,
-      show_running_config_cmd,
-      "show running-config", SHOW_STR "running configuration\n")
-
-/* Write startup configuration into the terminal. */
-    DEFUN(show_startup_config,
-      show_startup_config_cmd,
-      "show startup-config", SHOW_STR "Contentes of startup configuration\n")
-{
-	char buf[BUFSIZ];
-	FILE *confp;
-
-	confp = fopen(host.config, "r");
-	if (confp == NULL) {
-		vty_out(vty, "Can't open configuration file [%s]%s",
-			host.config, VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	while (fgets(buf, BUFSIZ, confp)) {
-		char *cp = buf;
-
-		while (*cp != '\r' && *cp != '\n' && *cp != '\0')
-			cp++;
-		*cp = '\0';
-
-		vty_out(vty, "%s%s", buf, VTY_NEWLINE);
-	}
-
-	fclose(confp);
-
-	return CMD_SUCCESS;
-}
-
-/* Hostname configuration */
-DEFUN(config_hostname,
-      hostname_cmd,
-      "hostname WORD",
-      "Set system's network name\n" "This system's network name\n")
-{
-	if (!isalpha((int)*argv[0])) {
-		vty_out(vty, "Please specify string starting with alphabet%s",
-			VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	if (host.name)
-		talloc_free(host.name);
-
-	host.name = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
-	return CMD_SUCCESS;
-}
-
-DEFUN(config_no_hostname,
-      no_hostname_cmd,
-      "no hostname [HOSTNAME]",
-      NO_STR "Reset system's network name\n" "Host name of this router\n")
-{
-	if (host.name)
-		talloc_free(host.name);
-	host.name = NULL;
-	return CMD_SUCCESS;
-}
-
-/* VTY interface password set. */
-DEFUN(config_password, password_cmd,
-      "password (8|) WORD",
-      "Assign the terminal connection password\n"
-      "Specifies a HIDDEN password will follow\n"
-      "dummy string \n" "The HIDDEN line password string\n")
-{
-	/* Argument check. */
-	if (argc == 0) {
-		vty_out(vty, "Please specify password.%s", VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	if (argc == 2) {
-		if (*argv[0] == '8') {
-			if (host.password)
-				talloc_free(host.password);
-			host.password = NULL;
-			if (host.password_encrypt)
-				talloc_free(host.password_encrypt);
-			host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, argv[1]);
-			return CMD_SUCCESS;
-		} else {
-			vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE);
-			return CMD_WARNING;
-		}
-	}
-
-	if (!isalnum((int)*argv[0])) {
-		vty_out(vty,
-			"Please specify string starting with alphanumeric%s",
-			VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	if (host.password)
-		talloc_free(host.password);
-	host.password = NULL;
-
-#ifdef VTY_CRYPT_PW
-	if (host.encrypt) {
-		if (host.password_encrypt)
-			talloc_free(host.password_encrypt);
-		host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(argv[0]));
-	} else
-#endif
-		host.password = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
-
-	return CMD_SUCCESS;
-}
-
-ALIAS(config_password, password_text_cmd,
-      "password LINE",
-      "Assign the terminal connection password\n"
-      "The UNENCRYPTED (cleartext) line password\n")
-
-/* VTY enable password set. */
-    DEFUN(config_enable_password, enable_password_cmd,
-      "enable password (8|) WORD",
-      "Modify enable password parameters\n"
-      "Assign the privileged level password\n"
-      "Specifies a HIDDEN password will follow\n"
-      "dummy string \n" "The HIDDEN 'enable' password string\n")
-{
-	/* Argument check. */
-	if (argc == 0) {
-		vty_out(vty, "Please specify password.%s", VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	/* Crypt type is specified. */
-	if (argc == 2) {
-		if (*argv[0] == '8') {
-			if (host.enable)
-				talloc_free(host.enable);
-			host.enable = NULL;
-
-			if (host.enable_encrypt)
-				talloc_free(host.enable_encrypt);
-			host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, argv[1]);
-
-			return CMD_SUCCESS;
-		} else {
-			vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE);
-			return CMD_WARNING;
-		}
-	}
-
-	if (!isalnum((int)*argv[0])) {
-		vty_out(vty,
-			"Please specify string starting with alphanumeric%s",
-			VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	if (host.enable)
-		talloc_free(host.enable);
-	host.enable = NULL;
-
-	/* Plain password input. */
-#ifdef VTY_CRYPT_PW
-	if (host.encrypt) {
-		if (host.enable_encrypt)
-			talloc_free(host.enable_encrypt);
-		host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(argv[0]));
-	} else
-#endif
-		host.enable = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
-
-	return CMD_SUCCESS;
-}
-
-ALIAS(config_enable_password,
-      enable_password_text_cmd,
-      "enable password LINE",
-      "Modify enable password parameters\n"
-      "Assign the privileged level password\n"
-      "The UNENCRYPTED (cleartext) 'enable' password\n")
-
-/* VTY enable password delete. */
-    DEFUN(no_config_enable_password, no_enable_password_cmd,
-      "no enable password",
-      NO_STR
-      "Modify enable password parameters\n"
-      "Assign the privileged level password\n")
-{
-	if (host.enable)
-		talloc_free(host.enable);
-	host.enable = NULL;
-
-	if (host.enable_encrypt)
-		talloc_free(host.enable_encrypt);
-	host.enable_encrypt = NULL;
-
-	return CMD_SUCCESS;
-}
-
-#ifdef VTY_CRYPT_PW
-DEFUN(service_password_encrypt,
-      service_password_encrypt_cmd,
-      "service password-encryption",
-      "Set up miscellaneous service\n" "Enable encrypted passwords\n")
-{
-	if (host.encrypt)
-		return CMD_SUCCESS;
-
-	host.encrypt = 1;
-
-	if (host.password) {
-		if (host.password_encrypt)
-			talloc_free(host.password_encrypt);
-		host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(host.password));
-	}
-	if (host.enable) {
-		if (host.enable_encrypt)
-			talloc_free(host.enable_encrypt);
-		host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(host.enable));
-	}
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(no_service_password_encrypt,
-      no_service_password_encrypt_cmd,
-      "no service password-encryption",
-      NO_STR "Set up miscellaneous service\n" "Enable encrypted passwords\n")
-{
-	if (!host.encrypt)
-		return CMD_SUCCESS;
-
-	host.encrypt = 0;
-
-	if (host.password_encrypt)
-		talloc_free(host.password_encrypt);
-	host.password_encrypt = NULL;
-
-	if (host.enable_encrypt)
-		talloc_free(host.enable_encrypt);
-	host.enable_encrypt = NULL;
-
-	return CMD_SUCCESS;
-}
-#endif
-
-DEFUN(config_terminal_length, config_terminal_length_cmd,
-      "terminal length <0-512>",
-      "Set terminal line parameters\n"
-      "Set number of lines on a screen\n"
-      "Number of lines on screen (0 for no pausing)\n")
-{
-	int lines;
-	char *endptr = NULL;
-
-	lines = strtol(argv[0], &endptr, 10);
-	if (lines < 0 || lines > 512 || *endptr != '\0') {
-		vty_out(vty, "length is malformed%s", VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-	vty->lines = lines;
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(config_terminal_no_length, config_terminal_no_length_cmd,
-      "terminal no length",
-      "Set terminal line parameters\n"
-      NO_STR "Set number of lines on a screen\n")
-{
-	vty->lines = -1;
-	return CMD_SUCCESS;
-}
-
-DEFUN(service_terminal_length, service_terminal_length_cmd,
-      "service terminal-length <0-512>",
-      "Set up miscellaneous service\n"
-      "System wide terminal length configuration\n"
-      "Number of lines of VTY (0 means no line control)\n")
-{
-	int lines;
-	char *endptr = NULL;
-
-	lines = strtol(argv[0], &endptr, 10);
-	if (lines < 0 || lines > 512 || *endptr != '\0') {
-		vty_out(vty, "length is malformed%s", VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-	host.lines = lines;
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(no_service_terminal_length, no_service_terminal_length_cmd,
-      "no service terminal-length [<0-512>]",
-      NO_STR
-      "Set up miscellaneous service\n"
-      "System wide terminal length configuration\n"
-      "Number of lines of VTY (0 means no line control)\n")
-{
-	host.lines = -1;
-	return CMD_SUCCESS;
-}
-
-DEFUN_HIDDEN(do_echo,
-	     echo_cmd,
-	     "echo .MESSAGE",
-	     "Echo a message back to the vty\n" "The message to echo\n")
-{
-	char *message;
-
-	vty_out(vty, "%s%s",
-		((message =
-		  argv_concat(argv, argc, 0)) ? message : ""), VTY_NEWLINE);
-	if (message)
-		talloc_free(message);
-	return CMD_SUCCESS;
-}
-
-#if 0
-DEFUN(config_logmsg,
-      config_logmsg_cmd,
-      "logmsg " LOG_LEVELS " .MESSAGE",
-      "Send a message to enabled logging destinations\n"
-      LOG_LEVEL_DESC "The message to send\n")
-{
-	int level;
-	char *message;
-
-	if ((level = level_match(argv[0])) == ZLOG_DISABLED)
-		return CMD_ERR_NO_MATCH;
-
-	zlog(NULL, level,
-	     ((message = argv_concat(argv, argc, 1)) ? message : ""));
-	if (message)
-		talloc_free(message);
-	return CMD_SUCCESS;
-}
-
-DEFUN(show_logging,
-      show_logging_cmd,
-      "show logging", SHOW_STR "Show current logging configuration\n")
-{
-	struct zlog *zl = zlog_default;
-
-	vty_out(vty, "Syslog logging: ");
-	if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
-		vty_out(vty, "disabled");
-	else
-		vty_out(vty, "level %s, facility %s, ident %s",
-			zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
-			facility_name(zl->facility), zl->ident);
-	vty_out(vty, "%s", VTY_NEWLINE);
-
-	vty_out(vty, "Stdout logging: ");
-	if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
-		vty_out(vty, "disabled");
-	else
-		vty_out(vty, "level %s",
-			zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
-	vty_out(vty, "%s", VTY_NEWLINE);
-
-	vty_out(vty, "Monitor logging: ");
-	if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
-		vty_out(vty, "disabled");
-	else
-		vty_out(vty, "level %s",
-			zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
-	vty_out(vty, "%s", VTY_NEWLINE);
-
-	vty_out(vty, "File logging: ");
-	if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) || !zl->fp)
-		vty_out(vty, "disabled");
-	else
-		vty_out(vty, "level %s, filename %s",
-			zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
-			zl->filename);
-	vty_out(vty, "%s", VTY_NEWLINE);
-
-	vty_out(vty, "Protocol name: %s%s",
-		zlog_proto_names[zl->protocol], VTY_NEWLINE);
-	vty_out(vty, "Record priority: %s%s",
-		(zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(config_log_stdout,
-      config_log_stdout_cmd,
-      "log stdout", "Logging control\n" "Set stdout logging level\n")
-{
-	zlog_set_level(NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
-	return CMD_SUCCESS;
-}
-
-DEFUN(config_log_stdout_level,
-      config_log_stdout_level_cmd,
-      "log stdout " LOG_LEVELS,
-      "Logging control\n" "Set stdout logging level\n" LOG_LEVEL_DESC)
-{
-	int level;
-
-	if ((level = level_match(argv[0])) == ZLOG_DISABLED)
-		return CMD_ERR_NO_MATCH;
-	zlog_set_level(NULL, ZLOG_DEST_STDOUT, level);
-	return CMD_SUCCESS;
-}
-
-DEFUN(no_config_log_stdout,
-      no_config_log_stdout_cmd,
-      "no log stdout [LEVEL]",
-      NO_STR "Logging control\n" "Cancel logging to stdout\n" "Logging level\n")
-{
-	zlog_set_level(NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
-	return CMD_SUCCESS;
-}
-
-DEFUN(config_log_monitor,
-      config_log_monitor_cmd,
-      "log monitor",
-      "Logging control\n" "Set terminal line (monitor) logging level\n")
-{
-	zlog_set_level(NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
-	return CMD_SUCCESS;
-}
-
-DEFUN(config_log_monitor_level,
-      config_log_monitor_level_cmd,
-      "log monitor " LOG_LEVELS,
-      "Logging control\n"
-      "Set terminal line (monitor) logging level\n" LOG_LEVEL_DESC)
-{
-	int level;
-
-	if ((level = level_match(argv[0])) == ZLOG_DISABLED)
-		return CMD_ERR_NO_MATCH;
-	zlog_set_level(NULL, ZLOG_DEST_MONITOR, level);
-	return CMD_SUCCESS;
-}
-
-DEFUN(no_config_log_monitor,
-      no_config_log_monitor_cmd,
-      "no log monitor [LEVEL]",
-      NO_STR
-      "Logging control\n"
-      "Disable terminal line (monitor) logging\n" "Logging level\n")
-{
-	zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
-	return CMD_SUCCESS;
-}
-
-static int set_log_file(struct vty *vty, const char *fname, int loglevel)
-{
-	int ret;
-	char *p = NULL;
-	const char *fullpath;
-
-	/* Path detection. */
-	if (!IS_DIRECTORY_SEP(*fname)) {
-		char cwd[MAXPATHLEN + 1];
-		cwd[MAXPATHLEN] = '\0';
-
-		if (getcwd(cwd, MAXPATHLEN) == NULL) {
-			zlog_err("config_log_file: Unable to alloc mem!");
-			return CMD_WARNING;
-		}
-
-		if ((p = _talloc_zero(tall_vcmd_ctx,
-				      strlen(cwd) + strlen(fname) + 2),
-				      "set_log_file")
-		    == NULL) {
-			zlog_err("config_log_file: Unable to alloc mem!");
-			return CMD_WARNING;
-		}
-		sprintf(p, "%s/%s", cwd, fname);
-		fullpath = p;
-	} else
-		fullpath = fname;
-
-	ret = zlog_set_file(NULL, fullpath, loglevel);
-
-	if (p)
-		talloc_free(p);
-
-	if (!ret) {
-		vty_out(vty, "can't open logfile %s\n", fname);
-		return CMD_WARNING;
-	}
-
-	if (host.logfile)
-		talloc_free(host.logfile);
-
-	host.logfile = talloc_strdup(tall_vty_cmd_ctx, fname);
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(config_log_file,
-      config_log_file_cmd,
-      "log file FILENAME",
-      "Logging control\n" "Logging to file\n" "Logging filename\n")
-{
-	return set_log_file(vty, argv[0], zlog_default->default_lvl);
-}
-
-DEFUN(config_log_file_level,
-      config_log_file_level_cmd,
-      "log file FILENAME " LOG_LEVELS,
-      "Logging control\n"
-      "Logging to file\n" "Logging filename\n" LOG_LEVEL_DESC)
-{
-	int level;
-
-	if ((level = level_match(argv[1])) == ZLOG_DISABLED)
-		return CMD_ERR_NO_MATCH;
-	return set_log_file(vty, argv[0], level);
-}
-
-DEFUN(no_config_log_file,
-      no_config_log_file_cmd,
-      "no log file [FILENAME]",
-      NO_STR
-      "Logging control\n" "Cancel logging to file\n" "Logging file name\n")
-{
-	zlog_reset_file(NULL);
-
-	if (host.logfile)
-		talloc_free(host.logfile);
-
-	host.logfile = NULL;
-
-	return CMD_SUCCESS;
-}
-
-ALIAS(no_config_log_file,
-      no_config_log_file_level_cmd,
-      "no log file FILENAME LEVEL",
-      NO_STR
-      "Logging control\n"
-      "Cancel logging to file\n" "Logging file name\n" "Logging level\n")
-
-    DEFUN(config_log_syslog,
-      config_log_syslog_cmd,
-      "log syslog", "Logging control\n" "Set syslog logging level\n")
-{
-	zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
-	return CMD_SUCCESS;
-}
-
-DEFUN(config_log_syslog_level,
-      config_log_syslog_level_cmd,
-      "log syslog " LOG_LEVELS,
-      "Logging control\n" "Set syslog logging level\n" LOG_LEVEL_DESC)
-{
-	int level;
-
-	if ((level = level_match(argv[0])) == ZLOG_DISABLED)
-		return CMD_ERR_NO_MATCH;
-	zlog_set_level(NULL, ZLOG_DEST_SYSLOG, level);
-	return CMD_SUCCESS;
-}
-
-DEFUN_DEPRECATED(config_log_syslog_facility,
-		 config_log_syslog_facility_cmd,
-		 "log syslog facility " LOG_FACILITIES,
-		 "Logging control\n"
-		 "Logging goes to syslog\n"
-		 "(Deprecated) Facility parameter for syslog messages\n"
-		 LOG_FACILITY_DESC)
-{
-	int facility;
-
-	if ((facility = facility_match(argv[0])) < 0)
-		return CMD_ERR_NO_MATCH;
-
-	zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
-	zlog_default->facility = facility;
-	return CMD_SUCCESS;
-}
-
-DEFUN(no_config_log_syslog,
-      no_config_log_syslog_cmd,
-      "no log syslog [LEVEL]",
-      NO_STR "Logging control\n" "Cancel logging to syslog\n" "Logging level\n")
-{
-	zlog_set_level(NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
-	return CMD_SUCCESS;
-}
-
-ALIAS(no_config_log_syslog,
-      no_config_log_syslog_facility_cmd,
-      "no log syslog facility " LOG_FACILITIES,
-      NO_STR
-      "Logging control\n"
-      "Logging goes to syslog\n"
-      "Facility parameter for syslog messages\n" LOG_FACILITY_DESC)
-
-    DEFUN(config_log_facility,
-      config_log_facility_cmd,
-      "log facility " LOG_FACILITIES,
-      "Logging control\n"
-      "Facility parameter for syslog messages\n" LOG_FACILITY_DESC)
-{
-	int facility;
-
-	if ((facility = facility_match(argv[0])) < 0)
-		return CMD_ERR_NO_MATCH;
-	zlog_default->facility = facility;
-	return CMD_SUCCESS;
-}
-
-DEFUN(no_config_log_facility,
-      no_config_log_facility_cmd,
-      "no log facility [FACILITY]",
-      NO_STR
-      "Logging control\n"
-      "Reset syslog facility to default (daemon)\n" "Syslog facility\n")
-{
-	zlog_default->facility = LOG_DAEMON;
-	return CMD_SUCCESS;
-}
-
-DEFUN_DEPRECATED(config_log_trap,
-		 config_log_trap_cmd,
-		 "log trap " LOG_LEVELS,
-		 "Logging control\n"
-		 "(Deprecated) Set logging level and default for all destinations\n"
-		 LOG_LEVEL_DESC)
-{
-	int new_level;
-	int i;
-
-	if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
-		return CMD_ERR_NO_MATCH;
-
-	zlog_default->default_lvl = new_level;
-	for (i = 0; i < ZLOG_NUM_DESTS; i++)
-		if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
-			zlog_default->maxlvl[i] = new_level;
-	return CMD_SUCCESS;
-}
-
-DEFUN_DEPRECATED(no_config_log_trap,
-		 no_config_log_trap_cmd,
-		 "no log trap [LEVEL]",
-		 NO_STR
-		 "Logging control\n"
-		 "Permit all logging information\n" "Logging level\n")
-{
-	zlog_default->default_lvl = LOG_DEBUG;
-	return CMD_SUCCESS;
-}
-
-DEFUN(config_log_record_priority,
-      config_log_record_priority_cmd,
-      "log record-priority",
-      "Logging control\n"
-      "Log the priority of the message within the message\n")
-{
-	zlog_default->record_priority = 1;
-	return CMD_SUCCESS;
-}
-
-DEFUN(no_config_log_record_priority,
-      no_config_log_record_priority_cmd,
-      "no log record-priority",
-      NO_STR
-      "Logging control\n"
-      "Do not log the priority of the message within the message\n")
-{
-	zlog_default->record_priority = 0;
-	return CMD_SUCCESS;
-}
-#endif
-
-DEFUN(banner_motd_file,
-      banner_motd_file_cmd,
-      "banner motd file [FILE]",
-      "Set banner\n" "Banner for motd\n" "Banner from a file\n" "Filename\n")
-{
-	if (host.motdfile)
-		talloc_free(host.motdfile);
-	host.motdfile = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(banner_motd_default,
-      banner_motd_default_cmd,
-      "banner motd default",
-      "Set banner string\n" "Strings for motd\n" "Default string\n")
-{
-	host.motd = default_motd;
-	return CMD_SUCCESS;
-}
-
-DEFUN(no_banner_motd,
-      no_banner_motd_cmd,
-      "no banner motd", NO_STR "Set banner string\n" "Strings for motd\n")
-{
-	host.motd = NULL;
-	if (host.motdfile)
-		talloc_free(host.motdfile);
-	host.motdfile = NULL;
-	return CMD_SUCCESS;
-}
-
-/* Set config filename.  Called from vty.c */
-void host_config_set(const char *filename)
-{
-	host.config = talloc_strdup(tall_vty_cmd_ctx, filename);
-}
-
-void install_default(enum node_type node)
-{
-	install_element(node, &config_exit_cmd);
-	install_element(node, &config_quit_cmd);
-	install_element(node, &config_end_cmd);
-	install_element(node, &config_help_cmd);
-	install_element(node, &config_list_cmd);
-
-	install_element(node, &config_write_terminal_cmd);
-	install_element(node, &config_write_file_cmd);
-	install_element(node, &config_write_memory_cmd);
-	install_element(node, &config_write_cmd);
-	install_element(node, &show_running_config_cmd);
-}
-
-/* Initialize command interface. Install basic nodes and commands. */
-void cmd_init(int terminal)
-{
-	/* Allocate initial top vector of commands. */
-	cmdvec = vector_init(VECTOR_MIN_SIZE);
-
-	/* Default host value settings. */
-	host.name = NULL;
-	host.password = NULL;
-	host.enable = NULL;
-	host.logfile = NULL;
-	host.config = NULL;
-	host.lines = -1;
-	host.motd = default_motd;
-	host.motdfile = NULL;
-
-	/* Install top nodes. */
-	install_node(&view_node, NULL);
-	install_node(&enable_node, NULL);
-	install_node(&auth_node, NULL);
-	install_node(&auth_enable_node, NULL);
-	install_node(&config_node, config_write_host);
-
-	/* Each node's basic commands. */
-	install_element(VIEW_NODE, &show_version_cmd);
-	if (terminal) {
-		install_element(VIEW_NODE, &config_list_cmd);
-		install_element(VIEW_NODE, &config_exit_cmd);
-		install_element(VIEW_NODE, &config_quit_cmd);
-		install_element(VIEW_NODE, &config_help_cmd);
-		install_element(VIEW_NODE, &config_enable_cmd);
-		install_element(VIEW_NODE, &config_terminal_length_cmd);
-		install_element(VIEW_NODE, &config_terminal_no_length_cmd);
-		install_element(VIEW_NODE, &echo_cmd);
-	}
-
-	if (terminal) {
-		install_default(ENABLE_NODE);
-		install_element(ENABLE_NODE, &config_disable_cmd);
-		install_element(ENABLE_NODE, &config_terminal_cmd);
-		install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
-	}
-	install_element (ENABLE_NODE, &show_startup_config_cmd);
-	install_element(ENABLE_NODE, &show_version_cmd);
-
-	if (terminal) {
-		install_element(ENABLE_NODE, &config_terminal_length_cmd);
-		install_element(ENABLE_NODE, &config_terminal_no_length_cmd);
-		install_element(ENABLE_NODE, &echo_cmd);
-
-		install_default(CONFIG_NODE);
-	}
-
-	install_element(CONFIG_NODE, &hostname_cmd);
-	install_element(CONFIG_NODE, &no_hostname_cmd);
-
-	if (terminal) {
-		install_element(CONFIG_NODE, &password_cmd);
-		install_element(CONFIG_NODE, &password_text_cmd);
-		install_element(CONFIG_NODE, &enable_password_cmd);
-		install_element(CONFIG_NODE, &enable_password_text_cmd);
-		install_element(CONFIG_NODE, &no_enable_password_cmd);
-
-#ifdef VTY_CRYPT_PW
-		install_element(CONFIG_NODE, &service_password_encrypt_cmd);
-		install_element(CONFIG_NODE, &no_service_password_encrypt_cmd);
-#endif
-		install_element(CONFIG_NODE, &banner_motd_default_cmd);
-		install_element(CONFIG_NODE, &banner_motd_file_cmd);
-		install_element(CONFIG_NODE, &no_banner_motd_cmd);
-		install_element(CONFIG_NODE, &service_terminal_length_cmd);
-		install_element(CONFIG_NODE, &no_service_terminal_length_cmd);
-
-	}
-	srand(time(NULL));
-}
diff --git a/openbsc/src/vty/vector.c b/openbsc/src/vty/vector.c
deleted file mode 100644
index db47ae5..0000000
--- a/openbsc/src/vty/vector.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/* 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 <vty/vector.h>
-#include <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;
-}
diff --git a/openbsc/src/vty/vty.c b/openbsc/src/vty/vty.c
deleted file mode 100644
index 1260f38..0000000
--- a/openbsc/src/vty/vty.c
+++ /dev/null
@@ -1,1678 +0,0 @@
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <ctype.h>
-#include <termios.h>
-
-#include <sys/utsname.h>
-#include <sys/param.h>
-
-#include <arpa/telnet.h>
-
-#include "cardshell.h"
-#include <vty/vty.h>
-#include <vty/command.h>
-#include <vty/buffer.h>
-#include <osmocore/talloc.h>
-
-/* our callback, located in telnet_interface.c */
-void vty_event(enum event event, int sock, struct vty *vty);
-
-extern struct host host;
-
-/* Vector which store each vty structure. */
-static vector vtyvec;
-
-vector Vvty_serv_thread;
-
-char *vty_cwd = NULL;
-
-/* Configure lock. */
-static int vty_config;
-
-static int no_password_check = 1;
-
-void *tall_vty_ctx;
-
-static void vty_clear_buf(struct vty *vty)
-{
-	memset(vty->buf, 0, vty->max);
-}
-
-/* Allocate new vty struct. */
-struct vty *vty_new()
-{
-	struct vty *new = talloc_zero(tall_vty_ctx, struct vty);
-
-	if (!new)
-		goto out;
-
-	new->obuf = buffer_new(0);	/* Use default buffer size. */
-	if (!new->obuf)
-		goto out_new;
-	new->buf = _talloc_zero(tall_vty_ctx, VTY_BUFSIZ, "vty_new->buf");
-	if (!new->buf)
-		goto out_obuf;
-
-	new->max = VTY_BUFSIZ;
-
-	return new;
-
-out_obuf:
-	buffer_free(new->obuf);
-out_new:
-	talloc_free(new);
-	new = NULL;
-out:
-	return new;
-}
-
-/* Authentication of vty */
-static void vty_auth(struct vty *vty, char *buf)
-{
-	char *passwd = NULL;
-	enum node_type next_node = 0;
-	int fail;
-	char *crypt(const char *, const char *);
-
-	switch (vty->node) {
-	case AUTH_NODE:
-#ifdef VTY_CRYPT_PW
-		if (host.encrypt)
-			passwd = host.password_encrypt;
-		else
-#endif
-			passwd = host.password;
-		if (host.advanced)
-			next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
-		else
-			next_node = VIEW_NODE;
-		break;
-	case AUTH_ENABLE_NODE:
-#ifdef VTY_CRYPT_PW
-		if (host.encrypt)
-			passwd = host.enable_encrypt;
-		else
-#endif
-			passwd = host.enable;
-		next_node = ENABLE_NODE;
-		break;
-	}
-
-	if (passwd) {
-#ifdef VTY_CRYPT_PW
-		if (host.encrypt)
-			fail = strcmp(crypt(buf, passwd), passwd);
-		else
-#endif
-			fail = strcmp(buf, passwd);
-	} else
-		fail = 1;
-
-	if (!fail) {
-		vty->fail = 0;
-		vty->node = next_node;	/* Success ! */
-	} else {
-		vty->fail++;
-		if (vty->fail >= 3) {
-			if (vty->node == AUTH_NODE) {
-				vty_out(vty,
-					"%% Bad passwords, too many failures!%s",
-					VTY_NEWLINE);
-				vty->status = VTY_CLOSE;
-			} else {
-				/* AUTH_ENABLE_NODE */
-				vty->fail = 0;
-				vty_out(vty,
-					"%% Bad enable passwords, too many failures!%s",
-					VTY_NEWLINE);
-				vty->node = VIEW_NODE;
-			}
-		}
-	}
-}
-
-/* Close vty interface. */
-void vty_close(struct vty *vty)
-{
-	int i;
-
-	if (vty->obuf)  {
-		/* Flush buffer. */
-		buffer_flush_all(vty->obuf, vty->fd);
-
-		/* Free input buffer. */
-		buffer_free(vty->obuf);
-		vty->obuf = NULL;
-	}
-
-	/* Free command history. */
-	for (i = 0; i < VTY_MAXHIST; i++)
-		if (vty->hist[i])
-			talloc_free(vty->hist[i]);
-
-	/* Unset vector. */
-	vector_unset(vtyvec, vty->fd);
-
-	/* Close socket. */
-	if (vty->fd > 0)
-		close(vty->fd);
-
-	if (vty->buf) {
-		talloc_free(vty->buf);
-		vty->buf = NULL;
-	}
-
-	/* Check configure. */
-	vty_config_unlock(vty);
-
-	/* FIXME: memory leak. We need to call telnet_close_client() but don't
-	 * have bfd */
-	vty_event(VTY_CLOSED, vty->fd, vty);
-
-	/* OK free vty. */
-	talloc_free(vty);
-}
-
-int vty_shell(struct vty *vty)
-{
-	return vty->type == VTY_SHELL ? 1 : 0;
-}
-
-
-/* VTY standard output function. */
-int vty_out(struct vty *vty, const char *format, ...)
-{
-	va_list args;
-	int len = 0;
-	int size = 1024;
-	char buf[1024];
-	char *p = NULL;
-
-	if (vty_shell(vty)) {
-		va_start(args, format);
-		vprintf(format, args);
-		va_end(args);
-	} else {
-		/* Try to write to initial buffer.  */
-		va_start(args, format);
-		len = vsnprintf(buf, sizeof buf, format, args);
-		va_end(args);
-
-		/* Initial buffer is not enough.  */
-		if (len < 0 || len >= size) {
-			while (1) {
-				if (len > -1)
-					size = len + 1;
-				else
-					size = size * 2;
-
-				p = talloc_realloc_size(tall_vty_ctx, p, size);
-				if (!p)
-					return -1;
-
-				va_start(args, format);
-				len = vsnprintf(p, size, format, args);
-				va_end(args);
-
-				if (len > -1 && len < size)
-					break;
-			}
-		}
-
-		/* When initial buffer is enough to store all output.  */
-		if (!p)
-			p = buf;
-
-		/* Pointer p must point out buffer. */
-		buffer_put(vty->obuf, (u_char *) p, len);
-
-		/* If p is not different with buf, it is allocated buffer.  */
-		if (p != buf)
-			talloc_free(p);
-	}
-
-	vty_event(VTY_WRITE, vty->fd, vty);
-
-	return len;
-}
-
-int vty_out_newline(struct vty *vty)
-{
-	char *p = vty_newline(vty);
-	buffer_put(vty->obuf, p, strlen(p));
-	return 0;
-}
-
-int vty_config_lock(struct vty *vty)
-{
-	if (vty_config == 0) {
-		vty->config = 1;
-		vty_config = 1;
-	}
-	return vty->config;
-}
-
-int vty_config_unlock(struct vty *vty)
-{
-	if (vty_config == 1 && vty->config == 1) {
-		vty->config = 0;
-		vty_config = 0;
-	}
-	return vty->config;
-}
-
-/* Say hello to vty interface. */
-void vty_hello(struct vty *vty)
-{
-	if (host.motdfile) {
-		FILE *f;
-		char buf[4096];
-
-		f = fopen(host.motdfile, "r");
-		if (f) {
-			while (fgets(buf, sizeof(buf), f)) {
-				char *s;
-				/* work backwards to ignore trailling isspace() */
-				for (s = buf + strlen(buf);
-				     (s > buf) && isspace(*(s - 1)); s--) ;
-				*s = '\0';
-				vty_out(vty, "%s%s", buf, VTY_NEWLINE);
-			}
-			fclose(f);
-		} else
-			vty_out(vty, "MOTD file not found%s", VTY_NEWLINE);
-	} else if (host.motd)
-		vty_out(vty, "%s", host.motd);
-}
-
-/* Put out prompt and wait input from user. */
-static void vty_prompt(struct vty *vty)
-{
-	struct utsname names;
-	const char *hostname;
-
-	if (vty->type == VTY_TERM) {
-		hostname = host.name;
-		if (!hostname) {
-			uname(&names);
-			hostname = names.nodename;
-		}
-		vty_out(vty, cmd_prompt(vty->node), hostname);
-	}
-}
-
-/* Command execution over the vty interface. */
-static int vty_command(struct vty *vty, char *buf)
-{
-	int ret;
-	vector vline;
-
-	/* Split readline string up into the vector */
-	vline = cmd_make_strvec(buf);
-
-	if (vline == NULL)
-		return CMD_SUCCESS;
-
-	ret = cmd_execute_command(vline, vty, NULL, 0);
-	if (ret != CMD_SUCCESS)
-		switch (ret) {
-		case CMD_WARNING:
-			if (vty->type == VTY_FILE)
-				vty_out(vty, "Warning...%s", VTY_NEWLINE);
-			break;
-		case CMD_ERR_AMBIGUOUS:
-			vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
-			break;
-		case CMD_ERR_NO_MATCH:
-			vty_out(vty, "%% Unknown command.%s", VTY_NEWLINE);
-			break;
-		case CMD_ERR_INCOMPLETE:
-			vty_out(vty, "%% Command incomplete.%s", VTY_NEWLINE);
-			break;
-		}
-	cmd_free_strvec(vline);
-
-	return ret;
-}
-
-static const char telnet_backward_char = 0x08;
-static const char telnet_space_char = ' ';
-
-/* Basic function to write buffer to vty. */
-static void vty_write(struct vty *vty, const char *buf, size_t nbytes)
-{
-	if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
-		return;
-
-	/* Should we do buffering here ?  And make vty_flush (vty) ? */
-	buffer_put(vty->obuf, buf, nbytes);
-}
-
-/* Ensure length of input buffer.  Is buffer is short, double it. */
-static void vty_ensure(struct vty *vty, int length)
-{
-	if (vty->max <= length) {
-		vty->max *= 2;
-		vty->buf = talloc_realloc_size(tall_vty_ctx, vty->buf, vty->max);
-		// FIXME: check return
-	}
-}
-
-/* Basic function to insert character into vty. */
-static void vty_self_insert(struct vty *vty, char c)
-{
-	int i;
-	int length;
-
-	vty_ensure(vty, vty->length + 1);
-	length = vty->length - vty->cp;
-	memmove(&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
-	vty->buf[vty->cp] = c;
-
-	vty_write(vty, &vty->buf[vty->cp], length + 1);
-	for (i = 0; i < length; i++)
-		vty_write(vty, &telnet_backward_char, 1);
-
-	vty->cp++;
-	vty->length++;
-}
-
-/* Self insert character 'c' in overwrite mode. */
-static void vty_self_insert_overwrite(struct vty *vty, char c)
-{
-	vty_ensure(vty, vty->length + 1);
-	vty->buf[vty->cp++] = c;
-
-	if (vty->cp > vty->length)
-		vty->length++;
-
-	if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
-		return;
-
-	vty_write(vty, &c, 1);
-}
-
-/* Insert a word into vty interface with overwrite mode. */
-static void vty_insert_word_overwrite(struct vty *vty, char *str)
-{
-	int len = strlen(str);
-	vty_write(vty, str, len);
-	strcpy(&vty->buf[vty->cp], str);
-	vty->cp += len;
-	vty->length = vty->cp;
-}
-
-/* Forward character. */
-static void vty_forward_char(struct vty *vty)
-{
-	if (vty->cp < vty->length) {
-		vty_write(vty, &vty->buf[vty->cp], 1);
-		vty->cp++;
-	}
-}
-
-/* Backward character. */
-static void vty_backward_char(struct vty *vty)
-{
-	if (vty->cp > 0) {
-		vty->cp--;
-		vty_write(vty, &telnet_backward_char, 1);
-	}
-}
-
-/* Move to the beginning of the line. */
-static void vty_beginning_of_line(struct vty *vty)
-{
-	while (vty->cp)
-		vty_backward_char(vty);
-}
-
-/* Move to the end of the line. */
-static void vty_end_of_line(struct vty *vty)
-{
-	while (vty->cp < vty->length)
-		vty_forward_char(vty);
-}
-
-/* Add current command line to the history buffer. */
-static void vty_hist_add(struct vty *vty)
-{
-	int index;
-
-	if (vty->length == 0)
-		return;
-
-	index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
-
-	/* Ignore the same string as previous one. */
-	if (vty->hist[index])
-		if (strcmp(vty->buf, vty->hist[index]) == 0) {
-			vty->hp = vty->hindex;
-			return;
-		}
-
-	/* Insert history entry. */
-	if (vty->hist[vty->hindex])
-		talloc_free(vty->hist[vty->hindex]);
-	vty->hist[vty->hindex] = talloc_strdup(tall_vty_ctx, vty->buf);
-
-	/* History index rotation. */
-	vty->hindex++;
-	if (vty->hindex == VTY_MAXHIST)
-		vty->hindex = 0;
-
-	vty->hp = vty->hindex;
-}
-
-/* Get telnet window size. */
-static int
-vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
-{
-#ifdef TELNET_OPTION_DEBUG
-  int i;
-
-  for (i = 0; i < nbytes; i++)
-    {
-      switch (buf[i])
-	{
-	case IAC:
-	  vty_out (vty, "IAC ");
-	  break;
-	case WILL:
-	  vty_out (vty, "WILL ");
-	  break;
-	case WONT:
-	  vty_out (vty, "WONT ");
-	  break;
-	case DO:
-	  vty_out (vty, "DO ");
-	  break;
-	case DONT:
-	  vty_out (vty, "DONT ");
-	  break;
-	case SB:
-	  vty_out (vty, "SB ");
-	  break;
-	case SE:
-	  vty_out (vty, "SE ");
-	  break;
-	case TELOPT_ECHO:
-	  vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
-	  break;
-	case TELOPT_SGA:
-	  vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
-	  break;
-	case TELOPT_NAWS:
-	  vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
-	  break;
-	default:
-	  vty_out (vty, "%x ", buf[i]);
-	  break;
-	}
-    }
-  vty_out (vty, "%s", VTY_NEWLINE);
-
-#endif /* TELNET_OPTION_DEBUG */
-
-  switch (buf[0])
-    {
-    case SB:
-      vty->sb_len = 0;
-      vty->iac_sb_in_progress = 1;
-      return 0;
-      break;
-    case SE: 
-      {
-	if (!vty->iac_sb_in_progress)
-	  return 0;
-
-	if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
-	  {
-	    vty->iac_sb_in_progress = 0;
-	    return 0;
-	  }
-	switch (vty->sb_buf[0])
-	  {
-	  case TELOPT_NAWS:
-	    if (vty->sb_len != TELNET_NAWS_SB_LEN)
-	      vty_out(vty,"RFC 1073 violation detected: telnet NAWS option "
-			"should send %d characters, but we received %lu",
-			TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
-	    else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
-	      vty_out(vty, "Bug detected: sizeof(vty->sb_buf) %lu < %d, "
-		       "too small to handle the telnet NAWS option",
-		       (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
-	    else
-	      {
-		vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
-		vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
-#ifdef TELNET_OPTION_DEBUG
-		vty_out(vty, "TELNET NAWS window size negotiation completed: "
-			      "width %d, height %d%s",
-			vty->width, vty->height, VTY_NEWLINE);
-#endif
-	      }
-	    break;
-	  }
-	vty->iac_sb_in_progress = 0;
-	return 0;
-	break;
-      }
-    default:
-      break;
-    }
-  return 1;
-}
-
-/* Execute current command line. */
-static int vty_execute(struct vty *vty)
-{
-	int ret;
-
-	ret = CMD_SUCCESS;
-
-	switch (vty->node) {
-	case AUTH_NODE:
-	case AUTH_ENABLE_NODE:
-		vty_auth(vty, vty->buf);
-		break;
-	default:
-		ret = vty_command(vty, vty->buf);
-		if (vty->type == VTY_TERM)
-			vty_hist_add(vty);
-		break;
-	}
-
-	/* Clear command line buffer. */
-	vty->cp = vty->length = 0;
-	vty_clear_buf(vty);
-
-	if (vty->status != VTY_CLOSE)
-		vty_prompt(vty);
-
-	return ret;
-}
-
-/* Send WILL TELOPT_ECHO to remote server. */
-static void
-vty_will_echo (struct vty *vty)
-{
-	unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
-	vty_out (vty, "%s", cmd);
-}
-
-/* Make suppress Go-Ahead telnet option. */
-static void
-vty_will_suppress_go_ahead (struct vty *vty)
-{
-	unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
-	vty_out (vty, "%s", cmd);
-}
-
-/* Make don't use linemode over telnet. */
-static void
-vty_dont_linemode (struct vty *vty)
-{
-	unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
-	vty_out (vty, "%s", cmd);
-}
-
-/* Use window size. */
-static void
-vty_do_window_size (struct vty *vty)
-{
-	unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
-	vty_out (vty, "%s", cmd);
-}
-
-static void vty_kill_line_from_beginning(struct vty *);
-static void vty_redraw_line(struct vty *);
-
-/* Print command line history.  This function is called from
-   vty_next_line and vty_previous_line. */
-static void vty_history_print(struct vty *vty)
-{
-	int length;
-
-	vty_kill_line_from_beginning(vty);
-
-	/* Get previous line from history buffer */
-	length = strlen(vty->hist[vty->hp]);
-	memcpy(vty->buf, vty->hist[vty->hp], length);
-	vty->cp = vty->length = length;
-
-	/* Redraw current line */
-	vty_redraw_line(vty);
-}
-
-/* Show next command line history. */
-static void vty_next_line(struct vty *vty)
-{
-	int try_index;
-
-	if (vty->hp == vty->hindex)
-		return;
-
-	/* Try is there history exist or not. */
-	try_index = vty->hp;
-	if (try_index == (VTY_MAXHIST - 1))
-		try_index = 0;
-	else
-		try_index++;
-
-	/* If there is not history return. */
-	if (vty->hist[try_index] == NULL)
-		return;
-	else
-		vty->hp = try_index;
-
-	vty_history_print(vty);
-}
-
-/* Show previous command line history. */
-static void vty_previous_line(struct vty *vty)
-{
-	int try_index;
-
-	try_index = vty->hp;
-	if (try_index == 0)
-		try_index = VTY_MAXHIST - 1;
-	else
-		try_index--;
-
-	if (vty->hist[try_index] == NULL)
-		return;
-	else
-		vty->hp = try_index;
-
-	vty_history_print(vty);
-}
-
-/* This function redraw all of the command line character. */
-static void vty_redraw_line(struct vty *vty)
-{
-	vty_write(vty, vty->buf, vty->length);
-	vty->cp = vty->length;
-}
-
-/* Forward word. */
-static void vty_forward_word(struct vty *vty)
-{
-	while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
-		vty_forward_char(vty);
-
-	while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
-		vty_forward_char(vty);
-}
-
-/* Backward word without skipping training space. */
-static void vty_backward_pure_word(struct vty *vty)
-{
-	while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
-		vty_backward_char(vty);
-}
-
-/* Backward word. */
-static void vty_backward_word(struct vty *vty)
-{
-	while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
-		vty_backward_char(vty);
-
-	while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
-		vty_backward_char(vty);
-}
-
-/* When '^D' is typed at the beginning of the line we move to the down
-   level. */
-static void vty_down_level(struct vty *vty)
-{
-	vty_out(vty, "%s", VTY_NEWLINE);
-	(*config_exit_cmd.func) (NULL, vty, 0, NULL);
-	vty_prompt(vty);
-	vty->cp = 0;
-}
-
-/* When '^Z' is received from vty, move down to the enable mode. */
-static void vty_end_config(struct vty *vty)
-{
-	vty_out(vty, "%s", VTY_NEWLINE);
-
-	switch (vty->node) {
-	case VIEW_NODE:
-	case ENABLE_NODE:
-		/* Nothing to do. */
-		break;
-	case CONFIG_NODE:
-	case VTY_NODE:
-		vty_config_unlock(vty);
-		vty->node = ENABLE_NODE;
-		break;
-	default:
-		/* Unknown node, we have to ignore it. */
-		break;
-	}
-
-	vty_prompt(vty);
-	vty->cp = 0;
-}
-
-/* Delete a charcter at the current point. */
-static void vty_delete_char(struct vty *vty)
-{
-	int i;
-	int size;
-
-	if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
-		return;
-
-	if (vty->length == 0) {
-		vty_down_level(vty);
-		return;
-	}
-
-	if (vty->cp == vty->length)
-		return;		/* completion need here? */
-
-	size = vty->length - vty->cp;
-
-	vty->length--;
-	memmove(&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
-	vty->buf[vty->length] = '\0';
-
-	vty_write(vty, &vty->buf[vty->cp], size - 1);
-	vty_write(vty, &telnet_space_char, 1);
-
-	for (i = 0; i < size; i++)
-		vty_write(vty, &telnet_backward_char, 1);
-}
-
-/* Delete a character before the point. */
-static void vty_delete_backward_char(struct vty *vty)
-{
-	if (vty->cp == 0)
-		return;
-
-	vty_backward_char(vty);
-	vty_delete_char(vty);
-}
-
-/* Kill rest of line from current point. */
-static void vty_kill_line(struct vty *vty)
-{
-	int i;
-	int size;
-
-	size = vty->length - vty->cp;
-
-	if (size == 0)
-		return;
-
-	for (i = 0; i < size; i++)
-		vty_write(vty, &telnet_space_char, 1);
-	for (i = 0; i < size; i++)
-		vty_write(vty, &telnet_backward_char, 1);
-
-	memset(&vty->buf[vty->cp], 0, size);
-	vty->length = vty->cp;
-}
-
-/* Kill line from the beginning. */
-static void vty_kill_line_from_beginning(struct vty *vty)
-{
-	vty_beginning_of_line(vty);
-	vty_kill_line(vty);
-}
-
-/* Delete a word before the point. */
-static void vty_forward_kill_word(struct vty *vty)
-{
-	while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
-		vty_delete_char(vty);
-	while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
-		vty_delete_char(vty);
-}
-
-/* Delete a word before the point. */
-static void vty_backward_kill_word(struct vty *vty)
-{
-	while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
-		vty_delete_backward_char(vty);
-	while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
-		vty_delete_backward_char(vty);
-}
-
-/* Transpose chars before or at the point. */
-static void vty_transpose_chars(struct vty *vty)
-{
-	char c1, c2;
-
-	/* If length is short or point is near by the beginning of line then
-	   return. */
-	if (vty->length < 2 || vty->cp < 1)
-		return;
-
-	/* In case of point is located at the end of the line. */
-	if (vty->cp == vty->length) {
-		c1 = vty->buf[vty->cp - 1];
-		c2 = vty->buf[vty->cp - 2];
-
-		vty_backward_char(vty);
-		vty_backward_char(vty);
-		vty_self_insert_overwrite(vty, c1);
-		vty_self_insert_overwrite(vty, c2);
-	} else {
-		c1 = vty->buf[vty->cp];
-		c2 = vty->buf[vty->cp - 1];
-
-		vty_backward_char(vty);
-		vty_self_insert_overwrite(vty, c1);
-		vty_self_insert_overwrite(vty, c2);
-	}
-}
-
-/* Do completion at vty interface. */
-static void vty_complete_command(struct vty *vty)
-{
-	int i;
-	int ret;
-	char **matched = NULL;
-	vector vline;
-
-	if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
-		return;
-
-	vline = cmd_make_strvec(vty->buf);
-	if (vline == NULL)
-		return;
-
-	/* In case of 'help \t'. */
-	if (isspace((int)vty->buf[vty->length - 1]))
-		vector_set(vline, '\0');
-
-	matched = cmd_complete_command(vline, vty, &ret);
-
-	cmd_free_strvec(vline);
-
-	vty_out(vty, "%s", VTY_NEWLINE);
-	switch (ret) {
-	case CMD_ERR_AMBIGUOUS:
-		vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
-		vty_prompt(vty);
-		vty_redraw_line(vty);
-		break;
-	case CMD_ERR_NO_MATCH:
-		/* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
-		vty_prompt(vty);
-		vty_redraw_line(vty);
-		break;
-	case CMD_COMPLETE_FULL_MATCH:
-		vty_prompt(vty);
-		vty_redraw_line(vty);
-		vty_backward_pure_word(vty);
-		vty_insert_word_overwrite(vty, matched[0]);
-		vty_self_insert(vty, ' ');
-		//talloc_free(matched[0]);
-		break;
-	case CMD_COMPLETE_MATCH:
-		vty_prompt(vty);
-		vty_redraw_line(vty);
-		vty_backward_pure_word(vty);
-		vty_insert_word_overwrite(vty, matched[0]);
-		talloc_free(matched[0]);
-		vector_only_index_free(matched);
-		return;
-		break;
-	case CMD_COMPLETE_LIST_MATCH:
-		for (i = 0; matched[i] != NULL; i++) {
-			if (i != 0 && ((i % 6) == 0))
-				vty_out(vty, "%s", VTY_NEWLINE);
-			vty_out(vty, "%-10s ", matched[i]);
-			talloc_free(matched[i]);
-		}
-		vty_out(vty, "%s", VTY_NEWLINE);
-
-		vty_prompt(vty);
-		vty_redraw_line(vty);
-		break;
-	case CMD_ERR_NOTHING_TODO:
-		vty_prompt(vty);
-		vty_redraw_line(vty);
-		break;
-	default:
-		break;
-	}
-	if (matched)
-		vector_only_index_free(matched);
-}
-
-static void
-vty_describe_fold(struct vty *vty, int cmd_width,
-		  unsigned int desc_width, struct desc *desc)
-{
-	char *buf;
-	const char *cmd, *p;
-	int pos;
-
-	cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
-
-	if (desc_width <= 0) {
-		vty_out(vty, "  %-*s  %s%s", cmd_width, cmd, desc->str,
-			VTY_NEWLINE);
-		return;
-	}
-
-	buf = _talloc_zero(tall_vty_ctx, strlen(desc->str) + 1, "describe_fold");
-	if (!buf)
-		return;
-
-	for (p = desc->str; strlen(p) > desc_width; p += pos + 1) {
-		for (pos = desc_width; pos > 0; pos--)
-			if (*(p + pos) == ' ')
-				break;
-
-		if (pos == 0)
-			break;
-
-		strncpy(buf, p, pos);
-		buf[pos] = '\0';
-		vty_out(vty, "  %-*s  %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
-
-		cmd = "";
-	}
-
-	vty_out(vty, "  %-*s  %s%s", cmd_width, cmd, p, VTY_NEWLINE);
-
-	talloc_free(buf);
-}
-
-/* Describe matched command function. */
-static void vty_describe_command(struct vty *vty)
-{
-	int ret;
-	vector vline;
-	vector describe;
-	unsigned int i, width, desc_width;
-	struct desc *desc, *desc_cr = NULL;
-
-	vline = cmd_make_strvec(vty->buf);
-
-	/* In case of '> ?'. */
-	if (vline == NULL) {
-		vline = vector_init(1);
-		vector_set(vline, '\0');
-	} else if (isspace((int)vty->buf[vty->length - 1]))
-		vector_set(vline, '\0');
-
-	describe = cmd_describe_command(vline, vty, &ret);
-
-	vty_out(vty, "%s", VTY_NEWLINE);
-
-	/* Ambiguous error. */
-	switch (ret) {
-	case CMD_ERR_AMBIGUOUS:
-		cmd_free_strvec(vline);
-		vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
-		vty_prompt(vty);
-		vty_redraw_line(vty);
-		return;
-		break;
-	case CMD_ERR_NO_MATCH:
-		cmd_free_strvec(vline);
-		vty_out(vty, "%% There is no matched command.%s", VTY_NEWLINE);
-		vty_prompt(vty);
-		vty_redraw_line(vty);
-		return;
-		break;
-	}
-
-	/* Get width of command string. */
-	width = 0;
-	for (i = 0; i < vector_active(describe); i++)
-		if ((desc = vector_slot(describe, i)) != NULL) {
-			unsigned int len;
-
-			if (desc->cmd[0] == '\0')
-				continue;
-
-			len = strlen(desc->cmd);
-			if (desc->cmd[0] == '.')
-				len--;
-
-			if (width < len)
-				width = len;
-		}
-
-	/* Get width of description string. */
-	desc_width = vty->width - (width + 6);
-
-	/* Print out description. */
-	for (i = 0; i < vector_active(describe); i++)
-		if ((desc = vector_slot(describe, i)) != NULL) {
-			if (desc->cmd[0] == '\0')
-				continue;
-
-			if (strcmp(desc->cmd, "<cr>") == 0) {
-				desc_cr = desc;
-				continue;
-			}
-
-			if (!desc->str)
-				vty_out(vty, "  %-s%s",
-					desc->cmd[0] ==
-					'.' ? desc->cmd + 1 : desc->cmd,
-					VTY_NEWLINE);
-			else if (desc_width >= strlen(desc->str))
-				vty_out(vty, "  %-*s  %s%s", width,
-					desc->cmd[0] ==
-					'.' ? desc->cmd + 1 : desc->cmd,
-					desc->str, VTY_NEWLINE);
-			else
-				vty_describe_fold(vty, width, desc_width, desc);
-
-#if 0
-			vty_out(vty, "  %-*s %s%s", width
-				desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
-				desc->str ? desc->str : "", VTY_NEWLINE);
-#endif				/* 0 */
-		}
-
-	if ((desc = desc_cr)) {
-		if (!desc->str)
-			vty_out(vty, "  %-s%s",
-				desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
-				VTY_NEWLINE);
-		else if (desc_width >= strlen(desc->str))
-			vty_out(vty, "  %-*s  %s%s", width,
-				desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
-				desc->str, VTY_NEWLINE);
-		else
-			vty_describe_fold(vty, width, desc_width, desc);
-	}
-
-	cmd_free_strvec(vline);
-	vector_free(describe);
-
-	vty_prompt(vty);
-	vty_redraw_line(vty);
-}
-
-/* ^C stop current input and do not add command line to the history. */
-static void vty_stop_input(struct vty *vty)
-{
-	vty->cp = vty->length = 0;
-	vty_clear_buf(vty);
-	vty_out(vty, "%s", VTY_NEWLINE);
-
-	switch (vty->node) {
-	case VIEW_NODE:
-	case ENABLE_NODE:
-		/* Nothing to do. */
-		break;
-	case CONFIG_NODE:
-	case VTY_NODE:
-		vty_config_unlock(vty);
-		vty->node = ENABLE_NODE;
-		break;
-	default:
-		/* Unknown node, we have to ignore it. */
-		break;
-	}
-	vty_prompt(vty);
-
-	/* Set history pointer to the latest one. */
-	vty->hp = vty->hindex;
-}
-
-#define CONTROL(X)  ((X) - '@')
-#define VTY_NORMAL     0
-#define VTY_PRE_ESCAPE 1
-#define VTY_ESCAPE     2
-
-/* Escape character command map. */
-static void vty_escape_map(unsigned char c, struct vty *vty)
-{
-	switch (c) {
-	case ('A'):
-		vty_previous_line(vty);
-		break;
-	case ('B'):
-		vty_next_line(vty);
-		break;
-	case ('C'):
-		vty_forward_char(vty);
-		break;
-	case ('D'):
-		vty_backward_char(vty);
-		break;
-	default:
-		break;
-	}
-
-	/* Go back to normal mode. */
-	vty->escape = VTY_NORMAL;
-}
-
-/* Quit print out to the buffer. */
-static void vty_buffer_reset(struct vty *vty)
-{
-	buffer_reset(vty->obuf);
-	vty_prompt(vty);
-	vty_redraw_line(vty);
-}
-
-/* Read data via vty socket. */
-int vty_read(struct vty *vty)
-{
-	int i;
-	int nbytes;
-	unsigned char buf[VTY_READ_BUFSIZ];
-
-	int vty_sock = vty->fd;
-
-	/* Read raw data from socket */
-	if ((nbytes = read(vty->fd, buf, VTY_READ_BUFSIZ)) <= 0) {
-		if (nbytes < 0) {
-			if (ERRNO_IO_RETRY(errno)) {
-				vty_event(VTY_READ, vty_sock, vty);
-				return 0;
-			}
-		}
-		buffer_reset(vty->obuf);
-		vty->status = VTY_CLOSE;
-	}
-
-	for (i = 0; i < nbytes; i++) {
-		if (buf[i] == IAC) {
-			if (!vty->iac) {
-				vty->iac = 1;
-				continue;
-			} else {
-				vty->iac = 0;
-			}
-		}
-
-		if (vty->iac_sb_in_progress && !vty->iac) {
-			if (vty->sb_len < sizeof(vty->sb_buf))
-				vty->sb_buf[vty->sb_len] = buf[i];
-			vty->sb_len++;
-			continue;
-		}
-
-		if (vty->iac) {
-			/* In case of telnet command */
-			int ret = 0;
-			ret = vty_telnet_option(vty, buf + i, nbytes - i);
-			vty->iac = 0;
-			i += ret;
-			continue;
-		}
-
-		if (vty->status == VTY_MORE) {
-			switch (buf[i]) {
-			case CONTROL('C'):
-			case 'q':
-			case 'Q':
-				vty_buffer_reset(vty);
-				break;
-#if 0				/* More line does not work for "show ip bgp".  */
-			case '\n':
-			case '\r':
-				vty->status = VTY_MORELINE;
-				break;
-#endif
-			default:
-				break;
-			}
-			continue;
-		}
-
-		/* Escape character. */
-		if (vty->escape == VTY_ESCAPE) {
-			vty_escape_map(buf[i], vty);
-			continue;
-		}
-
-		/* Pre-escape status. */
-		if (vty->escape == VTY_PRE_ESCAPE) {
-			switch (buf[i]) {
-			case '[':
-				vty->escape = VTY_ESCAPE;
-				break;
-			case 'b':
-				vty_backward_word(vty);
-				vty->escape = VTY_NORMAL;
-				break;
-			case 'f':
-				vty_forward_word(vty);
-				vty->escape = VTY_NORMAL;
-				break;
-			case 'd':
-				vty_forward_kill_word(vty);
-				vty->escape = VTY_NORMAL;
-				break;
-			case CONTROL('H'):
-			case 0x7f:
-				vty_backward_kill_word(vty);
-				vty->escape = VTY_NORMAL;
-				break;
-			default:
-				vty->escape = VTY_NORMAL;
-				break;
-			}
-			continue;
-		}
-
-		switch (buf[i]) {
-		case CONTROL('A'):
-			vty_beginning_of_line(vty);
-			break;
-		case CONTROL('B'):
-			vty_backward_char(vty);
-			break;
-		case CONTROL('C'):
-			vty_stop_input(vty);
-			break;
-		case CONTROL('D'):
-			vty_delete_char(vty);
-			break;
-		case CONTROL('E'):
-			vty_end_of_line(vty);
-			break;
-		case CONTROL('F'):
-			vty_forward_char(vty);
-			break;
-		case CONTROL('H'):
-		case 0x7f:
-			vty_delete_backward_char(vty);
-			break;
-		case CONTROL('K'):
-			vty_kill_line(vty);
-			break;
-		case CONTROL('N'):
-			vty_next_line(vty);
-			break;
-		case CONTROL('P'):
-			vty_previous_line(vty);
-			break;
-		case CONTROL('T'):
-			vty_transpose_chars(vty);
-			break;
-		case CONTROL('U'):
-			vty_kill_line_from_beginning(vty);
-			break;
-		case CONTROL('W'):
-			vty_backward_kill_word(vty);
-			break;
-		case CONTROL('Z'):
-			vty_end_config(vty);
-			break;
-		case '\n':
-		case '\r':
-			vty_out(vty, "%s", VTY_NEWLINE);
-			vty_execute(vty);
-			break;
-		case '\t':
-			vty_complete_command(vty);
-			break;
-		case '?':
-			if (vty->node == AUTH_NODE
-			    || vty->node == AUTH_ENABLE_NODE)
-				vty_self_insert(vty, buf[i]);
-			else
-				vty_describe_command(vty);
-			break;
-		case '\033':
-			if (i + 1 < nbytes && buf[i + 1] == '[') {
-				vty->escape = VTY_ESCAPE;
-				i++;
-			} else
-				vty->escape = VTY_PRE_ESCAPE;
-			break;
-		default:
-			if (buf[i] > 31 && buf[i] < 127)
-				vty_self_insert(vty, buf[i]);
-			break;
-		}
-	}
-
-	/* Check status. */
-	if (vty->status == VTY_CLOSE)
-		vty_close(vty);
-	else {
-		vty_event(VTY_WRITE, vty_sock, vty);
-		vty_event(VTY_READ, vty_sock, vty);
-	}
-	return 0;
-}
-
-/* Read up configuration file */
-static int
-vty_read_file(FILE *confp)
-{
-	int ret;
-	struct vty *vty;
-
-	vty = vty_new();
-	vty->fd = 0;
-	vty->type = VTY_FILE;
-	vty->node = CONFIG_NODE;
-
-	ret = config_from_file(vty, confp);
-
-	if (ret != CMD_SUCCESS) {
-		switch (ret) {
-		case CMD_ERR_AMBIGUOUS:
-			fprintf(stderr, "Ambiguous command.\n");
-			break;
-		case CMD_ERR_NO_MATCH:
-			fprintf(stderr, "There is no such command.\n");
-			break;
-		}
-		fprintf(stderr, "Error occurred during reading below "
-			"line:\n%s\n", vty->buf);
-		vty_close(vty);
-		return -EINVAL;
-	}
-
-	vty_close(vty);
-	return 0;
-}
-
-/* Create new vty structure. */
-struct vty *
-vty_create (int vty_sock, void *priv)
-{
-  struct vty *vty;
-
-	struct termios t;
-
-	tcgetattr(vty_sock, &t);
-	cfmakeraw(&t);
-	tcsetattr(vty_sock, TCSANOW, &t);
-
-  /* Allocate new vty structure and set up default values. */
-  vty = vty_new ();
-  vty->fd = vty_sock;
-  vty->priv = priv;
-  vty->type = VTY_TERM;
-  if (no_password_check)
-    {
-      if (host.advanced)
-	vty->node = ENABLE_NODE;
-      else
-	vty->node = VIEW_NODE;
-    }
-  else
-    vty->node = AUTH_NODE;
-  vty->fail = 0;
-  vty->cp = 0;
-  vty_clear_buf (vty);
-  vty->length = 0;
-  memset (vty->hist, 0, sizeof (vty->hist));
-  vty->hp = 0;
-  vty->hindex = 0;
-  vector_set_index (vtyvec, vty_sock, vty);
-  vty->status = VTY_NORMAL;
-  if (host.lines >= 0)
-    vty->lines = host.lines;
-  else
-    vty->lines = -1;
-
-  if (! no_password_check)
-    {
-      /* Vty is not available if password isn't set. */
-      if (host.password == NULL && host.password_encrypt == NULL)
-	{
-	  vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
-	  vty->status = VTY_CLOSE;
-	  vty_close (vty);
-	  return NULL;
-	}
-    }
-
-  /* Say hello to the world. */
-  vty_hello (vty);
-  if (! no_password_check)
-    vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
-
-  /* Setting up terminal. */
-  vty_will_echo (vty);
-  vty_will_suppress_go_ahead (vty);
-
-  vty_dont_linemode (vty);
-  vty_do_window_size (vty);
-  /* vty_dont_lflow_ahead (vty); */
-
-  vty_prompt (vty);
-
-  /* Add read/write thread. */
-  vty_event (VTY_WRITE, vty_sock, vty);
-  vty_event (VTY_READ, vty_sock, vty);
-
-  return vty;
-}
-
-DEFUN(config_who, config_who_cmd, "who", "Display who is on vty\n")
-{
-	unsigned int i;
-	struct vty *v;
-
-	for (i = 0; i < vector_active(vtyvec); i++)
-		if ((v = vector_slot(vtyvec, i)) != NULL)
-			vty_out(vty, "%svty[%d] %s",
-				v->config ? "*" : " ", i, VTY_NEWLINE);
-	return CMD_SUCCESS;
-}
-
-/* Move to vty configuration mode. */
-DEFUN(line_vty,
-      line_vty_cmd,
-      "line vty", "Configure a terminal line\n" "Virtual terminal\n")
-{
-	vty->node = VTY_NODE;
-	return CMD_SUCCESS;
-}
-
-/* vty login. */
-DEFUN(vty_login, vty_login_cmd, "login", "Enable password checking\n")
-{
-	no_password_check = 0;
-	return CMD_SUCCESS;
-}
-
-DEFUN(no_vty_login,
-      no_vty_login_cmd, "no login", NO_STR "Enable password checking\n")
-{
-	no_password_check = 1;
-	return CMD_SUCCESS;
-}
-
-DEFUN(service_advanced_vty,
-      service_advanced_vty_cmd,
-      "service advanced-vty",
-      "Set up miscellaneous service\n" "Enable advanced mode vty interface\n")
-{
-	host.advanced = 1;
-	return CMD_SUCCESS;
-}
-
-DEFUN(no_service_advanced_vty,
-      no_service_advanced_vty_cmd,
-      "no service advanced-vty",
-      NO_STR
-      "Set up miscellaneous service\n" "Enable advanced mode vty interface\n")
-{
-	host.advanced = 0;
-	return CMD_SUCCESS;
-}
-
-DEFUN(terminal_monitor,
-      terminal_monitor_cmd,
-      "terminal monitor",
-      "Set terminal line parameters\n"
-      "Copy debug output to the current terminal line\n")
-{
-	vty->monitor = 1;
-	return CMD_SUCCESS;
-}
-
-DEFUN(terminal_no_monitor,
-      terminal_no_monitor_cmd,
-      "terminal no monitor",
-      "Set terminal line parameters\n"
-      NO_STR "Copy debug output to the current terminal line\n")
-{
-	vty->monitor = 0;
-	return CMD_SUCCESS;
-}
-
-DEFUN(show_history,
-      show_history_cmd,
-      "show history", SHOW_STR "Display the session command history\n")
-{
-	int index;
-
-	for (index = vty->hindex + 1; index != vty->hindex;) {
-		if (index == VTY_MAXHIST) {
-			index = 0;
-			continue;
-		}
-
-		if (vty->hist[index] != NULL)
-			vty_out(vty, "  %s%s", vty->hist[index], VTY_NEWLINE);
-
-		index++;
-	}
-
-	return CMD_SUCCESS;
-}
-
-/* Display current configuration. */
-static int vty_config_write(struct vty *vty)
-{
-	vty_out(vty, "line vty%s", VTY_NEWLINE);
-
-	/* login */
-	if (no_password_check)
-		vty_out(vty, " no login%s", VTY_NEWLINE);
-
-	vty_out(vty, "!%s", VTY_NEWLINE);
-
-	return CMD_SUCCESS;
-}
-
-struct cmd_node vty_node = {
-	VTY_NODE,
-	"%s(config-line)# ",
-	1,
-};
-
-/* Reset all VTY status. */
-void vty_reset()
-{
-	unsigned int i;
-	struct vty *vty;
-	struct thread *vty_serv_thread;
-
-	for (i = 0; i < vector_active(vtyvec); i++)
-		if ((vty = vector_slot(vtyvec, i)) != NULL) {
-			buffer_reset(vty->obuf);
-			vty->status = VTY_CLOSE;
-			vty_close(vty);
-		}
-
-	for (i = 0; i < vector_active(Vvty_serv_thread); i++)
-		if ((vty_serv_thread =
-		     vector_slot(Vvty_serv_thread, i)) != NULL) {
-			//thread_cancel (vty_serv_thread);
-			vector_slot(Vvty_serv_thread, i) = NULL;
-			close(i);
-		}
-}
-
-static void vty_save_cwd(void)
-{
-	char cwd[MAXPATHLEN];
-	char *c ;
-
-	c = getcwd(cwd, MAXPATHLEN);
-
-	if (!c) {
-		if (chdir(SYSCONFDIR) != 0)
-		    perror("chdir failed");
-		if (getcwd(cwd, MAXPATHLEN) == NULL)
-		    perror("getcwd failed");
-	}
-
-	vty_cwd = _talloc_zero(tall_vty_ctx, strlen(cwd) + 1, "save_cwd");
-	strcpy(vty_cwd, cwd);
-}
-
-char *vty_get_cwd()
-{
-	return vty_cwd;
-}
-
-int vty_shell_serv(struct vty *vty)
-{
-	return vty->type == VTY_SHELL_SERV ? 1 : 0;
-}
-
-void vty_init_vtysh()
-{
-	vtyvec = vector_init(VECTOR_MIN_SIZE);
-}
-
-extern void *tall_bsc_ctx;
-/* Install vty's own commands like `who' command. */
-void vty_init()
-{
-	tall_vty_ctx = talloc_named_const(NULL, 0, "vty");
-	tall_vty_vec_ctx = talloc_named_const(tall_vty_ctx, 0, "vty_vector");
-	tall_vty_cmd_ctx = talloc_named_const(tall_vty_ctx, 0, "vty_command");
-
-	/* For further configuration read, preserve current directory. */
-	vty_save_cwd();
-
-	vtyvec = vector_init(VECTOR_MIN_SIZE);
-
-	/* Install bgp top node. */
-	install_node(&vty_node, vty_config_write);
-
-	install_element(VIEW_NODE, &config_who_cmd);
-	install_element(VIEW_NODE, &show_history_cmd);
-	install_element(ENABLE_NODE, &config_who_cmd);
-	install_element(CONFIG_NODE, &line_vty_cmd);
-	install_element(CONFIG_NODE, &service_advanced_vty_cmd);
-	install_element(CONFIG_NODE, &no_service_advanced_vty_cmd);
-	install_element(CONFIG_NODE, &show_history_cmd);
-	install_element(ENABLE_NODE, &terminal_monitor_cmd);
-	install_element(ENABLE_NODE, &terminal_no_monitor_cmd);
-	install_element(ENABLE_NODE, &show_history_cmd);
-
-	install_default(VTY_NODE);
-	install_element(VTY_NODE, &vty_login_cmd);
-	install_element(VTY_NODE, &no_vty_login_cmd);
-}
-
-int vty_read_config_file(const char *file_name)
-{
-	FILE *cfile;
-	int rc;
-
-	cfile = fopen(file_name, "r");
-	if (!cfile)
-		return -ENOENT;
-
-	rc = vty_read_file(cfile);
-	fclose(cfile);
-
-	host_config_set(file_name);
-
-	return rc;
-}
diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c
index b824c3d..7c32c05 100644
--- a/openbsc/src/vty_interface_layer3.c
+++ b/openbsc/src/vty_interface_layer3.c
@@ -23,9 +23,9 @@
 #include <unistd.h>
 #include <sys/types.h>
 
-#include <vty/command.h>
-#include <vty/buffer.h>
-#include <vty/vty.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/buffer.h>
+#include <osmocom/vty/vty.h>
 
 #include <arpa/inet.h>
 
@@ -41,36 +41,9 @@
 #include <osmocore/talloc.h>
 #include <openbsc/signal.h>
 #include <openbsc/debug.h>
+#include <openbsc/vty.h>
 
-static struct gsm_network *gsmnet;
-
-struct cmd_node subscr_node = {
-	SUBSCR_NODE,
-	"%s(subscriber)#",
-	1,
-};
-
-static int dummy_config_write(struct vty *v)
-{
-	return CMD_SUCCESS;
-}
-
-static struct buffer *argv_to_buffer(int argc, const char *argv[], int base)
-{
-	struct buffer *b = buffer_new(1024);
-	int i;
-
-	if (!b)
-		return NULL;
-
-	for (i = base; i < argc; i++) {
-		buffer_putstr(b, argv[i]);
-		buffer_putc(b, ' ');
-	}
-	buffer_putc(b, '\0');
-
-	return b;
-}
+extern struct gsm_network *gsmnet_from_vty(struct vty *v);
 
 static int hexparse(const char *str, u_int8_t *b, int max_len)
 
@@ -99,29 +72,6 @@
 	return i>>1;
 }
 
-/* per-subscriber configuration */
-DEFUN(cfg_subscr,
-      cfg_subscr_cmd,
-      "subscriber IMSI",
-      "Select a Subscriber to configure\n")
-{
-	const char *imsi = argv[0];
-	struct gsm_subscriber *subscr;
-
-	subscr = subscr_get_by_imsi(gsmnet, imsi);
-	if (!subscr) {
-		vty_out(vty, "%% No subscriber for IMSI %s%s",
-			imsi, VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	/* vty_go_parent should put this subscriber */
-	vty->index = subscr;
-	vty->node = SUBSCR_NODE;
-
-	return CMD_SUCCESS;
-}
-
 static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr)
 {
 	int rc;
@@ -141,7 +91,7 @@
 		vty_out(vty, "    TMSI: %08X%s", subscr->tmsi,
 			VTY_NEWLINE);
 
-	rc = get_authinfo_by_subscr(&ainfo, subscr);
+	rc = db_get_authinfo_for_subscr(&ainfo, subscr);
 	if (!rc) {
 		vty_out(vty, "    A3A8 algorithm id: %d%s",
 			ainfo.auth_algo, VTY_NEWLINE);
@@ -150,7 +100,7 @@
 			VTY_NEWLINE);
 	}
 
-	rc = get_authtuple_by_subscr(&atuple, subscr);
+	rc = db_get_lastauthtuple_for_subscr(&atuple, subscr);
 	if (!rc) {
 		vty_out(vty, "    A3A8 last tuple (used %d times):%s",
 			atuple.use_count, VTY_NEWLINE);
@@ -172,34 +122,6 @@
 
 
 /* Subscriber */
-DEFUN(show_subscr,
-      show_subscr_cmd,
-      "show subscriber [IMSI]",
-	SHOW_STR "Display information about a subscriber\n")
-{
-	const char *imsi;
-	struct gsm_subscriber *subscr;
-
-	if (argc >= 1) {
-		imsi = argv[0];
-		subscr = subscr_get_by_imsi(gsmnet, imsi);
-		if (!subscr) {
-			vty_out(vty, "%% unknown subscriber%s",
-				VTY_NEWLINE);
-			return CMD_WARNING;
-		}
-		subscr_dump_full_vty(vty, subscr);
-		subscr_put(subscr);
-
-		return CMD_SUCCESS;
-	}
-
-	/* FIXME: iterate over all subscribers ? */
-	return CMD_WARNING;
-
-	return CMD_SUCCESS;
-}
-
 DEFUN(show_subscr_cache,
       show_subscr_cache_cmd,
       "show subscriber cache",
@@ -220,6 +142,7 @@
       "sms send pending",
       "Send all pending SMS")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	struct gsm_sms *sms;
 	int id = 0;
 
@@ -252,7 +175,7 @@
 	strncpy(sms->text, text, sizeof(sms->text)-1);
 
 	/* FIXME: don't use ID 1 static */
-	sms->sender = subscr_get_by_id(gsmnet, 1);
+	sms->sender = subscr_get_by_id(receiver->net, 1);
 	sms->reply_path_req = 0;
 	sms->status_rep_req = 0;
 	sms->ud_hdr_ind = 0;
@@ -265,19 +188,20 @@
 	return sms;
 }
 
-static int _send_sms_buffer(struct gsm_subscriber *receiver,
-			     struct buffer *b, u_int8_t tp_pid)
+static int _send_sms_str(struct gsm_subscriber *receiver, char *str,
+			 u_int8_t tp_pid)
 {
 	struct gsm_sms *sms;
 
-	sms = sms_from_text(receiver, buffer_getstr(b));
+	sms = sms_from_text(receiver, str);
 	sms->protocol_id = tp_pid;
 	gsm411_send_sms_subscr(receiver, sms);
 
 	return CMD_SUCCESS;
 }
 
-static struct gsm_subscriber *get_subscr_by_argv(const char *type,
+static struct gsm_subscriber *get_subscr_by_argv(struct gsm_network *gsmnet,
+						 const char *type,
 						 const char *id)
 {
 	if (!strcmp(type, "extension"))
@@ -292,14 +216,43 @@
 	return NULL;
 }
 #define SUBSCR_TYPES "(extension|imsi|tmsi|id)"
+#define SUBSCR_HELP "Operations on a Subscriber\n"			\
+	"Identify subscriber by his extension (phone number)\n"		\
+	"Identify subscriber by his IMSI\n"				\
+	"Identify subscriber by his TMSI\n"				\
+	"Identify subscriber by his database ID\n"			\
+	"Identifier for the subscriber\n"
+
+DEFUN(show_subscr,
+      show_subscr_cmd,
+      "show subscriber " SUBSCR_TYPES " ID",
+	SHOW_STR SUBSCR_HELP)
+{
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+	struct gsm_subscriber *subscr =
+				get_subscr_by_argv(gsmnet, argv[0], argv[1]);
+
+	if (!subscr) {
+		vty_out(vty, "%% No subscriber found for %s %s%s",
+			argv[0], argv[1], VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	subscr_dump_full_vty(vty, subscr);
+
+	subscr_put(subscr);
+
+	return CMD_SUCCESS;
+}
 
 DEFUN(subscriber_send_sms,
       subscriber_send_sms_cmd,
-      "subscriber " SUBSCR_TYPES " EXTEN sms send .LINE",
-      "Select subscriber based on extension")
+      "subscriber " SUBSCR_TYPES " ID sms send .LINE",
+	SUBSCR_HELP "SMS Operations\n" "Send SMS\n" "Actual SMS Text")
 {
-	struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
-	struct buffer *b;
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+	struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
+	char *str;
 	int rc;
 
 	if (!subscr) {
@@ -307,9 +260,9 @@
 			argv[0], argv[1], VTY_NEWLINE);
 		return CMD_WARNING;
 	}
-	b = argv_to_buffer(argc, argv, 2);
-	rc = _send_sms_buffer(subscr, b, 0);
-	buffer_free(b);
+	str = argv_concat(argv, argc, 2);
+	rc = _send_sms_str(subscr, str, 0);
+	talloc_free(str);
 
 	subscr_put(subscr);
 
@@ -318,11 +271,13 @@
 
 DEFUN(subscriber_silent_sms,
       subscriber_silent_sms_cmd,
-      "subscriber " SUBSCR_TYPES " EXTEN silent sms send .LINE",
-      "Select subscriber based on extension")
+      "subscriber " SUBSCR_TYPES " ID silent-sms send .LINE",
+	SUBSCR_HELP
+	"Silent SMS Operation\n" "Send Silent SMS\n" "Actual SMS text\n")
 {
-	struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
-	struct buffer *b;
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+	struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
+	char *str;
 	int rc;
 
 	if (!subscr) {
@@ -331,21 +286,30 @@
 		return CMD_WARNING;
 	}
 
-	b = argv_to_buffer(argc, argv, 2);
-	rc = _send_sms_buffer(subscr, b, 64);
-	buffer_free(b);
+	str = argv_concat(argv, argc, 2);
+	rc = _send_sms_str(subscr, str, 0);
+	talloc_free(str);
 
 	subscr_put(subscr);
 
 	return rc;
 }
 
+#define CHAN_TYPES "(any|tch/f|tch/any|sdcch)"
+#define CHAN_TYPE_HELP 			\
+		"Any channel\n"		\
+		"TCH/F channel\n"	\
+		"Any TCH channel\n"	\
+		"SDCCH channel\n"
+
 DEFUN(subscriber_silent_call_start,
       subscriber_silent_call_start_cmd,
-      "subscriber " SUBSCR_TYPES " EXTEN silent call start (any|tch/f|tch/any|sdcch)",
-      "Start a silent call to a subscriber")
+      "subscriber " SUBSCR_TYPES " ID silent-call start (any|tch/f|tch/any|sdcch)",
+	SUBSCR_HELP "Silent call operation\n" "Start silent call\n"
+	CHAN_TYPE_HELP)
 {
-	struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+	struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
 	int rc, type;
 
 	if (!subscr) {
@@ -378,10 +342,12 @@
 
 DEFUN(subscriber_silent_call_stop,
       subscriber_silent_call_stop_cmd,
-      "subscriber " SUBSCR_TYPES " EXTEN silent call stop",
-      "Stop a silent call to a subscriber")
+      "subscriber " SUBSCR_TYPES " ID silent-call stop",
+	SUBSCR_HELP "Silent call operation\n" "Stop silent call\n"
+	CHAN_TYPE_HELP)
 {
-	struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+	struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
 	int rc;
 
 	if (!subscr) {
@@ -401,85 +367,140 @@
 	return CMD_SUCCESS;
 }
 
-DEFUN(cfg_subscr_name,
-      cfg_subscr_name_cmd,
-      "name NAME",
-      "Set the name of the subscriber")
+DEFUN(ena_subscr_authorizde,
+      ena_subscr_authorized_cmd,
+      "subscriber " SUBSCR_TYPES " ID authorized (0|1)",
+	SUBSCR_HELP "(De-)Authorize subscriber in HLR\n"
+	"Subscriber should NOT be authorized\n"
+	"Subscriber should be authorized\n")
 {
-	const char *name = argv[0];
-	struct gsm_subscriber *subscr = vty->index;
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+	struct gsm_subscriber *subscr =
+			get_subscr_by_argv(gsmnet, argv[0], argv[1]);
+
+	if (!subscr) {
+		vty_out(vty, "%% No subscriber found for %s %s%s",
+			argv[0], argv[1], VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	subscr->authorized = atoi(argv[2]);
+	db_sync_subscriber(subscr);
+
+	subscr_put(subscr);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(ena_subscr_name,
+      ena_subscr_name_cmd,
+      "subscriber " SUBSCR_TYPES " ID name NAME",
+	SUBSCR_HELP "Set the name of the subscriber\n"
+	"Name of the Subscriber\n")
+{
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+	struct gsm_subscriber *subscr =
+			get_subscr_by_argv(gsmnet, argv[0], argv[1]);
+	const char *name = argv[2];
+
+	if (!subscr) {
+		vty_out(vty, "%% No subscriber found for %s %s%s",
+			argv[0], argv[1], VTY_NEWLINE);
+		return CMD_WARNING;
+	}
 
 	strncpy(subscr->name, name, sizeof(subscr->name));
-
 	db_sync_subscriber(subscr);
 
+	subscr_put(subscr);
+
 	return CMD_SUCCESS;
 }
 
-DEFUN(cfg_subscr_extension,
-      cfg_subscr_extension_cmd,
-      "extension EXTENSION",
-      "Set the extension of the subscriber")
+DEFUN(ena_subscr_extension,
+      ena_subscr_extension_cmd,
+      "subscriber " SUBSCR_TYPES " ID extension EXTENSION",
+	SUBSCR_HELP "Set the extension (phone number) of the subscriber\n"
+	"Extension (phone number)\n")
 {
-	const char *name = argv[0];
-	struct gsm_subscriber *subscr = vty->index;
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+	struct gsm_subscriber *subscr =
+			get_subscr_by_argv(gsmnet, argv[0], argv[1]);
+	const char *name = argv[2];
 
-	strncpy(subscr->extension, name, sizeof(subscr->extension));
+	if (!subscr) {
+		vty_out(vty, "%% No subscriber found for %s %s%s",
+			argv[0], argv[1], VTY_NEWLINE);
+		return CMD_WARNING;
+	}
 
+	strncpy(subscr->extension, name, sizeof(subscr->name));
 	db_sync_subscriber(subscr);
 
+	subscr_put(subscr);
+
 	return CMD_SUCCESS;
 }
 
-DEFUN(cfg_subscr_authorized,
-      cfg_subscr_authorized_cmd,
-      "auth <0-1>",
-      "Set the authorization status of the subscriber")
+#define A3A8_ALG_TYPES "(none|xor|comp128v1)"
+#define A3A8_ALG_HELP 			\
+	"Use No A3A8 algorithm\n"	\
+	"Use XOR algorithm\n"		\
+	"Use COMP128v1 algorithm\n"
+
+DEFUN(ena_subscr_a3a8,
+      ena_subscr_a3a8_cmd,
+      "subscriber " SUBSCR_TYPES " ID a3a8 " A3A8_ALG_TYPES " [KI]",
+      SUBSCR_HELP "Set a3a8 parameters for the subscriber\n"
+      A3A8_ALG_HELP "Encryption Key Ki\n")
 {
-	int auth = atoi(argv[0]);
-	struct gsm_subscriber *subscr = vty->index;
-
-	if (auth)
-		subscr->authorized = 1;
-	else
-		subscr->authorized = 0;
-
-	db_sync_subscriber(subscr);
-
-	return CMD_SUCCESS;
-}
-
-#define A3A8_ALG_TYPES "(none|comp128v1)"
-
-DEFUN(cfg_subscr_a3a8,
-      cfg_subscr_a3a8_cmd,
-      "a3a8 " A3A8_ALG_TYPES " [KI]",
-      "Set a3a8 parameters for the subscriber")
-{
-	struct gsm_subscriber *subscr = vty->index;
-	const char *alg_str = argv[0];
-	const char *ki_str = argv[1];
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+	struct gsm_subscriber *subscr =
+			get_subscr_by_argv(gsmnet, argv[0], argv[1]);
+	const char *alg_str = argv[2];
+	const char *ki_str = argc == 4 ? argv[3] : NULL;
 	struct gsm_auth_info ainfo;
-	int rc;
+	int rc, minlen, maxlen;
+
+	if (!subscr) {
+		vty_out(vty, "%% No subscriber found for %s %s%s",
+			argv[0], argv[1], VTY_NEWLINE);
+		return CMD_WARNING;
+	}
 
 	if (!strcasecmp(alg_str, "none")) {
-		/* Just erase */
-		rc = set_authinfo_for_subscr(NULL, subscr);
+		ainfo.auth_algo = AUTH_ALGO_NONE;
+		minlen = maxlen = 0;
+	} else if (!strcasecmp(alg_str, "xor")) {
+		ainfo.auth_algo = AUTH_ALGO_XOR;
+		minlen = A38_XOR_MIN_KEY_LEN;
+		maxlen = A38_XOR_MAX_KEY_LEN;
 	} else if (!strcasecmp(alg_str, "comp128v1")) {
-		/* Parse hex string Ki */
-		rc = hexparse(ki_str, ainfo.a3a8_ki, sizeof(ainfo.a3a8_ki));
-		if (rc != 16)
-			return CMD_WARNING;
-
-		/* Set the infos */
 		ainfo.auth_algo = AUTH_ALGO_COMP128v1;
-		ainfo.a3a8_ki_len = rc;
-		rc = set_authinfo_for_subscr(&ainfo, subscr);
+		minlen = maxlen = A38_COMP128_KEY_LEN;
 	} else {
 		/* Unknown method */
 		return CMD_WARNING;
 	}
 
+	if (ki_str) {
+		rc = hexparse(ki_str, ainfo.a3a8_ki, sizeof(ainfo.a3a8_ki));
+		if ((rc > maxlen) || (rc < minlen))
+			return CMD_WARNING;
+		ainfo.a3a8_ki_len = rc;
+	} else {
+		ainfo.a3a8_ki_len = 0;
+		if (minlen)
+			return CMD_WARNING;
+	}
+
+	rc = db_sync_authinfo_for_subscr(
+		ainfo.auth_algo == AUTH_ALGO_NONE ? NULL : &ainfo,
+		subscr);
+
+	/* the last tuple probably invalid with the new auth settings */
+	db_sync_lastauthtuple_for_subscr(NULL, subscr);
+
 	return rc ? CMD_WARNING : CMD_SUCCESS;
 }
 
@@ -502,30 +523,60 @@
 	return 0;
 }
 
-int bsc_vty_init_extra(struct gsm_network *net)
+DEFUN(show_stats,
+      show_stats_cmd,
+      "show statistics",
+	SHOW_STR "Display network statistics\n")
 {
-	gsmnet = net;
+	struct gsm_network *net = gsmnet_from_vty(vty);
 
+	openbsc_vty_print_statistics(vty, net);
+	vty_out(vty, "Location Update         : %lu attach, %lu normal, %lu periodic%s",
+		counter_get(net->stats.loc_upd_type.attach),
+		counter_get(net->stats.loc_upd_type.normal),
+		counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE);
+	vty_out(vty, "IMSI Detach Indications : %lu%s",
+		counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE);
+	vty_out(vty, "Location Update Response: %lu accept, %lu reject%s",
+		counter_get(net->stats.loc_upd_resp.accept),
+		counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE);
+	vty_out(vty, "Handover                : %lu attempted, %lu no_channel, %lu timeout, "
+		"%lu completed, %lu failed%s",
+		counter_get(net->stats.handover.attempted),
+		counter_get(net->stats.handover.no_channel),
+		counter_get(net->stats.handover.timeout),
+		counter_get(net->stats.handover.completed),
+		counter_get(net->stats.handover.failed), VTY_NEWLINE);
+	vty_out(vty, "SMS MO                  : %lu submitted, %lu no receiver%s",
+		counter_get(net->stats.sms.submitted),
+		counter_get(net->stats.sms.no_receiver), VTY_NEWLINE);
+	vty_out(vty, "SMS MT                  : %lu delivered, %lu no memory, %lu other error%s",
+		counter_get(net->stats.sms.delivered),
+		counter_get(net->stats.sms.rp_err_mem),
+		counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE);
+	return CMD_SUCCESS;
+}
+
+
+int bsc_vty_init_extra(void)
+{
 	register_signal_handler(SS_SCALL, scall_cbfn, NULL);
 
-	install_element(VIEW_NODE, &show_subscr_cmd);
-	install_element(VIEW_NODE, &show_subscr_cache_cmd);
+	install_element_ve(&show_subscr_cmd);
+	install_element_ve(&show_subscr_cache_cmd);
 
-	install_element(VIEW_NODE, &sms_send_pend_cmd);
+	install_element_ve(&sms_send_pend_cmd);
 
-	install_element(VIEW_NODE, &subscriber_send_sms_cmd);
-	install_element(VIEW_NODE, &subscriber_silent_sms_cmd);
-	install_element(VIEW_NODE, &subscriber_silent_call_start_cmd);
-	install_element(VIEW_NODE, &subscriber_silent_call_stop_cmd);
+	install_element_ve(&subscriber_send_sms_cmd);
+	install_element_ve(&subscriber_silent_sms_cmd);
+	install_element_ve(&subscriber_silent_call_start_cmd);
+	install_element_ve(&subscriber_silent_call_stop_cmd);
+	install_element_ve(&show_stats_cmd);
 
-	install_element(CONFIG_NODE, &cfg_subscr_cmd);
-	install_node(&subscr_node, dummy_config_write);
-
-	install_default(SUBSCR_NODE);
-	install_element(SUBSCR_NODE, &cfg_subscr_name_cmd);
-	install_element(SUBSCR_NODE, &cfg_subscr_extension_cmd);
-	install_element(SUBSCR_NODE, &cfg_subscr_authorized_cmd);
-	install_element(SUBSCR_NODE, &cfg_subscr_a3a8_cmd);
+	install_element(ENABLE_NODE, &ena_subscr_name_cmd);
+	install_element(ENABLE_NODE, &ena_subscr_extension_cmd);
+	install_element(ENABLE_NODE, &ena_subscr_authorized_cmd);
+	install_element(ENABLE_NODE, &ena_subscr_a3a8_cmd);
 
 	return 0;
 }
diff --git a/openbsc/tests/debug/debug_test.c b/openbsc/tests/debug/debug_test.c
index 0f0c284..f3e4837 100644
--- a/openbsc/tests/debug/debug_test.c
+++ b/openbsc/tests/debug/debug_test.c
@@ -24,18 +24,20 @@
 
 int main(int argc, char** argv)
 {
-	struct debug_target *stderr_target;
+	struct log_target *stderr_target;
 
-	debug_init();
-	stderr_target = debug_target_create_stderr();
-	debug_add_target(stderr_target);
-	debug_set_all_filter(stderr_target, 1);
+	log_init(&log_info);
+	stderr_target = log_target_create_stderr();
+	log_add_target(stderr_target);
+	log_set_all_filter(stderr_target, 1);
 
-	debug_parse_category_mask(stderr_target, "DRLL");
+	log_parse_category_mask(stderr_target, "DRLL");
 	DEBUGP(DCC, "You should not see this\n");
 
-	debug_parse_category_mask(stderr_target, "DRLL:DCC");
+	log_parse_category_mask(stderr_target, "DRLL:DCC");
 	DEBUGP(DRLL, "You should see this\n");
 	DEBUGP(DCC, "You should see this\n");
 	DEBUGP(DMM, "You should not see this\n");
+
+	return 0;
 }
diff --git a/rrlp-ephemeris/.gitignore b/rrlp-ephemeris/.gitignore
deleted file mode 100644
index 88b45e4..0000000
--- a/rrlp-ephemeris/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-asn1_gen/*
-*.o
-*.a
-rrlp-test
diff --git a/rrlp-ephemeris/COPYING b/rrlp-ephemeris/COPYING
deleted file mode 100644
index 8d7088e..0000000
--- a/rrlp-ephemeris/COPYING
+++ /dev/null
@@ -1,2 +0,0 @@
-See the included gpl-2.0.txt or gpl-3.0.txt depending on your
-preferences.
diff --git a/rrlp-ephemeris/Makefile b/rrlp-ephemeris/Makefile
deleted file mode 100644
index 742cac7..0000000
--- a/rrlp-ephemeris/Makefile
+++ /dev/null
@@ -1,44 +0,0 @@
-
-ASN1C=../../../tmp/rrlp/asn1c/asn1c/asn1c
-ASN1_INCLUDE=/home/tnt/tmp/rrlp/asn1c/skeletons
-CC=gcc
-CFLAGS=-I$(ASN1_INCLUDE) -Iasn1_gen -O3 -Wall
-
-ASN1_FILES=$(wildcard asn1/*.asn)
-
-
-all: rrlp-test
-
-
-rrlp-test: libgsm-asn1.a gps.o ubx.o ubx-parse.o rrlp.o main.o
-	$(CC) -o $@ gps.o ubx.o ubx-parse.o rrlp.o main.o -L. -lgsm-asn1 -lm
-
-
-#
-# ASN1 file autogeneration (need recursive makefile call)
-#
-
-ASN1_SOURCES = $(wildcard asn1_gen/*.c)
-ASN1_OBJECTS = $(ASN1_SOURCES:.c=.o)
-
-libgsm-asn1.a: $(ASN1_FILES)
-	mkdir -p asn1_gen && \
-	cd asn1_gen && \
-	$(ASN1C) -fskeletons-copy -fnative-types -gen-PER $(addprefix ../,$^)
-	@rm asn1_gen/converter-sample.c asn1_gen/Makefile.am.sample
-	@$(MAKE) libgsm-asn1.a.submake
-
-libgsm-asn1.a.submake: $(ASN1_OBJECTS)
-	$(AR) rcs libgsm-asn1.a $^
-
-.PHONY: libgsm-asn1.a.submake
-
-
-#
-# Clean
-#
-
-clean:
-	rm -Rf asn1_gen
-	rm -f libgsm-asn1.a *.o rrlp-test
-
diff --git a/rrlp-ephemeris/asn1/MAP-BS-Code.asn b/rrlp-ephemeris/asn1/MAP-BS-Code.asn
deleted file mode 100644
index 1d25366..0000000
--- a/rrlp-ephemeris/asn1/MAP-BS-Code.asn
+++ /dev/null
@@ -1,131 +0,0 @@
--- $Id: MAP-BS-Code.asn 28149 2009-04-25 17:45:34Z etxrab $
--- 3GPP TS 29.002 V8.9.0 (2009-04) 
--- 17.7.10	Bearer Service Codes
- 
-MAP-BS-Code {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-BS-Code (20) version11 (11)}
-
-DEFINITIONS
-
-::=
-
-BEGIN
-
-BearerServiceCode ::= OCTET STRING (SIZE (1))
-	-- This type is used to represent the code identifying a single
-	-- bearer service, a group of bearer services, or all bearer
-	-- services. The services are defined in TS 3GPP TS 22.002 [3].
-	-- The internal structure is defined as follows:
-	--
-	-- plmn-specific bearer services:
-	-- bits 87654321: defined by the HPLMN operator
-
-	-- rest of bearer services:
-	-- bit 8: 0 (unused)
-	-- bits 7654321: group (bits 7654), and rate, if applicable
-	-- (bits 321)
-
-Ext-BearerServiceCode ::= OCTET STRING (SIZE (1..5))
-	-- This type is used to represent the code identifying a single
-	-- bearer service, a group of bearer services, or all bearer
-	-- services. The services are defined in TS 3GPP TS 22.002 [3].
-	-- The internal structure is defined as follows:
-	--
-	-- OCTET 1:
-	-- plmn-specific bearer services:
-	-- bits 87654321: defined by the HPLMN operator
-	--
-	-- rest of bearer services:
-	-- bit 8: 0 (unused)
-	-- bits 7654321: group (bits 7654), and rate, if applicable
-	-- (bits 321)
-
-	-- OCTETS 2-5: reserved for future use. If received the
-    -- Ext-TeleserviceCode shall be
-	-- treated according to the exception handling defined for the
-	-- operation that uses this type. 
-
-
-	-- Ext-BearerServiceCode includes all values defined for BearerServiceCode.
-
-allBearerServices	BearerServiceCode ::= '00000000'B
-
-allDataCDA-Services	BearerServiceCode ::= '00010000'B
-dataCDA-300bps		BearerServiceCode ::= '00010001'B
-dataCDA-1200bps	BearerServiceCode ::= '00010010'B
-dataCDA-1200-75bps	BearerServiceCode ::= '00010011'B
-dataCDA-2400bps	BearerServiceCode ::= '00010100'B
-dataCDA-4800bps	BearerServiceCode ::= '00010101'B
-dataCDA-9600bps	BearerServiceCode ::= '00010110'B
-general-dataCDA	BearerServiceCode ::= '00010111'B
-
-allDataCDS-Services	BearerServiceCode ::= '00011000'B
-dataCDS-1200bps	BearerServiceCode ::= '00011010'B
-dataCDS-2400bps	BearerServiceCode ::= '00011100'B
-dataCDS-4800bps	BearerServiceCode ::= '00011101'B
-dataCDS-9600bps	BearerServiceCode ::= '00011110'B
-general-dataCDS	BearerServiceCode ::= '00011111'B
-
-allPadAccessCA-Services	BearerServiceCode ::= '00100000'B
-padAccessCA-300bps	BearerServiceCode ::= '00100001'B
-padAccessCA-1200bps	BearerServiceCode ::= '00100010'B
-padAccessCA-1200-75bps	BearerServiceCode ::= '00100011'B
-padAccessCA-2400bps	BearerServiceCode ::= '00100100'B
-padAccessCA-4800bps	BearerServiceCode ::= '00100101'B
-padAccessCA-9600bps	BearerServiceCode ::= '00100110'B
-general-padAccessCA	BearerServiceCode ::= '00100111'B
-
-allDataPDS-Services	BearerServiceCode ::= '00101000'B
-dataPDS-2400bps	BearerServiceCode ::= '00101100'B
-dataPDS-4800bps	BearerServiceCode ::= '00101101'B
-dataPDS-9600bps	BearerServiceCode ::= '00101110'B
-general-dataPDS	BearerServiceCode ::= '00101111'B
-
-allAlternateSpeech-DataCDA	BearerServiceCode ::= '00110000'B
-
-allAlternateSpeech-DataCDS	BearerServiceCode ::= '00111000'B
-
-allSpeechFollowedByDataCDA	BearerServiceCode ::= '01000000'B
-
-allSpeechFollowedByDataCDS	BearerServiceCode ::= '01001000'B
-
--- The following non-hierarchical Compound Bearer Service
--- Groups are defined in TS 3GPP TS 22.030:
-allDataCircuitAsynchronous	BearerServiceCode ::= '01010000'B
-	-- covers "allDataCDA-Services", "allAlternateSpeech-DataCDA" and
-	-- "allSpeechFollowedByDataCDA"
-allAsynchronousServices	BearerServiceCode ::= '01100000'B
-	-- covers "allDataCDA-Services", "allAlternateSpeech-DataCDA",
-	-- "allSpeechFollowedByDataCDA" and "allPadAccessCDA-Services"
-allDataCircuitSynchronous	BearerServiceCode ::= '01011000'B
-	-- covers "allDataCDS-Services", "allAlternateSpeech-DataCDS" and
-	-- "allSpeechFollowedByDataCDS"
-allSynchronousServices	BearerServiceCode ::= '01101000'B
-	-- covers "allDataCDS-Services", "allAlternateSpeech-DataCDS",
-	-- "allSpeechFollowedByDataCDS" and "allDataPDS-Services"
---
--- Compound Bearer Service Group Codes are only used in call
--- independent supplementary service operations, i.e. they
--- are not used in InsertSubscriberData or in
--- DeleteSubscriberData messages.
-
-allPLMN-specificBS	BearerServiceCode ::= '11010000'B
-plmn-specificBS-1	BearerServiceCode ::= '11010001'B
-plmn-specificBS-2	BearerServiceCode ::= '11010010'B
-plmn-specificBS-3	BearerServiceCode ::= '11010011'B
-plmn-specificBS-4	BearerServiceCode ::= '11010100'B
-plmn-specificBS-5	BearerServiceCode ::= '11010101'B
-plmn-specificBS-6	BearerServiceCode ::= '11010110'B
-plmn-specificBS-7	BearerServiceCode ::= '11010111'B
-plmn-specificBS-8	BearerServiceCode ::= '11011000'B
-plmn-specificBS-9	BearerServiceCode ::= '11011001'B
-plmn-specificBS-A	BearerServiceCode ::= '11011010'B
-plmn-specificBS-B	BearerServiceCode ::= '11011011'B
-plmn-specificBS-C	BearerServiceCode ::= '11011100'B
-plmn-specificBS-D	BearerServiceCode ::= '11011101'B
-plmn-specificBS-E	BearerServiceCode ::= '11011110'B
-plmn-specificBS-F	BearerServiceCode ::= '11011111'B
-
-END
-
diff --git a/rrlp-ephemeris/asn1/MAP-CommonDataTypes.asn b/rrlp-ephemeris/asn1/MAP-CommonDataTypes.asn
deleted file mode 100644
index f3d202e..0000000
--- a/rrlp-ephemeris/asn1/MAP-CommonDataTypes.asn
+++ /dev/null
@@ -1,633 +0,0 @@
--- $Id: MAP-CommonDataTypes.asn 30470 2009-10-10 12:37:56Z krj $
--- 3GPP TS 29.002 V8.9.0 (2009-04)
--- 17.7.8	Common data types
-
-MAP-CommonDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-CommonDataTypes (18) version11 (11)}
-
-DEFINITIONS
-
-IMPLICIT TAGS
-
-::=
-
-BEGIN
-
-EXPORTS
-
-	-- general data types and values
-	AddressString,
-	ISDN-AddressString,
-	maxISDN-AddressLength,
-	FTN-AddressString,
-	ISDN-SubaddressString,
-	ExternalSignalInfo, 
-	Ext-ExternalSignalInfo, 
-AccessNetworkSignalInfo,
-	SignalInfo,
-	maxSignalInfoLength,
-	AlertingPattern,
-	TBCD-STRING,
-
-	-- data types for numbering and identification
-	IMSI,
-	TMSI, 
-	Identity,
-	SubscriberId,
-	IMEI,
-	HLR-List,
-	LMSI,
-	GlobalCellId,
-	NetworkResource,
-	AdditionalNetworkResource,
-	NAEA-PreferredCI, 
-	NAEA-CIC, 
-	ASCI-CallReference,
-	SubscriberIdentity,
-	PLMN-Id,
-
-	-- data types for CAMEL
-	CellGlobalIdOrServiceAreaIdOrLAI, 
-	CellGlobalIdOrServiceAreaIdFixedLength,
-	LAIFixedLength,
-
-	-- data types for subscriber management
-	BasicServiceCode,
-	Ext-BasicServiceCode,
-	EMLPP-Info,
-	EMLPP-Priority, 
-	MC-SS-Info,
-	MaxMC-Bearers,
-	MC-Bearers,
-	Ext-SS-Status,
-
-	-- data types for geographic location
-	AgeOfLocationInformation,
-	LCSClientExternalID,
-	LCSClientInternalID,
-	LCSServiceTypeID,
---- WS added exports needed by gsm_map.asn (extra asn1 file to handle older prot. ver.)
-	ProtocolId,
-	LCSServiceTypeID	
-;
-
-IMPORTS
-	TeleserviceCode,
-	Ext-TeleserviceCode
-FROM MAP-TS-Code {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-TS-Code (19) version11 (11)}
-
-	BearerServiceCode,
-	Ext-BearerServiceCode
-FROM MAP-BS-Code {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-BS-Code (20) version11 (11)}
-
-	SS-Code
-FROM MAP-SS-Code {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-SS-Code (15) version11 (11)}
-
-	ExtensionContainer
-FROM MAP-ExtensionDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)}
-;
-
-
--- general data types
-
-TBCD-STRING ::= OCTET STRING
-	-- This type (Telephony Binary Coded Decimal String) is used to
-	-- represent several digits from 0 through 9, *, #, a, b, c, two
-	-- digits per octet, each digit encoded 0000 to 1001 (0 to 9),
-	-- 1010 (*), 1011 (#), 1100 (a), 1101 (b) or 1110 (c); 1111 used
-	-- as filler when there is an odd number of digits.
-
-	-- bits 8765 of octet n encoding digit 2n
-	-- bits 4321 of octet n encoding digit 2(n-1) +1
-
-AddressString ::= OCTET STRING (SIZE (1..maxAddressLength))
-	-- This type is used to represent a number for addressing
-	-- purposes. It is composed of
-	--	a)	one octet for nature of address, and numbering plan
-	--		indicator.
-	--	b)	digits of an address encoded as TBCD-String.
-
-	-- a)	The first octet includes a one bit extension indicator, a
-	--		3 bits nature of address indicator and a 4 bits numbering
-	--		plan indicator, encoded as follows:
-
-	-- bit 8: 1  (no extension)
-
-	-- bits 765: nature of address indicator
-	--	000  unknown
-	--	001  international number
-	--	010  national significant number
-	--	011  network specific number
-	--	100  subscriber number
-	--	101  reserved
-	--	110  abbreviated number
-	--	111  reserved for extension
-
-	-- bits 4321: numbering plan indicator
-	--	0000  unknown
-	--	0001  ISDN/Telephony Numbering Plan (Rec ITU-T E.164)
-	--	0010  spare
-	--	0011  data numbering plan (ITU-T Rec X.121)
-	--	0100  telex numbering plan (ITU-T Rec F.69)
-	--	0101  spare
-	--	0110  land mobile numbering plan (ITU-T Rec E.212)
-	--	0111  spare
-	--	1000  national numbering plan
-	--	1001  private numbering plan
-	--	1111  reserved for extension
-
-	--	all other values are reserved.
-
-	-- b)	The following octets representing digits of an address
-	--		encoded as a TBCD-STRING.
-
-maxAddressLength  INTEGER ::= 20
-
-ISDN-AddressString ::= 
-			AddressString (SIZE (1..maxISDN-AddressLength))
-	-- This type is used to represent ISDN numbers.
-
-maxISDN-AddressLength  INTEGER ::= 9
-
-FTN-AddressString ::= 
-			AddressString (SIZE (1..maxFTN-AddressLength))
-	-- This type is used to represent forwarded-to numbers. 
-	-- If NAI = international the first digits represent the country code (CC)
-	-- and the network destination code (NDC) as for E.164.
-
-maxFTN-AddressLength  INTEGER ::= 15
-
-ISDN-SubaddressString ::= 
-			OCTET STRING (SIZE (1..maxISDN-SubaddressLength))
-	-- This type is used to represent ISDN subaddresses.
-	-- It is composed of
-	--	a)	one octet for type of subaddress and odd/even indicator.
-	--	b)	20 octets for subaddress information.
-
-	--	a)	The first octet includes a one bit extension indicator, a
-	--		3 bits type of subaddress and a one bit odd/even indicator,
-	--		encoded as follows:
-
-	--	bit 8: 1  (no extension)
-
-	--	bits 765: type of subaddress
-	--		000  NSAP (X.213/ISO 8348 AD2)
-	--		010  User Specified
-	--		All other values are reserved
-
-	--	bit 4: odd/even indicator
-	--		0  even number of address signals
-	--		1  odd number of address signals
-	--		The odd/even indicator is used when the type of subaddress
-	--		is "user specified" and the coding is BCD.
-
-	--	bits 321: 000 (unused)
-
-	--	b) Subaddress information.
-	--	The NSAP X.213/ISO8348AD2 address shall be formatted as specified
-	--	by octet 4 which contains the Authority and Format Identifier
-	--	(AFI). The encoding is made according to the "preferred binary
-	--	encoding" as defined in X.213/ISO834AD2. For the definition
-	--	of this type of subaddress, see ITU-T Rec I.334.
-
-	--	For User-specific subaddress, this field is encoded according
-	--	to the user specification, subject to a maximum length of 20
-	--	octets. When interworking with X.25 networks BCD coding should
-	--	be applied.
-
-maxISDN-SubaddressLength  INTEGER ::= 21
-
-ExternalSignalInfo ::= SEQUENCE {
-	protocolId	ProtocolId,
-	signalInfo	SignalInfo,
-	-- Information about the internal structure is given in
-	-- clause 7.6.9.
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	-- extensionContainer must not be used in version 2
-	...}
-
-SignalInfo ::= OCTET STRING (SIZE (1..maxSignalInfoLength))
-
-maxSignalInfoLength  INTEGER ::= 200
-	-- This NamedValue represents the theoretical maximum number of octets which is
-	-- available to carry a single instance of the SignalInfo data type,
-	-- without requiring segmentation to cope with the network layer service.
-	-- However, the actual maximum size available for an instance of the data
-	-- type may be lower, especially when other information elements
-	-- have to be included in the same component.
-
-ProtocolId ::= ENUMERATED {
-	gsm-0408  (1),
-	gsm-0806  (2),
-	gsm-BSSMAP  (3),
-	-- Value 3 is reserved and must not be used
-	ets-300102-1  (4)}
-
-Ext-ExternalSignalInfo ::= SEQUENCE {
-	ext-ProtocolId	Ext-ProtocolId,
-	signalInfo	SignalInfo,
-	-- Information about the internal structure is given in
-	-- clause 7.6.9.10
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-Ext-ProtocolId ::= ENUMERATED {
-	ets-300356  (1),
-	... 
-	 }
--- exception handling:
--- For Ext-ExternalSignalInfo sequences containing this parameter with any
--- other value than the ones listed the receiver shall ignore the whole 
--- Ext-ExternalSignalInfo sequence.
-
-AccessNetworkSignalInfo ::= SEQUENCE {
-	accessNetworkProtocolId	AccessNetworkProtocolId,
-	signalInfo	LongSignalInfo,
-	-- Information about the internal structure is given in clause 7.6.9.1
-	
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-LongSignalInfo ::= OCTET STRING (SIZE (1..maxLongSignalInfoLength))
-
-maxLongSignalInfoLength  INTEGER ::= 2560
-	-- This Named Value represents the maximum number of octets which is available
-	-- to carry a single instance of the LongSignalInfo data type using
-	-- White Book SCCP with the maximum number of segments.
-	-- It takes account of the octets used by the lower layers of the protocol, and
-	-- other information elements which may be included in the same component.
-
-AccessNetworkProtocolId ::= ENUMERATED {
-	ts3G-48006   (1),
-	ts3G-25413 (2),
-	...}
-	-- exception handling:
-	-- For AccessNetworkSignalInfo sequences containing this parameter with any
-	-- other value than the ones listed the receiver shall ignore the whole 
-	-- AccessNetworkSignalInfo sequence.
-
-AlertingPattern ::= OCTET STRING (SIZE (1) )
-	-- This type is used to represent Alerting Pattern
-
-	--	bits 8765 : 0000 (unused)
-
-	--	bits 43 : type of Pattern
-	--		00 level
-	--		01 category
-	--		10 category
-	--		all other values are reserved.
-
-	--	bits 21 : type of alerting
-
-alertingLevel-0   AlertingPattern ::= '00000000'B
-alertingLevel-1   AlertingPattern ::= '00000001'B
-alertingLevel-2   AlertingPattern ::= '00000010'B
-	-- all other values of Alerting level are reserved
-	-- Alerting Levels are defined in GSM 02.07
-	
-alertingCategory-1   AlertingPattern ::= '00000100'B
-alertingCategory-2   AlertingPattern ::= '00000101'B
-alertingCategory-3   AlertingPattern ::= '00000110'B
-alertingCategory-4   AlertingPattern ::= '00000111'B
-alertingCategory-5   AlertingPattern ::= '00001000'B
-	-- all other values of Alerting Category are reserved
-	-- Alerting categories are defined in GSM 02.07
-
--- data types for numbering and identification
-
-IMSI ::= TBCD-STRING (SIZE (3..8))
-	-- digits of MCC, MNC, MSIN are concatenated in this order.
-
-Identity ::= CHOICE {
-	imsi			IMSI,
-	imsi-WithLMSI	IMSI-WithLMSI}
-
-IMSI-WithLMSI ::= SEQUENCE {
-	imsi			IMSI,
-	lmsi			LMSI,
-	-- a special value 00000000 indicates that the LMSI is not in use
-	...}
-
-ASCI-CallReference ::= TBCD-STRING (SIZE (1..8))
-	-- digits of VGCS/VBS-area,Group-ID are concatenated in this order if there is a
-	-- VGCS/VBS-area.
-
-TMSI ::= OCTET STRING (SIZE (1..4))
-
-SubscriberId ::= CHOICE {
-	imsi			[0] IMSI,
-	tmsi			[1] TMSI}
-
-IMEI ::= TBCD-STRING (SIZE (8))
-	--	Refers to International Mobile Station Equipment Identity
-	--	and Software Version Number (SVN) defined in TS 3GPP TS 23.003 [17].
-	--	If the SVN is not present the last octet shall contain the
-	--	digit 0 and a filler.
-	--	If present the SVN shall be included in the last octet.
-
-HLR-Id ::= IMSI
-	-- leading digits of IMSI, i.e. (MCC, MNC, leading digits of
-	-- MSIN) forming HLR Id defined in TS 3GPP TS 23.003 [17].
-
-HLR-List ::= SEQUENCE SIZE (1..maxNumOfHLR-Id) OF
-				HLR-Id
-
-maxNumOfHLR-Id  INTEGER ::= 50
-
-LMSI ::= OCTET STRING (SIZE (4))
-
-GlobalCellId ::= OCTET STRING (SIZE (5..7))
-	-- Refers to Cell Global Identification defined in TS 3GPP TS 23.003 [17].
-	-- The internal structure is defined as follows:
-	-- octet 1 bits 4321	Mobile Country Code 1st digit
-	--         bits 8765	Mobile Country Code 2nd digit
-	-- octet 2 bits 4321	Mobile Country Code 3rd digit
-	--         bits 8765	Mobile Network Code 3rd digit
-	--			or filler (1111) for 2 digit MNCs
-	-- octet 3 bits 4321	Mobile Network Code 1st digit
-	--         bits 8765	Mobile Network Code 2nd digit
-	-- octets 4 and 5	Location Area Code according to TS 3GPP TS 24.008 [35]
-	-- octets 6 and 7	Cell Identity (CI) according to TS 3GPP TS 24.008 [35]
-
-NetworkResource ::= ENUMERATED {
-	plmn  (0),
-	hlr  (1),
-	vlr  (2),
-	pvlr  (3),
-	controllingMSC  (4),
-	vmsc  (5),
-	eir  (6),
-	rss  (7)}
-
-AdditionalNetworkResource ::= ENUMERATED {
-	sgsn (0),
-	ggsn (1),
-	gmlc (2),
-	gsmSCF (3),
-	nplr (4),
-	auc (5),
-	... ,
-	ue (6),
-	mme (7)}
-	-- if unknown value is received in AdditionalNetworkResource
-	-- it shall be ignored.
-
-
-NAEA-PreferredCI ::= SEQUENCE {
-	naea-PreferredCIC	[0] NAEA-CIC,
-	extensionContainer	[1] ExtensionContainer	OPTIONAL,
-	...}
-
-NAEA-CIC ::= OCTET STRING (SIZE (3))
-	-- The internal structure is defined by the Carrier Identification
-	-- parameter in ANSI T1.113.3. Carrier codes between "000" and "999" may
-	-- be encoded as 3 digits using "000" to "999" or as 4 digits using 
-	-- "0000" to "0999". Carrier codes between "1000" and "9999" are encoded
-	-- using 4 digits.
-
-SubscriberIdentity ::= CHOICE {
-	imsi			[0] IMSI,
-	msisdn		[1] ISDN-AddressString
-	}
-
-LCSClientExternalID ::= SEQUENCE {
-	externalAddress	[0] ISDN-AddressString	OPTIONAL,
-	extensionContainer	[1] ExtensionContainer	OPTIONAL,
-	... }
-
-LCSClientInternalID ::= ENUMERATED {
-	broadcastService	(0),
-	o-andM-HPLMN	(1),
-	o-andM-VPLMN	(2),
-	anonymousLocation	(3),
-	targetMSsubscribedService	(4),
-	... }
--- for a CAMEL phase 3 PLMN operator client, the value targetMSsubscribedService shall be used
-
-LCSServiceTypeID ::= INTEGER (0..127)
-	-- the integer values 0-63 are reserved for Standard LCS service types
-	-- the integer values 64-127 are reserved for Non Standard LCS service types
-
--- Standard LCS Service Types
-emergencyServices		LCSServiceTypeID ::= 0
-emergencyAlertServices		LCSServiceTypeID ::= 1
-personTracking			LCSServiceTypeID ::= 2
-fleetManagement		LCSServiceTypeID ::= 3
-assetManagement		LCSServiceTypeID ::= 4
-trafficCongestionReporting		LCSServiceTypeID ::= 5
-roadsideAssistance		LCSServiceTypeID ::= 6
-routingToNearestCommercialEnterprise		LCSServiceTypeID ::= 7
-navigation			LCSServiceTypeID ::= 8
-	--this service type is reserved for use in previous releases
-citySightseeing		LCSServiceTypeID ::= 9
-localizedAdvertising		LCSServiceTypeID ::= 10
-mobileYellowPages		LCSServiceTypeID ::= 11 
-trafficAndPublicTransportationInfo		LCSServiceTypeID ::= 12
-weather				LCSServiceTypeID ::= 13
-assetAndServiceFinding		LCSServiceTypeID ::= 14
-gaming				LCSServiceTypeID ::= 15
-findYourFriend			LCSServiceTypeID ::= 16
-dating				LCSServiceTypeID ::= 17
-chatting				LCSServiceTypeID ::= 18
-routeFinding			LCSServiceTypeID ::= 19
-whereAmI				LCSServiceTypeID ::= 20
-
--- The values of LCSServiceTypeID are defined according to 3GPP TS 22.071.
-
--- Non Standard LCS Service Types
-serv64				LCSServiceTypeID ::= 64
-serv65				LCSServiceTypeID ::= 65
-serv66				LCSServiceTypeID ::= 66
-serv67				LCSServiceTypeID ::= 67
-serv68				LCSServiceTypeID ::= 68
-serv69				LCSServiceTypeID ::= 69
-serv70				LCSServiceTypeID ::= 70
-serv71				LCSServiceTypeID ::= 71
-serv72				LCSServiceTypeID ::= 72
-serv73				LCSServiceTypeID ::= 73
-serv74				LCSServiceTypeID ::= 74
-serv75				LCSServiceTypeID ::= 75
-serv76				LCSServiceTypeID ::= 76
-serv77				LCSServiceTypeID ::= 77
-serv78				LCSServiceTypeID ::= 78
-serv79				LCSServiceTypeID ::= 79
-serv80				LCSServiceTypeID ::= 80
-serv81				LCSServiceTypeID ::= 81
-serv82				LCSServiceTypeID ::= 82
-serv83				LCSServiceTypeID ::= 83
-serv84				LCSServiceTypeID ::= 84
-serv85				LCSServiceTypeID ::= 85
-serv86				LCSServiceTypeID ::= 86
-serv87				LCSServiceTypeID ::= 87
-serv88				LCSServiceTypeID ::= 88
-serv89				LCSServiceTypeID ::= 89
-serv90				LCSServiceTypeID ::= 90
-serv91				LCSServiceTypeID ::= 91
-serv92				LCSServiceTypeID ::= 92
-serv93				LCSServiceTypeID ::= 93
-serv94				LCSServiceTypeID ::= 94
-serv95				LCSServiceTypeID ::= 95
-serv96				LCSServiceTypeID ::= 96
-serv97				LCSServiceTypeID ::= 97
-serv98				LCSServiceTypeID ::= 98
-serv99				LCSServiceTypeID ::= 99
-serv100				LCSServiceTypeID ::= 100
-serv101				LCSServiceTypeID ::= 101
-serv102				LCSServiceTypeID ::= 102
-serv103				LCSServiceTypeID ::= 103
-serv104				LCSServiceTypeID ::= 104
-serv105				LCSServiceTypeID ::= 105
-serv106				LCSServiceTypeID ::= 106
-serv107				LCSServiceTypeID ::= 107
-serv108				LCSServiceTypeID ::= 108
-serv109				LCSServiceTypeID ::= 109
-serv110				LCSServiceTypeID ::= 110
-serv111				LCSServiceTypeID ::= 111
-serv112				LCSServiceTypeID ::= 112
-serv113				LCSServiceTypeID ::= 113
-serv114				LCSServiceTypeID ::= 114
-serv115				LCSServiceTypeID ::= 115
-serv116				LCSServiceTypeID ::= 116
-serv117				LCSServiceTypeID ::= 117
-serv118				LCSServiceTypeID ::= 118
-serv119				LCSServiceTypeID ::= 119
-serv120				LCSServiceTypeID ::= 120
-serv121				LCSServiceTypeID ::= 121
-serv122				LCSServiceTypeID ::= 122
-serv123				LCSServiceTypeID ::= 123
-serv124				LCSServiceTypeID ::= 124
-serv125				LCSServiceTypeID ::= 125
-serv126				LCSServiceTypeID ::= 126
-serv127				LCSServiceTypeID ::= 127
-
-PLMN-Id ::= OCTET STRING (SIZE (3))
-	-- The internal structure is defined as follows:
-	-- octet 1 bits 4321	Mobile Country Code 1st digit
-	--         bits 8765	Mobile Country Code 2nd digit
-	-- octet 2 bits 4321	Mobile Country Code 3rd digit
-	--         bits 8765	Mobile Network Code 3rd digit
-	--			or filler (1111) for 2 digit MNCs
-	-- octet 3 bits 4321	Mobile Network Code 1st digit
-	--         bits 8765	Mobile Network Code 2nd digit
-
--- data types for CAMEL
-
-CellGlobalIdOrServiceAreaIdOrLAI ::= CHOICE {
-	cellGlobalIdOrServiceAreaIdFixedLength	[0] CellGlobalIdOrServiceAreaIdFixedLength,
-	laiFixedLength	[1] LAIFixedLength}
-
-CellGlobalIdOrServiceAreaIdFixedLength ::= OCTET STRING (SIZE (7))
-	-- Refers to Cell Global Identification or Service Are Identification
-	-- defined in 3GPP TS 23.003.
-	-- The internal structure is defined as follows:
-	-- octet 1 bits 4321	Mobile Country Code 1st digit
-	--         bits 8765	Mobile Country Code 2nd digit
-	-- octet 2 bits 4321	Mobile Country Code 3rd digit
-	--         bits 8765	Mobile Network Code 3rd digit
-	--			or filler (1111) for 2 digit MNCs
-	-- octet 3 bits 4321	Mobile Network Code 1st digit
-	--         bits 8765	Mobile Network Code 2nd digit
-	-- octets 4 and 5	Location Area Code according to 3GPP TS 24.008
-	-- octets 6 and 7	Cell Identity (CI) value or 
-	-- 			Service Area Code (SAC) value 
-	--			according to 3GPP TS 23.003
-
-LAIFixedLength ::= OCTET STRING (SIZE (5))
-	-- Refers to Location Area Identification defined in 3GPP TS 23.003 [17].
-	-- The internal structure is defined as follows:
-	-- octet 1 bits 4321	Mobile Country Code 1st digit
-	--         bits 8765	Mobile Country Code 2nd digit
-	-- octet 2 bits 4321	Mobile Country Code 3rd digit
-	--         bits 8765	Mobile Network Code 3rd digit
-	--			or filler (1111) for 2 digit MNCs
-	-- octet 3 bits 4321	Mobile Network Code 1st digit
-	--         bits 8765	Mobile Network Code 2nd digit
-	-- octets 4 and 5	Location Area Code according to 3GPP TS 24.008 [35]
-
--- data types for subscriber management
-
-BasicServiceCode ::= CHOICE {
-	bearerService	[2] BearerServiceCode,
-	teleservice	[3] TeleserviceCode}
-
-Ext-BasicServiceCode ::= CHOICE {
-	ext-BearerService	[2] Ext-BearerServiceCode,
-	ext-Teleservice	[3] Ext-TeleserviceCode}
-
-EMLPP-Info ::= SEQUENCE {
-	maximumentitledPriority	EMLPP-Priority,
-	defaultPriority	EMLPP-Priority,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-EMLPP-Priority ::= INTEGER (0..15)
-	-- The mapping from the values A,B,0,1,2,3,4 to the integer-value is
-	-- specified as follows where A is the highest and 4 is the lowest
-	-- priority level
-	-- the integer values 7-15 are spare and shall be mapped to value 4
-
-priorityLevelA		EMLPP-Priority ::= 6
-priorityLevelB		EMLPP-Priority ::= 5
-priorityLevel0		EMLPP-Priority ::= 0
-priorityLevel1		EMLPP-Priority ::= 1
-priorityLevel2		EMLPP-Priority ::= 2
-priorityLevel3		EMLPP-Priority ::= 3
-priorityLevel4		EMLPP-Priority ::= 4
-
-MC-SS-Info ::= SEQUENCE {
-	ss-Code		[0] SS-Code,
-	ss-Status		[1] Ext-SS-Status,
-	nbrSB		[2] MaxMC-Bearers,
-	nbrUser		[3] MC-Bearers,
-	extensionContainer	[4] ExtensionContainer	OPTIONAL,
-	...}
-
-MaxMC-Bearers ::= INTEGER (2..maxNumOfMC-Bearers)
-
-MC-Bearers ::= INTEGER (1..maxNumOfMC-Bearers)
-
-maxNumOfMC-Bearers  INTEGER ::= 7
-
-Ext-SS-Status ::= OCTET STRING (SIZE (1..5))
-
-	-- OCTET 1:
-	--
-	-- bits 8765: 0000 (unused)
-	-- bits 4321: Used to convey the "P bit","R bit","A bit" and "Q bit",
-	--		    representing supplementary service state information
-	--		    as defined in TS 3GPP TS 23.011 [22]
-
-	-- bit 4: "Q bit"
-
-	-- bit 3: "P bit"
-
-	-- bit 2: "R bit"
-
-	-- bit 1: "A bit"
-
-	-- OCTETS 2-5: reserved for future use. They shall be discarded if
-	-- received and not understood.
-
-
-	-- data types for geographic location
-
-AgeOfLocationInformation ::= INTEGER (0..32767)
--- the value represents the elapsed time in minutes since the last
--- network contact of the mobile station (i.e. the actuality of the
--- location information).
--- value "0" indicates that the MS is currently in contact with the
---           network
--- value "32767" indicates that the location information is at least
---               32767 minutes old
-
-END
-
diff --git a/rrlp-ephemeris/asn1/MAP-ER-DataTypes.asn b/rrlp-ephemeris/asn1/MAP-ER-DataTypes.asn
deleted file mode 100644
index d0b90fc..0000000
--- a/rrlp-ephemeris/asn1/MAP-ER-DataTypes.asn
+++ /dev/null
@@ -1,415 +0,0 @@
--- $Id: MAP-ER-DataTypes.asn 28149 2009-04-25 17:45:34Z etxrab $
--- 3GPP TS 29.002 V8.9.0 (2009-04) 
--- 17.7.7	Error data types
-
-MAP-ER-DataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-ER-DataTypes (17) version11 (11)}
-
-DEFINITIONS
-
-IMPLICIT TAGS
-
-::=
-
-BEGIN
-
-EXPORTS
-	RoamingNotAllowedParam,
-	CallBarredParam,
-	CUG-RejectParam,
-	SS-IncompatibilityCause,
-	PW-RegistrationFailureCause,
-	SM-DeliveryFailureCause,
-	SystemFailureParam,
-	DataMissingParam,
-	UnexpectedDataParam,
-	FacilityNotSupParam,
-	OR-NotAllowedParam,
-	UnknownSubscriberParam,
-	NumberChangedParam,
-	UnidentifiedSubParam,
-	IllegalSubscriberParam,
-	IllegalEquipmentParam,
-	BearerServNotProvParam,
-	TeleservNotProvParam,
-	TracingBufferFullParam,
-	NoRoamingNbParam,
-	AbsentSubscriberParam,
-	BusySubscriberParam,
-	NoSubscriberReplyParam,
-	ForwardingViolationParam,
-	ForwardingFailedParam, 
-	ATI-NotAllowedParam,
-	SubBusyForMT-SMS-Param,
-	MessageWaitListFullParam,
-	AbsentSubscriberSM-Param,
-	AbsentSubscriberDiagnosticSM,
-	ResourceLimitationParam,
-	NoGroupCallNbParam,
-	IncompatibleTerminalParam,
-	ShortTermDenialParam,
-	LongTermDenialParam,
-	UnauthorizedRequestingNetwork-Param,
-	UnauthorizedLCSClient-Param,
-	PositionMethodFailure-Param,
-UnknownOrUnreachableLCSClient-Param,
-	MM-EventNotSupported-Param,
-ATSI-NotAllowedParam,
-ATM-NotAllowedParam,
-IllegalSS-OperationParam,
-SS-NotAvailableParam,
-SS-SubscriptionViolationParam,
-InformationNotAvailableParam,
-TargetCellOutsideGCA-Param,
-OngoingGroupCallParam
-
-;
-
-IMPORTS
-	SS-Status
-FROM MAP-SS-DataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-SS-DataTypes (14) version11 (11)}
-
-	SignalInfo,
-	BasicServiceCode,
-	NetworkResource,
-	AdditionalNetworkResource
-FROM MAP-CommonDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-CommonDataTypes (18) version11 (11)}
-
-
-	SS-Code
-FROM MAP-SS-Code {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-SS-Code (15) version11 (11)}
-
-	ExtensionContainer
-FROM MAP-ExtensionDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)}
-;
-
-RoamingNotAllowedParam ::= SEQUENCE {
-	roamingNotAllowedCause	RoamingNotAllowedCause,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	additionalRoamingNotAllowedCause	[0] AdditionalRoamingNotAllowedCause OPTIONAL }
-
---	if the additionalRoamingNotallowedCause is received by the MSC/VLR or SGSN then the 
---	roamingNotAllowedCause shall be discarded.
-
-AdditionalRoamingNotAllowedCause ::= ENUMERATED {
-	supportedRAT-TypesNotAllowed (0),
-	...}
-
-RoamingNotAllowedCause ::= ENUMERATED {
-	plmnRoamingNotAllowed  (0),
-	operatorDeterminedBarring  (3)}
-
-CallBarredParam ::= CHOICE {
-	callBarringCause	CallBarringCause,
-	-- call BarringCause must not be used in version 3 and higher
-	extensibleCallBarredParam	ExtensibleCallBarredParam
-	-- extensibleCallBarredParam must not be used in version <3
-	}
-
-CallBarringCause ::= ENUMERATED {
-	barringServiceActive  (0),
-	operatorBarring  (1)}
-
-ExtensibleCallBarredParam ::= SEQUENCE {
-	callBarringCause	CallBarringCause	OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	... ,
-	unauthorisedMessageOriginator	[1] NULL		OPTIONAL }
-
-CUG-RejectParam ::= SEQUENCE {
-	cug-RejectCause	CUG-RejectCause	OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-CUG-RejectCause ::= ENUMERATED {
-	incomingCallsBarredWithinCUG  (0),
-	subscriberNotMemberOfCUG  (1),
-	requestedBasicServiceViolatesCUG-Constraints  (5),
-	calledPartySS-InteractionViolation  (7)}
-
-SS-IncompatibilityCause ::= SEQUENCE {
-	ss-Code		[1] SS-Code	OPTIONAL,
-	basicService	BasicServiceCode	OPTIONAL,
-	ss-Status		[4] SS-Status	OPTIONAL,
-	...}
-
-PW-RegistrationFailureCause ::= ENUMERATED {
-	undetermined  (0),
-	invalidFormat  (1),
-	newPasswordsMismatch  (2)}
-
-SM-EnumeratedDeliveryFailureCause ::= ENUMERATED {
-	memoryCapacityExceeded  (0),
-	equipmentProtocolError  (1),
-	equipmentNotSM-Equipped  (2),
-	unknownServiceCentre  (3),
-	sc-Congestion  (4),
-	invalidSME-Address  (5),
-	subscriberNotSC-Subscriber  (6)}
-
-SM-DeliveryFailureCause ::= SEQUENCE {
-	sm-EnumeratedDeliveryFailureCause	SM-EnumeratedDeliveryFailureCause,
-	diagnosticInfo	SignalInfo	OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-AbsentSubscriberSM-Param ::= SEQUENCE {
-	absentSubscriberDiagnosticSM	AbsentSubscriberDiagnosticSM	OPTIONAL,
-	-- AbsentSubscriberDiagnosticSM can be either for non-GPRS 
-	-- or for GPRS
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	additionalAbsentSubscriberDiagnosticSM  	[0] 	AbsentSubscriberDiagnosticSM	OPTIONAL }
-	-- if received, additionalAbsentSubscriberDiagnosticSM 
-	-- is for GPRS and absentSubscriberDiagnosticSM is 
-	-- for non-GPRS
-
-AbsentSubscriberDiagnosticSM ::= INTEGER (0..255)
-	-- AbsentSubscriberDiagnosticSM values are defined in 3GPP TS 23.040
-
-SystemFailureParam ::= CHOICE {
-	networkResource	NetworkResource,
-	-- networkResource must not be used in version 3
-	extensibleSystemFailureParam	ExtensibleSystemFailureParam
-	-- extensibleSystemFailureParam must not be used in version <3
-	}
-
-ExtensibleSystemFailureParam ::= SEQUENCE {
-	networkResource	NetworkResource	OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	additionalNetworkResource	[0] AdditionalNetworkResource	OPTIONAL,
-	failureCauseParam	[1] FailureCauseParam	OPTIONAL }
-
-FailureCauseParam ::= ENUMERATED {
-	limitReachedOnNumberOfConcurrentLocationRequests (0),
-	... }
-	-- if unknown value is received in FailureCauseParam it shall be ignored
-
-
-DataMissingParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-UnexpectedDataParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-FacilityNotSupParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	shapeOfLocationEstimateNotSupported [0]	NULL		OPTIONAL,
-	neededLcsCapabilityNotSupportedInServingNode [1] NULL	OPTIONAL }
-
-OR-NotAllowedParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-UnknownSubscriberParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	unknownSubscriberDiagnostic	UnknownSubscriberDiagnostic	OPTIONAL}
-
-UnknownSubscriberDiagnostic ::= ENUMERATED {
-	imsiUnknown  (0),
-	gprs-eps-SubscriptionUnknown  (1),
-	...,
-	npdbMismatch  (2)}
-	-- if unknown values are received in 	
-	-- UnknownSubscriberDiagnostic they shall be discarded
-
-NumberChangedParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-UnidentifiedSubParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-IllegalSubscriberParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-IllegalEquipmentParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-BearerServNotProvParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-TeleservNotProvParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-TracingBufferFullParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-NoRoamingNbParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-AbsentSubscriberParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	absentSubscriberReason	[0] AbsentSubscriberReason	OPTIONAL}
-
-AbsentSubscriberReason ::= ENUMERATED {
-	imsiDetach (0),
-	restrictedArea (1),
-	noPageResponse (2),
-	... ,
-	purgedMS (3)}
--- exception handling: at reception of other values than the ones listed the 
--- AbsentSubscriberReason shall be ignored. 
--- The AbsentSubscriberReason: purgedMS is defined for the Super-Charger feature 
--- (see TS 23.116). If this value is received in a Provide Roaming Number response
--- it shall be mapped to the AbsentSubscriberReason: imsiDetach in the Send Routeing
--- Information response
-
-BusySubscriberParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	ccbs-Possible	[0] NULL		OPTIONAL,
-	ccbs-Busy		[1] NULL		OPTIONAL}
-
-NoSubscriberReplyParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-ForwardingViolationParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-ForwardingFailedParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-ATI-NotAllowedParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-ATSI-NotAllowedParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-ATM-NotAllowedParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-IllegalSS-OperationParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-SS-NotAvailableParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-SS-SubscriptionViolationParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-InformationNotAvailableParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-SubBusyForMT-SMS-Param ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	... ,
-	gprsConnectionSuspended	NULL			OPTIONAL }
-	-- If GprsConnectionSuspended is not understood it shall 
-	-- be discarded
-
-MessageWaitListFullParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-ResourceLimitationParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-NoGroupCallNbParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-IncompatibleTerminalParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-ShortTermDenialParam ::= SEQUENCE {
-	...}
-
-LongTermDenialParam ::= SEQUENCE {
-	...}
-
-UnauthorizedRequestingNetwork-Param ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-UnauthorizedLCSClient-Param ::= SEQUENCE {
-	unauthorizedLCSClient-Diagnostic	[0] UnauthorizedLCSClient-Diagnostic	OPTIONAL,
-	extensionContainer	[1] ExtensionContainer			OPTIONAL,
-	... }
-
-UnauthorizedLCSClient-Diagnostic ::= ENUMERATED {
-	noAdditionalInformation (0),
-	clientNotInMSPrivacyExceptionList (1),
-	callToClientNotSetup (2),
-	privacyOverrideNotApplicable (3),
-	disallowedByLocalRegulatoryRequirements (4),
-	...,
-	unauthorizedPrivacyClass (5),
-	unauthorizedCallSessionUnrelatedExternalClient (6),
-	unauthorizedCallSessionRelatedExternalClient (7) }
---	exception handling:
---	any unrecognized value shall be ignored
-
-PositionMethodFailure-Param ::= SEQUENCE {
-	positionMethodFailure-Diagnostic	[0] PositionMethodFailure-Diagnostic	OPTIONAL,
-	extensionContainer	[1] ExtensionContainer			OPTIONAL,
-	... }
-
-PositionMethodFailure-Diagnostic ::= ENUMERATED {
-	congestion  (0),
-	insufficientResources  (1),
-	insufficientMeasurementData  (2),
-	inconsistentMeasurementData  (3),
-	locationProcedureNotCompleted  (4),
-	locationProcedureNotSupportedByTargetMS  (5),
-	qoSNotAttainable  (6),
-	positionMethodNotAvailableInNetwork	(7),
-	positionMethodNotAvailableInLocationArea	(8),
-	... }
---	exception handling:
---	any unrecognized value shall be ignored
-
-UnknownOrUnreachableLCSClient-Param ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-MM-EventNotSupported-Param ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-TargetCellOutsideGCA-Param ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-OngoingGroupCallParam ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-
-END
-
diff --git a/rrlp-ephemeris/asn1/MAP-ExtensionDataTypes.asn b/rrlp-ephemeris/asn1/MAP-ExtensionDataTypes.asn
deleted file mode 100644
index d94c057..0000000
--- a/rrlp-ephemeris/asn1/MAP-ExtensionDataTypes.asn
+++ /dev/null
@@ -1,74 +0,0 @@
--- $Id: MAP-ExtensionDataTypes.asn 28149 2009-04-25 17:45:34Z etxrab $
--- MAP-ExtensionDataTypes.asn
---
--- Taken from 3GPP TS 29.002 V8.9.0 (2009-04)
---
--- 17.7.11 Extension data types
---
-
-MAP-ExtensionDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)}
-
-DEFINITIONS
-
-IMPLICIT TAGS
-
-::=
-
-BEGIN
-
-EXPORTS
-
-	PrivateExtension,
-	ExtensionContainer,
-	SLR-ArgExtensionContainer;
-
-
--- IOC for private MAP extensions
-
-
-MAP-EXTENSION  ::= CLASS {
-	&ExtensionType				OPTIONAL,
-	&extensionId 	OBJECT IDENTIFIER }
-	-- The length of the Object Identifier shall not exceed 16 octets and the
-	-- number of components of the Object Identifier shall not exceed 16
-
--- data types
-
-ExtensionContainer ::= SEQUENCE {
-	privateExtensionList	[0]PrivateExtensionList	OPTIONAL, 
-	pcs-Extensions	[1]PCS-Extensions	OPTIONAL,
-	...}
-
-SLR-ArgExtensionContainer ::= SEQUENCE {
-	privateExtensionList	[0]PrivateExtensionList	OPTIONAL, 
-	slr-Arg-PCS-Extensions	[1]SLR-Arg-PCS-Extensions	OPTIONAL,
-	...}
-
-PrivateExtensionList ::= SEQUENCE SIZE (1..maxNumOfPrivateExtensions) OF
-				PrivateExtension
-
-PrivateExtension ::= SEQUENCE {
-	extId		MAP-EXTENSION.&extensionId
-				({ExtensionSet}),
-	extType		MAP-EXTENSION.&ExtensionType
-				({ExtensionSet}{@extId})	OPTIONAL}
-
-maxNumOfPrivateExtensions  INTEGER ::= 10
-
-ExtensionSet		MAP-EXTENSION ::=
-		{...
-		 -- ExtensionSet is the set of all defined private extensions
-	}
-	-- Unsupported private extensions shall be discarded if received.
-
-PCS-Extensions ::= SEQUENCE {
-	...}
-
-SLR-Arg-PCS-Extensions ::= SEQUENCE {
-	...,
-	na-ESRK-Request	[0]	NULL		OPTIONAL }
-
-END
-
diff --git a/rrlp-ephemeris/asn1/MAP-LCS-DataTypes.asn b/rrlp-ephemeris/asn1/MAP-LCS-DataTypes.asn
deleted file mode 100644
index 2434b89..0000000
--- a/rrlp-ephemeris/asn1/MAP-LCS-DataTypes.asn
+++ /dev/null
@@ -1,657 +0,0 @@
--- $Id: MAP-LCS-DataTypes.asn 28149 2009-04-25 17:45:34Z etxrab $
--- MAP-LCS-DataTypes.asn
---
--- Taken from 3GPP TS 29.002  V8.9.0 (2009-04)
---
--- 17.7.13 Location service data types
---
-
-MAP-LCS-DataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-LCS-DataTypes (25) version11 (11)}
-
-DEFINITIONS
-IMPLICIT TAGS
-::=
-BEGIN
-
-EXPORTS
-	RoutingInfoForLCS-Arg,
-	RoutingInfoForLCS-Res,
-	ProvideSubscriberLocation-Arg,
-	ProvideSubscriberLocation-Res,
-	SubscriberLocationReport-Arg,
-	SubscriberLocationReport-Res,
-LocationType, 
-DeferredLocationEventType,
-LCSClientName,
-LCS-QoS,
-Horizontal-Accuracy,
-ResponseTime,
-Ext-GeographicalInformation, 
-VelocityEstimate,
-SupportedGADShapes,
-Add-GeographicalInformation,
-LCSRequestorID, 
-LCS-ReferenceNumber,
-LCSCodeword,
-AreaEventInfo,
-ReportingPLMNList,
-PeriodicLDRInfo,
-SequenceNumber
-;
-
-IMPORTS
-	AddressString,
-	ISDN-AddressString,
-	IMEI,
-	IMSI,
-	LMSI,
-	SubscriberIdentity,
-	AgeOfLocationInformation,
-	LCSClientExternalID,
-	LCSClientInternalID,
-LCSServiceTypeID,
-CellGlobalIdOrServiceAreaIdOrLAI,
-PLMN-Id
-FROM MAP-CommonDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-CommonDataTypes (18) version11 (11)}
-
-	ExtensionContainer,
-	SLR-ArgExtensionContainer
-FROM MAP-ExtensionDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)}
-
-	USSD-DataCodingScheme,
-USSD-String
-FROM MAP-SS-DataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0) gsm-Network (1) modules (3)
-   map-SS-DataTypes (14) version11 (11)}
-
-	APN,
-	GSN-Address,
-	SupportedLCS-CapabilitySets
-FROM MAP-MS-DataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-MS-DataTypes (11) version11 (11)}
-
-	Additional-Number
-FROM MAP-SM-DataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-SM-DataTypes (16) version11 (11)}
-;
-
-
-RoutingInfoForLCS-Arg ::= SEQUENCE {
-	mlcNumber		[0] ISDN-AddressString,
-	targetMS		[1] SubscriberIdentity,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	...}
-
-RoutingInfoForLCS-Res ::= SEQUENCE {
-	targetMS		[0] SubscriberIdentity,
-	lcsLocationInfo	[1] LCSLocationInfo,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	...,
-	v-gmlc-Address	[3]	GSN-Address	OPTIONAL,
-	h-gmlc-Address	[4]	GSN-Address	OPTIONAL,
-	ppr-Address	[5]	GSN-Address	OPTIONAL,
-	additional-v-gmlc-Address	[6]	GSN-Address	OPTIONAL }
-
-LCSLocationInfo ::= SEQUENCE {
-	networkNode-Number	ISDN-AddressString,
-	-- NetworkNode-number can be either msc-number or sgsn-number
-	lmsi			[0] LMSI		OPTIONAL,
-	extensionContainer	[1] ExtensionContainer	OPTIONAL,
-	... ,
-	gprsNodeIndicator 	[2] NULL		OPTIONAL,
-	-- gprsNodeIndicator is set only if the SGSN number is sent as the Network Node Number
-	additional-Number	[3] Additional-Number	OPTIONAL,
-	supportedLCS-CapabilitySets	[4]	SupportedLCS-CapabilitySets	OPTIONAL,
-	additional-LCS-CapabilitySets	[5]	SupportedLCS-CapabilitySets	OPTIONAL
-	}
-
-ProvideSubscriberLocation-Arg ::= SEQUENCE {
-	locationType	LocationType,
-	mlc-Number	ISDN-AddressString,
-	lcs-ClientID	[0] LCS-ClientID	OPTIONAL,
-	privacyOverride	[1] NULL		OPTIONAL,
-	imsi			[2] IMSI		OPTIONAL,
-	msisdn		[3] ISDN-AddressString	OPTIONAL,
-	lmsi			[4] LMSI		OPTIONAL,
-	imei			[5] IMEI		OPTIONAL,
-	lcs-Priority	[6] LCS-Priority	OPTIONAL,
-	lcs-QoS		[7] LCS-QoS	OPTIONAL,
-	extensionContainer	[8] ExtensionContainer	OPTIONAL,
-	... ,
-	supportedGADShapes	[9]	SupportedGADShapes	OPTIONAL,
-	lcs-ReferenceNumber	[10]	LCS-ReferenceNumber	OPTIONAL,
-	lcsServiceTypeID	[11]	LCSServiceTypeID	OPTIONAL,
-	lcsCodeword	[12]	LCSCodeword	OPTIONAL,
-	lcs-PrivacyCheck	[13]	LCS-PrivacyCheck	OPTIONAL,
-	areaEventInfo	[14]	AreaEventInfo	OPTIONAL,
-	h-gmlc-Address	[15]	GSN-Address	OPTIONAL,
-	mo-lrShortCircuitIndicator	[16] NULL		OPTIONAL,
-	periodicLDRInfo	[17] PeriodicLDRInfo	OPTIONAL,
-	reportingPLMNList	[18] ReportingPLMNList	OPTIONAL }
-
-	-- one of imsi or msisdn is mandatory
-	-- If a location estimate type indicates activate deferred location or cancel deferred 
-	-- location, a lcs-Reference number shall be included.
-
-LocationType ::= SEQUENCE {
-	locationEstimateType	[0] LocationEstimateType,
-	...,
-	deferredLocationEventType	[1] DeferredLocationEventType	OPTIONAL }
-
-LocationEstimateType ::= ENUMERATED {
-	currentLocation	(0),
-	currentOrLastKnownLocation	(1),
-	initialLocation	(2),
-	...,
-	activateDeferredLocation	(3),
-	cancelDeferredLocation	(4) ,
-	notificationVerificationOnly	(5) }
---	exception handling:
---	a ProvideSubscriberLocation-Arg containing an unrecognized LocationEstimateType
---	shall be rejected by the receiver with a return error cause of unexpected data value
-
-DeferredLocationEventType ::= BIT STRING {
-	msAvailable	(0) ,
-	enteringIntoArea	(1),
-	leavingFromArea	(2),
-	beingInsideArea	(3) ,
-	periodicLDR	(4)  } (SIZE (1..16)) 
--- beingInsideArea is always treated as oneTimeEvent regardless of the possible value
--- of occurrenceInfo inside areaEventInfo.
--- exception handling:
--- a ProvideSubscriberLocation-Arg containing other values than listed above in 
--- DeferredLocationEventType shall be rejected by the receiver with a return error cause of 
--- unexpected data value.
-
-LCS-ClientID ::= SEQUENCE {
-	lcsClientType	[0] LCSClientType,
-	lcsClientExternalID	[1] LCSClientExternalID	OPTIONAL,
-	lcsClientDialedByMS	[2] AddressString	OPTIONAL,
-	lcsClientInternalID	[3] LCSClientInternalID	OPTIONAL,
-	lcsClientName	[4] LCSClientName	OPTIONAL,
-	...,
-	lcsAPN		[5] APN		OPTIONAL,
-	lcsRequestorID	[6] LCSRequestorID	OPTIONAL }
-
-LCSClientType ::= ENUMERATED {
-	emergencyServices	(0),
-	valueAddedServices	(1),
-	plmnOperatorServices	(2),
-	lawfulInterceptServices	(3),
-	... }
-	--	exception handling:
-	--	unrecognized values may be ignored if the LCS client uses the privacy override
-	--	otherwise, an unrecognized value shall be treated as unexpected data by a receiver
-	--	a return error shall then be returned if received in a MAP invoke 
-
-LCSClientName ::= SEQUENCE {
-	dataCodingScheme	[0] USSD-DataCodingScheme,
-	nameString	[2] NameString,
-	...,
-	lcs-FormatIndicator	[3] LCS-FormatIndicator	OPTIONAL }
-
--- The USSD-DataCodingScheme shall indicate use of the default alphabet through the
--- following encoding
---	bit	7 6 5 4 3 2 1 0
---		0 0 0 0 1 1 1 1
-
-NameString ::= USSD-String (SIZE (1..maxNameStringLength))
-
-maxNameStringLength  INTEGER ::= 63
-
-LCSRequestorID ::= SEQUENCE {
-	dataCodingScheme	[0] USSD-DataCodingScheme,
-	requestorIDString	[1] RequestorIDString,
-	...,
-	lcs-FormatIndicator	[2] LCS-FormatIndicator	OPTIONAL }
-
-RequestorIDString ::= USSD-String (SIZE (1..maxRequestorIDStringLength))
-
-maxRequestorIDStringLength  INTEGER ::= 63
-
-LCS-FormatIndicator ::= ENUMERATED {
-	logicalName	(0),
-	e-mailAddress	(1),
-	msisdn		(2),
-	url			(3),
-	sipUrl		(4),
-	... }
-
-LCS-Priority ::= OCTET STRING (SIZE (1))
-	-- 0 = highest priority
-	-- 1 = normal priority
-	-- all other values treated as 1 
-
-LCS-QoS ::= SEQUENCE {
-	horizontal-accuracy	[0] Horizontal-Accuracy	OPTIONAL,
-	verticalCoordinateRequest	[1] NULL		OPTIONAL,
-	vertical-accuracy	[2] Vertical-Accuracy	OPTIONAL,	responseTime	[3] ResponseTime	OPTIONAL,
-	extensionContainer	[4] ExtensionContainer	OPTIONAL,
-	...,
-	velocityRequest	[5] NULL		OPTIONAL
-}
-
-Horizontal-Accuracy ::= OCTET STRING (SIZE (1))
-	-- bit 8 = 0
-	-- bits 7-1 = 7 bit Uncertainty Code defined in 3GPP TS 23.032. The horizontal location 
-	-- error should be less than the error indicated by the uncertainty code with 67%
-	-- confidence.
-
-Vertical-Accuracy ::= OCTET STRING (SIZE (1))
-	-- bit 8 = 0
-	-- bits 7-1 = 7 bit Vertical Uncertainty Code defined in 3GPP TS 23.032. 
-	-- The vertical location error should be less than the error indicated 
-	-- by the uncertainty code with 67% confidence.
-
-ResponseTime ::= SEQUENCE {
-	responseTimeCategory	ResponseTimeCategory,
-	...}
---	note: an expandable SEQUENCE simplifies later addition of a numeric response time.
-
-ResponseTimeCategory ::= ENUMERATED {
-	lowdelay  (0),
-	delaytolerant  (1),
-	... }
---	exception handling:
---	an unrecognized value shall be treated the same as value 1 (delaytolerant)
-
-SupportedGADShapes ::= BIT STRING {
-	ellipsoidPoint  (0),
-	ellipsoidPointWithUncertaintyCircle (1),
-	ellipsoidPointWithUncertaintyEllipse (2),
-	polygon (3),
-	ellipsoidPointWithAltitude (4),
-	ellipsoidPointWithAltitudeAndUncertaintyElipsoid (5),
-	ellipsoidArc  (6) } (SIZE (7..16))
--- A node shall mark in the BIT STRING all Shapes defined in 3GPP TS 23.032 it supports.
--- exception handling: bits 7 to 15 shall be ignored if received.
-
-LCS-ReferenceNumber::= OCTET STRING (SIZE(1))
-
-LCSCodeword ::= SEQUENCE {
-	dataCodingScheme	[0] USSD-DataCodingScheme,
-	lcsCodewordString	[1] LCSCodewordString,
-	...}
-
-LCSCodewordString ::= USSD-String (SIZE (1..maxLCSCodewordStringLength))
-
-maxLCSCodewordStringLength  INTEGER ::= 20
-
-LCS-PrivacyCheck ::= SEQUENCE {
-	callSessionUnrelated	[0] PrivacyCheckRelatedAction,
-	callSessionRelated	[1] PrivacyCheckRelatedAction	OPTIONAL,
-	...}
-
-PrivacyCheckRelatedAction ::= ENUMERATED {
-	allowedWithoutNotification (0),
-	allowedWithNotification (1),
-	allowedIfNoResponse (2),
-	restrictedIfNoResponse (3),
-	notAllowed (4),
-	...}
---	exception handling:
---	a ProvideSubscriberLocation-Arg containing an unrecognized PrivacyCheckRelatedAction
---	shall be rejected by the receiver with a return error cause of unexpected data value
-
-AreaEventInfo ::= SEQUENCE {
-	areaDefinition	[0]	AreaDefinition,
-	occurrenceInfo	[1]	OccurrenceInfo	OPTIONAL,
-	intervalTime	[2]	IntervalTime	OPTIONAL,
-	...}
-
-AreaDefinition ::= SEQUENCE {
-	areaList		[0]	AreaList,
-	...}
-
-AreaList ::= SEQUENCE SIZE (1..maxNumOfAreas) OF Area
-
-maxNumOfAreas  INTEGER ::= 10
-
-Area ::= SEQUENCE {
-	areaType		[0]	AreaType,
-	areaIdentification	[1]	AreaIdentification,
-	...}
-
-AreaType ::= ENUMERATED {
-	countryCode	(0),
-	plmnId		(1),
-	locationAreaId	(2),
-	routingAreaId	(3),
-	cellGlobalId	(4),
-	...,
-	utranCellId	(5) }
-
-AreaIdentification ::= OCTET STRING (SIZE (2..7))
-	-- The internal structure is defined as follows:
-	-- octet 1 bits 4321	Mobile Country Code 1st digit
-	--         bits 8765	Mobile Country Code 2nd digit
-	-- octet 2 bits 4321	Mobile Country Code 3rd digit
-	--         bits 8765	Mobile Network Code 3rd digit if 3 digit MNC included
-	--			or filler (1111)
-	-- octet 3 bits 4321	Mobile Network Code 1st digit
-	--         bits 8765	Mobile Network Code 2nd digit
-	-- octets 4 and 5	Location Area Code (LAC) for Local Area Id,
-	--			Routing Area Id and Cell Global Id
-	-- octet 6	Routing Area Code (RAC) for Routing Area Id
-	-- octets 6 and 7	Cell Identity (CI) for Cell Global Id
-	-- octets 4 until 7	Utran Cell Identity (UC-Id) for Utran Cell Id
-
-OccurrenceInfo ::= ENUMERATED {
-	oneTimeEvent	(0),
-	multipleTimeEvent	(1),
-	...}
-
-IntervalTime ::= INTEGER (1..32767)
-	-- minimum interval time between area reports in seconds
-
-PeriodicLDRInfo ::= SEQUENCE {
-	reportingAmount		ReportingAmount,
-	reportingInterval	ReportingInterval,
-	...}
--- reportingInterval x reportingAmount shall not exceed 8639999 (99 days, 23 hours,
--- 59 minutes and 59 seconds) for compatibility with OMA MLP and RLP
-
-ReportingAmount ::= INTEGER (1..maxReportingAmount)
-
-maxReportingAmount INTEGER ::= 8639999
-
-ReportingInterval ::= INTEGER (1..maxReportingInterval)
--- ReportingInterval is in seconds
-
-maxReportingInterval INTEGER ::= 8639999
-
-ReportingPLMNList::= SEQUENCE {
-	plmn-ListPrioritized			[0] NULL					OPTIONAL,
-	plmn-List 						[1] PLMNList,
-	...}
-
-PLMNList::= SEQUENCE SIZE (1..maxNumOfReportingPLMN) OF
-				ReportingPLMN
-
-maxNumOfReportingPLMN INTEGER ::= 20
-
-ReportingPLMN::= SEQUENCE {
-	plmn-Id 						[0] PLMN-Id,
-	ran-Technology 					[1] RAN-Technology			OPTIONAL,
-	ran-PeriodicLocationSupport		[2] NULL					OPTIONAL,
-	...}
-
-RAN-Technology ::= ENUMERATED {
-	gsm			(0),
-	umts		(1),
-	...}
-
-ProvideSubscriberLocation-Res ::= SEQUENCE {
-	locationEstimate	Ext-GeographicalInformation,
-	ageOfLocationEstimate	[0] AgeOfLocationInformation	OPTIONAL,
-	extensionContainer	[1] ExtensionContainer	OPTIONAL,
-	... ,
-	add-LocationEstimate	[2] Add-GeographicalInformation 	OPTIONAL,
-	deferredmt-lrResponseIndicator	[3] NULL		OPTIONAL,
-	geranPositioningData	[4] PositioningDataInformation	OPTIONAL,
-	utranPositioningData	[5] UtranPositioningDataInfo	OPTIONAL,
-	cellIdOrSai	[6] CellGlobalIdOrServiceAreaIdOrLAI	OPTIONAL,
-	sai-Present	[7] NULL		OPTIONAL,
-	accuracyFulfilmentIndicator	[8] AccuracyFulfilmentIndicator		OPTIONAL,
-	velocityEstimate	[9] VelocityEstimate	OPTIONAL,
-	mo-lrShortCircuitIndicator	[10] NULL		OPTIONAL }
-
---	if deferredmt-lrResponseIndicator is set, locationEstimate is ignored.
-
--- the add-LocationEstimate parameter shall not be sent to a node that did not indicate the
--- geographic shapes supported in the ProvideSubscriberLocation-Arg
--- The locationEstimate and the add-locationEstimate parameters shall not be sent if
--- the supportedGADShapes parameter has been received in ProvideSubscriberLocation-Arg
--- and the shape encoded in locationEstimate or add-LocationEstimate is not marked
--- as supported in supportedGADShapes. In such a case ProvideSubscriberLocation
--- shall be rejected with error FacilityNotSupported with additional indication
--- shapeOfLocationEstimateNotSupported.
--- sai-Present indicates that the cellIdOrSai parameter contains a Service Area Identity.
-
-AccuracyFulfilmentIndicator ::= ENUMERATED {
-	requestedAccuracyFulfilled  (0),
-	requestedAccuracyNotFulfilled  (1),
-	...	}
-
-Ext-GeographicalInformation ::= OCTET STRING (SIZE (1..maxExt-GeographicalInformation))
-	-- Refers to geographical Information defined in 3GPP TS 23.032.
-	-- This is composed of 1 or more octets with an internal structure according to
-	-- 3GPP TS 23.032
-	-- Octet 1: Type of shape, only the following shapes in 3GPP TS 23.032 are allowed:
-	--		(a) Ellipsoid point with uncertainty circle
-	--		(b) Ellipsoid point with uncertainty ellipse
-	--		(c) Ellipsoid point with altitude and uncertainty ellipsoid
-	--		(d) Ellipsoid Arc
-	--		(e) Ellipsoid Point
-	-- Any other value in octet 1 shall be treated as invalid
-	-- Octets 2 to 8 for case (a) – Ellipsoid point with uncertainty circle
-	--		Degrees of Latitude				3 octets
-	--		Degrees of Longitude				3 octets
-	--		Uncertainty code				1 octet
-	-- Octets 2 to 11 for case (b) – Ellipsoid point with uncertainty ellipse:
-	--		Degrees of Latitude				3 octets
-	--		Degrees of Longitude				3 octets
-	--		Uncertainty semi-major axis				1 octet
-	--		Uncertainty semi-minor axis				1 octet
-	--		Angle of major axis				1 octet
-	--		Confidence				1 octet
-	-- Octets 2 to 14 for case (c) – Ellipsoid point with altitude and uncertainty ellipsoid
-	--		Degrees of Latitude				3 octets
-	--		Degrees of Longitude				3 octets
-	--		Altitude				2 octets
-	--		Uncertainty semi-major axis				1 octet
-	--		Uncertainty semi-minor axis				1 octet
-	--		Angle of major axis				1 octet
-	--		Uncertainty altitude				1 octet
-	--		Confidence				1 octet
-	-- Octets 2 to 13 for case (d) – Ellipsoid Arc
-	--		Degrees of Latitude				3 octets
-	--		Degrees of Longitude				3 octets
-	--		Inner radius				2 octets
-	--		Uncertainty radius				1 octet
-	--		Offset angle				1 octet
-	--		Included angle				1 octet
-	--		Confidence				1 octet
-	-- Octets 2 to 7 for case (e) – Ellipsoid Point
-	--		Degrees of Latitude				3 octets
-	--		Degrees of Longitude				3 octets
-
-	--
-	-- An Ext-GeographicalInformation parameter comprising more than one octet and
-	-- containing any other shape or an incorrect number of octets or coding according
-	-- to 3GPP TS 23.032 shall be treated as invalid data by a receiver.
-	--
-	-- An Ext-GeographicalInformation parameter comprising one octet shall be discarded
-	-- by the receiver if an Add-GeographicalInformation parameter is received 
-	-- in the same message.
-	--
-	-- An Ext-GeographicalInformation parameter comprising one octet shall be treated as
-	-- invalid data by the receiver if an Add-GeographicalInformation parameter is not
-	-- received in the same message.
-
-maxExt-GeographicalInformation  INTEGER ::= 20
-	-- the maximum length allows for further shapes in 3GPP TS 23.032 to be included in later 
-	-- versions of 3GPP TS 29.002
-
-VelocityEstimate ::= OCTET STRING (SIZE (4..7))
-	-- Refers to Velocity description defined in 3GPP TS 23.032.
-	-- This is composed of 4 or more octets with an internal structure according to
-	-- 3GPP TS 23.032
-	-- Octet 1: Type of velocity, only the following types in 3GPP TS 23.032 are allowed:
-	--		(a) Horizontal Velocity
-	--		(b) Horizontal with Vertical Velocity
-	--		(c) Horizontal Velocity with Uncertainty
-	--		(d) Horizontal with Vertical Velocity and Uncertainty
-	-- For types Horizontal with Vertical Velocity and Horizontal with Vertical Velocity
-	-- and Uncertainty, the direction of the Vertical Speed is also included in Octet 1
-	-- Any other value in octet 1 shall be treated as invalid
-	-- Octets 2 to 4 for case (a) Horizontal velocity:
-	--		Bearing				1 octet
-	--		Horizontal Speed				2 octets
-	-- Octets 2 to 5 for case (b) – Horizontal with Vertical Velocity:
-	--		Bearing				1 octet
-	--		Horizontal Speed				2 octets
-	--		Vertical Speed				1 octet
-	-- Octets 2 to 5 for case (c) – Horizontal velocity with Uncertainty:
-	--		Bearing				1 octet
-	--		Horizontal Speed				2 octets
-	--		Uncertainty Speed				1 octet
-	-- Octets 2 to 7 for case (d) – Horizontal with Vertical Velocity and Uncertainty:
-	--		Bearing				1 octet
-	--		Horizontal Speed				2 octets
-	--		Vertical Speed				1 octet
-	--		Horizontal Uncertainty Speed			1 octet
-	--		Vertical Uncertainty Speed				1 octet
-
-PositioningDataInformation ::= OCTET STRING (SIZE (2..maxPositioningDataInformation))
-	-- Refers to the Positioning Data defined in 3GPP TS 49.031.
-	-- This is composed of 2 or more octets with an internal structure according to
-	-- 3GPP TS 49.031. 
-
-maxPositioningDataInformation INTEGER ::= 10
-	-- 
-
-UtranPositioningDataInfo ::= OCTET STRING (SIZE (3..maxUtranPositioningDataInfo))
-	-- Refers to the Position Data defined in 3GPP TS 25.413.
-	-- This is composed of the positioningDataDiscriminator and the positioningDataSet
-	-- included in positionData as defined in 3GPP TS 25.413.
-
-maxUtranPositioningDataInfo INTEGER ::= 11
-	-- 
-
-Add-GeographicalInformation ::= OCTET STRING (SIZE (1..maxAdd-GeographicalInformation))
-	-- Refers to geographical Information defined in 3GPP TS 23.032.
-	-- This is composed of 1 or more octets with an internal structure according to 
-	-- 3GPP TS 23.032
-	-- Octet 1: Type of shape, all the shapes defined in 3GPP TS 23.032 are allowed:
-	-- Octets 2 to n (where n is the total number of octets necessary to encode the shape
-	-- according to 3GPP TS 23.032) are used to encode the shape itself in accordance with the
-	-- encoding defined in 3GPP TS 23.032
-	--
-	-- An Add-GeographicalInformation parameter, whether valid or invalid, received 
-	-- together with a valid Ext-GeographicalInformation parameter in the same message 
-	-- shall be discarded.
-	--
-	-- An Add-GeographicalInformation parameter containing any shape not defined in 
-	-- 3GPP TS 23.032 or an incorrect number of octets or coding according to 
-	-- 3GPP TS 23.032 shall be treated as invalid data by a receiver if not received 
-	-- together with a valid Ext-GeographicalInformation parameter in the same message.
-
-maxAdd-GeographicalInformation  INTEGER ::= 91
-	-- the maximum length allows support for all the shapes currently defined in 3GPP TS 23.032
-
-SubscriberLocationReport-Arg ::= SEQUENCE {
-	lcs-Event		LCS-Event,
-	lcs-ClientID	LCS-ClientID, 
-	lcsLocationInfo	LCSLocationInfo,
-	msisdn		[0] ISDN-AddressString	OPTIONAL,
-	imsi			[1] IMSI		OPTIONAL,
-	imei			[2] IMEI		OPTIONAL,
-	na-ESRD		[3] ISDN-AddressString	OPTIONAL,
-	na-ESRK		[4] ISDN-AddressString	OPTIONAL,
-	locationEstimate	[5] Ext-GeographicalInformation	OPTIONAL,
-	ageOfLocationEstimate	[6] AgeOfLocationInformation	OPTIONAL,
-	slr-ArgExtensionContainer	[7] SLR-ArgExtensionContainer	OPTIONAL,
-	... ,
-	add-LocationEstimate	[8] Add-GeographicalInformation	OPTIONAL,
-	deferredmt-lrData	[9] Deferredmt-lrData	OPTIONAL, 
-	lcs-ReferenceNumber	[10] LCS-ReferenceNumber	OPTIONAL,
-	geranPositioningData	[11] PositioningDataInformation	OPTIONAL,
-	utranPositioningData	[12] UtranPositioningDataInfo	OPTIONAL,
-	cellIdOrSai	[13]	CellGlobalIdOrServiceAreaIdOrLAI	OPTIONAL,
-	h-gmlc-Address	[14]	GSN-Address	OPTIONAL,
-	lcsServiceTypeID	[15]	LCSServiceTypeID	OPTIONAL,
-	sai-Present	[17] NULL		OPTIONAL,
-	pseudonymIndicator	[18] NULL		OPTIONAL,
-	accuracyFulfilmentIndicator	[19] AccuracyFulfilmentIndicator	OPTIONAL,
-	velocityEstimate	[20] VelocityEstimate	OPTIONAL,
-	sequenceNumber	[21] SequenceNumber	OPTIONAL,
-	periodicLDRInfo	[22] PeriodicLDRInfo	OPTIONAL,
-	mo-lrShortCircuitIndicator	[23] NULL		OPTIONAL }
-
-	-- one of msisdn or imsi is mandatory
-	-- a location estimate that is valid for the locationEstimate parameter should 
-	-- be transferred in this parameter in preference to the add-LocationEstimate.
-	-- the deferredmt-lrData parameter shall be included if and only if the lcs-Event
-	-- indicates a deferredmt-lrResponse.
-	-- if the lcs-Event indicates a deferredmt-lrResponse then the locationEstimate 
-	-- and the add-locationEstimate parameters shall not be sent if the 
-	-- supportedGADShapes parameter had been received in ProvideSubscriberLocation-Arg
-	-- and the shape encoded in locationEstimate or add-LocationEstimate was not marked
-	-- as supported in supportedGADShapes. In such a case terminationCause 
-	-- in deferredmt-lrData shall be present with value 
-	-- shapeOfLocationEstimateNotSupported. 
-	-- If a lcs event indicates deferred mt-lr response, the lcs-Reference number shall be 
-	-- included. 
-	-- sai-Present indicates that the cellIdOrSai parameter contains a Service Area Identity.
-
-Deferredmt-lrData ::= SEQUENCE {
-	deferredLocationEventType	DeferredLocationEventType,
-	terminationCause	[0] TerminationCause	OPTIONAL,
-	lcsLocationInfo	[1] LCSLocationInfo	OPTIONAL,
-	...}
-	-- lcsLocationInfo may be included only if a terminationCause is present 
-	-- indicating mt-lrRestart.
-
-LCS-Event ::= ENUMERATED {
-	emergencyCallOrigination  (0),
-	emergencyCallRelease  (1), 
-	mo-lr  (2),
-	...,
-	deferredmt-lrResponse  (3) ,
-	deferredmo-lrTTTPInitiation  (4)  }
-	--	deferredmt-lrResponse is applicable to the delivery of a location estimate 
-	--	for an LDR initiated earlier by either the network (via an MT-LR activate deferred 
-	--	location) or the UE (via a deferred MO-LR TTTP initiation)
-	--	exception handling:
-	--	a SubscriberLocationReport-Arg containing an unrecognized LCS-Event
-	--	shall be rejected by a receiver with a return error cause of unexpected data value
-
-TerminationCause ::= ENUMERATED {
-	normal  (0),
-	errorundefined  (1),
-	internalTimeout  (2),
-	congestion  (3),
-	mt-lrRestart  (4),
-	privacyViolation  (5),
-	...,
-	shapeOfLocationEstimateNotSupported (6) ,
-	subscriberTermination (7),
-	uETermination (8),
-	networkTermination (9)  } 
--- mt-lrRestart shall be used to trigger the GMLC to restart the location procedure, 
--- either because the sending node knows that the terminal has moved under coverage 
--- of another MSC or SGSN (e.g. Send Identification received), or because the subscriber
--- has been deregistered due to a Cancel Location received from HLR.
---
--- exception handling
--- an unrecognized value shall be treated the same as value 1 (errorundefined) 
-
-SequenceNumber ::= INTEGER (1..maxReportingAmount)
-
-SubscriberLocationReport-Res ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL, 
-	..., 
-	na-ESRK		[0] ISDN-AddressString	OPTIONAL,
-	na-ESRD		[1] ISDN-AddressString	OPTIONAL,
-	h-gmlc-Address	[2]	GSN-Address	OPTIONAL,
-	mo-lrShortCircuitIndicator	[3] NULL		OPTIONAL,
-	reportingPLMNList	[4] ReportingPLMNList	OPTIONAL,
-	lcs-ReferenceNumber	[5]	LCS-ReferenceNumber	OPTIONAL }
-
--- na-ESRK and na-ESRD are mutually exclusive
---
--- exception handling
--- receipt of both na-ESRK and na-ESRD shall be treated the same as a return error
-
-
-END
-
diff --git a/rrlp-ephemeris/asn1/MAP-MS-DataTypes.asn b/rrlp-ephemeris/asn1/MAP-MS-DataTypes.asn
deleted file mode 100644
index 9c12a02..0000000
--- a/rrlp-ephemeris/asn1/MAP-MS-DataTypes.asn
+++ /dev/null
@@ -1,2780 +0,0 @@
--- $Id: MAP-MS-DataTypes.asn 28149 2009-04-25 17:45:34Z etxrab $
--- 3GPP TS 29.002 V8.9.0 (2009-04) 
--- 17.7.1	Mobile Service data types
-
-MAP-MS-DataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-MS-DataTypes (11) version11 (11)}
-
-DEFINITIONS
-
-IMPLICIT TAGS
-
-::=
-
-BEGIN
-
-EXPORTS
-
-	-- location registration types
-	UpdateLocationArg,
-	UpdateLocationRes,
-	CancelLocationArg,
-	CancelLocationRes, 
-	PurgeMS-Arg, 
-	PurgeMS-Res,
-	SendIdentificationArg,
-	SendIdentificationRes, 
-	UpdateGprsLocationArg,
-	UpdateGprsLocationRes,
-	IST-SupportIndicator, 
-	SupportedLCS-CapabilitySets,
-
-	-- gprs location registration types
-	GSN-Address,
-
-	-- handover types
-	ForwardAccessSignalling-Arg,
-	PrepareHO-Arg,
-	PrepareHO-Res,
-	PrepareSubsequentHO-Arg, 
-	PrepareSubsequentHO-Res,
-	ProcessAccessSignalling-Arg,
-	SendEndSignal-Arg,
-	SendEndSignal-Res,
-
-	-- authentication management types
-	SendAuthenticationInfoArg,
-	SendAuthenticationInfoRes, 
-	AuthenticationFailureReportArg,
-AuthenticationFailureReportRes,
-
-	-- security management types
-	Kc, 
-	Cksn,
-
-	-- equipment management types
-	CheckIMEI-Arg,
-	CheckIMEI-Res,
-
-	-- subscriber management types
-	InsertSubscriberDataArg,
-	InsertSubscriberDataRes, 
-	LSAIdentity,
-	DeleteSubscriberDataArg,
-	DeleteSubscriberDataRes,
-	Ext-QoS-Subscribed,
-	Ext2-QoS-Subscribed, 
-	Ext3-QoS-Subscribed,
-	SubscriberData,
-	ODB-Data,
-	SubscriberStatus,
-	ZoneCodeList,
-	maxNumOfZoneCodes, 
-	O-CSI, 
-D-CSI,
-	O-BcsmCamelTDPCriteriaList, 
-	T-BCSM-CAMEL-TDP-CriteriaList,
-	SS-CSI,
-	ServiceKey,
-	DefaultCallHandling,
-	CamelCapabilityHandling,
-	BasicServiceCriteria,
-	SupportedCamelPhases,
-	OfferedCamel4CSIs,
-	OfferedCamel4Functionalities,
-	maxNumOfCamelTDPData,
-	CUG-Index, 
-	CUG-Info,
-	CUG-Interlock,
-	InterCUG-Restrictions,
-	IntraCUG-Options,
-	NotificationToMSUser, 
-	QoS-Subscribed,
-IST-AlertTimerValue,
-	T-CSI,
-	T-BcsmTriggerDetectionPoint,
-APN,
-AdditionalInfo,
-
-	-- fault recovery types
-	ResetArg,
-	RestoreDataArg,
-	RestoreDataRes,
-
--- provide subscriber info types 
-GeographicalInformation, 
-MS-Classmark2,
-GPRSMSClass,
-
-	-- subscriber information enquiry types
-	ProvideSubscriberInfoArg,
-	ProvideSubscriberInfoRes,
-	SubscriberInfo,
-	LocationInformation,
-	LocationInformationGPRS,
-	RAIdentity,
-	SubscriberState,
-	GPRSChargingID, 
-MNPInfoRes,
-	RouteingNumber,
-
-	-- any time information enquiry types
-	AnyTimeInterrogationArg,
-	AnyTimeInterrogationRes,
-
-	-- any time information handling types
-	AnyTimeSubscriptionInterrogationArg,
-	AnyTimeSubscriptionInterrogationRes,
-	AnyTimeModificationArg,
-	AnyTimeModificationRes,
-
-	-- subscriber data modification notification types
-	NoteSubscriberDataModifiedArg,
-	NoteSubscriberDataModifiedRes,
-
-	-- gprs location information retrieval types
-	SendRoutingInfoForGprsArg,
-	SendRoutingInfoForGprsRes,
-
-	-- failure reporting types
-	FailureReportArg,
-	FailureReportRes,
-
-	-- gprs notification types
-	NoteMsPresentForGprsArg,
-	NoteMsPresentForGprsRes,
-
-	-- Mobility Management types
-NoteMM-EventArg,
-	NoteMM-EventRes,
-	NumberPortabilityStatus,
-	PagingArea,
-
-	-- VGCS / VBS types types
-GroupId, 
-Long-GroupId,
-AdditionalSubscriptions
-
-;
-
-IMPORTS
-	maxNumOfSS,
-	SS-SubscriptionOption,
-	SS-List,
-	SS-ForBS-Code,
-	Password
-FROM MAP-SS-DataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-SS-DataTypes (14) version11 (11)}
-
-	SS-Code
-FROM MAP-SS-Code {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-SS-Code (15) version11 (11)}
-
-	Ext-BearerServiceCode
-FROM MAP-BS-Code {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-BS-Code (20) version11 (11)}
-
-	Ext-TeleserviceCode
-FROM MAP-TS-Code {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-TS-Code (19) version11 (11)}
-
-	AddressString,
-ISDN-AddressString, 
-	ISDN-SubaddressString, 
-	FTN-AddressString,
-	AccessNetworkSignalInfo,
-	IMSI, 
-	IMEI,
-	TMSI,
-	HLR-List,
-	LMSI,
-	Identity,
-	GlobalCellId,
-	CellGlobalIdOrServiceAreaIdOrLAI,
-	Ext-BasicServiceCode,
-	NAEA-PreferredCI,
-	EMLPP-Info, 
-	MC-SS-Info,
-	SubscriberIdentity,
-	AgeOfLocationInformation,
-	LCSClientExternalID,
-	LCSClientInternalID,
-	Ext-SS-Status,
-	LCSServiceTypeID,
-	ASCI-CallReference,
-	TBCD-STRING,
-	LAIFixedLength,
-	PLMN-Id,
-EMLPP-Priority
-FROM MAP-CommonDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-CommonDataTypes (18) version11 (11)}
-
-	ExtensionContainer
-FROM MAP-ExtensionDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)}
-
-	AbsentSubscriberDiagnosticSM
-FROM MAP-ER-DataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-ER-DataTypes (17) version11 (11)}
-
-	TracePropagationList
-FROM MAP-OM-DataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-OM-DataTypes (12) version11 (11)}
-
-;
-
--- location registration types
-
-UpdateLocationArg ::= SEQUENCE {
-	imsi			IMSI,
-	msc-Number	[1] ISDN-AddressString,
-	vlr-Number	ISDN-AddressString,
-	lmsi			[10] LMSI		OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	... ,
-	vlr-Capability	[6] VLR-Capability	OPTIONAL,
-	informPreviousNetworkEntity	[11]	NULL		OPTIONAL,
-	cs-LCS-NotSupportedByUE	[12]	NULL		OPTIONAL,
-	v-gmlc-Address	[2]	GSN-Address	OPTIONAL,
-	add-info		[13] ADD-Info	OPTIONAL,
-	pagingArea	[14] PagingArea	OPTIONAL,
-	skipSubscriberDataUpdate	[15] NULL		OPTIONAL 
-	-- The skipSubscriberDataUpdate parameter in the UpdateLocationArg and the ADD-Info
-	-- structures carry the same semantic.
-	 }
-
-VLR-Capability ::= SEQUENCE{
-	supportedCamelPhases  	[0] SupportedCamelPhases	OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	... ,
-	solsaSupportIndicator	[2] NULL		OPTIONAL,
-	istSupportIndicator	[1] IST-SupportIndicator	OPTIONAL,
-	superChargerSupportedInServingNetworkEntity	[3] SuperChargerInfo	OPTIONAL,
-	longFTN-Supported	[4]	NULL		OPTIONAL,
-	supportedLCS-CapabilitySets	[5]	SupportedLCS-CapabilitySets	OPTIONAL,
-	offeredCamel4CSIs	[6] OfferedCamel4CSIs	OPTIONAL,
-	supportedRAT-TypesIndicator	[7]	SupportedRAT-Types	OPTIONAL,
-	longGroupID-Supported	[8]	NULL		OPTIONAL }
-
-SupportedRAT-Types::= BIT STRING {
-	utran  (0),
-	geran  (1),
-	gan    (2),
-	i-hspa-evolution (3),
-	e-utran	(4)} (SIZE (2..8))
-	-- exception handling: bits 5 to 7 shall be ignored if received and not understood
-	 
-
-
-SuperChargerInfo ::= CHOICE {
-	sendSubscriberData	[0] NULL,
-	subscriberDataStored	[1] AgeIndicator }
-
-AgeIndicator ::= OCTET STRING (SIZE (1..6))
-	-- The internal structure of this parameter is implementation specific.
-
-IST-SupportIndicator ::=  ENUMERATED {
-	basicISTSupported	(0),
-	istCommandSupported	(1),
-	...}
--- exception handling:
--- reception of values > 1 shall be mapped to ' istCommandSupported '
-
-SupportedLCS-CapabilitySets ::= BIT STRING {
-	lcsCapabilitySet1 (0),
-	lcsCapabilitySet2 (1),
-	lcsCapabilitySet3 (2),
-	lcsCapabilitySet4 (3) ,
-	lcsCapabilitySet5 (4) } (SIZE (2..16)) 
--- Core network signalling capability set1 indicates LCS Release98 or Release99 version.
--- Core network signalling capability set2 indicates LCS Release4.
--- Core network signalling capability set3 indicates LCS Release5.
--- Core network signalling capability set4 indicates LCS Release6.
--- Core network signalling capability set5 indicates LCS Release7 or later version.
--- A node shall mark in the BIT STRING all LCS capability sets it supports. 
--- If no bit is set then the sending node does not support LCS.
--- If the parameter is not sent by an VLR then the VLR may support at most capability set1.
--- If the parameter is not sent by an SGSN then no support for LCS is assumed.
--- An SGSN is not allowed to indicate support of capability set1.
--- Other bits than listed above shall be discarded.
-
-UpdateLocationRes ::= SEQUENCE {
-	hlr-Number	ISDN-AddressString,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	add-Capability	NULL			OPTIONAL,
-	pagingArea-Capability	[0]NULL			OPTIONAL }
-
-ADD-Info ::= SEQUENCE {
-	imeisv		[0] IMEI,
-	skipSubscriberDataUpdate	[1] NULL		OPTIONAL,
-	-- The skipSubscriberDataUpdate parameter in the UpdateLocationArg and the ADD-Info
-	-- structures carry the same semantic.
-	...}
-
-
-PagingArea ::= SEQUENCE SIZE (1..5) OF LocationArea 
-
-
-LocationArea ::= CHOICE {
-	laiFixedLength	[0] LAIFixedLength,
-	lac			[1] LAC}
-
-
-LAC ::= OCTET STRING (SIZE (2))
-	-- Refers to Location Area Code of the Location Area Identification defined in 
-     -- 3GPP TS 23.003 [17].
-	-- Location Area Code according to 3GPP TS 24.008 [35]
-
-CancelLocationArg ::= [3] SEQUENCE {
-	identity		Identity,
-	cancellationType	CancellationType	OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	typeOfUpdate	[0] TypeOfUpdate	OPTIONAL }
-
-TypeOfUpdate ::= ENUMERATED {
-	sgsn-change (0),
-	mme-change (1),
-	...}
-	-- TypeOfUpdate shall be absent if CancellationType is different from updateProcedure
-
-CancellationType ::= ENUMERATED {
-	updateProcedure	(0),
-	subscriptionWithdraw	(1),
-	...}
-	-- The HLR shall not send values other than listed above
-
-CancelLocationRes ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-PurgeMS-Arg ::= [3] SEQUENCE {
-	imsi			IMSI,
-	vlr-Number	[0] ISDN-AddressString	OPTIONAL,
-	sgsn-Number	[1]	ISDN-AddressString	OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-PurgeMS-Res ::= SEQUENCE {
-	freezeTMSI	[0]	NULL		OPTIONAL,
-	freezeP-TMSI	[1]	NULL		OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	freezeM-TMSI	[2]	NULL		OPTIONAL }
-
-SendIdentificationArg ::= SEQUENCE {
-	tmsi			TMSI,
-	numberOfRequestedVectors	NumberOfRequestedVectors 	OPTIONAL,
-	-- within a dialogue numberOfRequestedVectors shall be present in 
-	-- the first service request and shall not be present in subsequent service requests. 
-	-- If received in a subsequent service request it shall be discarded. 
-	segmentationProhibited	NULL			OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	msc-Number	ISDN-AddressString 	OPTIONAL,
-	previous-LAI	[0] LAIFixedLength	OPTIONAL,
-	hopCounter	[1] HopCounter	OPTIONAL }
-
-HopCounter ::= INTEGER (0..3)
-
-SendIdentificationRes ::= [3] SEQUENCE {
-	imsi			IMSI			OPTIONAL,
-	-- IMSI shall be present in the first (or only) service response of a dialogue.
-	-- If multiple service requests are present in a dialogue then IMSI
-	-- shall not be present in any service response other than the first one.
-	authenticationSetList	AuthenticationSetList	OPTIONAL,
-	currentSecurityContext	[2]CurrentSecurityContext	OPTIONAL,
-	extensionContainer	[3] ExtensionContainer	OPTIONAL,
-	...}
-
--- authentication management types
-
-AuthenticationSetList ::= CHOICE {
-	tripletList	[0] TripletList,
-	quintupletList	[1] QuintupletList }
-
-TripletList ::= SEQUENCE SIZE (1..5) OF
-				AuthenticationTriplet
-
-QuintupletList ::= SEQUENCE SIZE (1..5) OF
-				AuthenticationQuintuplet
-
-AuthenticationTriplet ::= SEQUENCE {
-	rand			RAND,
-	sres			SRES,
-	kc			Kc,
-	...}
-
-AuthenticationQuintuplet ::= SEQUENCE {
-	rand			RAND,
-	xres			XRES,
-	ck			CK,
-	ik			IK,
-	autn			AUTN,
-	...}
-
-CurrentSecurityContext ::= CHOICE {
-	gsm-SecurityContextData	[0] GSM-SecurityContextData,
-	umts-SecurityContextData	[1] UMTS-SecurityContextData }
-
-GSM-SecurityContextData ::= SEQUENCE {
-	kc			Kc,
-	cksn			Cksn,
-	... }
-
-UMTS-SecurityContextData ::= SEQUENCE {
-	ck			CK,
-	ik			IK,
-	ksi			KSI,
-	... }
-
-RAND ::= OCTET STRING (SIZE (16))
-
-SRES ::= OCTET STRING (SIZE (4))
-
-Kc ::= OCTET STRING (SIZE (8))
-
-XRES ::= OCTET STRING (SIZE (4..16))
-
-CK ::= OCTET STRING (SIZE (16))
-
-IK ::= OCTET STRING (SIZE (16))
-
-AUTN ::= OCTET STRING (SIZE (16))
-
-AUTS ::= OCTET STRING (SIZE (14))
-
-Cksn ::= OCTET STRING (SIZE (1))
-	-- The internal structure is defined in 3GPP TS 24.008
-
-KSI ::= OCTET STRING (SIZE (1))
-	-- The internal structure is defined in 3GPP TS 24.008
-
-AuthenticationFailureReportArg ::= SEQUENCE {
-	imsi			IMSI,
-	failureCause	FailureCause,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	... ,
-	re-attempt	BOOLEAN		OPTIONAL,
-	accessType	AccessType	OPTIONAL,
-	rand			RAND			OPTIONAL,
-	vlr-Number	[0] ISDN-AddressString	OPTIONAL,
-	sgsn-Number	[1] ISDN-AddressString	OPTIONAL }
-
-AccessType ::= ENUMERATED {
-	call (0),
-	emergencyCall (1),
-	locationUpdating (2),
-	supplementaryService (3),
-	shortMessage (4),
-	gprsAttach (5),
-	routingAreaUpdating (6),
-	serviceRequest (7),
-	pdpContextActivation (8),
-	pdpContextDeactivation (9),
-	...,
-	gprsDetach (10)}
-	-- exception handling:
-	-- received values greater than 10 shall be ignored.
-
-AuthenticationFailureReportRes ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-FailureCause ::= ENUMERATED {
-	wrongUserResponse  (0),
-	wrongNetworkSignature  (1)}
-
--- gprs location registration types
-
-UpdateGprsLocationArg ::= SEQUENCE {
-	imsi			IMSI,
-	sgsn-Number	ISDN-AddressString,	
-	sgsn-Address	GSN-Address,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	... ,
-	sgsn-Capability	[0] SGSN-Capability	OPTIONAL,
-	informPreviousNetworkEntity	[1]	NULL		OPTIONAL,
-	ps-LCS-NotSupportedByUE	[2]	NULL		OPTIONAL,
-	v-gmlc-Address	[3]	GSN-Address	OPTIONAL,
-	add-info		[4]  ADD-Info	OPTIONAL,
-	eps-info		[5]	EPS-Info	OPTIONAL,
-	servingNodeTypeIndicator	[6]	NULL		OPTIONAL,
-	skipSubscriberDataUpdate	[7] NULL		OPTIONAL,
-	usedRAT-Type	[8] Used-RAT-Type	OPTIONAL 
-	 }
-
-Used-RAT-Type::= ENUMERATED {
-	utran  (0),
-	geran  (1),
-	gan    (2),
-	i-hspa-evolution (3),
-	e-utran	(4),
-	...}
-
-EPS-Info ::= CHOICE{
-	pdn-gw-update	[0] PDN-GW-Update,
-	isr-Information	[1] ISR-Information }
-
-PDN-GW-Update ::= SEQUENCE{
-	apn			[0] APN		OPTIONAL,
-	pdn-gw-Identity	[1] PDN-GW-Identity	OPTIONAL,
-	contextId		[2] ContextId                     OPTIONAL,
-	extensionContainer	[3] ExtensionContainer	OPTIONAL,
-	... }
-
-ISR-Information::= BIT STRING {
-	updateMME  (0),
-	cancelSGSN  (1)} (SIZE (2..8))
-	-- exception handling: reception of unknown bit assignments in the
-	-- ISR-Information data type shall be discarded by the receiver 
-
-SGSN-Capability ::= SEQUENCE{
-	solsaSupportIndicator	NULL			OPTIONAL,
-	extensionContainer	[1] ExtensionContainer	OPTIONAL,
-	... ,
-	superChargerSupportedInServingNetworkEntity	[2] SuperChargerInfo	OPTIONAL ,
-	gprsEnhancementsSupportIndicator 	[3] NULL		OPTIONAL,
-	supportedCamelPhases  	[4] SupportedCamelPhases	OPTIONAL,
-	supportedLCS-CapabilitySets	[5]  SupportedLCS-CapabilitySets	OPTIONAL,
-	offeredCamel4CSIs	[6] OfferedCamel4CSIs	OPTIONAL,
-	smsCallBarringSupportIndicator	[7]	NULL		OPTIONAL,	supportedRAT-TypesIndicator	[8]	SupportedRAT-Types	OPTIONAL,
-	supportedFeatures	[9] SupportedFeatures	OPTIONAL }
-
-SupportedFeatures::= BIT STRING {
-	odb-all (0),
-	odb-HPLMN-APN (1),
-	odb-VPLMN-APN (2),
-	regSub (3)} (SIZE (4..8))
-
-GSN-Address ::= OCTET STRING (SIZE (5..17))
-	-- Octets are coded according to TS 3GPP TS 23.003 [17]
-
-UpdateGprsLocationRes ::= SEQUENCE {
-	hlr-Number	ISDN-AddressString,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	add-Capability	NULL			OPTIONAL,
-	sgsn-mmeSeparationSupported	[0] NULL		OPTIONAL }
-
--- handover types
-
-ForwardAccessSignalling-Arg ::= [3] SEQUENCE {
-	an-APDU		AccessNetworkSignalInfo,
-	integrityProtectionInfo	[0] IntegrityProtectionInformation		OPTIONAL,
-	encryptionInfo	[1] EncryptionInformation		OPTIONAL,
-	keyStatus		[2]	KeyStatus	OPTIONAL,
-	allowedGSM-Algorithms	[4]	AllowedGSM-Algorithms	OPTIONAL,
-	allowedUMTS-Algorithms	[5]	AllowedUMTS-Algorithms	OPTIONAL,
-	radioResourceInformation	[6] RadioResourceInformation	OPTIONAL,
-	extensionContainer	[3]	ExtensionContainer 	OPTIONAL,
-	...,
-	radioResourceList	[7]	RadioResourceList	OPTIONAL,
-	bssmap-ServiceHandover	[9]	BSSMAP-ServiceHandover	OPTIONAL,
-	ranap-ServiceHandover	[8]	RANAP-ServiceHandover	OPTIONAL,
-	bssmap-ServiceHandoverList	[10]	BSSMAP-ServiceHandoverList	OPTIONAL,
-	currentlyUsedCodec	[11] Codec	OPTIONAL,
-	iuSupportedCodecsList	[12] SupportedCodecsList	OPTIONAL,
-	rab-ConfigurationIndicator	[13] NULL		OPTIONAL,
-	iuSelectedCodec	[14]	Codec	OPTIONAL,
-	alternativeChannelType	[15]	RadioResourceInformation	OPTIONAL,
-	tracePropagationList	[17]	TracePropagationList	OPTIONAL }
-
-AllowedGSM-Algorithms ::= OCTET STRING (SIZE (1))
-	-- internal structure is coded as Algorithm identifier octet from
-	-- Permitted Algorithms defined in 3GPP TS 48.008
-	-- A node shall mark all GSM algorithms that are allowed in MSC-B
-
-AllowedUMTS-Algorithms ::= SEQUENCE {
-	integrityProtectionAlgorithms	[0] 	PermittedIntegrityProtectionAlgorithms	OPTIONAL,
-	encryptionAlgorithms	[1] 	PermittedEncryptionAlgorithms		OPTIONAL,
-	extensionContainer	[2]	ExtensionContainer	OPTIONAL,
-	...}
-
-PermittedIntegrityProtectionAlgorithms ::=
-		OCTET STRING (SIZE (1..maxPermittedIntegrityProtectionAlgorithmsLength))
-	-- Octets contain a complete PermittedIntegrityProtectionAlgorithms data type 
-	-- as defined in 3GPP TS 25.413, encoded according to the encoding scheme 
-	-- mandated by 3GPP TS 25.413. 
-	-- Padding bits are included, if needed, in the least significant bits of the 
-	-- last octet of the octet string. 
-
-
-maxPermittedIntegrityProtectionAlgorithmsLength INTEGER ::= 9
-
-PermittedEncryptionAlgorithms ::=
-		OCTET STRING (SIZE (1..maxPermittedEncryptionAlgorithmsLength))
-	-- Octets contain a complete PermittedEncryptionAlgorithms data type 
-	-- as defined in 3GPP TS 25.413, encoded according to the encoding scheme 
-	-- mandated by 3GPP TS 25.413
-	-- Padding bits are included, if needed, in the least significant bits of the 
-	-- last octet of the octet string. 
-
-
-maxPermittedEncryptionAlgorithmsLength INTEGER ::= 9
-
-KeyStatus ::= ENUMERATED {
-	old  (0),
-	new  (1),
-	...}
-	-- exception handling:
-	-- received values in range 2-31 shall be treated as "old"
-	-- received values greater than 31 shall be treated as "new"
-
-PrepareHO-Arg ::= [3] SEQUENCE {
-	targetCellId	[0] GlobalCellId	OPTIONAL,
-	ho-NumberNotRequired	NULL			OPTIONAL, 
-	targetRNCId	[1] RNCId		OPTIONAL,
-	an-APDU		[2] AccessNetworkSignalInfo	OPTIONAL,
-	multipleBearerRequested	[3] NULL		OPTIONAL,
-	imsi			[4] IMSI		OPTIONAL,
-	integrityProtectionInfo	[5] IntegrityProtectionInformation		OPTIONAL,
-	encryptionInfo	[6] EncryptionInformation		OPTIONAL,
-	radioResourceInformation	[7] RadioResourceInformation	OPTIONAL,
-	allowedGSM-Algorithms	[9]	AllowedGSM-Algorithms	OPTIONAL,
-	allowedUMTS-Algorithms	[10]	AllowedUMTS-Algorithms	OPTIONAL,
-	radioResourceList	[11] RadioResourceList	OPTIONAL,
-	extensionContainer	[8] ExtensionContainer	OPTIONAL,
-	... ,
-	rab-Id		[12] RAB-Id	OPTIONAL,
-	bssmap-ServiceHandover	[13]	BSSMAP-ServiceHandover	OPTIONAL,
-	ranap-ServiceHandover	[14]	RANAP-ServiceHandover	OPTIONAL, 
-	bssmap-ServiceHandoverList	[15]	BSSMAP-ServiceHandoverList	OPTIONAL,
-	asciCallReference	[20]	ASCI-CallReference	OPTIONAL,
-	geran-classmark	[16] GERAN-Classmark	OPTIONAL,
-	iuCurrentlyUsedCodec	[17] Codec	OPTIONAL,
-	iuSupportedCodecsList	[18] SupportedCodecsList	OPTIONAL,
-	rab-ConfigurationIndicator	[19] NULL		OPTIONAL,
-	uesbi-Iu		[21]	UESBI-Iu	OPTIONAL,
-	imeisv		[22]	IMEI		OPTIONAL,
-	alternativeChannelType	[23]	RadioResourceInformation	OPTIONAL,
-	tracePropagationList	[25]	TracePropagationList	OPTIONAL	 }
-
-BSSMAP-ServiceHandoverList ::= SEQUENCE SIZE (1.. maxNumOfServiceHandovers) OF
-				BSSMAP-ServiceHandoverInfo
-
-BSSMAP-ServiceHandoverInfo ::= SEQUENCE {
-	bssmap-ServiceHandover	BSSMAP-ServiceHandover,
-	rab-Id		RAB-Id,
-	-- RAB Identity is needed to relate the service handovers with the radio access bearers. 
-	...}
-
-maxNumOfServiceHandovers  INTEGER ::= 7
-
-BSSMAP-ServiceHandover ::= OCTET STRING (SIZE (1))
-	-- Octets are coded according the Service Handover information element in
-	-- 3GPP TS 48.008.
-
-RANAP-ServiceHandover ::= OCTET STRING (SIZE (1))
-	-- Octet contains a complete Service-Handover data type 
-	-- as defined in 3GPP TS 25.413, encoded according to the encoding scheme 
-	-- mandated by 3GPP TS 25.413
-	-- Padding bits are included in the least significant bits. 
-
-
-RadioResourceList ::= SEQUENCE SIZE (1.. maxNumOfRadioResources) OF
-				RadioResource
-
-RadioResource ::= SEQUENCE {
-	radioResourceInformation	RadioResourceInformation,
-	rab-Id		RAB-Id,
-	-- RAB Identity is needed to relate the radio resources with the radio access bearers. 
-	...}
-
-maxNumOfRadioResources  INTEGER ::= 7
-
-PrepareHO-Res ::= [3] SEQUENCE {
-	handoverNumber	[0] ISDN-AddressString	OPTIONAL,
-	relocationNumberList	[1]	RelocationNumberList	OPTIONAL,
-	an-APDU		[2]	AccessNetworkSignalInfo	OPTIONAL,
-	multicallBearerInfo	[3]	MulticallBearerInfo	OPTIONAL,
-	multipleBearerNotSupported	NULL			OPTIONAL,
-	selectedUMTS-Algorithms	[5]	SelectedUMTS-Algorithms	OPTIONAL,
-	chosenRadioResourceInformation	[6] ChosenRadioResourceInformation	 OPTIONAL,
-	extensionContainer	[4]	ExtensionContainer	OPTIONAL,
-	...,
-	iuSelectedCodec	[7] Codec		OPTIONAL,
-	iuAvailableCodecsList	[8] CodecList	OPTIONAL }
-
-SelectedUMTS-Algorithms ::= SEQUENCE {
-	integrityProtectionAlgorithm	[0] 	ChosenIntegrityProtectionAlgorithm	OPTIONAL,
-	encryptionAlgorithm	[1] 	ChosenEncryptionAlgorithm	OPTIONAL,
-	extensionContainer	[2]	ExtensionContainer	OPTIONAL,
-	...}
-
-ChosenIntegrityProtectionAlgorithm ::= OCTET STRING (SIZE (1))
-	-- Octet contains a complete IntegrityProtectionAlgorithm data type 
-	-- as defined in 3GPP TS 25.413, encoded according to the encoding scheme 
-	-- mandated by 3GPP TS 25.413
-	-- Padding bits are included in the least significant bits. 
-
-ChosenEncryptionAlgorithm ::= OCTET STRING (SIZE (1))
-	-- Octet contains a complete EncryptionAlgorithm data type 
-	-- as defined in 3GPP TS 25.413, encoded according to the encoding scheme 
-	-- mandated by 3GPP TS 25.413
-	-- Padding bits are included in the least significant bits. 
-
-ChosenRadioResourceInformation ::= SEQUENCE {
-	chosenChannelInfo	[0] ChosenChannelInfo	OPTIONAL,
-	chosenSpeechVersion	[1] ChosenSpeechVersion	OPTIONAL,
-	...}
-
-ChosenChannelInfo ::= OCTET STRING (SIZE (1))
-	-- Octets are coded according the Chosen Channel information element in 3GPP TS 48.008
-
-ChosenSpeechVersion ::= OCTET STRING (SIZE (1))
-	-- Octets are coded according the Speech Version (chosen) information element in 3GPP TS
-	-- 48.008 
-
-PrepareSubsequentHO-Arg ::= [3] SEQUENCE {
-	targetCellId	[0] GlobalCellId	OPTIONAL,
-	targetMSC-Number	[1] ISDN-AddressString,
-	targetRNCId	[2] RNCId		OPTIONAL,
-	an-APDU		[3]	AccessNetworkSignalInfo	OPTIONAL,
-	selectedRab-Id	[4]	RAB-Id	OPTIONAL,
-	extensionContainer	[5]	ExtensionContainer	OPTIONAL,
-	...,
-	geran-classmark	[6] GERAN-Classmark	OPTIONAL,
-	rab-ConfigurationIndicator	[7] NULL		OPTIONAL }
-
-PrepareSubsequentHO-Res ::= [3] SEQUENCE {
-	an-APDU		AccessNetworkSignalInfo,
-	extensionContainer	[0]	ExtensionContainer	OPTIONAL,
-	...}
-
-ProcessAccessSignalling-Arg ::= [3] SEQUENCE {
-	an-APDU		AccessNetworkSignalInfo,
-	selectedUMTS-Algorithms	[1]	SelectedUMTS-Algorithms	OPTIONAL,
-	selectedGSM-Algorithm	[2]	SelectedGSM-Algorithm	OPTIONAL,
-	chosenRadioResourceInformation	[3] ChosenRadioResourceInformation OPTIONAL,
-	selectedRab-Id	[4] RAB-Id	OPTIONAL,
-	extensionContainer	[0]	ExtensionContainer 	OPTIONAL,
-	...,
-	iUSelectedCodec	[5] Codec		OPTIONAL,
-	iuAvailableCodecsList	[6] CodecList	OPTIONAL }
-
-SupportedCodecsList ::= SEQUENCE {
-	utranCodecList	[0] CodecList	OPTIONAL,
-	geranCodecList	[1] CodecList	OPTIONAL,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	...}
-
-CodecList ::= SEQUENCE {
-	codec1		[1] Codec,
-	codec2		[2] Codec		OPTIONAL,
-	codec3		[3] Codec		OPTIONAL,
-	codec4		[4] Codec		OPTIONAL,
-	codec5		[5] Codec		OPTIONAL,
-	codec6		[6] Codec		OPTIONAL,
-	codec7		[7] Codec		OPTIONAL,
-	codec8		[8] Codec		OPTIONAL,
-	extensionContainer	[9] ExtensionContainer	OPTIONAL,
-	...}
-	-- Codecs are sent in priority order where codec1 has highest priority
-
-Codec ::= OCTET STRING (SIZE (1..4))
-
-	-- The internal structure is defined as follows:
-	-- octet 1	Coded as Codec Identification code in 3GPP TS 26.103
-	-- octets 2,3,4	Parameters for the Codec as defined in 3GPP TS
-	--			26.103, if available, length depending on the codec
-
-GERAN-Classmark ::= OCTET STRING (SIZE (2..87))
-	-- Octets are coded according the GERAN Classmark information element in 3GPP TS 48.008
-
-SelectedGSM-Algorithm ::= OCTET STRING (SIZE (1))
-	-- internal structure is coded as Algorithm identifier octet from Chosen Encryption
-	-- Algorithm defined in 3GPP TS 48.008
-	-- A node shall mark only the selected GSM algorithm
-
-SendEndSignal-Arg ::= [3] SEQUENCE {
-	an-APDU		AccessNetworkSignalInfo,
-	extensionContainer	[0]	ExtensionContainer 	OPTIONAL,
-	...}
-
-SendEndSignal-Res ::= SEQUENCE {
-	extensionContainer	[0]	ExtensionContainer 	OPTIONAL,
-	...}
-
-RNCId ::= OCTET STRING (SIZE (7))
-	-- The internal structure is defined as follows:
-	-- octet 1 bits 4321	Mobile Country Code 1st digit
-	--         bits 8765	Mobile Country Code 2nd digit
-	-- octet 2 bits 4321	Mobile Country Code 3rd digit
-	--         bits 8765	Mobile Network Code 3rd digit
-	--			or filler (1111) for 2 digit MNCs
-	-- octet 3 bits 4321	Mobile Network Code 1st digit
-	--         bits 8765	Mobile Network Code 2nd digit
-	-- octets 4 and 5	Location Area Code according to 3GPP TS 24.008
-	-- octets 6 and 7	RNC Id value according to 3GPP TS 25.413
-
-RelocationNumberList ::= SEQUENCE SIZE (1..maxNumOfRelocationNumber) OF
-				RelocationNumber
-
-MulticallBearerInfo ::= INTEGER (1..maxNumOfRelocationNumber)
-
-RelocationNumber ::= SEQUENCE {
-	handoverNumber	ISDN-AddressString,
-	rab-Id		RAB-Id,
-	-- RAB Identity is needed to relate the calls with the radio access bearers. 
-	...}
-
-RAB-Id ::= INTEGER (1..maxNrOfRABs)
-
-maxNrOfRABs INTEGER ::= 255
-
-maxNumOfRelocationNumber  INTEGER ::= 7
-
-RadioResourceInformation ::= OCTET STRING (SIZE (3..13))
-	-- Octets are coded according the Channel Type information element in 3GPP TS 48.008
-
-IntegrityProtectionInformation ::= OCTET STRING (SIZE (18..maxNumOfIntegrityInfo))
-	-- Octets contain a complete IntegrityProtectionInformation data type 
-	-- as defined in 3GPP TS 25.413, encoded according to the encoding scheme 
-	-- mandated by 3GPP TS 25.413
-	-- Padding bits are included, if needed, in the least significant bits of the 
-	-- last octet of the octet string. 
-
-maxNumOfIntegrityInfo INTEGER ::= 100
-
-EncryptionInformation ::= OCTET STRING (SIZE (18..maxNumOfEncryptionInfo))
-	-- Octets contain a complete EncryptionInformation data type 
-	-- as defined in 3GPP TS 25.413, encoded according to the encoding scheme 
-	-- mandated by 3GPP TS 25.413
-	-- Padding bits are included, if needed, in the least significant bits of the 
-	-- last octet of the octet string. 
-
-maxNumOfEncryptionInfo INTEGER ::= 100
-
--- authentication management types
-
-SendAuthenticationInfoArg ::= SEQUENCE {
-	imsi			[0] IMSI,
-	numberOfRequestedVectors	NumberOfRequestedVectors,
-	segmentationProhibited	NULL			OPTIONAL,
-	immediateResponsePreferred	[1] NULL			OPTIONAL,
-	re-synchronisationInfo	Re-synchronisationInfo	OPTIONAL,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	...,
-	requestingNodeType	[3] RequestingNodeType	OPTIONAL,
-	requestingPLMN-Id	[4] PLMN-Id	OPTIONAL,
-	numberOfRequestedAdditional-Vectors	[5] NumberOfRequestedVectors	OPTIONAL,
-	additionalVectorsAreForEPS	[6] NULL		OPTIONAL }	
-
-
-NumberOfRequestedVectors ::= INTEGER (1..5)
-
-Re-synchronisationInfo ::= SEQUENCE {
-	rand			RAND,
-	auts			AUTS,
-	...}
-
-SendAuthenticationInfoRes ::= [3] SEQUENCE {
-	authenticationSetList	AuthenticationSetList 	OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	eps-AuthenticationSetList	[2] EPS-AuthenticationSetList	OPTIONAL }
-
-EPS-AuthenticationSetList ::= SEQUENCE SIZE (1..5) OF
-				EPC-AV
-
-EPC-AV ::= SEQUENCE {
-	rand			RAND,
-	xres			XRES,
-	autn			AUTN,
-	kasme		KASME,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-KASME ::= OCTET STRING (SIZE (16))
-
-RequestingNodeType ::= ENUMERATED {
-	vlr  (0),
-	sgsn  (1),
-	...,
-	s-cscf  (2),
-	bsf  (3),
-	gan-aaa-server  (4),
-	wlan-aaa-server  (5),
-	mme		(16),
-	mme-sgsn	(17)
-	}
-	-- the values 2, 3, 4 and 5 shall not be used on the MAP-D or Gr interfaces
-	-- exception handling:
-	-- received values in the range (6-15) shall be treated as "vlr"
-	-- received values greater than 17 shall be treated as "sgsn"
-
--- equipment management types
-
-CheckIMEI-Arg ::= SEQUENCE {
-	imei			IMEI,
-	requestedEquipmentInfo	RequestedEquipmentInfo,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-CheckIMEI-Res ::= SEQUENCE {
-	equipmentStatus	EquipmentStatus	OPTIONAL,
-	bmuef		UESBI-Iu		OPTIONAL,
-	extensionContainer	[0] ExtensionContainer	OPTIONAL,
-	...}
-
-RequestedEquipmentInfo::= BIT STRING {
-	equipmentStatus  (0),
-	bmuef  (1)} (SIZE (2..8))
-	-- exception handling: reception of unknown bit assignments in the
-	-- RequestedEquipmentInfo data type shall be discarded by the receiver 
-
-UESBI-Iu ::= SEQUENCE {
-	uesbi-IuA	[0] UESBI-IuA				OPTIONAL,
-	uesbi-IuB	[1] UESBI-IuB				OPTIONAL,
-	...}
-
-UESBI-IuA				::= BIT STRING (SIZE(1..128))
--- See 3GPP TS 25.413
-
-UESBI-IuB				::= BIT STRING (SIZE(1..128))
--- See 3GPP TS 25.413
-
-EquipmentStatus ::= ENUMERATED {
-	whiteListed  (0),
-	blackListed  (1),
-	greyListed  (2)}
-
--- subscriber management types
-
-InsertSubscriberDataArg ::= SEQUENCE {
-	imsi			[0] IMSI		OPTIONAL,
-	COMPONENTS OF	SubscriberData,
-	extensionContainer	[14] ExtensionContainer	OPTIONAL,
-	... ,	
-	naea-PreferredCI	[15] NAEA-PreferredCI	OPTIONAL,
-	-- naea-PreferredCI is included at the discretion of the HLR operator.
-	gprsSubscriptionData	[16] GPRSSubscriptionData	OPTIONAL,
-	roamingRestrictedInSgsnDueToUnsupportedFeature [23] 	NULL	
-							OPTIONAL, 
-	networkAccessMode	[24] NetworkAccessMode	OPTIONAL,
-	lsaInformation	[25] LSAInformation	OPTIONAL,
-	lmu-Indicator	[21]	NULL		OPTIONAL,
-	lcsInformation	[22]	LCSInformation	OPTIONAL,
-	istAlertTimer	[26] IST-AlertTimerValue	OPTIONAL,
-	superChargerSupportedInHLR	[27] AgeIndicator	OPTIONAL,
-	mc-SS-Info	[28] MC-SS-Info	OPTIONAL,
-	cs-AllocationRetentionPriority	[29] CS-AllocationRetentionPriority		OPTIONAL,
-	sgsn-CAMEL-SubscriptionInfo	[17] SGSN-CAMEL-SubscriptionInfo	OPTIONAL,
-	chargingCharacteristics 	[18]	ChargingCharacteristics 	OPTIONAL,
-	accessRestrictionData	[19] AccessRestrictionData	OPTIONAL,
-	ics-Indicator	[20]	BOOLEAN	OPTIONAL,
-	eps-SubscriptionData	[31]	EPS-SubscriptionData	OPTIONAL,
-	csg-SubscriptionDataList	[32] CSG-SubscriptionDataList	OPTIONAL }
-	-- If the Network Access Mode parameter is sent, it shall be present only in 
-	-- the first sequence if seqmentation is used
-
-CSG-SubscriptionDataList ::= SEQUENCE SIZE (1..50) OF
-				CSG-SubscriptionData
-
-CSG-SubscriptionData ::= SEQUENCE {
-	csg-Id	 		CSG-Id,
-	expirationDate		Time		OPTIONAL,
-	extensionContainer		ExtensionContainer 	OPTIONAL,
-	...}
-
-CSG-Id ::= BIT STRING (SIZE (27))
-	-- coded according to 3GPP TS 23.003 [17].
-
-Time ::= OCTET STRING (SIZE (4))
-	-- Octets are coded according to IETF RFC 3588 [139]
-
-
-EPS-SubscriptionData ::= SEQUENCE {
-	apn-oi-Replacement	[0]	APN-OI-Replacement	OPTIONAL,
-	rfsp-id		[2]	RFSP-ID		OPTIONAL,
-	ambr			[3]	AMBR		OPTIONAL,
-	apn-ConfigurationProfile	[4]	APN-ConfigurationProfile	OPTIONAL,
-	stn-sr		[6]	ISDN-AddressString	OPTIONAL,
-	extensionContainer	[5]	ExtensionContainer	OPTIONAL,
-	... }
-
-APN-OI-Replacement ::=  OCTET STRING (SIZE (9..100))
-	-- Octets are coded as APN Operator Identifier according to TS 3GPP TS 23.003 [17] 
-
-RFSP-ID ::=  INTEGER (1..256)
-
-APN-ConfigurationProfile ::= SEQUENCE {
-	defaultContext	ContextId,
-	completeDataListIncluded	NULL			OPTIONAL,
-		-- If segmentation is used, completeDataListIncluded may only be present in the
-		-- first segment of APN-ConfigurationProfile.
-	epsDataList	[1]	EPS-DataList,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	... }
-
-EPS-DataList ::= SEQUENCE SIZE (1..maxNumOfAPN-Configurations) OF
-				APN-Configuration
-
-
-maxNumOfAPN-Configurations  INTEGER ::= 50
-
-
-APN-Configuration ::= SEQUENCE {
-	contextId		[0] ContextId,
-	servedPartyIP-Address	[1] PDP-Address	OPTIONAL,
-	apn			[2] APN,
-	eps-qos-Subscribed	[3] EPS-QoS-Subscribed,
-	pdn-gw-Identity	[4] PDN-GW-Identity	OPTIONAL,
-	pdn-gw-AllocationType	[5] PDN-GW-AllocationType	OPTIONAL,
-	vplmnAddressAllowed	[6] NULL		OPTIONAL,
-	chargingCharacteristics	[7] ChargingCharacteristics	OPTIONAL,
-	ambr			[8] AMBR		OPTIONAL,
-	specificAPNInfoList	[9] SpecificAPNInfoList	OPTIONAL,	extensionContainer	[10] ExtensionContainer	OPTIONAL,
-	... }
-
-EPS-QoS-Subscribed ::= SEQUENCE {
-	qos-Class-Identifier	[0] QoS-Class-Identifier,
-	allocation-Retention-Priority	[1] Allocation-Retention-Priority,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	... }
-
-AMBR ::= SEQUENCE {
-	max-RequestedBandwidth-UL	[0] Bandwidth,
-	max-RequestedBandwidth-DL	[1] Bandwidth,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	... }
-
-
-SpecificAPNInfoList ::= SEQUENCE SIZE (1..maxNumOfSpecificAPNInfos) OF
-				SpecificAPNInfo
-
-maxNumOfSpecificAPNInfos  INTEGER ::= 50
-
-SpecificAPNInfo ::= SEQUENCE {
-	apn			[0] APN,
-	pdn-gw-Identity	[1] PDN-GW-Identity,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	... }
-
-Bandwidth ::= INTEGER 
-	-- bits per second
-
-QoS-Class-Identifier ::= INTEGER (1..9)
-	-- values are defined in  3GPP TS 29.212
-
-
-
-Allocation-Retention-Priority ::= SEQUENCE {
-	priority-level	[0] INTEGER,
-	pre-emption-capability	[1] BOOLEAN	OPTIONAL,
-	pre-emption-vulnerability	[2] BOOLEAN	OPTIONAL,
-	extensionContainer	[3] ExtensionContainer	OPTIONAL,
-	... }
-
-PDN-GW-Identity ::= SEQUENCE {
-	pdn-gw-ipv4-Address	[0] PDP-Address	OPTIONAL,
-	pdn-gw-ipv6-Address	[1] PDP-Address	OPTIONAL,
-	pdn-gw-name	[2] FQDN		OPTIONAL,
-	extensionContainer	[3] ExtensionContainer	OPTIONAL,
-	... }
-
-FQDN ::=  OCTET STRING (SIZE (9..100))
-
-
-PDN-GW-AllocationType ::= ENUMERATED {
-	static	(0),
-	dynamic	(1)}
-
-
-AccessRestrictionData ::= BIT STRING {
-	utranNotAllowed (0),
-	geranNotAllowed (1),
-	ganNotAllowed   (2),
-	i-hspa-evolutionNotAllowed (3),
-	e-utranNotAllowed (4),
-	ho-toNon3GPP-AccessNotAllowed (5) } (SIZE (2..8))
-	-- exception handling: 
-	-- access restriction data related to an access type not supported by a node
-	-- shall be ignored
-	-- bits 6 to 7 shall be ignored if received and not understood
-	
-
-CS-AllocationRetentionPriority ::= OCTET STRING (SIZE (1))
-	-- This data type encodes each priority level defined in TS 23.107 as the binary value
-	-- of the priority level.
-
-IST-AlertTimerValue ::= INTEGER (15..255)
-
-LCSInformation ::= SEQUENCE {
-	gmlc-List	[0]	GMLC-List	OPTIONAL,
-	lcs-PrivacyExceptionList	[1]	LCS-PrivacyExceptionList	OPTIONAL,
-	molr-List		[2]	MOLR-List	OPTIONAL,
-	...,
-	add-lcs-PrivacyExceptionList	[3]	LCS-PrivacyExceptionList	OPTIONAL }
-	-- add-lcs-PrivacyExceptionList may be sent only if lcs-PrivacyExceptionList is
-	-- present and contains four instances of LCS-PrivacyClass. If the mentioned condition
-	-- is not satisfied the receiving node shall discard add-lcs-PrivacyExceptionList.
-	-- If an LCS-PrivacyClass is received both in lcs-PrivacyExceptionList and in
-	-- add-lcs-PrivacyExceptionList with the same SS-Code, then the error unexpected 
-	-- data value shall be returned.
-
-GMLC-List ::= SEQUENCE SIZE (1..maxNumOfGMLC) OF
-				ISDN-AddressString
-	-- if segmentation is used, the complete GMLC-List shall be sent in one segment
-
-maxNumOfGMLC  INTEGER ::= 5
-
-NetworkAccessMode ::= ENUMERATED {
-	packetAndCircuit	(0),
-	onlyCircuit		(1),
-	onlyPacket		(2),
-	...}
-	-- if unknown values are received in NetworkAccessMode
-	-- they shall be discarded.
-
-GPRSDataList ::= SEQUENCE SIZE (1..maxNumOfPDP-Contexts) OF
-				PDP-Context
-
-maxNumOfPDP-Contexts  INTEGER ::= 50
-
-PDP-Context ::= SEQUENCE {
-	pdp-ContextId	ContextId,
-	pdp-Type		[16] PDP-Type,
-	pdp-Address	[17] PDP-Address	OPTIONAL,
-	qos-Subscribed	[18] QoS-Subscribed,
-	vplmnAddressAllowed	[19] NULL	OPTIONAL,
-	apn			[20] APN,
-	extensionContainer	[21] ExtensionContainer	OPTIONAL,
-	... ,
-	ext-QoS-Subscribed	[0] Ext-QoS-Subscribed	OPTIONAL, 
-	pdp-ChargingCharacteristics	[1] ChargingCharacteristics	OPTIONAL,
-	ext2-QoS-Subscribed	[2] Ext2-QoS-Subscribed	OPTIONAL,
-	-- ext2-QoS-Subscribed may be present only if ext-QoS-Subscribed is present.
-	ext3-QoS-Subscribed	[3] Ext3-QoS-Subscribed	OPTIONAL
-	-- ext3-QoS-Subscribed may be present only if ext2-QoS-Subscribed is present.
-	 }
-
-ContextId ::= INTEGER (1..maxNumOfPDP-Contexts)
-
-GPRSSubscriptionData ::= SEQUENCE {
-	completeDataListIncluded	NULL			OPTIONAL,
-		-- If segmentation is used, completeDataListIncluded may only be present in the
-		-- first segment of GPRSSubscriptionData.
-	gprsDataList	[1]	GPRSDataList,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	... }
-
-SGSN-CAMEL-SubscriptionInfo ::= SEQUENCE {
-	gprs-CSI		[0]	GPRS-CSI	OPTIONAL,
-	mo-sms-CSI	[1]	SMS-CSI	OPTIONAL,
-	extensionContainer	[2]	ExtensionContainer	OPTIONAL,
-	...,
-	mt-sms-CSI	[3]	SMS-CSI	OPTIONAL,
-	mt-smsCAMELTDP-CriteriaList	[4]	MT-smsCAMELTDP-CriteriaList	OPTIONAL,
-	mg-csi		[5]	MG-CSI	OPTIONAL
-	}
-
-GPRS-CSI ::= SEQUENCE {
-	gprs-CamelTDPDataList	[0] GPRS-CamelTDPDataList	OPTIONAL,
-	camelCapabilityHandling	[1] CamelCapabilityHandling	OPTIONAL,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	notificationToCSE	[3]	NULL		OPTIONAL,
-	csi-Active	[4]	NULL		OPTIONAL,
-	...}
---	notificationToCSE and csi-Active shall not be present when GPRS-CSI is sent to SGSN.
---	They may only be included in ATSI/ATM ack/NSDC message. 
---	GPRS-CamelTDPData and  camelCapabilityHandling shall be present in 
---	the GPRS-CSI sequence.
---	If GPRS-CSI is segmented, gprs-CamelTDPDataList and camelCapabilityHandling shall be 
---	present in the first segment
-
-GPRS-CamelTDPDataList ::= SEQUENCE SIZE (1..maxNumOfCamelTDPData) OF
-	GPRS-CamelTDPData
---	GPRS-CamelTDPDataList shall not contain more than one instance of
---	GPRS-CamelTDPData containing the same value for gprs-TriggerDetectionPoint.
-
-GPRS-CamelTDPData ::= SEQUENCE {
-	gprs-TriggerDetectionPoint	[0] GPRS-TriggerDetectionPoint,
-	serviceKey	[1] ServiceKey,
-	gsmSCF-Address	[2] ISDN-AddressString,
-	defaultSessionHandling	[3] DefaultGPRS-Handling,
-	extensionContainer	[4] ExtensionContainer	OPTIONAL,
-	...
-	}
-
-DefaultGPRS-Handling ::= ENUMERATED {
-	continueTransaction (0) ,
-	releaseTransaction (1) ,
-	...}
--- exception handling:
--- reception of values in range 2-31 shall be treated as "continueTransaction"
--- reception of values greater than 31 shall be treated as "releaseTransaction"
-
-GPRS-TriggerDetectionPoint ::= ENUMERATED {
-	attach 			(1),
-	attachChangeOfPosition 		(2),
-	pdp-ContextEstablishment 		(11),
-	pdp-ContextEstablishmentAcknowledgement	(12),
-	pdp-ContextChangeOfPosition 		(14),
-	... }
--- exception handling:
--- For GPRS-CamelTDPData sequences containing this parameter with any
--- other value than the ones listed the receiver shall ignore the whole 
--- GPRS-CamelTDPDatasequence.
-
-APN ::=  OCTET STRING (SIZE (2..63))
-	-- Octets are coded according to TS 3GPP TS 23.003 [17] 
-
-PDP-Type ::= OCTET STRING (SIZE (2))
-	-- Octets are coded according to TS 3GPP TS 29.060 [105]
-
-PDP-Address ::= OCTET STRING (SIZE (1..16))
-	-- Octets are coded according to TS 3GPP TS 29.060 [105]
-
-	-- The possible size values are:
-	-- 1-7 octets  X.25 address type
-	--  4  octets  IPv4 address type
-	-- 16  octets  Ipv6 address type
-
-QoS-Subscribed ::= OCTET STRING (SIZE (3))
-	-- Octets are coded according to TS 3GPP TS 24.008 [35] Quality of Service Octets 
-	-- 3-5.
-
-Ext-QoS-Subscribed ::= OCTET STRING (SIZE (1..9))
-	-- OCTET 1: 
-	--  Allocation/Retention Priority (This octet encodes each priority level defined in
-	--     23.107 as the binary value of the priority level, declaration in 29.060)
-	-- Octets 2-9 are coded according to 3GPP TS 24.008 [35] Quality of Service Octets 
-	-- 6-13.
-
-Ext2-QoS-Subscribed ::= OCTET STRING (SIZE (1..3))
-	-- Octets 1-3 are coded according to 3GPP TS 24.008 [35] Quality of Service Octets 14-16.
-	-- If Quality of Service information is structured with 14 octet length, then
-	-- Octet 1 is coded according to 3GPP TS 24.008 [35] Quality of Service Octet 14.
-
-Ext3-QoS-Subscribed ::= OCTET STRING (SIZE (1..2))
-	-- Octets 1-2 are coded according to 3GPP TS 24.008 [35] Quality of Service Octets 17-18.
-
-ChargingCharacteristics ::= OCTET STRING (SIZE (2))
-	-- Octets are coded according to 3GPP TS 32.215.
-
-LSAOnlyAccessIndicator ::= ENUMERATED {
-	accessOutsideLSAsAllowed  (0),
-	accessOutsideLSAsRestricted (1)}
-
-LSADataList ::= SEQUENCE SIZE (1..maxNumOfLSAs) OF
-				LSAData
-
-maxNumOfLSAs  INTEGER ::= 20
-
-LSAData ::= SEQUENCE {
-	lsaIdentity	[0] LSAIdentity,
-	lsaAttributes	[1] LSAAttributes,
-	lsaActiveModeIndicator	[2] NULL		OPTIONAL,
-	extensionContainer	[3] ExtensionContainer	OPTIONAL,
-	...}
-
-LSAInformation ::= SEQUENCE {
-	completeDataListIncluded	NULL			OPTIONAL,
-
-		-- If segmentation is used, completeDataListIncluded may only be present in the
-		-- first segment.
-	lsaOnlyAccessIndicator	[1]	LSAOnlyAccessIndicator	OPTIONAL,
-	lsaDataList	[2]	LSADataList	OPTIONAL,
-	extensionContainer	[3] ExtensionContainer	OPTIONAL,
-	...}
-
-LSAIdentity ::= OCTET STRING (SIZE (3))
-	-- Octets are coded according to TS 3GPP TS 23.003 [17]
-
-LSAAttributes ::= OCTET STRING (SIZE (1))
-	-- Octets are coded according to TS 3GPP TS 48.008 [49]
-
-SubscriberData ::= SEQUENCE {
-	msisdn		[1] ISDN-AddressString	OPTIONAL,
-	category		[2] Category	OPTIONAL,
-	subscriberStatus	[3] SubscriberStatus	OPTIONAL,
-	bearerServiceList	[4] BearerServiceList	OPTIONAL,
-	-- The exception handling for reception of unsupported / not allocated
-	-- bearerServiceCodes is defined in section 8.8.1
-	teleserviceList	[6] TeleserviceList	OPTIONAL,
-	-- The exception handling for reception of unsupported / not allocated
-	-- teleserviceCodes is defined in section 8.8.1
-	provisionedSS	[7] Ext-SS-InfoList	OPTIONAL,
-	odb-Data		[8] ODB-Data	OPTIONAL,
-	roamingRestrictionDueToUnsupportedFeature  [9] NULL	OPTIONAL,
-	regionalSubscriptionData	[10] ZoneCodeList	OPTIONAL,
-	vbsSubscriptionData	[11] VBSDataList	OPTIONAL,
-	vgcsSubscriptionData	[12] VGCSDataList	OPTIONAL,
-	vlrCamelSubscriptionInfo	[13] VlrCamelSubscriptionInfo	OPTIONAL
-	}
-
-Category ::= OCTET STRING (SIZE (1))
-	-- The internal structure is defined in ITU-T Rec Q.763.
-
-SubscriberStatus ::= ENUMERATED {
-	serviceGranted  (0),
-	operatorDeterminedBarring  (1)}
-
-BearerServiceList ::= SEQUENCE SIZE (1..maxNumOfBearerServices) OF
-				Ext-BearerServiceCode
-
-maxNumOfBearerServices  INTEGER ::= 50
-
-TeleserviceList ::= SEQUENCE SIZE (1..maxNumOfTeleservices) OF
-				Ext-TeleserviceCode
-
-maxNumOfTeleservices  INTEGER ::= 20
-
-ODB-Data ::= SEQUENCE {
-	odb-GeneralData	ODB-GeneralData,
-	odb-HPLMN-Data	ODB-HPLMN-Data	OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-ODB-GeneralData ::= BIT STRING {
-	allOG-CallsBarred  (0),
-	internationalOGCallsBarred  (1),
-	internationalOGCallsNotToHPLMN-CountryBarred  (2),
-	interzonalOGCallsBarred (6),
-	interzonalOGCallsNotToHPLMN-CountryBarred (7),
-	interzonalOGCallsAndInternationalOGCallsNotToHPLMN-CountryBarred (8),
-	premiumRateInformationOGCallsBarred  (3),
-	premiumRateEntertainementOGCallsBarred  (4),
-	ss-AccessBarred  (5),
-	allECT-Barred (9),
-	chargeableECT-Barred (10),
-	internationalECT-Barred (11),
-	interzonalECT-Barred (12),
-	doublyChargeableECT-Barred (13),
-	multipleECT-Barred (14),
-	allPacketOrientedServicesBarred (15),
-	roamerAccessToHPLMN-AP-Barred  (16),
-	roamerAccessToVPLMN-AP-Barred  (17),
-	roamingOutsidePLMNOG-CallsBarred  (18),
-	allIC-CallsBarred  (19),
-	roamingOutsidePLMNIC-CallsBarred  (20),
-	roamingOutsidePLMNICountryIC-CallsBarred  (21),
-	roamingOutsidePLMN-Barred  (22),
-	roamingOutsidePLMN-CountryBarred  (23),
-	registrationAllCF-Barred  (24),
-	registrationCFNotToHPLMN-Barred  (25),
-	registrationInterzonalCF-Barred  (26),
-	registrationInterzonalCFNotToHPLMN-Barred  (27),
-	registrationInternationalCF-Barred  (28)} (SIZE (15..32))
-	-- exception handling: reception of unknown bit assignments in the
-	-- ODB-GeneralData type shall be treated like unsupported ODB-GeneralData
-	-- When the ODB-GeneralData type is removed from the HLR for a given subscriber, 
-	-- in NoteSubscriberDataModified operation sent toward the gsmSCF 
-	-- all bits shall be set to "O".
-
-ODB-HPLMN-Data ::= BIT STRING {
-	plmn-SpecificBarringType1  (0),
-	plmn-SpecificBarringType2  (1),
-	plmn-SpecificBarringType3  (2),
-	plmn-SpecificBarringType4  (3)} (SIZE (4..32))
-	-- exception handling: reception of unknown bit assignments in the
-	-- ODB-HPLMN-Data type shall be treated like unsupported ODB-HPLMN-Data 
-	-- When the ODB-HPLMN-Data type is removed from the HLR for a given subscriber, 
-	-- in NoteSubscriberDataModified operation sent toward the gsmSCF
-	-- all bits shall be set to "O".
-
-Ext-SS-InfoList ::= SEQUENCE SIZE (1..maxNumOfSS) OF
-				Ext-SS-Info
-
-Ext-SS-Info ::= CHOICE {
-	forwardingInfo	[0] Ext-ForwInfo,
-	callBarringInfo	[1] Ext-CallBarInfo,
-	cug-Info		[2] CUG-Info,
-	ss-Data		[3] Ext-SS-Data,
-	emlpp-Info	[4] EMLPP-Info}
-
-Ext-ForwInfo ::= SEQUENCE {
-	ss-Code		SS-Code,
-	forwardingFeatureList	Ext-ForwFeatureList,
-	extensionContainer	[0] ExtensionContainer	OPTIONAL,
-	...}
-
-Ext-ForwFeatureList ::= SEQUENCE SIZE (1..maxNumOfExt-BasicServiceGroups) OF
-				Ext-ForwFeature
-
-Ext-ForwFeature ::= SEQUENCE {
-	basicService	Ext-BasicServiceCode	OPTIONAL,
-	ss-Status		[4] Ext-SS-Status,
-	forwardedToNumber	[5] ISDN-AddressString	OPTIONAL,
-	-- When this data type is sent from an HLR which supports CAMEL Phase 2
-	-- to a VLR that supports CAMEL Phase 2 the VLR shall not check the
-	-- format of the number
-	forwardedToSubaddress	[8] ISDN-SubaddressString	OPTIONAL,
-	forwardingOptions	[6] Ext-ForwOptions	OPTIONAL,
-	noReplyConditionTime	[7] Ext-NoRepCondTime	OPTIONAL,
-	extensionContainer	[9] ExtensionContainer	OPTIONAL,
-	...,
-	longForwardedToNumber	[10] FTN-AddressString	OPTIONAL }
-
-Ext-ForwOptions ::= OCTET STRING (SIZE (1..5))
-
-	-- OCTET 1:
-
-	--  bit 8: notification to forwarding party
-	--	0  no notification
-	--	1  notification
-
-	--  bit 7: redirecting presentation
-	--	0 no presentation  
-	--	1  presentation
-
-	--  bit 6: notification to calling party
-	--	0  no notification
-	--	1  notification
-
-	--  bit 5: 0 (unused)
-
-	--  bits 43: forwarding reason
-	--	00  ms not reachable
-	--	01  ms busy
-	--	10  no reply
-	--	11  unconditional
-
-	-- bits 21: 00 (unused)
-
-	-- OCTETS 2-5: reserved for future use. They shall be discarded if
-	-- received and not understood.
-
-Ext-NoRepCondTime ::= INTEGER (1..100)
-	-- Only values 5-30 are used.
-	-- Values in the ranges 1-4 and 31-100 are reserved for future use
-	-- If received:
-	--		values 1-4 shall be mapped on to value 5
-	--		values 31-100 shall be mapped on to value 30
-
-Ext-CallBarInfo ::= SEQUENCE {
-	ss-Code		SS-Code,
-	callBarringFeatureList	Ext-CallBarFeatureList,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-Ext-CallBarFeatureList ::= SEQUENCE SIZE (1..maxNumOfExt-BasicServiceGroups) OF
-				Ext-CallBarringFeature
-
-Ext-CallBarringFeature ::= SEQUENCE {
-	basicService	Ext-BasicServiceCode	OPTIONAL,
-	ss-Status		[4] Ext-SS-Status,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-CUG-Info ::= SEQUENCE {
-	cug-SubscriptionList	CUG-SubscriptionList,
-	cug-FeatureList	CUG-FeatureList	OPTIONAL,
-	extensionContainer	[0] ExtensionContainer	OPTIONAL,
-	...}
-
-CUG-SubscriptionList ::= SEQUENCE SIZE (0..maxNumOfCUG) OF
-				CUG-Subscription
-
-CUG-Subscription ::= SEQUENCE {
-	cug-Index	CUG-Index,
-	cug-Interlock	CUG-Interlock,
-	intraCUG-Options	IntraCUG-Options,
-	basicServiceGroupList	Ext-BasicServiceGroupList	OPTIONAL,
-	extensionContainer	[0] ExtensionContainer	OPTIONAL,
-	...}
-
-CUG-Index ::= INTEGER (0..32767)
-	-- The internal structure is defined in ETS 300 138.
-
-CUG-Interlock ::= OCTET STRING (SIZE (4))
-
-IntraCUG-Options ::= ENUMERATED {
-	noCUG-Restrictions  (0),
-	cugIC-CallBarred  (1),
-	cugOG-CallBarred  (2)}
-
-maxNumOfCUG  INTEGER ::= 10
-
-CUG-FeatureList ::= SEQUENCE SIZE (1..maxNumOfExt-BasicServiceGroups) OF
-				CUG-Feature
-
-Ext-BasicServiceGroupList ::= SEQUENCE SIZE (1..maxNumOfExt-BasicServiceGroups) OF
-				Ext-BasicServiceCode
-
-maxNumOfExt-BasicServiceGroups  INTEGER ::= 32
-
-CUG-Feature ::= SEQUENCE {
-	basicService	Ext-BasicServiceCode	OPTIONAL,
-	preferentialCUG-Indicator	CUG-Index	OPTIONAL,
-	interCUG-Restrictions	InterCUG-Restrictions,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-InterCUG-Restrictions ::= OCTET STRING (SIZE (1))
-
-	-- bits 876543: 000000 (unused)
-	-- Exception handling:
-	-- bits 876543 shall be ignored if received and not understood
-
-	-- bits 21
-	--	00  CUG only facilities
-	--	01  CUG with outgoing access
-	--	10  CUG with incoming access
-	--	11  CUG with both outgoing and incoming access
-
-Ext-SS-Data ::= SEQUENCE {
-	ss-Code		SS-Code,
-	ss-Status	[4] Ext-SS-Status,
-	ss-SubscriptionOption	SS-SubscriptionOption	OPTIONAL,
-	basicServiceGroupList	Ext-BasicServiceGroupList	OPTIONAL,
-	extensionContainer	[5] ExtensionContainer	OPTIONAL,
-	...}
-
-LCS-PrivacyExceptionList ::= SEQUENCE SIZE (1..maxNumOfPrivacyClass) OF
-				LCS-PrivacyClass
-
-maxNumOfPrivacyClass  INTEGER ::= 4
-
-LCS-PrivacyClass ::= SEQUENCE {
-	ss-Code		SS-Code,
-	ss-Status		Ext-SS-Status,
-	notificationToMSUser	[0] NotificationToMSUser	OPTIONAL,
-	-- notificationToMSUser may be sent only for SS-codes callSessionRelated
-	-- and callSessionUnrelated. If not received for SS-codes callSessionRelated
-	-- and callSessionUnrelated,
-	-- the default values according to 3GPP TS 23.271 shall be assumed.
-	externalClientList	[1] ExternalClientList	OPTIONAL,
-	-- externalClientList may be sent only for SS-code callSessionUnrelated to a
-	-- visited node that does not support LCS Release 4 or later versions.
-	-- externalClientList may be sent only for SS-codes callSessionUnrelated and
-	-- callSessionRelated to a visited node that supports LCS Release 4 or later versions.
-	plmnClientList	[2] PLMNClientList	OPTIONAL,
-	-- plmnClientList may be sent only for SS-code plmnoperator.
-	extensionContainer	[3] ExtensionContainer	OPTIONAL,
-	...,
-	ext-externalClientList	[4] Ext-ExternalClientList	OPTIONAL,
-	-- Ext-externalClientList may be sent only if the visited node supports LCS Release 4 or
-	-- later versions, the user did specify more than 5 clients, and White Book SCCP is used.
-	serviceTypeList	[5]	ServiceTypeList	OPTIONAL
-	-- serviceTypeList may be sent only for SS-code serviceType and if the visited node
-	-- supports LCS Release 5 or later versions.
-	-- 
-	-- if segmentation is used, the complete LCS-PrivacyClass shall be sent in one segment
-}
-
-ExternalClientList ::= SEQUENCE SIZE (0..maxNumOfExternalClient) OF
-				ExternalClient
-
-maxNumOfExternalClient  INTEGER ::= 5
-
-PLMNClientList ::= SEQUENCE SIZE (1..maxNumOfPLMNClient) OF
-				LCSClientInternalID
-
-maxNumOfPLMNClient  INTEGER ::= 5
-
-Ext-ExternalClientList ::= SEQUENCE SIZE (1..maxNumOfExt-ExternalClient) OF
-				ExternalClient
-
-maxNumOfExt-ExternalClient  INTEGER ::= 35
-
-ExternalClient ::= SEQUENCE {
-	clientIdentity	LCSClientExternalID,
-	gmlc-Restriction	[0] GMLC-Restriction	OPTIONAL,
-	notificationToMSUser	[1] NotificationToMSUser	OPTIONAL,
-	-- If notificationToMSUser is not received, the default value according to 
-	-- 3GPP TS 23.271 shall be assumed.
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	... }
-
-GMLC-Restriction ::= ENUMERATED {
-	gmlc-List		(0),
-	home-Country	(1) ,
-	... }
--- exception handling:
--- At reception of any other value than the ones listed the receiver shall ignore
--- GMLC-Restriction.
-
-NotificationToMSUser ::= ENUMERATED {
-	notifyLocationAllowed	(0),
-	notifyAndVerify-LocationAllowedIfNoResponse	(1),
-	notifyAndVerify-LocationNotAllowedIfNoResponse	(2),
-	...,
-	locationNotAllowed (3) }
--- exception handling:
--- At reception of any other value than the ones listed the receiver shall ignore
--- NotificationToMSUser.
-
-ServiceTypeList ::= SEQUENCE SIZE (1..maxNumOfServiceType) OF
-				ServiceType
-
-maxNumOfServiceType  INTEGER ::= 32
-
-ServiceType ::= SEQUENCE {
-	serviceTypeIdentity	LCSServiceTypeID,
-	gmlc-Restriction	[0] GMLC-Restriction	OPTIONAL,
-	notificationToMSUser	[1] NotificationToMSUser	OPTIONAL,
-	-- If notificationToMSUser is not received, the default value according to 
-	-- 3GPP TS 23.271 shall be assumed.
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	... }
-
-MOLR-List ::= SEQUENCE SIZE (1..maxNumOfMOLR-Class) OF
-				MOLR-Class
-
-maxNumOfMOLR-Class  INTEGER ::= 3
-
-MOLR-Class ::= SEQUENCE {
-	ss-Code		SS-Code,
-	ss-Status		Ext-SS-Status,
-	extensionContainer	[0] ExtensionContainer	OPTIONAL,
-	...}
-
-ZoneCodeList ::= SEQUENCE SIZE (1..maxNumOfZoneCodes)
-				OF ZoneCode
-
-ZoneCode ::= OCTET STRING (SIZE (2))
-	-- internal structure is defined in TS 3GPP TS 23.003 [17]
-
-maxNumOfZoneCodes  INTEGER ::= 10
-
-InsertSubscriberDataRes ::= SEQUENCE {
-	teleserviceList	[1] TeleserviceList	OPTIONAL,
-	bearerServiceList	[2] BearerServiceList	OPTIONAL,
-	ss-List		[3] SS-List	OPTIONAL,
-	odb-GeneralData	[4] ODB-GeneralData	OPTIONAL,
-	regionalSubscriptionResponse	[5] RegionalSubscriptionResponse	OPTIONAL,
-	supportedCamelPhases	[6] SupportedCamelPhases	OPTIONAL,
-	extensionContainer	[7] ExtensionContainer	OPTIONAL,
-	... ,
-	offeredCamel4CSIs	[8] OfferedCamel4CSIs	OPTIONAL,
-	supportedFeatures	[9] SupportedFeatures	OPTIONAL }
-
-RegionalSubscriptionResponse ::= ENUMERATED {
-	networkNode-AreaRestricted	(0),
-	tooManyZoneCodes	(1),
-	zoneCodesConflict	(2),
-	regionalSubscNotSupported	(3)}
-
-DeleteSubscriberDataArg ::= SEQUENCE {
-	imsi			[0] IMSI,
-	basicServiceList	[1] BasicServiceList	OPTIONAL,
-	-- The exception handling for reception of unsupported/not allocated
-	-- basicServiceCodes is defined in section 6.8.2
-	ss-List		[2] SS-List	OPTIONAL,
-	roamingRestrictionDueToUnsupportedFeature [4] NULL	OPTIONAL,
-	regionalSubscriptionIdentifier	[5] ZoneCode	OPTIONAL,
-	vbsGroupIndication	[7] NULL		OPTIONAL,
-	vgcsGroupIndication	[8] NULL	 	OPTIONAL,
-	camelSubscriptionInfoWithdraw	[9] NULL	 	OPTIONAL,
-	extensionContainer	[6] ExtensionContainer 	OPTIONAL,
-	...,
-	gprsSubscriptionDataWithdraw	[10] GPRSSubscriptionDataWithdraw	OPTIONAL,
-	roamingRestrictedInSgsnDueToUnsuppportedFeature [11] NULL	OPTIONAL,
-	lsaInformationWithdraw	[12] LSAInformationWithdraw	OPTIONAL,
-	gmlc-ListWithdraw 	[13]	NULL		OPTIONAL,
-	istInformationWithdraw	[14] NULL		OPTIONAL,
-	specificCSI-Withdraw	[15] SpecificCSI-Withdraw	OPTIONAL,
-	chargingCharacteristicsWithdraw	[16] NULL		OPTIONAL,
-	stn-srWithdraw	[17] NULL		OPTIONAL,
-	epsSubscriptionDataWithdraw	[18] EPS-SubscriptionDataWithdraw	OPTIONAL,
-	apn-oi-replacementWithdraw	[19] NULL		OPTIONAL,
-	csg-SubscriptionDeleted	[20]	NULL		OPTIONAL }
-
-SpecificCSI-Withdraw ::= BIT STRING {
-	o-csi (0),
-	ss-csi (1),
-	tif-csi (2),
-	d-csi (3),
-	vt-csi (4),
-	mo-sms-csi (5),
-	m-csi (6),
-	gprs-csi (7),
-	t-csi (8),
-	mt-sms-csi (9),
-	mg-csi (10),
-	o-IM-CSI (11), 
-	d-IM-CSI (12),
-	vt-IM-CSI (13) } (SIZE(8..32)) 
--- exception handling:
--- bits 11 to 31 shall be ignored if received by a non-IP Multimedia Core Network entity.
--- bits 0-10 and 14-31 shall be ignored if received by an IP Multimedia Core Network entity.
--- bits 11-13 are only applicable in an IP Multimedia Core Network.
--- Bit 8 and bits 11-13 are only applicable for the NoteSubscriberDataModified operation.
-
-GPRSSubscriptionDataWithdraw ::= CHOICE {
-	allGPRSData	NULL,
-	contextIdList	ContextIdList}
-
-EPS-SubscriptionDataWithdraw ::= CHOICE {
-	allEPS-Data	NULL,
-	contextIdList	ContextIdList}
-
-ContextIdList ::= SEQUENCE SIZE (1..maxNumOfPDP-Contexts) OF
-				ContextId
-
-LSAInformationWithdraw ::= CHOICE {
-	allLSAData	NULL,
-	lsaIdentityList	LSAIdentityList }
-
-LSAIdentityList ::= SEQUENCE SIZE (1..maxNumOfLSAs) OF
-				LSAIdentity
-
-BasicServiceList ::= SEQUENCE SIZE (1..maxNumOfBasicServices) OF
-				Ext-BasicServiceCode
-
-maxNumOfBasicServices  INTEGER ::= 70
-
-DeleteSubscriberDataRes ::= SEQUENCE {
-	regionalSubscriptionResponse	[0] RegionalSubscriptionResponse	OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-VlrCamelSubscriptionInfo ::= SEQUENCE {
-	o-CSI		[0] O-CSI		OPTIONAL,
-	extensionContainer	[1] ExtensionContainer	OPTIONAL,
-	...,
-	ss-CSI		[2] SS-CSI	OPTIONAL,
-	o-BcsmCamelTDP-CriteriaList	[4] O-BcsmCamelTDPCriteriaList	OPTIONAL,
-	tif-CSI		[3] NULL	OPTIONAL,
-	m-CSI		[5] M-CSI	OPTIONAL,
-	mo-sms-CSI	[6] SMS-CSI	OPTIONAL,
-	vt-CSI		[7] T-CSI	OPTIONAL,
-	t-BCSM-CAMEL-TDP-CriteriaList	[8] T-BCSM-CAMEL-TDP-CriteriaList	OPTIONAL,
-	d-CSI		[9] D-CSI	OPTIONAL,
-	mt-sms-CSI	[10] SMS-CSI	OPTIONAL,
-	mt-smsCAMELTDP-CriteriaList	[11]	MT-smsCAMELTDP-CriteriaList	OPTIONAL
-	}
-
-MT-smsCAMELTDP-CriteriaList ::= SEQUENCE SIZE (1.. maxNumOfCamelTDPData) OF
-	MT-smsCAMELTDP-Criteria
-
-MT-smsCAMELTDP-Criteria ::= SEQUENCE {
-	sms-TriggerDetectionPoint	SMS-TriggerDetectionPoint,
-	tpdu-TypeCriterion	[0]	TPDU-TypeCriterion		OPTIONAL,
-	... }
-
-TPDU-TypeCriterion ::= SEQUENCE SIZE (1..maxNumOfTPDUTypes) OF
-	MT-SMS-TPDU-Type
-
-
-maxNumOfTPDUTypes INTEGER ::= 5
-
-MT-SMS-TPDU-Type ::= ENUMERATED {
-	sms-DELIVER 	(0),
-	sms-SUBMIT-REPORT 	(1),
-	sms-STATUS-REPORT 	(2),
-	... }
-
---	exception handling:
---	For TPDU-TypeCriterion sequences containing this parameter with any
---	other value than the ones listed above the receiver shall ignore 
---	the whole TPDU-TypeCriterion sequence.
---	In CAMEL phase 4, sms-SUBMIT-REPORT shall not be used and a received TPDU-TypeCriterion
---	sequence containing sms-SUBMIT-REPORT shall be wholly ignored.
-
-D-CSI ::= SEQUENCE {
-	dp-AnalysedInfoCriteriaList	[0] DP-AnalysedInfoCriteriaList	OPTIONAL,
-	camelCapabilityHandling	[1] CamelCapabilityHandling	OPTIONAL,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	notificationToCSE	[3]	NULL		OPTIONAL,
-	csi-Active	[4]	NULL		OPTIONAL,
-	...} 
---	notificationToCSE and csi-Active shall not be present when D-CSI is sent to VLR/GMSC.
---	They may only be included in ATSI/ATM ack/NSDC message.
---	DP-AnalysedInfoCriteria and  camelCapabilityHandling shall be present in 
---	the D-CSI sequence.
---	If D-CSI is segmented, then the first segment shall contain dp-AnalysedInfoCriteriaList
---	and camelCapabilityHandling. Subsequent segments shall not contain
---	camelCapabilityHandling, but may contain dp-AnalysedInfoCriteriaList.
-
-DP-AnalysedInfoCriteriaList  ::= SEQUENCE SIZE (1..maxNumOfDP-AnalysedInfoCriteria) OF
-				DP-AnalysedInfoCriterium
-
-maxNumOfDP-AnalysedInfoCriteria INTEGER ::= 10
-
-DP-AnalysedInfoCriterium ::= SEQUENCE {
-	dialledNumber	ISDN-AddressString,
-	serviceKey	ServiceKey,
-	gsmSCF-Address	ISDN-AddressString,
-	defaultCallHandling	DefaultCallHandling,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-SS-CSI ::= SEQUENCE {
-	ss-CamelData	SS-CamelData,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	notificationToCSE	[0]	NULL		OPTIONAL,
-	csi-Active	[1]	NULL		OPTIONAL
---	notificationToCSE and csi-Active shall not be present when SS-CSI is sent to VLR.
---	They may only be included in ATSI/ATM ack/NSDC message.
-}
-
-SS-CamelData  ::= SEQUENCE {
-	ss-EventList	SS-EventList,
-	gsmSCF-Address	ISDN-AddressString,
-	extensionContainer	[0] ExtensionContainer	OPTIONAL, 
-	...}
-
-SS-EventList  ::= SEQUENCE SIZE (1..maxNumOfCamelSSEvents) OF SS-Code
-	-- Actions for the following SS-Code values are defined in CAMEL Phase 3:
-	-- ect		SS-Code ::= '00110001'B
-	-- multiPTY	SS-Code ::= '01010001'B
-	-- cd		SS-Code ::= '00100100'B
-	-- ccbs		SS-Code ::= '01000100'B
-	-- all other SS codes shall be ignored
-	-- When SS-CSI is sent to the VLR, it shall not contain a marking for ccbs.
-	-- If the VLR receives SS-CSI containing a marking for ccbs, the VLR shall discard the
-	-- ccbs marking in SS-CSI.
-
-maxNumOfCamelSSEvents INTEGER ::= 10
-
-O-CSI ::= SEQUENCE {
-	o-BcsmCamelTDPDataList	O-BcsmCamelTDPDataList,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	camelCapabilityHandling	[0] CamelCapabilityHandling	OPTIONAL,
-	notificationToCSE	[1]	NULL		OPTIONAL,
-	csiActive		[2]	NULL		OPTIONAL}
---	notificationtoCSE and csiActive shall not be present when O-CSI is sent to VLR/GMSC.
---	They may only be included in ATSI/ATM ack/NSDC message.
---	O-CSI shall not be segmented.
-
-O-BcsmCamelTDPDataList ::= SEQUENCE SIZE (1..maxNumOfCamelTDPData) OF
-	O-BcsmCamelTDPData
-	-- O-BcsmCamelTDPDataList shall not contain more than one instance of
-	-- O-BcsmCamelTDPData containing the same value for o-BcsmTriggerDetectionPoint.
-	-- For CAMEL Phase 2, this means that only one instance of O-BcsmCamelTDPData is allowed
-	-- with o-BcsmTriggerDetectionPoint being equal to DP2.
-
-maxNumOfCamelTDPData  INTEGER ::= 10
-
-O-BcsmCamelTDPData ::= SEQUENCE {
-	o-BcsmTriggerDetectionPoint	O-BcsmTriggerDetectionPoint,
-	serviceKey	ServiceKey,
-	gsmSCF-Address	[0] ISDN-AddressString,
-	defaultCallHandling	[1] DefaultCallHandling,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	...
-	}
-
-ServiceKey ::= INTEGER (0..2147483647)
-
-O-BcsmTriggerDetectionPoint ::= ENUMERATED {
-	collectedInfo (2),
-	...,
-	routeSelectFailure (4) }
-	-- exception handling:
-	-- For O-BcsmCamelTDPData sequences containing this parameter with any
-	-- other value than the ones listed the receiver shall ignore the whole 
-	-- O-BcsmCamelTDPDatasequence. 
-	-- For O-BcsmCamelTDP-Criteria sequences containing this parameter with any
-	-- other value than the ones listed the receiver shall ignore the whole
-	-- O-BcsmCamelTDP-Criteria sequence.
-
-O-BcsmCamelTDPCriteriaList ::= SEQUENCE SIZE (1..maxNumOfCamelTDPData) OF
-	O-BcsmCamelTDP-Criteria 
-
-T-BCSM-CAMEL-TDP-CriteriaList ::= SEQUENCE SIZE (1..maxNumOfCamelTDPData) OF
-	T-BCSM-CAMEL-TDP-Criteria 
-
-O-BcsmCamelTDP-Criteria ::= SEQUENCE {
-	o-BcsmTriggerDetectionPoint	O-BcsmTriggerDetectionPoint,	
-	destinationNumberCriteria 	[0] DestinationNumberCriteria	OPTIONAL,
-	basicServiceCriteria	[1] BasicServiceCriteria	OPTIONAL,
-	callTypeCriteria	[2] CallTypeCriteria	OPTIONAL,
-	...,
-	o-CauseValueCriteria	[3] O-CauseValueCriteria	OPTIONAL,
-	extensionContainer	[4] ExtensionContainer	OPTIONAL }
-
-T-BCSM-CAMEL-TDP-Criteria ::= SEQUENCE {
-	t-BCSM-TriggerDetectionPoint	T-BcsmTriggerDetectionPoint,	
-	basicServiceCriteria	[0] BasicServiceCriteria	OPTIONAL,
-	t-CauseValueCriteria	[1] T-CauseValueCriteria	OPTIONAL,
-	... }
-
-DestinationNumberCriteria  ::= SEQUENCE {
-	matchType		[0] MatchType,
-	destinationNumberList 	[1] DestinationNumberList	OPTIONAL,
-	destinationNumberLengthList	[2] DestinationNumberLengthList	OPTIONAL,
-	-- one or both of destinationNumberList and destinationNumberLengthList 
-	-- shall be present
-	...}
-
-DestinationNumberList  ::= SEQUENCE SIZE	(1..maxNumOfCamelDestinationNumbers) OF
-				ISDN-AddressString
-	-- The receiving entity shall not check the format of a number in
-	-- the dialled number list
-
-DestinationNumberLengthList  ::= SEQUENCE SIZE (1..maxNumOfCamelDestinationNumberLengths) OF 
-					INTEGER(1..maxNumOfISDN-AddressDigits)
-
-BasicServiceCriteria   ::= SEQUENCE SIZE(1..maxNumOfCamelBasicServiceCriteria) OF
-	Ext-BasicServiceCode
-
-maxNumOfISDN-AddressDigits  INTEGER ::= 15
-
-maxNumOfCamelDestinationNumbers  INTEGER ::= 10
-
-maxNumOfCamelDestinationNumberLengths  INTEGER ::= 3
-
-maxNumOfCamelBasicServiceCriteria  INTEGER ::= 5
-
-CallTypeCriteria       ::= ENUMERATED {
-	forwarded 	(0),
-	notForwarded	(1)}
-
-MatchType       ::= ENUMERATED {
-	inhibiting 	(0),
-	enabling		(1)}
-
-O-CauseValueCriteria   ::= SEQUENCE SIZE(1..maxNumOfCAMEL-O-CauseValueCriteria) OF
-	CauseValue
-
-T-CauseValueCriteria   ::= SEQUENCE SIZE(1..maxNumOfCAMEL-T-CauseValueCriteria) OF
-	CauseValue
-
-maxNumOfCAMEL-O-CauseValueCriteria  INTEGER ::= 5
-
-maxNumOfCAMEL-T-CauseValueCriteria  INTEGER ::= 5
-
-CauseValue ::= OCTET STRING (SIZE(1))
--- Type extracted from Cause parameter in ITU-T Recommendation Q.763.
--- For the use of cause value refer to ITU-T Recommendation Q.850.
-
-DefaultCallHandling ::= ENUMERATED {
-	continueCall (0) ,
-	releaseCall (1) ,
-	...}
-	-- exception handling:
-	-- reception of values in range 2-31 shall be treated as "continueCall"
-	-- reception of values greater than 31 shall be treated as "releaseCall"
-
-CamelCapabilityHandling ::= INTEGER(1..16) 
-	-- value 1 = CAMEL phase 1,
-	-- value 2 = CAMEL phase 2,
-	-- value 3 = CAMEL Phase 3,
-	-- value 4 = CAMEL phase 4:
-	-- reception of values greater than 4 shall be treated as CAMEL phase 4.
-
-SupportedCamelPhases ::= BIT STRING {
-	phase1 (0),
-	phase2 (1),
-	phase3 (2),
-	phase4 (3)} (SIZE (1..16)) 
--- A node shall mark in the BIT STRING all CAMEL Phases it supports.
--- Other values than listed above shall be discarded.
-
-OfferedCamel4CSIs ::= BIT STRING { 	
-	o-csi		(0),
-	d-csi		(1),
-	vt-csi		(2),
-	t-csi		(3),
-	mt-sms-csi	(4),
-	mg-csi		(5),
-	psi-enhancements	(6) 
-} (SIZE (7..16))
--- A node supporting Camel phase 4 shall mark in the BIT STRING all Camel4 CSIs 
--- it offers.
--- Other values than listed above shall be discarded.
-
-OfferedCamel4Functionalities ::= BIT STRING { 	
-	initiateCallAttempt	(0),
-	splitLeg		(1),
-	moveLeg		(2),
-	disconnectLeg	(3),
-	entityReleased	(4),
-	dfc-WithArgument	(5),
-	playTone		(6),
-	dtmf-MidCall	(7),
-	chargingIndicator	(8),
-	alertingDP	(9),
-	locationAtAlerting	(10),
-	changeOfPositionDP	(11),
-	or-Interactions	(12),
-	warningToneEnhancements	(13),
-	cf-Enhancements	(14),
-	subscribedEnhancedDialledServices 	(15),
-	servingNetworkEnhancedDialledServices (16),
-	criteriaForChangeOfPositionDP	(17),
-	serviceChangeDP	(18),
-	collectInformation	(19)
-} (SIZE (15..64))
--- A node supporting Camel phase 4 shall mark in the BIT STRING all CAMEL4 
--- functionalities it offers.
--- Other values than listed above shall be discarded.
-
-SMS-CSI ::= SEQUENCE {
-	sms-CAMEL-TDP-DataList	[0] SMS-CAMEL-TDP-DataList	OPTIONAL,
-	camelCapabilityHandling	[1] CamelCapabilityHandling	OPTIONAL,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	notificationToCSE	[3] NULL		OPTIONAL,
-	csi-Active	[4] NULL		OPTIONAL,
-	...}
---	notificationToCSE and csi-Active shall not be present
---	when MO-SMS-CSI or MT-SMS-CSI is sent to VLR or SGSN.
---	They may only be included in ATSI/ATM ack/NSDC message.
---	SMS-CAMEL-TDP-Data and  camelCapabilityHandling shall be present in 
---	the SMS-CSI sequence.
---	If SMS-CSI is segmented, sms-CAMEL-TDP-DataList and camelCapabilityHandling shall be 
---	present in the first segment
-
-SMS-CAMEL-TDP-DataList ::= SEQUENCE SIZE (1..maxNumOfCamelTDPData) OF
-	SMS-CAMEL-TDP-Data
---	SMS-CAMEL-TDP-DataList shall not contain more than one instance of
---	SMS-CAMEL-TDP-Data containing the same value for sms-TriggerDetectionPoint.
-
-SMS-CAMEL-TDP-Data ::= SEQUENCE {
-	sms-TriggerDetectionPoint	[0] SMS-TriggerDetectionPoint,
-	serviceKey	[1] ServiceKey,
-	gsmSCF-Address	[2] ISDN-AddressString,
-	defaultSMS-Handling	[3] DefaultSMS-Handling,
-	extensionContainer	[4] ExtensionContainer	OPTIONAL,
-	...
-	}
-
-SMS-TriggerDetectionPoint ::= ENUMERATED {
-	sms-CollectedInfo (1),
-	...,
-	sms-DeliveryRequest (2)
-	}
---	exception handling:
---	For SMS-CAMEL-TDP-Data and MT-smsCAMELTDP-Criteria sequences containing this 
---	parameter with any other value than the ones listed the receiver shall ignore
---	the whole sequence.
---
---	If this parameter is received with any other value than sms-CollectedInfo
---	in an SMS-CAMEL-TDP-Data sequence contained in mo-sms-CSI, then the receiver shall
---	ignore the whole SMS-CAMEL-TDP-Data sequence.
---
---	If this parameter is received with any other value than sms-DeliveryRequest
---	in an SMS-CAMEL-TDP-Data sequence contained in mt-sms-CSI then the receiver shall
---	ignore the whole SMS-CAMEL-TDP-Data sequence.
---
---	If this parameter is received with any other value than sms-DeliveryRequest
---	in an MT-smsCAMELTDP-Criteria sequence then the receiver shall
---	ignore the whole MT-smsCAMELTDP-Criteria sequence.
-
-DefaultSMS-Handling ::= ENUMERATED {
-	continueTransaction (0) ,
-	releaseTransaction (1) ,
-	...}
---	exception handling:
---	reception of values in range 2-31 shall be treated as "continueTransaction"
---	reception of values greater than 31 shall be treated as "releaseTransaction"
-
-M-CSI ::= SEQUENCE {
-	mobilityTriggers	MobilityTriggers,
-	serviceKey	ServiceKey,
-	gsmSCF-Address	[0]	ISDN-AddressString,
-	extensionContainer	[1]	ExtensionContainer	OPTIONAL,
-	notificationToCSE	[2] NULL		OPTIONAL,
-	csi-Active	[3] NULL		OPTIONAL,
-	...}
---	notificationToCSE and csi-Active shall not be present when M-CSI is sent to VLR.
---	They may only be included in ATSI/ATM ack/NSDC message.
-
-MG-CSI ::= SEQUENCE {
-	mobilityTriggers	MobilityTriggers,
-	serviceKey	ServiceKey,
-	gsmSCF-Address	[0]	ISDN-AddressString,
-	extensionContainer	[1]	ExtensionContainer	OPTIONAL,
-	notificationToCSE	[2] NULL		OPTIONAL,
-	csi-Active	[3] NULL		OPTIONAL,
-	...}
---	notificationToCSE and csi-Active shall not be present when MG-CSI is sent to SGSN.
---	They may only be included in ATSI/ATM ack/NSDC message.
-
-MobilityTriggers  ::= SEQUENCE SIZE (1..maxNumOfMobilityTriggers) OF
-	MM-Code
-
-maxNumOfMobilityTriggers INTEGER ::= 10
-
-MM-Code ::= OCTET STRING (SIZE (1))
---	This type is used to indicate a Mobility Management event.
---	Actions for the following MM-Code values are defined in CAMEL Phase 4:
---
---	CS domain MM events:
---	Location-update-in-same-VLR	MM-Code ::= '00000000'B
---	Location-update-to-other-VLR	MM-Code ::= '00000001'B
---	IMSI-Attach	MM-Code ::= '00000010'B
---	MS-initiated-IMSI-Detach	MM-Code ::= '00000011'B
---	Network-initiated-IMSI-Detach	MM-Code ::= '00000100'B
---
---	PS domain MM events:
---	Routeing-Area-update-in-same-SGSN	MM-Code ::= '10000000'B
---	Routeing-Area-update-to-other-SGSN-update-from-new-SGSN
---				MM-Code ::= '10000001'B
---	Routeing-Area-update-to-other-SGSN-disconnect-by-detach
---				MM-Code ::= '10000010'B
---	GPRS-Attach	MM-Code ::= '10000011'B
---	MS-initiated-GPRS-Detach	MM-Code ::= '10000100'B
---	Network-initiated-GPRS-Detach	MM-Code ::= '10000101'B 
---	Network-initiated-transfer-to-MS-not-reachable-for-paging
---				MM-Code ::= '10000110'B
---
---	If the MSC receives any other MM-code than the ones listed above for the
---	CS domain, then the MSC shall ignore that MM-code.
---	If the SGSN receives any other MM-code than the ones listed above for the
---	PS domain, then the SGSN shall ignore that MM-code.
-
-T-CSI ::= SEQUENCE {
-	t-BcsmCamelTDPDataList	T-BcsmCamelTDPDataList,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	camelCapabilityHandling	[0] CamelCapabilityHandling	OPTIONAL,
-	notificationToCSE	[1] NULL		OPTIONAL,
-	csi-Active	[2] NULL		OPTIONAL}
---	notificationToCSE and csi-Active shall not be present when VT-CSI/T-CSI is sent
---	to VLR/GMSC.
---	They may only be included in ATSI/ATM ack/NSDC message.
---	T-CSI shall not be segmented.
-
-T-BcsmCamelTDPDataList ::= SEQUENCE SIZE (1..maxNumOfCamelTDPData) OF
-	T-BcsmCamelTDPData
-	--- T-BcsmCamelTDPDataList shall not contain more than one instance of
-	--- T-BcsmCamelTDPData containing the same value for t-BcsmTriggerDetectionPoint.
-	--- For CAMEL Phase 2, this means that only one instance of T-BcsmCamelTDPData is allowed
-	--- with t-BcsmTriggerDetectionPoint being equal to DP12. 
-	--- For CAMEL Phase 3, more TDPÂ’s are allowed.
-
-T-BcsmCamelTDPData ::= SEQUENCE {
-	t-BcsmTriggerDetectionPoint	T-BcsmTriggerDetectionPoint,
-	serviceKey	ServiceKey,
-	gsmSCF-Address	[0] ISDN-AddressString,
-	defaultCallHandling	[1] DefaultCallHandling,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	...}
-
-T-BcsmTriggerDetectionPoint ::= ENUMERATED {
-	termAttemptAuthorized (12),
-	... ,
-	tBusy (13),
-	tNoAnswer (14)}
-	-- exception handling:
-	-- For T-BcsmCamelTDPData sequences containing this parameter with any other
-	-- value than the ones listed above, the receiver shall ignore the whole
-	-- T-BcsmCamelTDPData sequence.
-
--- gprs location information retrieval types
-
-SendRoutingInfoForGprsArg ::= SEQUENCE {
-	imsi				[0] IMSI,
-	ggsn-Address		[1] GSN-Address	OPTIONAL, 
-	ggsn-Number		[2]	ISDN-AddressString,
-	extensionContainer		[3] ExtensionContainer	OPTIONAL,
-	...}
-
-SendRoutingInfoForGprsRes ::= SEQUENCE {
-	sgsn-Address		[0] GSN-Address,
-	ggsn-Address		[1]	GSN-Address	OPTIONAL,
-	mobileNotReachableReason		[2]	AbsentSubscriberDiagnosticSM		OPTIONAL,
-	extensionContainer		[3] ExtensionContainer	OPTIONAL,
-	...}
-
--- failure report types
-
-FailureReportArg ::= SEQUENCE {
-	imsi				[0] IMSI,
-	ggsn-Number		[1] ISDN-AddressString	,
-	ggsn-Address		[2] GSN-Address	OPTIONAL,
-	extensionContainer		[3] ExtensionContainer	OPTIONAL,
-	...}
-
-FailureReportRes ::= SEQUENCE {
-	ggsn-Address		[0] GSN-Address	OPTIONAL,
-	extensionContainer		[1] ExtensionContainer	OPTIONAL,
-	...}
-
--- gprs notification types
-
-NoteMsPresentForGprsArg ::= SEQUENCE {
-	imsi				[0] IMSI,
-	sgsn-Address		[1] GSN-Address,
-	ggsn-Address		[2] GSN-Address	OPTIONAL,
-	extensionContainer		[3] ExtensionContainer	OPTIONAL,
-	...}
-
-NoteMsPresentForGprsRes ::= SEQUENCE {
-	extensionContainer		[0] ExtensionContainer	OPTIONAL,
-	...}
-
--- fault recovery types
-
-ResetArg ::= SEQUENCE {
-	hlr-Number	ISDN-AddressString,
-	hlr-List		HLR-List		OPTIONAL,
-	...}
-
-RestoreDataArg ::= SEQUENCE {
-	imsi			IMSI,
-	lmsi			LMSI			OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	... ,
-	vlr-Capability	[6] VLR-Capability	OPTIONAL }
-
-RestoreDataRes ::= SEQUENCE {
-	hlr-Number	ISDN-AddressString,
-	msNotReachable	NULL			OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
--- VBS/VGCS types
-VBSDataList ::= SEQUENCE SIZE (1..maxNumOfVBSGroupIds) OF
-				VoiceBroadcastData
-
-VGCSDataList ::= SEQUENCE SIZE (1..maxNumOfVGCSGroupIds) OF
-				VoiceGroupCallData
-
-maxNumOfVBSGroupIds  INTEGER ::= 50
-
-maxNumOfVGCSGroupIds  INTEGER ::= 50
-
-VoiceGroupCallData  ::= SEQUENCE {
-	groupId		GroupId, 
-	-- groupId shall be filled with six TBCD fillers (1111)if the longGroupId is present  
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	additionalSubscriptions	AdditionalSubscriptions	OPTIONAL,
-	additionalInfo	[0] AdditionalInfo	OPTIONAL,
-	longGroupId	[1] Long-GroupId	OPTIONAL }
-
-	-- VoiceGroupCallData containing a longGroupId shall not be sent to VLRs that did not
-	-- indicate support of long Group IDs within the Update Location or Restore Data 
-	-- request message
-
-AdditionalInfo ::= BIT STRING (SIZE (1..136))
---	 Refers to Additional Info as specified in 3GPP TS 43.068 
-
-AdditionalSubscriptions ::= BIT STRING {
-	privilegedUplinkRequest (0),
-	emergencyUplinkRequest (1),
-	emergencyReset (2)} (SIZE (3..8))
--- Other bits than listed above shall be discarded.
-
-VoiceBroadcastData ::= SEQUENCE {
-	groupid		GroupId, 
-	-- groupId shall be filled with six TBCD fillers (1111)if the longGroupId is present
-	broadcastInitEntitlement	NULL			OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	longGroupId	[0] Long-GroupId	OPTIONAL }
-	
--- VoiceBroadcastData containing a longGroupId shall not be sent to VLRs that did not
--- indicate support of long Group IDs within the Update Location or Restore Data 
-	-- request message
-
-GroupId  ::= TBCD-STRING (SIZE (3))
-	-- When Group-Id is less than six characters in length, the TBCD filler (1111)
-	-- is used to fill unused half octets.
-	-- Refers to the Group Identification as specified in 3GPP TS 23.003 
-	-- and 3GPP TS 43.068/ 43.069
-
-Long-GroupId  ::= TBCD-STRING (SIZE (4))
-	-- When Long-Group-Id is less than eight characters in length, the TBCD filler (1111)
-	-- is used to fill unused half octets.
-	-- Refers to the Group Identification as specified in 3GPP TS 23.003 
-	-- and 3GPP TS 43.068/ 43.069
-
-
--- provide subscriber info types
-
-ProvideSubscriberInfoArg ::= SEQUENCE {
-	imsi		[0] IMSI,
-	lmsi		[1] LMSI	OPTIONAL,
-	requestedInfo	[2] RequestedInfo,
-	extensionContainer	[3] ExtensionContainer	OPTIONAL,
-	...,
-	callPriority	[4]	EMLPP-Priority	OPTIONAL
-	}
-
-ProvideSubscriberInfoRes ::= SEQUENCE {
-	subscriberInfo	SubscriberInfo,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-SubscriberInfo ::= SEQUENCE {
-	locationInformation	[0] LocationInformation	OPTIONAL,
-	subscriberState	[1] SubscriberState	OPTIONAL,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	... ,
-	locationInformationGPRS	[3] LocationInformationGPRS	OPTIONAL,
-	ps-SubscriberState	[4] PS-SubscriberState	OPTIONAL,
-	imei			[5] IMEI		OPTIONAL,
-	ms-Classmark2	[6] MS-Classmark2	OPTIONAL,
-	gprs-MS-Class	[7] GPRSMSClass	OPTIONAL,
-	mnpInfoRes	[8] MNPInfoRes	OPTIONAL }
-
---	If the HLR receives locationInformation, subscriberState or ms-Classmark2 from an SGSN
---	it shall discard them.
---	If the HLR receives locationInformationGPRS, ps-SubscriberState or gprs-MS-Class from
---	a VLR it shall discard them.
---	If the HLR receives parameters which it has not requested, it shall discard them.
-
-MNPInfoRes ::= SEQUENCE {
-	routeingNumber	[0] RouteingNumber 	OPTIONAL,
-	imsi			[1] IMSI		OPTIONAL,
-	msisdn		[2] ISDN-AddressString 	OPTIONAL,
-	numberPortabilityStatus	[3] NumberPortabilityStatus	OPTIONAL,
-	extensionContainer	[4] ExtensionContainer	OPTIONAL,
-	... }
---	The IMSI parameter contains a generic IMSI, i.e. it is not tied necessarily to the 
---	Subscriber. MCC and MNC values in this IMSI shall point to the Subscription Network of 
---	the Subscriber. See 3GPP TS 23.066 [108].
-
-RouteingNumber ::= TBCD-STRING (SIZE (1..5))
-
-
-NumberPortabilityStatus ::= ENUMERATED {
-	notKnownToBePorted	(0),
-	ownNumberPortedOut	(1),
-	foreignNumberPortedToForeignNetwork	(2),
-	...,
-	ownNumberNotPortedOut	(4),
-	foreignNumberPortedIn	(5)
-	}
-	--	exception handling: 
-	--  reception of other values than the ones listed the receiver shall ignore the 
-	--  whole NumberPortabilityStatus;
-	--  ownNumberNotPortedOut or foreignNumberPortedIn may only be included in Any Time 
-	--  Interrogation message.
-
-MS-Classmark2 ::= OCTET STRING (SIZE (3))
-	-- This parameter carries the value part of the MS Classmark 2 IE defined in 
-	-- 3GPP TS 24.008 [35].
-
-GPRSMSClass ::= SEQUENCE {
-	mSNetworkCapability	[0] MSNetworkCapability,
-	mSRadioAccessCapability	[1] MSRadioAccessCapability	OPTIONAL
-	}
-
-MSNetworkCapability ::= OCTET STRING (SIZE (1..8))
-	-- This parameter carries the value part of the MS Network Capability IE defined in 
-	-- 3GPP TS 24.008 [35].
-	
-MSRadioAccessCapability ::= OCTET STRING (SIZE (1..50))
-	-- This parameter carries the value part of the MS Radio Access Capability IE defined in
-	-- 3GPP TS 24.008 [35].
-
-RequestedInfo ::= SEQUENCE {
-	locationInformation	[0] NULL		OPTIONAL,
-	subscriberState	[1] NULL		OPTIONAL,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	..., 
-	currentLocation	[3] NULL		OPTIONAL,
-	requestedDomain	[4] DomainType	OPTIONAL,
-	imei			[6] NULL		OPTIONAL,
-	ms-classmark	[5] NULL		OPTIONAL,
-	mnpRequestedInfo	[7] NULL 		OPTIONAL }
-
---	currentLocation shall be absent if locationInformation is absent
-
-DomainType ::=  ENUMERATED {
-	cs-Domain		(0),
-	ps-Domain		(1),
-	...}
--- exception handling:
--- reception of values > 1 shall be mapped to 'cs-Domain'
-
-LocationInformation ::= SEQUENCE {
-	ageOfLocationInformation	AgeOfLocationInformation	OPTIONAL,
-	geographicalInformation	[0] GeographicalInformation	OPTIONAL,
-	vlr-number	[1] ISDN-AddressString	OPTIONAL,
-	locationNumber	[2] LocationNumber	OPTIONAL,
-	cellGlobalIdOrServiceAreaIdOrLAI	[3] CellGlobalIdOrServiceAreaIdOrLAI	OPTIONAL,
-	extensionContainer	[4] ExtensionContainer	OPTIONAL,
-	... ,
-	selectedLSA-Id	[5] LSAIdentity	OPTIONAL,
-	msc-Number	[6] ISDN-AddressString	OPTIONAL,
-	geodeticInformation	[7] GeodeticInformation	OPTIONAL, 
-	currentLocationRetrieved	[8] NULL		OPTIONAL,
-	sai-Present	[9] NULL		OPTIONAL }
--- sai-Present indicates that the cellGlobalIdOrServiceAreaIdOrLAI parameter contains
--- a Service Area Identity.
--- currentLocationRetrieved shall be present 
--- if the location information were retrieved after a successfull paging.
-
-LocationInformationGPRS ::= SEQUENCE {
-	cellGlobalIdOrServiceAreaIdOrLAI	[0] CellGlobalIdOrServiceAreaIdOrLAI OPTIONAL,
-	routeingAreaIdentity	[1] RAIdentity	OPTIONAL,
-	geographicalInformation	[2] GeographicalInformation	OPTIONAL,
-	sgsn-Number	[3] ISDN-AddressString	OPTIONAL,
-	selectedLSAIdentity	[4] LSAIdentity	OPTIONAL,
-	extensionContainer	[5] ExtensionContainer	OPTIONAL,
-	...,
-	sai-Present	[6] NULL		OPTIONAL,
-	geodeticInformation	[7] GeodeticInformation	OPTIONAL,
-	currentLocationRetrieved	[8] NULL		OPTIONAL,
-	ageOfLocationInformation	[9] AgeOfLocationInformation	OPTIONAL }
--- sai-Present indicates that the cellGlobalIdOrServiceAreaIdOrLAI parameter contains
--- a Service Area Identity.
--- currentLocationRetrieved shall be present if the location information
--- was retrieved after successful paging.
-
-RAIdentity ::= OCTET STRING (SIZE (6))
--- Routing Area Identity is coded in accordance with 3GPP TS 29.060 [105].
--- It shall contain the value part defined in 3GPP TS 29.060 only. I.e. the 3GPP TS 29.060
--- type identifier octet shall not be included.
-
-
-GeographicalInformation ::= OCTET STRING (SIZE (8))
---	Refers to geographical Information defined in 3GPP TS 23.032.
---	Only the description of an ellipsoid point with uncertainty circle
---	as specified in 3GPP TS 23.032 is allowed to be used
---	The internal structure according to 3GPP TS 23.032 is as follows:
---		Type of shape (ellipsoid point with uncertainty circle)	1 octet
---		Degrees of Latitude				3 octets
---		Degrees of Longitude				3 octets
---		Uncertainty code				1 octet
-
-GeodeticInformation ::= OCTET STRING (SIZE (10))
---	Refers to Calling Geodetic Location defined in Q.763 (1999).
---	Only the description of an ellipsoid point with uncertainty circle
---	as specified in Q.763 (1999) is allowed to be used
---	The internal structure according to Q.763 (1999) is as follows:
---		Screening and presentation indicators		1 octet
---		Type of shape (ellipsoid point with uncertainty circle)	1 octet
---		Degrees of Latitude				3 octets
---		Degrees of Longitude				3 octets
---		Uncertainty code				1 octet
---		Confidence				1 octet
-
-LocationNumber ::= OCTET STRING (SIZE (2..10))
-	-- the internal structure is defined in ITU-T Rec Q.763
-
-SubscriberState ::= CHOICE {
-	assumedIdle	[0] NULL,
-	camelBusy		[1] NULL,
-	netDetNotReachable	NotReachableReason,
-	notProvidedFromVLR	[2] NULL}
-
-PS-SubscriberState ::= CHOICE {
-	notProvidedFromSGSN	[0] NULL,
-	ps-Detached	[1] NULL,
-	ps-AttachedNotReachableForPaging	[2] NULL,
-	ps-AttachedReachableForPaging	[3] NULL,
-	ps-PDP-ActiveNotReachableForPaging	[4] PDP-ContextInfoList,
-	ps-PDP-ActiveReachableForPaging	[5] PDP-ContextInfoList,
-	netDetNotReachable	NotReachableReason }
-
-PDP-ContextInfoList ::= SEQUENCE SIZE (1..maxNumOfPDP-Contexts) OF
-				PDP-ContextInfo
-
-PDP-ContextInfo ::= SEQUENCE {
-	pdp-ContextIdentifier	[0] ContextId,
-	pdp-ContextActive	[1] NULL		OPTIONAL,
-	pdp-Type		[2] PDP-Type,
-	pdp-Address	[3] PDP-Address	OPTIONAL,
-	apn-Subscribed	[4] APN		OPTIONAL,
-	apn-InUse		[5] APN		OPTIONAL,
-	nsapi		[6] NSAPI		OPTIONAL,
-	transactionId	[7] TransactionId	OPTIONAL,
-	teid-ForGnAndGp	[8] TEID		OPTIONAL,
-	teid-ForIu	[9] TEID		OPTIONAL,
-	ggsn-Address	[10] GSN-Address 	OPTIONAL,
-	qos-Subscribed	[11] Ext-QoS-Subscribed	OPTIONAL,
-	qos-Requested	[12] Ext-QoS-Subscribed	OPTIONAL,
-	qos-Negotiated	[13] Ext-QoS-Subscribed	OPTIONAL,
-	chargingId	[14] GPRSChargingID	OPTIONAL,
-	chargingCharacteristics	[15] ChargingCharacteristics	OPTIONAL,
-	rnc-Address	[16] GSN-Address	OPTIONAL,
-	extensionContainer	[17] ExtensionContainer	OPTIONAL,
-	...,
-	qos2-Subscribed	[18] Ext2-QoS-Subscribed	OPTIONAL,
-	-- qos2-Subscribed may be present only if qos-Subscribed is present.
-	qos2-Requested	[19] Ext2-QoS-Subscribed	OPTIONAL,
-	-- qos2-Requested may be present only if qos-Requested is present.
-	qos2-Negotiated	[20] Ext2-QoS-Subscribed	OPTIONAL,
-	-- qos2-Negotiated may be present only if qos-Negotiated is present.
-		qos3-Subscribed	[21] Ext3-QoS-Subscribed	OPTIONAL,
-	-- qos3-Subscribed may be present only if qos2-Subscribed is present.
-	qos3-Requested	[22] Ext3-QoS-Subscribed	OPTIONAL,
-	-- qos3-Requested may be present only if qos2-Requested is present.
-	qos3-Negotiated	[23] Ext3-QoS-Subscribed	OPTIONAL
-	-- qos3-Negotiated may be present only if qos2-Negotiated is present.
-}
-
-NSAPI ::= INTEGER (0..15)
---	This type is used to indicate the Network layer Service Access Point
-
-TransactionId ::= OCTET STRING (SIZE (1..2))
---	This type carries the value part of the transaction identifier which is used in the 
---	session management messages on the access interface. The encoding is defined in 
---	3GPP TS 24.008
-
-TEID ::= OCTET STRING (SIZE (4))
---	This type carries the value part of the Tunnel Endpoint Identifier which is used to 
---	distinguish between different tunnels between the same pair of entities which communicate 
---	using the GPRS Tunnelling Protocol The encoding is defined in 3GPP TS 29.060.
-
-GPRSChargingID ::= OCTET STRING (SIZE (4))
---	The Charging ID is a unique four octet value generated by the GGSN when 
---	a PDP Context is activated. A Charging ID is generated for each activated context.
---	The encoding is defined in 3GPP TS 29.060.
-
-NotReachableReason ::= ENUMERATED {
-	msPurged (0),
-	imsiDetached (1),
-	restrictedArea (2),
-	notRegistered (3)}
-
--- any time interrogation info types
-
-AnyTimeInterrogationArg ::= SEQUENCE {
-	subscriberIdentity	[0] SubscriberIdentity,
-	requestedInfo	[1] RequestedInfo,
-	gsmSCF-Address	[3] ISDN-AddressString,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	...}
-
-AnyTimeInterrogationRes ::= SEQUENCE {
-	subscriberInfo	SubscriberInfo,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
--- any time information handling types
-
-AnyTimeSubscriptionInterrogationArg ::= SEQUENCE {
-	subscriberIdentity	[0] SubscriberIdentity,
-	requestedSubscriptionInfo	[1] RequestedSubscriptionInfo,
-	gsmSCF-Address	[2] ISDN-AddressString,
-	extensionContainer	[3] ExtensionContainer	OPTIONAL,
-	longFTN-Supported	[4]	NULL		OPTIONAL,
-	...}
-
-AnyTimeSubscriptionInterrogationRes ::= SEQUENCE {
-	callForwardingData	[1] CallForwardingData	OPTIONAL,
-	callBarringData	[2] CallBarringData	OPTIONAL,
-	odb-Info		[3] ODB-Info	OPTIONAL,
-	camel-SubscriptionInfo	[4] CAMEL-SubscriptionInfo	OPTIONAL,
-	supportedVLR-CAMEL-Phases	[5] SupportedCamelPhases	OPTIONAL,
-	supportedSGSN-CAMEL-Phases	[6] SupportedCamelPhases	OPTIONAL,
-	extensionContainer	[7] ExtensionContainer	OPTIONAL,
-	... ,
-	offeredCamel4CSIsInVLR	[8] OfferedCamel4CSIs	OPTIONAL,
-	offeredCamel4CSIsInSGSN	[9] OfferedCamel4CSIs	OPTIONAL,
-	msisdn-BS-List	[10] MSISDN-BS-List	OPTIONAL }
-
-RequestedSubscriptionInfo ::= SEQUENCE {
-	requestedSS-Info	[1] SS-ForBS-Code	OPTIONAL,
-	odb			[2] NULL		OPTIONAL,
-	requestedCAMEL-SubscriptionInfo	[3] RequestedCAMEL-SubscriptionInfo		OPTIONAL,
-	supportedVLR-CAMEL-Phases	[4] NULL		OPTIONAL,
-	supportedSGSN-CAMEL-Phases	[5] NULL		OPTIONAL,
-	extensionContainer	[6] ExtensionContainer	OPTIONAL,
-	...,
-	additionalRequestedCAMEL-SubscriptionInfo
-				[7] AdditionalRequestedCAMEL-SubscriptionInfo
-							OPTIONAL,
-	msisdn-BS-List	[8] NULL		OPTIONAL }
-
-MSISDN-BS-List ::= SEQUENCE SIZE (1..maxNumOfMSISDN) OF
-				MSISDN-BS
-
-maxNumOfMSISDN  INTEGER ::= 50
-
-
-MSISDN-BS ::= SEQUENCE {
-	msisdn			ISDN-AddressString,	
-	basicServiceList	[0]	BasicServiceList	OPTIONAL,
-	extensionContainer	[1]	ExtensionContainer	OPTIONAL,
-	...}
-
-RequestedCAMEL-SubscriptionInfo ::= ENUMERATED {
-	o-CSI		(0),
-	t-CSI		(1),
-	vt-CSI		(2),
-	tif-CSI		(3),
-	gprs-CSI		(4),
-	mo-sms-CSI	(5),
-	ss-CSI		(6),
-	m-CSI		(7),
-	d-csi		(8)}
-
-AdditionalRequestedCAMEL-SubscriptionInfo ::= ENUMERATED {
-	mt-sms-CSI	(0),
-	mg-csi		(1),
-	o-IM-CSI 		(2),
-	d-IM-CSI		(3),
-	vt-IM-CSI	 	(4),
-	...}
---	exception handling: unknown values shall be discarded by the receiver.
-
-CallForwardingData ::= SEQUENCE {
-	forwardingFeatureList	Ext-ForwFeatureList,
-	notificationToCSE	NULL			OPTIONAL,
-	extensionContainer	[0] ExtensionContainer	OPTIONAL,
-	...}
-
-CallBarringData ::= SEQUENCE {
-	callBarringFeatureList	Ext-CallBarFeatureList,
-	password		Password		OPTIONAL,
-	wrongPasswordAttemptsCounter	WrongPasswordAttemptsCounter	OPTIONAL,
-	notificationToCSE	NULL			OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-WrongPasswordAttemptsCounter ::= INTEGER (0..4)
-
-ODB-Info ::= SEQUENCE {
-	odb-Data		ODB-Data,
-	notificationToCSE	NULL			OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-CAMEL-SubscriptionInfo ::= SEQUENCE {
-	o-CSI		[0]	O-CSI	OPTIONAL,
-	o-BcsmCamelTDP-CriteriaList	[1]	O-BcsmCamelTDPCriteriaList	OPTIONAL, 
-	d-CSI		[2]	D-CSI	OPTIONAL,
-	t-CSI		[3]	T-CSI	OPTIONAL,
-	t-BCSM-CAMEL-TDP-CriteriaList	[4]	T-BCSM-CAMEL-TDP-CriteriaList	OPTIONAL,
-	vt-CSI		[5]	T-CSI	OPTIONAL,
-	vt-BCSM-CAMEL-TDP-CriteriaList	[6]	T-BCSM-CAMEL-TDP-CriteriaList	OPTIONAL,
-	tif-CSI		[7]	NULL		OPTIONAL,
-	tif-CSI-NotificationToCSE	[8]	NULL		OPTIONAL,
-	gprs-CSI		[9]	GPRS-CSI	OPTIONAL,
-	mo-sms-CSI	[10]	SMS-CSI	OPTIONAL,
-	ss-CSI		[11]	SS-CSI	OPTIONAL,
-	m-CSI		[12]	M-CSI	OPTIONAL,
-	extensionContainer	[13]	ExtensionContainer	OPTIONAL,
-	...,
-	specificCSIDeletedList	[14]	SpecificCSI-Withdraw	OPTIONAL,
-	mt-sms-CSI	[15]	SMS-CSI	OPTIONAL,
-	mt-smsCAMELTDP-CriteriaList	[16]	MT-smsCAMELTDP-CriteriaList	OPTIONAL,
-	mg-csi		[17]	MG-CSI	OPTIONAL,
-	o-IM-CSI		[18] O-CSI	OPTIONAL,
-	o-IM-BcsmCamelTDP-CriteriaList	[19] O-BcsmCamelTDPCriteriaList	OPTIONAL,
-	d-IM-CSI		[20] D-CSI	OPTIONAL,
-	vt-IM-CSI		[21] T-CSI	OPTIONAL,
-	vt-IM-BCSM-CAMEL-TDP-CriteriaList	[22]	T-BCSM-CAMEL-TDP-CriteriaList	OPTIONAL
-	}
-
-AnyTimeModificationArg ::= SEQUENCE {
-	subscriberIdentity	[0]	SubscriberIdentity,
-	gsmSCF-Address	[1]	ISDN-AddressString,
-	modificationRequestFor-CF-Info	[2]	ModificationRequestFor-CF-Info OPTIONAL,
-	modificationRequestFor-CB-Info	[3]	ModificationRequestFor-CB-Info OPTIONAL,
-	modificationRequestFor-CSI	[4]	ModificationRequestFor-CSI	OPTIONAL,
-	extensionContainer	[5]	ExtensionContainer	OPTIONAL,
-	longFTN-Supported	[6]	NULL		OPTIONAL,
-	...,
-	modificationRequestFor-ODB-data	[7]	ModificationRequestFor-ODB-data OPTIONAL,
-	modificationRequestFor-IP-SM-GW-Data	[8]	ModificationRequestFor-IP-SM-GW-Data OPTIONAL }
-
-AnyTimeModificationRes ::= SEQUENCE {
-	ss-InfoFor-CSE	[0]	Ext-SS-InfoFor-CSE	OPTIONAL,
-	camel-SubscriptionInfo	[1]	CAMEL-SubscriptionInfo	OPTIONAL,
-	extensionContainer	[2]	ExtensionContainer	OPTIONAL,
-	...,
-	odb-Info		[3]	ODB-Info	OPTIONAL }
-
-ModificationRequestFor-CF-Info ::= SEQUENCE {
-	ss-Code		[0]	SS-Code,
-	basicService	[1]	Ext-BasicServiceCode	OPTIONAL,
-	ss-Status		[2]	Ext-SS-Status	OPTIONAL,
-	forwardedToNumber	[3]	AddressString	OPTIONAL,
-	forwardedToSubaddress	[4]	ISDN-SubaddressString	OPTIONAL,
-	noReplyConditionTime	[5]	Ext-NoRepCondTime	OPTIONAL,
-	modifyNotificationToCSE	[6]	ModificationInstruction	OPTIONAL,
-	extensionContainer	[7]	ExtensionContainer	OPTIONAL,
-	...}
-
-ModificationRequestFor-CB-Info ::= SEQUENCE {
-	ss-Code		[0]	SS-Code,
-	basicService	[1]	Ext-BasicServiceCode	OPTIONAL,
-	ss-Status		[2]	Ext-SS-Status	OPTIONAL,
-	password		[3]	Password	OPTIONAL,
-	wrongPasswordAttemptsCounter	[4]	WrongPasswordAttemptsCounter	OPTIONAL,
-	modifyNotificationToCSE	[5]	ModificationInstruction	OPTIONAL,
-	extensionContainer	[6]	ExtensionContainer	OPTIONAL,
-	...}
-
-ModificationRequestFor-ODB-data ::= SEQUENCE {
-	odb-data		[0]	ODB-Data	OPTIONAL,
-	modifyNotificationToCSE	[1]	ModificationInstruction	OPTIONAL,
-	extensionContainer	[2]	ExtensionContainer	OPTIONAL,
-	...}
-
-ModificationRequestFor-CSI ::= SEQUENCE {
-	requestedCamel-SubscriptionInfo	[0]	RequestedCAMEL-SubscriptionInfo,
-	modifyNotificationToCSE	[1]	ModificationInstruction	OPTIONAL,
-	modifyCSI-State	[2]	ModificationInstruction	OPTIONAL,
-	extensionContainer	[3]	ExtensionContainer	OPTIONAL,
-	...,
-	additionalRequestedCAMEL-SubscriptionInfo
-				[4] AdditionalRequestedCAMEL-SubscriptionInfo
-							OPTIONAL }
--- requestedCamel-SubscriptionInfo shall be discarded if
--- additionalRequestedCAMEL-SubscriptionInfo is received
-
-ModificationRequestFor-IP-SM-GW-Data ::= SEQUENCE {
-	modifyRegistrationStatus	[0]	ModificationInstruction	OPTIONAL,
-	extensionContainer	[1]	ExtensionContainer	OPTIONAL,
-	...}
-
-ModificationInstruction ::= ENUMERATED {
-	deactivate	(0),
-	activate		(1)}
-
--- subscriber data modification notification types
-
-NoteSubscriberDataModifiedArg ::= SEQUENCE {
-	imsi			IMSI,
-	msisdn		ISDN-AddressString,
-	forwardingInfoFor-CSE	[0] Ext-ForwardingInfoFor-CSE	OPTIONAL,
-	callBarringInfoFor-CSE	[1] Ext-CallBarringInfoFor-CSE	OPTIONAL,
-	odb-Info		[2] ODB-Info	OPTIONAL,
-	camel-SubscriptionInfo	[3] CAMEL-SubscriptionInfo	OPTIONAL,
-	allInformationSent	[4] NULL		OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-NoteSubscriberDataModifiedRes ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
--- mobility management event notificatioon info types
-
-NoteMM-EventArg::= SEQUENCE {
-	serviceKey	ServiceKey,
-	eventMet		[0]	MM-Code,
-	imsi			[1]	IMSI,
-	msisdn		[2]	ISDN-AddressString,
-	locationInformation	[3]	LocationInformation	OPTIONAL,
-	supportedCAMELPhases	[5]	SupportedCamelPhases	OPTIONAL,
-	extensionContainer	[6]	ExtensionContainer	OPTIONAL,
-	...,
-	locationInformationGPRS	[7]	LocationInformationGPRS	OPTIONAL,
-	offeredCamel4Functionalities	[8] OfferedCamel4Functionalities	OPTIONAL
-}
-
-NoteMM-EventRes ::= SEQUENCE {
-	extensionContainer	ExtensionContainer 	OPTIONAL,
-	...}
-
-Ext-SS-InfoFor-CSE ::= CHOICE {
-	forwardingInfoFor-CSE	[0] Ext-ForwardingInfoFor-CSE,
-	callBarringInfoFor-CSE	[1] Ext-CallBarringInfoFor-CSE
-	}
-
-Ext-ForwardingInfoFor-CSE ::= SEQUENCE {
-	ss-Code		[0]	SS-Code,
-	forwardingFeatureList	[1]	Ext-ForwFeatureList,
-	notificationToCSE	[2]	NULL		OPTIONAL,
-	extensionContainer	[3]	ExtensionContainer	OPTIONAL,
-	...}
-
-Ext-CallBarringInfoFor-CSE ::= SEQUENCE {
-	ss-Code		[0]	SS-Code,
-	callBarringFeatureList	[1]	Ext-CallBarFeatureList,
-	password		[2]	Password	OPTIONAL,
-	wrongPasswordAttemptsCounter	[3]	WrongPasswordAttemptsCounter	OPTIONAL,
-	notificationToCSE	[4]	NULL		OPTIONAL,
-	extensionContainer	[5]	ExtensionContainer 	OPTIONAL,
-	...}
-
-END
-
diff --git a/rrlp-ephemeris/asn1/MAP-OM-DataTypes.asn b/rrlp-ephemeris/asn1/MAP-OM-DataTypes.asn
deleted file mode 100644
index 024dd6f..0000000
--- a/rrlp-ephemeris/asn1/MAP-OM-DataTypes.asn
+++ /dev/null
@@ -1,216 +0,0 @@
--- $Id: MAP-OM-DataTypes.asn 28149 2009-04-25 17:45:34Z etxrab $
--- 17.7.2	Operation and maintenance data types
--- 3GPP TS 29.002 V8.9.0 (2009-04)
- 
-MAP-OM-DataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-OM-DataTypes (12) version11 (11)}
-
-DEFINITIONS
-
-IMPLICIT TAGS
-
-::=
-
-BEGIN
-
-EXPORTS
-	ActivateTraceModeArg,
-	ActivateTraceModeRes,
-	DeactivateTraceModeArg,
-	DeactivateTraceModeRes,
-	TracePropagationList
-;
-
-IMPORTS
-	AddressString,
-	IMSI
-FROM MAP-CommonDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-CommonDataTypes (18) version11 (11)}
-
-	ExtensionContainer
-FROM MAP-ExtensionDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)}
-
-;
-
-ActivateTraceModeArg ::= SEQUENCE {
-	imsi			[0] IMSI		OPTIONAL,
-	traceReference	[1] TraceReference,
-	traceType		[2] TraceType,
-	omc-Id		[3] AddressString	OPTIONAL,
-	extensionContainer	[4] ExtensionContainer	OPTIONAL,
-	...,
-	traceReference2	[5] TraceReference2	OPTIONAL,
-	traceDepthList	[6] TraceDepthList	OPTIONAL,
-	traceNE-TypeList	[7] TraceNE-TypeList	OPTIONAL,
-	traceInterfaceList	[8] TraceInterfaceList	OPTIONAL,
-	traceEventList	[9] TraceEventList	OPTIONAL
-	}
-
-TraceReference ::= OCTET STRING (SIZE (1..2))
-
-TraceReference2 ::= OCTET STRING (SIZE (3))
-
-TraceRecordingSessionReference ::= OCTET STRING (SIZE (2))
-
-TraceType ::= INTEGER
-	(0..255)
-	-- Trace types are fully defined in  3GPP TS 52.008. [61]
-
-TraceDepthList ::= SEQUENCE {
-	msc-s-TraceDepth	[0] TraceDepth	OPTIONAL,
-	mgw-TraceDepth	[1] TraceDepth	OPTIONAL,
-	sgsn-TraceDepth	[2] TraceDepth	OPTIONAL,
-	ggsn-TraceDepth	[3] TraceDepth	OPTIONAL,
-	rnc-TraceDepth	[4] TraceDepth	OPTIONAL,
-	bmsc-TraceDepth	[5] TraceDepth	OPTIONAL,
-	...}
-
-TraceDepth ::= ENUMERATED {
-	minimum (0),
-	medium (1),
-	maximum (2),
-	...}
--- The value medium is applicable only for RNC. For other network elements, if value medium
--- is received, value minimum shall be applied.
-
-TraceNE-TypeList ::= BIT STRING {
-	msc-s (0),
-	mgw (1),
-	sgsn (2),
-	ggsn (3),
-	rnc (4),
-	bm-sc (5)} (SIZE (6..16))
--- Other bits than listed above shall be discarded.
-
-TraceInterfaceList ::= SEQUENCE {
-	msc-s-List	[0] MSC-S-InterfaceList	OPTIONAL,
-	mgw-List		[1] MGW-InterfaceList	OPTIONAL,
-	sgsn-List		[2] SGSN-InterfaceList	OPTIONAL,
-	ggsn-List		[3] GGSN-InterfaceList	OPTIONAL,
-	rnc-List		[4] RNC-InterfaceList	OPTIONAL,
-	bmsc-List		[5] BMSC-InterfaceList	OPTIONAL,
-	...}
-
-MSC-S-InterfaceList ::= BIT STRING {
-	a (0),
-	iu (1),
-	mc (2),
-	map-g (3),
-	map-b (4),
-	map-e (5),
-	map-f (6),
-	cap (7),
-	map-d (8),
-	map-c (9)} (SIZE (10..16))
--- Other bits than listed above shall be discarded.
-
-MGW-InterfaceList ::= BIT STRING {
-	mc (0),
-	nb-up (1),
-	iu-up (2)} (SIZE (3..8))
--- Other bits than listed above shall be discarded.
-
-SGSN-InterfaceList ::= BIT STRING {
-	gb (0),
-	iu (1),
-	gn (2),
-	map-gr (3),
-	map-gd (4),
-	map-gf (5),
-	gs (6),
-	ge (7)} (SIZE (8..16))
--- Other bits than listed above shall be discarded.
-
-GGSN-InterfaceList ::= BIT STRING {
-	gn (0),
-	gi (1),
-	gmb (2)} (SIZE (3..8))
--- Other bits than listed above shall be discarded.
-
-RNC-InterfaceList ::= BIT STRING {
-	iu (0),
-	iur (1),
-	iub (2),
-	uu (3)} (SIZE (4..8))
--- Other bits than listed above shall be discarded.
-
-BMSC-InterfaceList ::= BIT STRING {
-	gmb (0)} (SIZE (1..8))
--- Other bits than listed above shall be discarded.
-
-TraceEventList ::= SEQUENCE {
-	msc-s-List	[0] MSC-S-EventList	OPTIONAL,
-	mgw-List		[1] MGW-EventList	OPTIONAL,
-	sgsn-List		[2] SGSN-EventList	OPTIONAL,
-	ggsn-List		[3] GGSN-EventList	OPTIONAL,
-	bmsc-List		[4] BMSC-EventList	OPTIONAL,
-	...}
-
-MSC-S-EventList ::= BIT STRING {
-	mo-mtCall (0),
-	mo-mt-sms (1),
-	lu-imsiAttach-imsiDetach (2),
-	handovers (3),
-	ss (4)} (SIZE (5..16))
--- Other bits than listed above shall be discarded.
-
-MGW-EventList ::= BIT STRING {
-	context (0)} (SIZE (1..8))
--- Other bits than listed above shall be discarded.
-
-SGSN-EventList ::= BIT STRING {
-	pdpContext (0),
-	mo-mt-sms (1),
-	rau-gprsAttach-gprsDetach (2),
-	mbmsContext (3)} (SIZE (4..16))
--- Other bits than listed above shall be discarded.
-
-GGSN-EventList ::= BIT STRING {
-	pdpContext (0),
-	mbmsContext (1)} (SIZE (2..8))
--- Other bits than listed above shall be discarded.
-
-BMSC-EventList ::= BIT STRING {
-	mbmsMulticastServiceActivation (0)} (SIZE (1..8))
--- Other bits than listed above shall be discarded.
-
-
-TracePropagationList ::= SEQUENCE {
-	traceReference	[0] TraceReference	OPTIONAL,
-	traceType		[1] TraceType	OPTIONAL,
-	traceReference2	[2] TraceReference2	OPTIONAL,
-	traceRecordingSessionReference	[3] TraceRecordingSessionReference OPTIONAL,
-	rnc-TraceDepth	[4] TraceDepth	OPTIONAL,
-	rnc-InterfaceList	[5] RNC-InterfaceList	OPTIONAL,
-	msc-s-TraceDepth	[6] TraceDepth	OPTIONAL,
-	msc-s-InterfaceList	[7] MSC-S-InterfaceList	OPTIONAL,
-	msc-s-EventList	[8] MSC-S-EventList	OPTIONAL,
-	mgw-TraceDepth	[9] TraceDepth	OPTIONAL,
-	mgw-InterfaceList	[10] MGW-InterfaceList	OPTIONAL,
-	mgw-EventList	[11] MGW-EventList	OPTIONAL,
-	...}
-
-ActivateTraceModeRes ::= SEQUENCE {
-	extensionContainer	[0] ExtensionContainer	OPTIONAL,
-	...,
-	traceSupportIndicator	[1]	NULL		OPTIONAL
-	}
-
-DeactivateTraceModeArg ::= SEQUENCE {
-	imsi			[0] IMSI		OPTIONAL,
-	traceReference	[1] TraceReference,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	...,
-	traceReference2	[3] TraceReference2	OPTIONAL
-	}
-
-DeactivateTraceModeRes ::= SEQUENCE {
-	extensionContainer	[0] ExtensionContainer	OPTIONAL,
-	...}
-
-END
-
diff --git a/rrlp-ephemeris/asn1/MAP-SM-DataTypes.asn b/rrlp-ephemeris/asn1/MAP-SM-DataTypes.asn
deleted file mode 100644
index 0ef941f..0000000
--- a/rrlp-ephemeris/asn1/MAP-SM-DataTypes.asn
+++ /dev/null
@@ -1,270 +0,0 @@
--- $Id: MAP-SM-DataTypes.asn 28149 2009-04-25 17:45:34Z etxrab $
--- 3GPP TS 29.002  V8.9.0 (2009-04)  
--- 17.7.6	Short message data types
-
-MAP-SM-DataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-SM-DataTypes (16) version11 (11)}
-
-DEFINITIONS
-
-IMPLICIT TAGS
-
-::=
-
-BEGIN
-
-EXPORTS
-	RoutingInfoForSM-Arg,
-	RoutingInfoForSM-Res,
-	MO-ForwardSM-Arg,
-	MO-ForwardSM-Res,
-	MT-ForwardSM-Arg,
-	MT-ForwardSM-Res,
-	ReportSM-DeliveryStatusArg,
-	ReportSM-DeliveryStatusRes,
-	AlertServiceCentreArg,
-	InformServiceCentreArg,
-	ReadyForSM-Arg, 
-	ReadyForSM-Res,
-	SM-DeliveryOutcome,
-	AlertReason,
-	Additional-Number,
-	MT-ForwardSM-VGCS-Arg,
-	MT-ForwardSM-VGCS-Res
-;
-
-IMPORTS
-	AddressString,
-	ISDN-AddressString,
-	SignalInfo,
-	IMSI,
-	LMSI,
-	ASCI-CallReference
-
-FROM MAP-CommonDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-CommonDataTypes (18) version11 (11)}
-
-	AbsentSubscriberDiagnosticSM
-FROM MAP-ER-DataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-ER-DataTypes (17) version11 (11)}
-
-	ExtensionContainer
-FROM MAP-ExtensionDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)}
-;
-
-
-RoutingInfoForSM-Arg ::= SEQUENCE {
-	msisdn		[0] ISDN-AddressString,
-	sm-RP-PRI		[1] BOOLEAN,
-	serviceCentreAddress	[2] AddressString,
-	extensionContainer	[6] ExtensionContainer	OPTIONAL,
-	... ,
-	gprsSupportIndicator	[7]	NULL		OPTIONAL,
-	-- gprsSupportIndicator is set only if the SMS-GMSC supports
-	-- receiving of two numbers from the HLR
-	sm-RP-MTI		[8] SM-RP-MTI	OPTIONAL,
-	sm-RP-SMEA	[9] SM-RP-SMEA	OPTIONAL,
-	sm-deliveryNotIntended	[10] SM-DeliveryNotIntended	OPTIONAL }
-
-SM-DeliveryNotIntended ::= ENUMERATED {
-	onlyIMSI-requested  (0),
-	onlyMCC-MNC-requested  (1),
-	...}
-
-SM-RP-MTI ::= INTEGER (0..10)
-	-- 0 SMS Deliver 
-	-- 1 SMS Status Report
-	-- other values are reserved for future use and shall be discarded if
-	-- received
-
-SM-RP-SMEA ::= OCTET STRING (SIZE (1..12))
-	-- this parameter contains an address field which is encoded 
-	-- as defined in 3GPP TS 23.040. An address field contains 3 elements :
-	-- 		address-length
-	-- 		type-of-address
-	-- 		address-value
-
-RoutingInfoForSM-Res ::= SEQUENCE {
-	imsi			IMSI,
-	locationInfoWithLMSI	[0] LocationInfoWithLMSI,
-	extensionContainer	[4] ExtensionContainer	OPTIONAL,
-	...}
-
-LocationInfoWithLMSI ::= SEQUENCE {
-	networkNode-Number	[1] ISDN-AddressString,
-	lmsi			LMSI			OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	gprsNodeIndicator	[5]	NULL		OPTIONAL,
-	-- gprsNodeIndicator is set only if the SGSN number is sent as the 
-	-- Network Node Number
-	additional-Number	[6] Additional-Number	OPTIONAL 
-	-- NetworkNode-number can be either msc-number or sgsn-number or IP-SM-GW
-	-- number or SMS Router number
-	}
-
-Additional-Number ::= CHOICE {
-	msc-Number	[0] ISDN-AddressString,
-	sgsn-Number	[1] ISDN-AddressString}
-	-- additional-number can be either msc-number or sgsn-number
-	-- if received networkNode-number is msc-number then the 	
-	-- additional number is sgsn-number 
-	-- if received networkNode-number is sgsn-number then the 
-	-- additional number is msc-number 
-
-MO-ForwardSM-Arg ::= SEQUENCE {
-	sm-RP-DA		SM-RP-DA,
-	sm-RP-OA		SM-RP-OA,
-	sm-RP-UI		SignalInfo,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	... ,
-	imsi			IMSI 		OPTIONAL }
-
-MO-ForwardSM-Res ::= SEQUENCE {
-	sm-RP-UI		SignalInfo 	OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-MT-ForwardSM-Arg ::= SEQUENCE {
-	sm-RP-DA		SM-RP-DA,
-	sm-RP-OA		SM-RP-OA,
-	sm-RP-UI		SignalInfo,
-	moreMessagesToSend	NULL			OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-MT-ForwardSM-Res ::= SEQUENCE {
-	sm-RP-UI		SignalInfo	OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-SM-RP-DA ::= CHOICE {
-	imsi			[0] IMSI,
-	lmsi			[1] LMSI,
-	serviceCentreAddressDA	[4] AddressString,
-	noSM-RP-DA	[5] NULL}
-
-SM-RP-OA ::= CHOICE {
-	msisdn		[2] ISDN-AddressString,
-	serviceCentreAddressOA	[4] AddressString,
-	noSM-RP-OA	[5] NULL}
-
-ReportSM-DeliveryStatusArg ::= SEQUENCE {
-	msisdn		ISDN-AddressString,
-	serviceCentreAddress	AddressString,
-	sm-DeliveryOutcome	SM-DeliveryOutcome,
-	absentSubscriberDiagnosticSM	[0] AbsentSubscriberDiagnosticSM
-							OPTIONAL,
-	extensionContainer	[1] ExtensionContainer	OPTIONAL,
-	...,
-	gprsSupportIndicator	[2]	NULL		OPTIONAL,
-	-- gprsSupportIndicator is set only if the SMS-GMSC supports 
-	-- handling of two delivery outcomes
-	deliveryOutcomeIndicator	[3] 	NULL		OPTIONAL,
-	-- DeliveryOutcomeIndicator is set when the SM-DeliveryOutcome
-	-- is for GPRS
-	additionalSM-DeliveryOutcome	[4] 	SM-DeliveryOutcome 	OPTIONAL,
-	-- If received, additionalSM-DeliveryOutcome is for GPRS
-	-- If DeliveryOutcomeIndicator is set, then AdditionalSM-DeliveryOutcome shall be absent
-	additionalAbsentSubscriberDiagnosticSM	[5] 	AbsentSubscriberDiagnosticSM OPTIONAL,
-	-- If received additionalAbsentSubscriberDiagnosticSM is for GPRS
-	-- If DeliveryOutcomeIndicator is set, then AdditionalAbsentSubscriberDiagnosticSM 
-	-- shall be absent
-	ip-sm-gw-Indicator	[6] 	NULL		OPTIONAL,
-	-- the ip-sm-gw indicator indicates by its presence that sm-deliveryOutcome
-	-- is for delivery via IMS
-	-- If present, deliveryOutcomeIndicator shall be absent.
-	ip-sm-gw-sm-deliveryOutcome	[7] 	SM-DeliveryOutcome	OPTIONAL, 
-	-- If received ip-sm-gw-sm-deliveryOutcome is for delivery via IMS
-	-- If ip-sm-gw-Indicator is set, then ip-sm-gw-sm-deliveryOutcome shall be absent
-	ip-sm-gw-absentSubscriberDiagnosticSM	[8]	AbsentSubscriberDiagnosticSM	OPTIONAL
-	-- If received ip-sm-gw-sm-absentSubscriberDiagnosticSM is for delivery via IMS
-	-- If ip-sm-gw-Indicator is set, then ip-sm-gw-sm-absentSubscriberDiagnosticSM 
-	-- shall be absent
-}
-
-SM-DeliveryOutcome ::= ENUMERATED {
-	memoryCapacityExceeded  (0),
-	absentSubscriber  (1),
-	successfulTransfer  (2)}
-
-ReportSM-DeliveryStatusRes ::= SEQUENCE {
-	storedMSISDN	ISDN-AddressString	OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-AlertServiceCentreArg ::= SEQUENCE {
-	msisdn		ISDN-AddressString,
-	serviceCentreAddress	AddressString,
-	...}
-
-InformServiceCentreArg ::= SEQUENCE {
-	storedMSISDN	ISDN-AddressString	OPTIONAL,
-	mw-Status	MW-Status	OPTIONAL,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	... ,
-	absentSubscriberDiagnosticSM	AbsentSubscriberDiagnosticSM	OPTIONAL,
-	additionalAbsentSubscriberDiagnosticSM	[0]	AbsentSubscriberDiagnosticSM	OPTIONAL }
-	-- additionalAbsentSubscriberDiagnosticSM may be present only if 
-	-- absentSubscriberDiagnosticSM is present.
-	-- if included, additionalAbsentSubscriberDiagnosticSM is for GPRS and
-	-- absentSubscriberDiagnosticSM is for non-GPRS
-
-MW-Status ::= BIT STRING {
-	sc-AddressNotIncluded  (0),
-	mnrf-Set  (1),
-	mcef-Set  (2) ,
-	mnrg-Set	  (3)} (SIZE (6..16))
-	-- exception handling:
-	-- bits 4 to 15 shall be ignored if received and not understood
-
-ReadyForSM-Arg ::= SEQUENCE {
-	imsi			[0] IMSI,
-	alertReason	AlertReason,
-	alertReasonIndicator	NULL			OPTIONAL,
-	-- alertReasonIndicator is set only when the alertReason 
-	-- sent to HLR is for GPRS
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...,
-	additionalAlertReasonIndicator	[1] NULL		OPTIONAL
-	-- additionalAlertReasonIndicator is set only when the alertReason
-	-- sent to HLR is for IP-SM-GW
-	}
-
-ReadyForSM-Res ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-AlertReason ::= ENUMERATED {
-	ms-Present  (0),
-	memoryAvailable  (1)}
-
-MT-ForwardSM-VGCS-Arg ::= SEQUENCE {
-	asciCallReference	ASCI-CallReference,
-	sm-RP-OA		SM-RP-OA,
-	sm-RP-UI		SignalInfo,
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...}
-
-MT-ForwardSM-VGCS-Res ::= SEQUENCE {
-	sm-RP-UI		[0] SignalInfo	OPTIONAL,
-	dispatcherList	[1] DispatcherList	OPTIONAL,
-	ongoingCall	NULL			OPTIONAL,
-	extensionContainer	[2] ExtensionContainer	OPTIONAL,
-	...}
-
-DispatcherList ::= 
-	SEQUENCE SIZE (1..maxNumOfDispatchers) OF
-				ISDN-AddressString
-
-maxNumOfDispatchers  INTEGER ::= 5
-
-
-
-END
-
diff --git a/rrlp-ephemeris/asn1/MAP-SS-Code.asn b/rrlp-ephemeris/asn1/MAP-SS-Code.asn
deleted file mode 100644
index 163f2dc..0000000
--- a/rrlp-ephemeris/asn1/MAP-SS-Code.asn
+++ /dev/null
@@ -1,190 +0,0 @@
--- $Id: MAP-SS-Code.asn 28149 2009-04-25 17:45:34Z etxrab $
--- 3GPP TS 29.002 V8.9.0 (2009-04)
--- 17.7.5	Supplementary service codes
-
-MAP-SS-Code {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-SS-Code (15) version11 (11)}
-
-DEFINITIONS
-
-::=
-
-BEGIN
-
-SS-Code ::= OCTET STRING (SIZE (1))
-	-- This type is used to represent the code identifying a single
-	-- supplementary service, a group of supplementary services, or
-	-- all supplementary services. The services and abbreviations
-	-- used are defined in TS 3GPP TS 22.004 [5]. The internal structure is
-	-- defined as follows:
-	--
-	-- bits 87654321: group (bits 8765), and specific service
-	-- (bits 4321)
-
-allSS			SS-Code ::= '00000000'B
-	-- reserved for possible future use
-	-- all SS
-
-allLineIdentificationSS	SS-Code ::= '00010000'B
-	-- reserved for possible future use
-	-- all line identification SS
-clip				SS-Code ::= '00010001'B
-	-- calling line identification presentation
-clir				SS-Code ::= '00010010'B
-	-- calling line identification restriction
-colp				SS-Code ::= '00010011'B
-	-- connected line identification presentation
-colr				SS-Code ::= '00010100'B
-	-- connected line identification restriction
-mci				SS-Code ::= '00010101'B
-	-- reserved for possible future use
-	-- malicious call identification
-
-allNameIdentificationSS	SS-Code ::= '00011000'B
-	-- all name identification SS
-cnap				SS-Code ::= '00011001'B
-	-- calling name presentation
-
-	-- SS-Codes '00011010'B to '00011111'B are reserved for future 
-	-- NameIdentification Supplementary Service use.
-
-allForwardingSS	SS-Code ::= '00100000'B
-	-- all forwarding SS
-cfu				SS-Code ::= '00100001'B
-	-- call forwarding unconditional
-allCondForwardingSS	SS-Code ::= '00101000'B
-	-- all conditional forwarding SS
-cfb				SS-Code ::= '00101001'B
-	-- call forwarding on mobile subscriber busy
-cfnry			SS-Code ::= '00101010'B
-	-- call forwarding on no reply
-cfnrc			SS-Code ::= '00101011'B
-	-- call forwarding on mobile subscriber not reachable 
-cd				SS-Code ::= '00100100'B
-	-- call deflection
-
-allCallOfferingSS	SS-Code ::= '00110000'B
-	-- reserved for possible future use
-	-- all call offering SS includes also all forwarding SS
-ect				SS-Code ::= '00110001'B
-		-- explicit call transfer
-mah				SS-Code ::= '00110010'B
-	-- reserved for possible future use
-	-- mobile access hunting
-
-allCallCompletionSS	SS-Code ::= '01000000'B
-	-- reserved for possible future use
-	-- all Call completion SS
-cw				SS-Code ::= '01000001'B
-	-- call waiting
-hold				SS-Code ::= '01000010'B
-	-- call hold
-ccbs-A			SS-Code ::= '01000011'B
-	-- completion of call to busy subscribers, originating side
-	-- this SS-Code is used only in InsertSubscriberData, DeleteSubscriberData 
-	-- and InterrogateSS
-ccbs-B			SS-Code ::= '01000100'B
-	-- completion of call to busy subscribers, destination side
-	-- this SS-Code is used only in InsertSubscriberData and DeleteSubscriberData
-mc				SS-Code ::= '01000101'B
-	-- multicall
-
-allMultiPartySS	SS-Code ::= '01010000'B
-	-- reserved for possible future use
-	-- all multiparty SS
-multiPTY			SS-Code ::= '01010001'B
-	-- multiparty
-
-allCommunityOfInterest-SS	SS-Code ::= '01100000'B
-	-- reserved for possible future use
-	-- all community of interest SS
-cug				SS-Code ::= '01100001'B
-	-- closed user group
-
-allChargingSS		SS-Code ::= '01110000'B
-	-- reserved for possible future use
-	-- all charging SS
-aoci				SS-Code ::= '01110001'B
-	-- advice of charge information
-aocc				SS-Code ::= '01110010'B
-	-- advice of charge charging
-
-allAdditionalInfoTransferSS	SS-Code ::= '10000000'B
-	-- reserved for possible future use
-	-- all additional information transfer SS
-uus1				SS-Code ::= '10000001'B
-	-- UUS1 user-to-user signalling 
-uus2				SS-Code ::= '10000010'B
-	-- UUS2 user-to-user signalling
-uus3				SS-Code ::= '10000011'B
-	-- UUS3 user-to-user signalling
-
-allBarringSS		SS-Code ::= '10010000'B
-	-- all barring SS
-barringOfOutgoingCalls	SS-Code ::= '10010001'B
-	-- barring of outgoing calls
-baoc				SS-Code ::= '10010010'B
-	-- barring of all outgoing calls
-boic				SS-Code ::= '10010011'B
-	-- barring of outgoing international calls
-boicExHC			SS-Code ::= '10010100'B
-	-- barring of outgoing international calls except those directed
-	-- to the home PLMN Country
-barringOfIncomingCalls	SS-Code ::= '10011001'B
-	-- barring of incoming calls
-baic				SS-Code ::= '10011010'B
-	-- barring of all incoming calls
-bicRoam			SS-Code ::= '10011011'B
-	-- barring of incoming calls when roaming outside home PLMN
-	-- Country
-
-allPLMN-specificSS	SS-Code ::= '11110000'B
-plmn-specificSS-1	SS-Code ::= '11110001'B
-plmn-specificSS-2	SS-Code ::= '11110010'B
-plmn-specificSS-3	SS-Code ::= '11110011'B
-plmn-specificSS-4	SS-Code ::= '11110100'B
-plmn-specificSS-5	SS-Code ::= '11110101'B
-plmn-specificSS-6	SS-Code ::= '11110110'B
-plmn-specificSS-7	SS-Code ::= '11110111'B
-plmn-specificSS-8	SS-Code ::= '11111000'B
-plmn-specificSS-9	SS-Code ::= '11111001'B
-plmn-specificSS-A	SS-Code ::= '11111010'B
-plmn-specificSS-B	SS-Code ::= '11111011'B
-plmn-specificSS-C	SS-Code ::= '11111100'B
-plmn-specificSS-D	SS-Code ::= '11111101'B
-plmn-specificSS-E	SS-Code ::= '11111110'B
-plmn-specificSS-F	SS-Code ::= '11111111'B
-
-allCallPrioritySS	SS-Code ::= '10100000'B
-	-- reserved for possible future use
-	-- all call priority SS
-emlpp			SS-Code ::= '10100001'B
-	-- enhanced Multilevel Precedence Pre-emption (EMLPP) service
-
-allLCSPrivacyException	SS-Code ::= '10110000'B
-	-- all LCS Privacy Exception Classes
-universal			SS-Code ::= '10110001'B
-	-- allow location by any LCS client
-callSessionRelated	SS-Code ::= '10110010'B
-	-- allow location by any value added LCS client to which a call/session 
-	-- is established from the target MS
-callSessionUnrelated	SS-Code ::= '10110011'B
-	-- allow location by designated external value added LCS clients
-plmnoperator		SS-Code ::= '10110100'B
-	-- allow location by designated PLMN operator LCS clients 
-serviceType		SS-Code ::= '10110101'B
-	-- allow location by LCS clients of a designated LCS service type
-
-allMOLR-SS		SS-Code ::= '11000000'B
-	-- all Mobile Originating Location Request Classes
-basicSelfLocation	SS-Code ::= '11000001'B
-	-- allow an MS to request its own location
-autonomousSelfLocation	SS-Code ::= '11000010'B
-	-- allow an MS to perform self location without interaction
-	-- with the PLMN for a predetermined period of time
-transferToThirdParty	SS-Code ::= '11000011'B
-	-- allow an MS to request transfer of its location to another LCS client
-
-END
-
diff --git a/rrlp-ephemeris/asn1/MAP-SS-DataTypes.asn b/rrlp-ephemeris/asn1/MAP-SS-DataTypes.asn
deleted file mode 100644
index 253f7f0..0000000
--- a/rrlp-ephemeris/asn1/MAP-SS-DataTypes.asn
+++ /dev/null
@@ -1,342 +0,0 @@
--- $Id: MAP-SS-DataTypes.asn 28149 2009-04-25 17:45:34Z etxrab $
--- 3GPP TS 29.002 V8.9.0 (2009-04)  
--- 17.7.4	Supplementary service data types
- 
-MAP-SS-DataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-SS-DataTypes (14) version11 (11)}
-
-DEFINITIONS
-
-IMPLICIT TAGS
-
-::=
-
-BEGIN
-
-EXPORTS
-	RegisterSS-Arg,
-	SS-Info,
-	SS-Status,
-	SS-SubscriptionOption,
-	SS-ForBS-Code,
-	InterrogateSS-Res,
-	USSD-Arg,
-	USSD-Res, 
-	USSD-DataCodingScheme,
-	USSD-String,
-	Password,
-	GuidanceInfo,
-	SS-List,
-	SS-InfoList,
-	OverrideCategory,
-	CliRestrictionOption,
-	NoReplyConditionTime,
-	ForwardingOptions,
-	maxNumOfSS,
-	SS-Data,
-	SS-InvocationNotificationArg,
-	SS-InvocationNotificationRes,
-	CCBS-Feature,
-	RegisterCC-EntryArg,
-	RegisterCC-EntryRes,
-	EraseCC-EntryArg,
-	EraseCC-EntryRes
-;
-
-IMPORTS
-	AddressString,
-	ISDN-AddressString,
-	ISDN-SubaddressString,
-	FTN-AddressString,
-	IMSI,
-	BasicServiceCode,
-	AlertingPattern,
-	EMLPP-Priority, 
-	MaxMC-Bearers,
-	MC-Bearers,
-	ExternalSignalInfo
-FROM MAP-CommonDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-CommonDataTypes (18) version11 (11)}
-
-	ExtensionContainer
-FROM MAP-ExtensionDataTypes {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)}
-
-	SS-Code
-FROM MAP-SS-Code {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-SS-Code (15) version11 (11)}
-;
-
-
-RegisterSS-Arg ::= SEQUENCE {
-	ss-Code		SS-Code,
-	basicService	BasicServiceCode	OPTIONAL,
-	forwardedToNumber	[4] AddressString	OPTIONAL,
-	forwardedToSubaddress	[6] ISDN-SubaddressString	OPTIONAL,
-	noReplyConditionTime	[5] NoReplyConditionTime	OPTIONAL,
-	...,
-	defaultPriority	[7] EMLPP-Priority	OPTIONAL,
-	nbrUser		[8] MC-Bearers	OPTIONAL,
-	longFTN-Supported	[9]	NULL		OPTIONAL }
-
-NoReplyConditionTime ::= INTEGER (5..30)
-
-SS-Info ::= CHOICE {
-	forwardingInfo	[0] ForwardingInfo,
-	callBarringInfo	[1] CallBarringInfo,
-	ss-Data		[3] SS-Data}
-
-ForwardingInfo ::= SEQUENCE {
-	ss-Code		SS-Code		OPTIONAL,
-	forwardingFeatureList	ForwardingFeatureList,
-	...}
-
-ForwardingFeatureList ::= 
-	SEQUENCE SIZE (1..maxNumOfBasicServiceGroups) OF
-				ForwardingFeature
-
-ForwardingFeature ::= SEQUENCE {
-	basicService	BasicServiceCode	OPTIONAL,
-	ss-Status		[4] SS-Status	OPTIONAL,
-	forwardedToNumber	[5] ISDN-AddressString	OPTIONAL,
-	forwardedToSubaddress	[8] ISDN-SubaddressString	OPTIONAL,
-	forwardingOptions	[6] ForwardingOptions	OPTIONAL,
-	noReplyConditionTime	[7] NoReplyConditionTime	OPTIONAL,
-	...,
-	longForwardedToNumber	[9] FTN-AddressString	OPTIONAL }
-
-SS-Status ::= OCTET STRING (SIZE (1))
-
-	-- bits 8765: 0000 (unused)
-	-- bits 4321: Used to convey the "P bit","R bit","A bit" and "Q bit",
-	--		    representing supplementary service state information
-	--		    as defined in TS 3GPP TS 23.011 [22]
-
-	-- bit 4: "Q bit"
-
-	-- bit 3: "P bit"
-
-	-- bit 2: "R bit"
-
-	-- bit 1: "A bit"
-
-ForwardingOptions ::= OCTET STRING (SIZE (1))
-
-	-- bit 8: notification to forwarding party
-	--	0  no notification
-	--	1  notification
-
-	-- bit 7: redirecting presentation
-	--	0 no presentation  
-	--	1  presentation
-
-	-- bit 6: notification to calling party
-	--	0  no notification
-	--	1  notification
-
-	-- bit 5: 0 (unused)
-
-	-- bits 43: forwarding reason
-	--	00  ms not reachable
-	--	01  ms busy
-	--	10  no reply
-	--	11  unconditional when used in a SRI Result, 
-	--	    or call deflection when used in a RCH Argument
-	-- bits 21: 00 (unused)
-
-CallBarringInfo ::= SEQUENCE {
-	ss-Code		SS-Code		OPTIONAL,
-	callBarringFeatureList	CallBarringFeatureList,
-	...}
-
-CallBarringFeatureList ::= SEQUENCE SIZE (1..maxNumOfBasicServiceGroups) OF
-				CallBarringFeature
-
-CallBarringFeature ::= SEQUENCE {
-	basicService	BasicServiceCode	OPTIONAL,
-	ss-Status	[4] SS-Status	OPTIONAL,
-	...}
-
-SS-Data ::= SEQUENCE {
-	ss-Code		SS-Code		OPTIONAL,
-	ss-Status		[4] SS-Status	OPTIONAL,
-	ss-SubscriptionOption	SS-SubscriptionOption	OPTIONAL,
-	basicServiceGroupList	BasicServiceGroupList	OPTIONAL,
-	...,
-	defaultPriority	EMLPP-Priority	OPTIONAL,
-	nbrUser		[5] MC-Bearers	OPTIONAL
-	}
-
-SS-SubscriptionOption ::= CHOICE {
-	cliRestrictionOption	[2] CliRestrictionOption,
-	overrideCategory	[1] OverrideCategory}
-
-CliRestrictionOption ::= ENUMERATED {
-	permanent  (0),
-	temporaryDefaultRestricted  (1),
-	temporaryDefaultAllowed  (2)}
-
-OverrideCategory ::= ENUMERATED {
-	overrideEnabled  (0),
-	overrideDisabled  (1)}
-
-SS-ForBS-Code ::= SEQUENCE {
-	ss-Code		SS-Code,
-	basicService	BasicServiceCode	OPTIONAL,
-	...,
-	longFTN-Supported	[4]	NULL		OPTIONAL }
-
-GenericServiceInfo ::= SEQUENCE {
-	ss-Status	SS-Status,
-	cliRestrictionOption	CliRestrictionOption	OPTIONAL,
-	...,
-	maximumEntitledPriority	[0] EMLPP-Priority	OPTIONAL,
-	defaultPriority	[1] EMLPP-Priority	OPTIONAL,
-	ccbs-FeatureList	[2] CCBS-FeatureList	OPTIONAL,
-	nbrSB		[3] MaxMC-Bearers	OPTIONAL,
-	nbrUser		[4] MC-Bearers	OPTIONAL,
-	nbrSN		[5] MC-Bearers	OPTIONAL }
-
-CCBS-FeatureList ::= SEQUENCE SIZE (1..maxNumOfCCBS-Requests) OF
-				CCBS-Feature
-
-maxNumOfCCBS-Requests  INTEGER ::= 5
-
-CCBS-Feature ::= SEQUENCE {
-	ccbs-Index	[0] CCBS-Index	OPTIONAL,
-	b-subscriberNumber	[1] ISDN-AddressString	OPTIONAL,
-	b-subscriberSubaddress	[2] ISDN-SubaddressString	OPTIONAL,
-	basicServiceGroup	[3] BasicServiceCode	OPTIONAL,
-	...}
-
-CCBS-Index  ::= INTEGER (1..maxNumOfCCBS-Requests)
-
-InterrogateSS-Res ::= CHOICE {
-	ss-Status		[0] SS-Status,
-	basicServiceGroupList	[2] BasicServiceGroupList,
-	forwardingFeatureList	[3] ForwardingFeatureList,
-	genericServiceInfo	[4]	GenericServiceInfo }
-
-USSD-Arg ::= SEQUENCE {
-	ussd-DataCodingScheme	USSD-DataCodingScheme,
-	ussd-String	USSD-String,
-	... ,
-	alertingPattern	AlertingPattern	OPTIONAL,
-	msisdn		[0] ISDN-AddressString	OPTIONAL }
-
-USSD-Res ::= SEQUENCE {
-	ussd-DataCodingScheme	USSD-DataCodingScheme,
-	ussd-String	USSD-String,
-	...}
-
-USSD-DataCodingScheme ::= OCTET STRING (SIZE (1))
-	-- The structure of the USSD-DataCodingScheme is defined by
-	-- the Cell Broadcast Data Coding Scheme as described in
-	-- TS 3GPP TS 23.038 [25]
-
-USSD-String ::= OCTET STRING (SIZE (1..maxUSSD-StringLength))
-	-- The structure of the contents of the USSD-String is dependent
-	-- on the USSD-DataCodingScheme as described in TS 3GPP TS 23.038 [25].
-
-maxUSSD-StringLength  INTEGER ::= 160
-
-Password ::= NumericString
-	(FROM ("0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"))
-	(SIZE (4))
-
-GuidanceInfo ::= ENUMERATED {
-	enterPW  (0),
-	enterNewPW  (1),
-	enterNewPW-Again  (2)}
-	-- How this information is really delivered to the subscriber
-	-- (display, announcement, ...) is not part of this
-	-- specification.
-
-SS-List ::= SEQUENCE SIZE (1..maxNumOfSS) OF
-				SS-Code
-
-maxNumOfSS  INTEGER ::= 30
-
-SS-InfoList ::= SEQUENCE SIZE (1..maxNumOfSS) OF
-				SS-Info
-
-BasicServiceGroupList ::= SEQUENCE SIZE (1..maxNumOfBasicServiceGroups) OF
-				BasicServiceCode
-
-maxNumOfBasicServiceGroups  INTEGER ::= 13
-
-SS-InvocationNotificationArg ::= SEQUENCE {
-	imsi			[0] IMSI,
-	msisdn		[1] ISDN-AddressString,
-	ss-Event		[2] SS-Code,
-	-- The following SS-Code values are allowed :
-	-- ect		SS-Code ::= '00110001'B
-	-- multiPTY	SS-Code ::= '01010001'B
-	-- cd		SS-Code ::= '00100100'B
-	-- ccbs		SS-Code ::= '01000100'B
-	ss-EventSpecification	[3] SS-EventSpecification	OPTIONAL,
-	extensionContainer	[4] ExtensionContainer	OPTIONAL,
-	...,
-	b-subscriberNumber	[5]	ISDN-AddressString	OPTIONAL,
-	ccbs-RequestState	[6]	CCBS-RequestState	OPTIONAL
-	}
-
-CCBS-RequestState ::= ENUMERATED {
-	request  	(0),
-	recall  	(1),
-	active  	(2),
-	completed	(3),
-	suspended	(4),
-	frozen	(5),
-	deleted	(6)
-	}
-
-SS-InvocationNotificationRes ::= SEQUENCE {
-	extensionContainer	ExtensionContainer	OPTIONAL,
-	...
-	}
-
-SS-EventSpecification ::= SEQUENCE SIZE (1..maxEventSpecification) OF
-				AddressString
-
-maxEventSpecification  INTEGER ::= 2
-
-RegisterCC-EntryArg ::= SEQUENCE {
-	ss-Code		[0]	SS-Code,
-	ccbs-Data		[1]	CCBS-Data	OPTIONAL,
-	...}
-
-CCBS-Data ::= SEQUENCE {
-	ccbs-Feature	[0]	CCBS-Feature,
-	translatedB-Number	[1]	ISDN-AddressString,
-	serviceIndicator	[2]	ServiceIndicator	OPTIONAL,
-	callInfo		[3]	ExternalSignalInfo,
-	networkSignalInfo	[4]	ExternalSignalInfo,
-	...}
-
-ServiceIndicator ::= BIT STRING {
-	clir-invoked (0),
-	camel-invoked (1)} (SIZE(2..32)) 
-	-- exception handling:
-	-- bits 2 to 31 shall be ignored if received and not understood
-
-RegisterCC-EntryRes ::= SEQUENCE {
-	ccbs-Feature	[0] CCBS-Feature	OPTIONAL,
-	...}
-
-EraseCC-EntryArg ::= SEQUENCE {
-	ss-Code		[0]	SS-Code,
-	ccbs-Index	[1]	CCBS-Index	OPTIONAL,
-	...}
-
-EraseCC-EntryRes ::= SEQUENCE {
-	ss-Code		[0]	SS-Code,
-	ss-Status		[1] SS-Status	OPTIONAL,
-	...}
-
-END
-
diff --git a/rrlp-ephemeris/asn1/MAP-TS-Code.asn b/rrlp-ephemeris/asn1/MAP-TS-Code.asn
deleted file mode 100644
index 5ac00bf..0000000
--- a/rrlp-ephemeris/asn1/MAP-TS-Code.asn
+++ /dev/null
@@ -1,92 +0,0 @@
--- $Id: MAP-TS-Code.asn 28149 2009-04-25 17:45:34Z etxrab $
--- 3GPP TS 29.002 V8.9.0 (2009-04) 
--- 17.7.9	Teleservice Codes
- 
-MAP-TS-Code {
-   itu-t identified-organization (4) etsi (0) mobileDomain (0)
-   gsm-Network (1) modules (3) map-TS-Code (19) version11 (11)}
-
-DEFINITIONS
-
-::=
-
-BEGIN
-
-TeleserviceCode ::= OCTET STRING (SIZE (1))
-	-- This type is used to represent the code identifying a single
-	-- teleservice, a group of teleservices, or all teleservices. The
-	-- services are defined in TS GSM 22.003 [4].
-	-- The internal structure is defined as follows:
-
-	-- bits 87654321: group (bits 8765) and specific service
-	-- (bits 4321)
-
-Ext-TeleserviceCode ::= OCTET STRING (SIZE (1..5))
-	-- This type is used to represent the code identifying a single
-	-- teleservice, a group of teleservices, or all teleservices. The
-	-- services are defined in TS GSM 22.003 [4].
-	-- The internal structure is defined as follows:
-
-	-- OCTET 1:
-	-- bits 87654321: group (bits 8765) and specific service
-	-- (bits 4321)
-
-	-- OCTETS 2-5: reserved for future use. If received the
-    -- Ext-TeleserviceCode shall be
- 	-- treated according to the exception handling defined for the
-	-- operation that uses this type.
-
-	-- Ext-TeleserviceCode includes all values defined for TeleserviceCode.
-
-allTeleservices	TeleserviceCode ::= '00000000'B
-
-allSpeechTransmissionServices	TeleserviceCode ::= '00010000'B
-telephony			TeleserviceCode ::= '00010001'B
-emergencyCalls		TeleserviceCode ::= '00010010'B
-
-allShortMessageServices	TeleserviceCode ::= '00100000'B
-shortMessageMT-PP	TeleserviceCode ::= '00100001'B
-shortMessageMO-PP	TeleserviceCode ::= '00100010'B
-
-allFacsimileTransmissionServices	TeleserviceCode ::= '01100000'B
-facsimileGroup3AndAlterSpeech	TeleserviceCode ::= '01100001'B
-automaticFacsimileGroup3	TeleserviceCode ::= '01100010'B
-facsimileGroup4	TeleserviceCode ::= '01100011'B
-
--- The following non-hierarchical Compound Teleservice Groups
--- are defined in TS 3GPP TS 22.030:
-allDataTeleservices	TeleserviceCode ::= '01110000'B
-	-- covers Teleservice Groups 'allFacsimileTransmissionServices'
-	-- and 'allShortMessageServices'
-allTeleservices-ExeptSMS	TeleserviceCode ::= '10000000'B
-	-- covers Teleservice Groups 'allSpeechTransmissionServices' and
-	-- 'allFacsimileTransmissionServices'
---
--- Compound Teleservice Group Codes are only used in call
--- independent supplementary service operations, i.e. they
--- are not used in InsertSubscriberData or in
--- DeleteSubscriberData messages.
-
-allVoiceGroupCallServices	TeleserviceCode ::= '10010000'B
-voiceGroupCall		TeleserviceCode ::= '10010001'B
-voiceBroadcastCall	TeleserviceCode ::= '10010010'B
-
-allPLMN-specificTS	TeleserviceCode ::= '11010000'B
-plmn-specificTS-1	TeleserviceCode ::= '11010001'B
-plmn-specificTS-2	TeleserviceCode ::= '11010010'B
-plmn-specificTS-3	TeleserviceCode ::= '11010011'B
-plmn-specificTS-4	TeleserviceCode ::= '11010100'B
-plmn-specificTS-5	TeleserviceCode ::= '11010101'B
-plmn-specificTS-6	TeleserviceCode ::= '11010110'B
-plmn-specificTS-7	TeleserviceCode ::= '11010111'B
-plmn-specificTS-8	TeleserviceCode ::= '11011000'B
-plmn-specificTS-9	TeleserviceCode ::= '11011001'B
-plmn-specificTS-A	TeleserviceCode ::= '11011010'B
-plmn-specificTS-B	TeleserviceCode ::= '11011011'B
-plmn-specificTS-C	TeleserviceCode ::= '11011100'B
-plmn-specificTS-D	TeleserviceCode ::= '11011101'B
-plmn-specificTS-E	TeleserviceCode ::= '11011110'B
-plmn-specificTS-F	TeleserviceCode ::= '11011111'B
-
-END
-
diff --git a/rrlp-ephemeris/asn1/RRLP-Components.asn b/rrlp-ephemeris/asn1/RRLP-Components.asn
deleted file mode 100644
index 3bade6a..0000000
--- a/rrlp-ephemeris/asn1/RRLP-Components.asn
+++ /dev/null
@@ -1,1488 +0,0 @@
--- RRLP-Components.asn
--- $Id$
--- Taken from 3GPP TS 44.031 V7.4.0 (2007-03)
--- http://www.3gpp.org/ftp/Specs/archive/44_series/44.031/44031-740.zip/44031-740.doc
---
--- 4 Components
--- 5 Elements of Components
---
-
-RRLP-Components
--- { RRLP-Components }
-
-DEFINITIONS AUTOMATIC TAGS ::=
-
-BEGIN
-
-IMPORTS
-	Ext-GeographicalInformation, VelocityEstimate
-FROM
-	MAP-LCS-DataTypes {
-	itu-t identified-organization (4) etsi (0) mobileDomain (0)
-	gsm-Network (1) modules (3) map-LCS-DataTypes (25) version11 (11)}
-
-	ExtensionContainer
-FROM MAP-ExtensionDataTypes {
-	itu-t identified-organization (4) etsi (0) mobileDomain (0)
-	gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)}
-;
-
-
--- Add here other ASN.1 definitions presented below
--- in chapters 4 and 5.
-
--- Measurement Position request component
-MsrPosition-Req ::= SEQUENCE {
-	positionInstruct		PositionInstruct,
-	referenceAssistData		ReferenceAssistData		OPTIONAL,
-	msrAssistData			MsrAssistData			OPTIONAL,
-	systemInfoAssistData	SystemInfoAssistData	OPTIONAL,
-	gps-AssistData			GPS-AssistData			OPTIONAL,
-	extensionContainer		ExtensionContainer		OPTIONAL,
-	...,
-	-- Release 98 extension element
-rel98-MsrPosition-Req-extension			Rel98-MsrPosition-Req-Extension			OPTIONAL,	
-	-- Release 5 extension element
-rel5-MsrPosition-Req-extension			Rel5-MsrPosition-Req-Extension			OPTIONAL,
-	-- Release 7 extension element
-rel7-MsrPosition-Req-extension			Rel7-MsrPosition-Req-Extension			OPTIONAL
-}
-
--- Measurement Position response component
-MsrPosition-Rsp ::= SEQUENCE {
-	multipleSets			MultipleSets			OPTIONAL,
-	referenceIdentity		ReferenceIdentity		OPTIONAL,
-	otd-MeasureInfo			OTD-MeasureInfo			OPTIONAL,
-	locationInfo			LocationInfo			OPTIONAL,
-	gps-MeasureInfo			GPS-MeasureInfo			OPTIONAL,
-	locationError			LocationError			OPTIONAL,
-	extensionContainer		ExtensionContainer		OPTIONAL,
-	...,	
-	-- Release extension here
-	rel-98-MsrPosition-Rsp-Extension		
-							Rel-98-MsrPosition-Rsp-Extension		OPTIONAL,
-	rel-5-MsrPosition-Rsp-Extension
-							Rel-5-MsrPosition-Rsp-Extension		OPTIONAL,
-	-- rel-5-MsrPosition-Rsp-Extension and other possible future extensions
-	-- are the only information elements that may be included in the 2nd
-	-- MsrPosition-Rsp component when RRLP pseudo-segmentation is used
-	rel-7-MsrPosition-Rsp-Extension
-							Rel-7-MsrPosition-Rsp-Extension		OPTIONAL
-}
-
--- Assistance Data component
-AssistanceData ::= SEQUENCE {
-	referenceAssistData	ReferenceAssistData			OPTIONAL,
-	msrAssistData			MsrAssistData			OPTIONAL,
-	systemInfoAssistData	SystemInfoAssistData	OPTIONAL,
-	gps-AssistData			GPS-AssistData			OPTIONAL,	
-	moreAssDataToBeSent		MoreAssDataToBeSent		OPTIONAL,	-- If not present, interpret as only
-																-- Assistance Data component used to
-																-- deliver entire set of assistance
-																-- data.
-	extensionContainer		ExtensionContainer		OPTIONAL,
-	...,
-	-- Release extension here
-	rel98-AssistanceData-Extension	Rel98-AssistanceData-Extension	OPTIONAL,
-	rel5-AssistanceData-Extension	Rel5-AssistanceData-Extension	OPTIONAL,
- rel7-AssistanceData-Extension Rel7-AssistanceData-Extension OPTIONAL	
-}
-
--- Protocol Error component
-ProtocolError ::= SEQUENCE {
-	errorCause				ErrorCodes,	
-	extensionContainer		ExtensionContainer		OPTIONAL,
-	...,
-	-- Release extensions here
-	rel-5-ProtocolError-Extension Rel-5-ProtocolError-Extension		OPTIONAL
-}
-
--- Position instructions
-PositionInstruct ::= SEQUENCE {
-	-- Method type
-	methodType				MethodType,	
-	positionMethod			PositionMethod,
-	measureResponseTime		MeasureResponseTime,		
-	useMultipleSets			UseMultipleSets,		
-	environmentCharacter	EnvironmentCharacter	OPTIONAL	
-}
-
---
-MethodType ::= CHOICE {
-	msAssisted		AccuracyOpt,	-- accuracy is optional
-	msBased			Accuracy,		-- accuracy is mandatory
-	msBasedPref		Accuracy,		-- accuracy is mandatory
-	msAssistedPref	Accuracy 		-- accuracy is mandatory
-}
-
--- Accuracy of the location estimation
-AccuracyOpt ::= SEQUENCE {
-	accuracy		Accuracy	OPTIONAL
-}
-
--- The values of this field are defined in 3GPP TS 23.032 (Uncertainty code)
-Accuracy ::= INTEGER (0..127)
-
-
--- Position Method
-PositionMethod ::= ENUMERATED {
-	eotd (0),
-	gps (1),
-	gpsOrEOTD (2)
-}
-
--- Measurement request response time
-MeasureResponseTime ::= INTEGER (0..7)
-
--- useMultiple Sets, FFS!
-UseMultipleSets ::= ENUMERATED {
-	multipleSets (0),		-- multiple sets are allowed
-	oneSet (1)				-- sending of multiple is not allowed
-}
-
--- Environment characterization
-EnvironmentCharacter ::= ENUMERATED {
-	badArea (0),		-- bad urban or suburban, heavy multipath and NLOS
-	notBadArea (1),		-- light multipath and NLOS
-	mixedArea (2),		-- not defined or mixed environment
-	...
-}
-
--- E-OTD reference BTS for Assitance data IE
-ReferenceAssistData ::= SEQUENCE {
-	bcchCarrier		BCCHCarrier,						-- BCCH carrier
-	bsic			BSIC,								-- BSIC
-	timeSlotScheme	TimeSlotScheme, 					-- Timeslot scheme
-	btsPosition		BTSPosition			OPTIONAL
-}
-
--- ellipsoid point and
--- ellipsoid point with altitude and uncertainty ellipsoid shapes are supported
-BTSPosition ::= Ext-GeographicalInformation
-
--- RF channel number of BCCH
-BCCHCarrier ::= INTEGER (0..1023)
-
--- Base station Identity Code
-BSIC ::= INTEGER (0..63)
-
--- Timeslot scheme
-TimeSlotScheme ::= ENUMERATED {
-	equalLength (0),
-	variousLength (1)
-}
-
--- Time slot (modulo)
-ModuloTimeSlot ::= INTEGER (0..3)
-
--- E-OTD measurement assistance data IE
--- The total number of neighbors in this element (MsrAssistData)
--- and in SystemInfoAssistData element (presented neighbors
--- can be at a maximum 15!)
-MsrAssistData ::= SEQUENCE {
-	 msrAssistList SeqOfMsrAssistBTS
-}
-SeqOfMsrAssistBTS ::= SEQUENCE (SIZE(1..15)) OF MsrAssistBTS
-
-MsrAssistBTS ::= SEQUENCE {
-	bcchCarrier			BCCHCarrier,		-- BCCH carrier
-	bsic				BSIC,				-- BSIC
-	multiFrameOffset	MultiFrameOffset, 	-- multiframe offset
-	timeSlotScheme		TimeSlotScheme,		-- Timeslot scheme
-	roughRTD			RoughRTD,			-- rough RTD value
-
-	-- Location Calculation Assistance data is moved here
-	calcAssistanceBTS	CalcAssistanceBTS	OPTIONAL
-}
-
--- Multiframe offset
-MultiFrameOffset ::= INTEGER (0..51)
--- The Multiframe Offset value 51 shall not be encoded by the transmitting entity and
--- shall be treated by the receiving entity as 0.
-
--- Rough RTD value between one base station and reference BTS
-RoughRTD ::= INTEGER (0..1250)
--- The RoughRTD value 1250 shall not be encoded by the transmitting entity and shall
--- be treated by the receiving entity as 0.
-
--- E-OTD Measurement assistance data for system information List IE
--- The total number of base stations in this element (SystemInfoAssistData
--- presented neighbors) and in MsrAssistData element can be at a maximum 15.
-SystemInfoAssistData ::= SEQUENCE {
-	systemInfoAssistList 	SeqOfSystemInfoAssistBTS
-}
-SeqOfSystemInfoAssistBTS::= SEQUENCE (SIZE(1..32)) OF SystemInfoAssistBTS
-
--- whether n.th is present or not ?
-SystemInfoAssistBTS ::= CHOICE {
-	notPresent		NULL,
-	present			AssistBTSData
-}
-
--- Actual assistance data for system information base station
-AssistBTSData ::= SEQUENCE {
-	bsic				BSIC,				-- BSIC
-	multiFrameOffset	MultiFrameOffset,	-- multiframe offset
-	timeSlotScheme		TimeSlotScheme,		-- Timeslot scheme
-	roughRTD			RoughRTD,			-- rough RTD value
-
-	-- Location Calculation Assistance data
-	calcAssistanceBTS	CalcAssistanceBTS	OPTIONAL
-}
-
--- E-OTD Location calculation assistance data,
--- CalcAssistanceBTS element is optional not subfields
-CalcAssistanceBTS ::= SEQUENCE {
-	fineRTD				FineRTD,		-- fine RTD value between base stations
-	referenceWGS84		ReferenceWGS84	-- reference coordinates
-}
-
--- Coordinates of neighbour BTS, WGS-84 ellipsoid
-ReferenceWGS84 ::= SEQUENCE {
-	relativeNorth	RelDistance,				-- relative distance (south negative)
-	relativeEast	RelDistance,				-- relative distance (west negative)
-	-- Relative Altitude is not always known
-	relativeAlt		RelativeAlt		OPTIONAL	-- relative altitude
-}
-
--- Fine RTD value between this BTS and the reference BTS	
-FineRTD ::= INTEGER (0..255)
-
--- Relative north/east distance
-RelDistance ::= INTEGER (-200000..200000)
-
--- Relative altitude
-RelativeAlt ::= INTEGER (-4000..4000)
-
--- Measure position response IEs
--- Reference Identity
--- Multiple sets
-MultipleSets ::= SEQUENCE {
-	-- number of reference sets
-	nbrOfSets			INTEGER (2..3),		
-
-	-- This field actually tells the number of reference BTSs
-	nbrOfReferenceBTSs	INTEGER (1..3),
-
-	-- This field is conditional and included optionally only if
-	-- nbrOfSets is 3 and number of reference BTSs is 2.
-	referenceRelation		ReferenceRelation		OPTIONAL
-}
-
--- Relation between refence BTSs and sets
-ReferenceRelation ::= ENUMERATED {
-	secondBTSThirdSet (0),	-- 1st BTS related to 1st and 2nd sets
-	secondBTSSecondSet (1),	-- 1st BTS related to 1st and 3rd sets
-	firstBTSFirstSet (2)	-- 1st BTS related to 1st set
-}
-
--- Reference BTS Identity, this element contains number of
--- BTSs told nbrOfReferenceBTSs field in Multiple sets element)
-ReferenceIdentity ::= SEQUENCE {
-	-- Reference BTS list
-	refBTSList		SeqOfReferenceIdentityType
-}
-SeqOfReferenceIdentityType ::= SEQUENCE (SIZE(1..3)) OF ReferenceIdentityType
-
--- Cell identity
-ReferenceIdentityType ::= CHOICE {
-	bsicAndCarrier	BSICAndCarrier,		-- BSIC and Carrier
-	ci				CellID,				-- Cell ID, LAC not needed
-	requestIndex	RequestIndex,		-- Index to Requested Neighbor List
-	systemInfoIndex	SystemInfoIndex,	-- Index to System info list, this type of ref. identity
-										-- shall not be used by the MS unless it has received
-										-- the SystemInfoAssistData from the SMLC for this cell.
-	ciAndLAC		CellIDAndLAC		-- CI and LAC
-}
-
-BSICAndCarrier ::= SEQUENCE {
-	carrier	BCCHCarrier,
-	bsic		BSIC
-}
-
-RequestIndex ::= INTEGER (1..16)
-
-SystemInfoIndex ::= INTEGER (1..32)
-
-CellIDAndLAC ::= SEQUENCE {
-	referenceLAC	LACID,				-- Location area code
-	referenceCI		CellID				-- Cell identity
-}
-CellID ::= INTEGER (0..65535)
-LACID ::= INTEGER (0..65535)
-
--- OTD-MeasureInfo
-OTD-MeasureInfo ::= SEQUENCE {
-	-- Measurement info elements, OTD-MsrElement is repeated number of times
-	-- told in nbrOfReferenceBTSs in MultipleSets, default value is 1
-	otdMsrFirstSets		OTD-MsrElementFirst,
-
-	-- if more than one sets are present this element is repeated
-	-- NumberOfSets - 1 (-1 = first set)
-	otdMsrRestSets		SeqOfOTD-MsrElementRest		OPTIONAL
-}
-
-SeqOfOTD-MsrElementRest ::= SEQUENCE (SIZE(1..2)) OF OTD-MsrElementRest
-
--- OTD measurent information for 1 set
-OTD-MsrElementFirst ::= SEQUENCE {
-	refFrameNumber			INTEGER (0..42431), 				-- Frame number modulo 42432
-	referenceTimeSlot		ModuloTimeSlot,
-	toaMeasurementsOfRef	TOA-MeasurementsOfRef	OPTIONAL,
-	stdResolution			StdResolution,
-	taCorrection			INTEGER (0..960)		OPTIONAL,	-- TA correction
-
-	-- measured neighbors in OTD measurements
-	otd-FirstSetMsrs 		SeqOfOTD-FirstSetMsrs 	OPTIONAL
-}
-SeqOfOTD-FirstSetMsrs ::= SEQUENCE (SIZE(1..10)) OF OTD-FirstSetMsrs
-
--- OTD measurent information 2 and 3 sets if exist
-OTD-MsrElementRest ::= SEQUENCE {
-	refFrameNumber			INTEGER (0..42431), 					-- Frame number modulo 42432
-	referenceTimeSlot		ModuloTimeSlot,
-	toaMeasurementsOfRef	TOA-MeasurementsOfRef		OPTIONAL,
-	stdResolution			StdResolution,
-	taCorrection			INTEGER (0..960)			OPTIONAL,	-- TA correction
-
-	-- measured neighbors in OTD measurements
-	otd-MsrsOfOtherSets 	SeqOfOTD-MsrsOfOtherSets	OPTIONAL
-}
-SeqOfOTD-MsrsOfOtherSets ::= SEQUENCE (SIZE(1..10)) OF OTD-MsrsOfOtherSets
-
--- Standard deviation of the TOA measurements from the reference BTS
-TOA-MeasurementsOfRef ::= SEQUENCE {
-	refQuality			RefQuality,
-	numOfMeasurements	NumOfMeasurements
-}
-
-RefQuality ::= INTEGER (0..31)			-- St Dev of TOA of reference as defined in annex
-NumOfMeasurements ::= INTEGER (0..7)	-- No. of measurements for RefQuality as defined in annex
-StdResolution ::= INTEGER (0..3)		-- Values of resolution are defined in annex
-
-OTD-FirstSetMsrs ::= OTD-MeasurementWithID
-
--- Neighbour info in OTD measurements 0-10 times in TD measurement info
-OTD-MsrsOfOtherSets ::= CHOICE {
-	identityNotPresent	OTD-Measurement,	
-	identityPresent		OTD-MeasurementWithID
-}
-
--- For this OTD measurement identity is same as the identity of BTS
--- in the first set with same sequence number
-OTD-Measurement ::= SEQUENCE {
-	nborTimeSlot	ModuloTimeSlot,
-	eotdQuality		EOTDQuality,
-	otdValue		OTDValue
-}
-
--- This measurement contains the BTS identity and measurement
-OTD-MeasurementWithID ::=SEQUENCE {
-	neighborIdentity	NeighborIdentity,
-	nborTimeSlot		ModuloTimeSlot,
-	eotdQuality			EOTDQuality,
-	otdValue			OTDValue
-}
-
-EOTDQuality ::= SEQUENCE {
-	nbrOfMeasurements	INTEGER	(0..7),
-	stdOfEOTD			INTEGER (0..31)
-}
-
-NeighborIdentity ::= CHOICE {
-	bsicAndCarrier		BSICAndCarrier,		-- BSIC and Carrier
-	ci					CellID,				-- Cell ID, LAC not needed
-	multiFrameCarrier	MultiFrameCarrier, 	-- MultiFrameOffest and BSIC
-	requestIndex		RequestIndex,		-- Index to Requested Neighbor List
-	systemInfoIndex		SystemInfoIndex,	-- Index to System info list, this type of neighbour
-											-- identity shall not be used by the MS unless it has
-											-- received the SystemInfoAssistData from the SMLC for
-											-- this cell.
-	ciAndLAC			CellIDAndLAC		-- CI and LAC
-}
-
--- Multiframe and carrier
-MultiFrameCarrier ::= SEQUENCE {
-	bcchCarrier			BCCHCarrier,
-	multiFrameOffset	MultiFrameOffset
-}
-
--- OTD measurement value for neighbour
-OTDValue ::= INTEGER (0..39999)
-
--- Location information IE
-LocationInfo ::= SEQUENCE {
-	refFrame		INTEGER (0..65535),			-- Reference Frame number
-	-- If refFrame is within (42432..65535), it shall be ignored by the receiver
-	-- in that case the MS should provide GPS TOW if available
-	gpsTOW			INTEGER (0..14399999)	OPTIONAL,	-- GPS TOW
-	fixType			FixType,
-	-- Note that applicable range for refFrame is 0 - 42431
-	-- Possible shapes carried in posEstimate are
-	-- ellipsoid point,
-	-- ellipsoid point with uncertainty circle
-	-- ellipsoid point with uncertainty ellipse
-	-- ellipsoid point with altitude and uncertainty ellipsoid
-	posEstimate		Ext-GeographicalInformation
-}
-
-FixType ::= INTEGER {
-	twoDFix (0),
-	threeDFix (1)
-} (0..1)
-
--- GPS-Measurement information
-GPS-MeasureInfo ::= SEQUENCE {
-	-- Measurement info elements
-	-- user has to make sure that in this element is number of elements
-	-- defined in reference BTS identity
-	gpsMsrSetList	SeqOfGPS-MsrSetElement	
-}
-SeqOfGPS-MsrSetElement ::= SEQUENCE (SIZE(1..3)) OF GPS-MsrSetElement
-
--- OTD measurent information 1-3 times in message
-GPS-MsrSetElement ::= SEQUENCE {
-	refFrame		INTEGER (0..65535)	OPTIONAL, 	-- Reference Frame number
-	gpsTOW			GPSTOW24b,						-- GPS TOW
-	-- Note that applicable range for refFrame is 0 - 42431
-
---N_SAT can be read from number of elements of gps-msrList
-
-	gps-msrList		SeqOfGPS-MsrElement
-}
-
--- 24 bit presentation for GPSTOW
-GPSTOW24b ::= INTEGER (0..14399999)
-
--- measured elements in measurement parameters field
-SeqOfGPS-MsrElement ::= SEQUENCE (SIZE(1..16)) OF GPS-MsrElement
-
-GPS-MsrElement ::= SEQUENCE {
-	satelliteID		SatelliteID,				-- Satellite identifier
-	cNo				INTEGER (0..63),			-- carrier noise ratio
-	doppler			INTEGER (-32768..32767), 	-- doppler, mulltiply by 0.2
-	wholeChips		INTEGER (0..1022),			-- whole value of the code phase measurement
-	fracChips		INTEGER (0..1024),			-- fractional value of the code phase measurement
-											-- a value of 1024 shall not be encoded by the sender
-											-- the receiver shall consider a value of 1024 to be
-											-- invalid data
-	mpathIndic		MpathIndic,					-- multipath indicator
-	pseuRangeRMSErr	INTEGER (0..63)				-- index		
-}
-
--- Multipath indicator
-MpathIndic ::= ENUMERATED {
-	notMeasured (0),
-	low (1),
-	medium (2),
-	high (3)
-}
-
--- Location error IE
-LocationError ::= SEQUENCE {
-	locErrorReason				LocErrorReason,
-	additionalAssistanceData	AdditionalAssistanceData	OPTIONAL,
-	...
-}
-
-LocErrorReason ::= ENUMERATED {
-	unDefined (0),	
-	notEnoughBTSs (1),
-	notEnoughSats (2),
-	eotdLocCalAssDataMissing (3),
-	eotdAssDataMissing (4),
-	gpsLocCalAssDataMissing (5),
-	gpsAssDataMissing (6),
-	methodNotSupported (7),
-	notProcessed (8),
-	refBTSForGPSNotServingBTS (9),
-	refBTSForEOTDNotServingBTS (10),
-	...,
-	notEnoughGANSSSats (11),	
- ganssAssDataMissing (12),
-	refBTSForGANSSNotServingBTS (13)
-}
-
--- exception handling:
--- an unrecognized value shall be treated the same as value 0
-
-
--- defines additional assistance data needed for any new location attempt
--- MS shall retain any assistance data already received
-AdditionalAssistanceData ::= SEQUENCE {
-	gpsAssistanceData		GPSAssistanceData		OPTIONAL,
-	extensionContainer		ExtensionContainer		OPTIONAL,
-	...,
-	ganssAssistanceData GANSSAssistanceData OPTIONAL
-}
-
-GPSAssistanceData ::= OCTET STRING (SIZE (1..maxGPSAssistanceData))
--- GPSAssistanceData has identical structure and encoding to octets 3 to n of the
--- GPS Assistance Data IE in 3GPP TS 49.031
-
-maxGPSAssistanceData	INTEGER ::= 40
-
-GANSSAssistanceData ::= OCTET STRING (SIZE (1..maxGANSSAssistanceData))
--- GANSSAssistanceData has identical structure and encoding to octets 3 to n of the
--- GANSS Assistance Data IE in 3GPP TS 49.031
-
-maxGANSSAssistanceData	INTEGER ::= 40
-
-
--- Protocol Error Causes
-ErrorCodes ::= ENUMERATED {
-	unDefined (0),
-missingComponet (1),			
-incorrectData (2),			
-missingIEorComponentElement (3),		
-messageTooShort (4),			
-unknowReferenceNumber (5),		
-...
-}
-
--- exception handling:
--- an unrecognized value shall be treated the same as value 0
-
--- GPS assistance data IE
-GPS-AssistData ::= SEQUENCE {
-	controlHeader		ControlHeader
-}
-
--- More Assistance Data To Be Sent IE
--- More Assistance Data Components On the Way indication for delivery of an entire set of assistance
--- data in multiple Assistance Data components.
-
-MoreAssDataToBeSent ::= ENUMERATED {
-	noMoreMessages (0),			-- This is the only or last Assistance Data message used to deliver
-								-- the entire set of assistance data.
-	moreMessagesOnTheWay (1)	-- The SMLC will send more Assistance Data messages or a final RRLP
-								-- Measure Position Request message to deliver the
-								-- the entire set of assistance data.
-}
-
--- Control header of the GPS assistance data
-ControlHeader ::= SEQUENCE {
-
-	-- Field type Present information
-	referenceTime		ReferenceTime		OPTIONAL,
-	refLocation			RefLocation			OPTIONAL,
-	dgpsCorrections		DGPSCorrections		OPTIONAL,
-	navigationModel		NavigationModel		OPTIONAL,
-	ionosphericModel		IonosphericModel		OPTIONAL,
-	utcModel			UTCModel			OPTIONAL,
-	almanac			Almanac			OPTIONAL,
-	acquisAssist		AcquisAssist		OPTIONAL,
-	realTimeIntegrity SeqOf-BadSatelliteSet OPTIONAL
-}
-
-ReferenceTime ::= SEQUENCE {
-	gpsTime				GPSTime,
-	gsmTime				GSMTime				OPTIONAL,
-	gpsTowAssist		GPSTOWAssist		OPTIONAL
-}
-
--- GPS Time includes week number and time-of-week (TOW)
-GPSTime ::= SEQUENCE {
-	gpsTOW23b			GPSTOW23b,
-	gpsWeek				GPSWeek
-}
-
--- GPSTOW, range 0-604799.92, resolution 0.08 sec, 23-bit presentation
-GPSTOW23b ::= INTEGER (0..7559999)
-
--- GPS week number
-GPSWeek ::= INTEGER (0..1023)
-
--- GPSTOWAssist consists of TLM message, Anti-spoof flag, Alert flag, and 2 reserved bits in TLM Word
--- for each visible satellite.
--- N_SAT can be read from number of elements in GPSTOWAssist
-GPSTOWAssist ::= SEQUENCE (SIZE(1..12)) OF GPSTOWAssistElement
-
-GPSTOWAssistElement ::= SEQUENCE {
-	satelliteID			SatelliteID,
-	tlmWord				TLMWord,
-	antiSpoof			AntiSpoofFlag,
-	alert				AlertFlag,
-	tlmRsvdBits			TLMReservedBits
-}
-
--- TLM Word, 14 bits
-TLMWord ::= INTEGER (0..16383)
-
--- Anti-Spoof flag
-AntiSpoofFlag ::= INTEGER (0..1)
-
--- Alert flag
-AlertFlag ::= INTEGER (0..1)
-
--- Reserved bits in TLM word, MSB occurs earlier in TLM Word transmitted by satellite
-TLMReservedBits ::= INTEGER (0..3)
-
-GSMTime ::= SEQUENCE {
-	bcchCarrier		BCCHCarrier,	-- BCCH carrier
-	bsic			BSIC,			-- BSIC
-	frameNumber		FrameNumber,
-	timeSlot		TimeSlot,
-	bitNumber		BitNumber
-}
-
--- Frame number
-FrameNumber ::= INTEGER (0..2097151)
-
--- Time slot number
-TimeSlot ::= INTEGER (0..7)
-
--- Bit number
-BitNumber ::= INTEGER (0..156)
-
-
--- Reference Location IE
-RefLocation ::= SEQUENCE {
-	threeDLocation			Ext-GeographicalInformation
-}
-
--- DGPS Corrections IE
-DGPSCorrections ::= SEQUENCE {
-
-	gpsTOW		INTEGER (0..604799),	-- DGPS reference time
-	status		INTEGER (0..7),
-	-- N_SAT can be read from number of elements of satList
-	satList		SeqOfSatElement 	
-}
-SeqOfSatElement ::= SEQUENCE (SIZE (1..16)) OF SatElement
-
--- number of correction for satellites
-SatElement ::= SEQUENCE {
-	satelliteID		SatelliteID,
-
-
---- Sequence number for ephemeris
-	iode 			INTEGER (0..239),
-	-- User Differential Range Error
-	udre			INTEGER (0..3),		
-
-	-- Pseudo Range Correction, range is
-	-- -655.04 - +655.04,
-	pseudoRangeCor	INTEGER (-2047..2047), 	
-
-	-- Pseudo Range Rate Correction, range is
-	-- -4.064 - +4.064,
-	rangeRateCor	INTEGER (-127..127),
-
--- Delta Pseudo Range Correction 2 	
-	deltaPseudoRangeCor2 	INTEGER (-127..127),	-- This IE shall be ignored by the receiver and
-													-- set to zero by the sender
-	-- Delta Pseudo Range Correction 2	
-	deltaRangeRateCor2		INTEGER (-7..7),		-- This IE shall be ignored by the receiver and
-													-- set to zero by the sender
-	-- Delta Pseudo Range Correction 3
-	deltaPseudoRangeCor3 	INTEGER (-127..127),	-- This IE shall be ignored by the receiver and
-													-- set to zero by the sender
-	-- Delta Pseudo Range Correction 3
-	deltaRangeRateCor3		INTEGER (-7..7)			-- This IE shall be ignored by the receiver and
-													-- set to zero by the sender
-}
-
-SatelliteID ::= INTEGER (0..63)	-- identifies satellite
-
--- Navigation Model IE
-NavigationModel ::= SEQUENCE {
-	navModelList	SeqOfNavModelElement	
-}
-
--- navigation model satellite list
-SeqOfNavModelElement ::= SEQUENCE (SIZE(1..16)) OF NavModelElement
-
-NavModelElement ::= SEQUENCE {
-	satelliteID		SatelliteID,			
-	satStatus		SatStatus		-- satellite status
-}
-
--- the Status of the navigation model
-SatStatus ::= CHOICE {
-	-- New satellite, new Navigation Model
-	newSatelliteAndModelUC	UncompressedEphemeris,
-
-	-- Existing satellite, Existing Navigation Model
-	oldSatelliteAndModel	NULL,
-
-	-- Existing satellite, new Navigation Model
-	newNaviModelUC			UncompressedEphemeris,
-	...
-}
-
--- Uncompressed satellite emhemeris and clock corrections
-UncompressedEphemeris ::= SEQUENCE {
-	ephemCodeOnL2	INTEGER (0..3),
-	ephemURA		INTEGER (0..15),
-	ephemSVhealth	INTEGER (0..63),
-	ephemIODC		INTEGER	(0..1023),
-	ephemL2Pflag	INTEGER (0..1),
-	ephemSF1Rsvd	EphemerisSubframe1Reserved,
-	ephemTgd		INTEGER (-128..127),
-	ephemToc		INTEGER (0..37799),
-	ephemAF2		INTEGER (-128..127),
-	ephemAF1		INTEGER (-32768..32767),
-	ephemAF0		INTEGER (-2097152..2097151),
-	ephemCrs		INTEGER (-32768..32767),
-	ephemDeltaN		INTEGER (-32768..32767),
-	ephemM0			INTEGER (-2147483648..2147483647),
-	ephemCuc		INTEGER (-32768..32767),
-	ephemE			INTEGER (0..4294967295),
-	ephemCus		INTEGER (-32768..32767),
-	ephemAPowerHalf	INTEGER (0..4294967295),
-	ephemToe		INTEGER (0..37799),
-	ephemFitFlag	INTEGER (0..1),
-	ephemAODA		INTEGER (0..31),
-	ephemCic		INTEGER (-32768..32767),
-	ephemOmegaA0	INTEGER (-2147483648..2147483647),
-	ephemCis		INTEGER (-32768..32767),
-	ephemI0			INTEGER (-2147483648..2147483647),
-	ephemCrc		INTEGER (-32768..32767),
-	ephemW			INTEGER (-2147483648..2147483647),
-	ephemOmegaADot	INTEGER (-8388608..8388607),
-	ephemIDot		INTEGER (-8192..8191)
-}
-
--- Reserved bits in subframe 1 of navigation message
-EphemerisSubframe1Reserved ::= SEQUENCE {
-	reserved1		INTEGER (0..8388607),	-- 23-bit field
-	reserved2		INTEGER (0..16777215),	-- 24-bit field
-	reserved3		INTEGER (0..16777215),	-- 24-bit field
-	reserved4		INTEGER (0..65535)		-- 16-bit field
-}
-
--- Ionospheric Model IE
-IonosphericModel ::= SEQUENCE {
-	alfa0			INTEGER (-128..127),
-	alfa1			INTEGER (-128..127),
-	alfa2			INTEGER (-128..127),
-	alfa3			INTEGER (-128..127),
-	beta0			INTEGER (-128..127),
-	beta1			INTEGER (-128..127),
-	beta2			INTEGER (-128..127),
-	beta3			INTEGER (-128..127)
-}
-
--- Universal Time Coordinate Model
-UTCModel ::= SEQUENCE {
-	utcA1			INTEGER (-8388608..8388607),
-	utcA0			INTEGER (-2147483648..2147483647),
-	utcTot			INTEGER (0..255),
-	utcWNt			INTEGER (0..255),
-	utcDeltaTls		INTEGER (-128..127),
-	utcWNlsf		INTEGER (0..255),
-	utcDN			INTEGER (-128..127),
-	utcDeltaTlsf	INTEGER (-128..127)
-}
-
--- Almanac, Long term model
--- NOTE: These are parameters are subset of the ephemeris
--- NOTE: But with reduced resolution and accuracy
-Almanac ::= SEQUENCE {
-	alamanacWNa		INTEGER (0..255),	-- Once per message
-
-	-- navigation model satellite list.
-	-- The size of almanacList is actually Nums_Sats_Total field
-	almanacList		SeqOfAlmanacElement		
-}
-SeqOfAlmanacElement ::= SEQUENCE (SIZE(1..64)) OF AlmanacElement
-
--- Almanac info once per satellite
-AlmanacElement ::= SEQUENCE {
-	satelliteID			SatelliteID,
-	almanacE			INTEGER (0..65535),
-	alamanacToa			INTEGER (0..255),
-	almanacKsii			INTEGER (-32768..32767),
-	almanacOmegaDot		INTEGER (-32768..32767),
-	almanacSVhealth		INTEGER (0..255),
-	almanacAPowerHalf	INTEGER (0..16777215),
-	almanacOmega0		INTEGER (-8388608..8388607),
-	almanacW			INTEGER (-8388608..8388607),
-	almanacM0			INTEGER (-8388608..8388607),
-	almanacAF0			INTEGER (-1024..1023),
-	almanacAF1			INTEGER (-1024..1023)
-}
-
--- Acquisition Assistance
-AcquisAssist ::= SEQUENCE {
-
-	-- Number of Satellites can be read from acquistList
-	timeRelation	TimeRelation,
-
-	-- Acquisition assistance list
-	-- The size of Number of Satellites is actually Number of Satellites field
-	acquisList		SeqOfAcquisElement		
-}
-SeqOfAcquisElement ::= SEQUENCE (SIZE(1..16)) OF AcquisElement
-
--- the relationship between GPS time and air-interface timing
-TimeRelation ::= SEQUENCE {
-	--
-	gpsTOW		GPSTOW23b,		-- 23b presentation
-	gsmTime		GSMTime		OPTIONAL
-}
-
--- data occuring per number of satellites
-AcquisElement ::= SEQUENCE {
-	svid					SatelliteID,
-
-	-- Doppler 0th order term,
-	-- -5120.0 - 5117.5 Hz (= -2048 - 2047 with 2.5 Hz resolution)
-	doppler0				INTEGER (-2048..2047),	
-	addionalDoppler			AddionalDopplerFields	OPTIONAL,
-	codePhase				INTEGER (0..1022),	-- Code Phase
-	intCodePhase			INTEGER (0..19),	-- Integer Code Phase
-	gpsBitNumber			INTEGER (0..3), 	-- GPS bit number
-	codePhaseSearchWindow	INTEGER (0..15),	-- Code Phase Search Window
-	addionalAngle			AddionalAngleFields		OPTIONAL
-}
-
-AddionalDopplerFields ::= SEQUENCE {
-	-- Doppler 1st order term, -1.0 - +0.5 Hz/sec
- -- (= -42 + (0 to 63) with 1/42 Hz/sec. resolution)
-	doppler1				INTEGER (0..63),
-	dopplerUncertainty		INTEGER (0..7)
- -- a sender shall not encode any DopplerUncertainty value in the range 5 to 7
- -- a receiver shall ignore any value between 5 and 7.
-}
-
-AddionalAngleFields	::= SEQUENCE {
-	-- azimuth angle, 0 - 348.75 deg (= 0 - 31 with 11.25 deg resolution)
-	azimuth					INTEGER (0..31),
-	-- elevation angle, 0 - 78.75 deg (= 0 - 7 with 11.25 deg resolution)
-	elevation				INTEGER (0..7)
-}
-
--- Real-Time Integrity
--- number of bad satellites can be read from this element
-SeqOf-BadSatelliteSet ::= SEQUENCE (SIZE(1..16)) OF SatelliteID
-
--- Extension Elements
-
--- Release 98 Extensions here
-Rel98-MsrPosition-Req-Extension ::= SEQUENCE {
-	rel98-Ext-ExpOTD			Rel98-Ext-ExpOTD		OPTIONAL,	-- ExpectedOTD extension
-	..., 
- gpsTimeAssistanceMeasurementRequest NULL OPTIONAL, 
- gpsReferenceTimeUncertainty GPSReferenceTimeUncertainty OPTIONAL
-
--- Further R98 extensions here
-}
-Rel98-AssistanceData-Extension ::= SEQUENCE {
-	rel98-Ext-ExpOTD			Rel98-Ext-ExpOTD		OPTIONAL,	-- ExpectedOTD extension
-	..., 
- gpsTimeAssistanceMeasurementRequest NULL OPTIONAL,
- gpsReferenceTimeUncertainty GPSReferenceTimeUncertainty OPTIONAL
-
--- Further R98 extensions here
-}
-
--- Release 98 ExpOTD extension
-Rel98-Ext-ExpOTD ::= SEQUENCE {
--- If MsrAssistBTS is included in message, msrAssistData-R98-ExpOTD shall be included.
-	msrAssistData-R98-ExpOTD			MsrAssistData-R98-ExpOTD			OPTIONAL,
-
--- If SystemInfoAssistaData is included in message, systemInfoAssistData-R98-ExpOTD shall be
--- included.
-	systemInfoAssistData-R98-ExpOTD	SystemInfoAssistData-R98-ExpOTD	OPTIONAL
-}
-
--- MsrAssistData R98 extension
-MsrAssistData-R98-ExpOTD ::= SEQUENCE {
-	 msrAssistList-R98-ExpOTD			 SeqOfMsrAssistBTS-R98-ExpOTD
-}
-
--- Indexes in SeqOfMsrAssistBTS-R98-ExpOTD refer to SeqOfMsrAssistBTS
--- If the index exceeds the SegOfMsrAssistBTS range or if there is other
--- inconsistencies between the BTS indices, the MS shall apply protocol
--- error cause incorrectData
-SeqOfMsrAssistBTS-R98-ExpOTD ::= SEQUENCE (SIZE(1..15)) OF MsrAssistBTS-R98-ExpOTD
-
--- This element completes MsrAssistBTS IE
-MsrAssistBTS-R98-ExpOTD ::= SEQUENCE {
-	expectedOTD				ExpectedOTD,
-	expOTDUncertainty		ExpOTDUncertainty
-}
-
--- SystemInfoAssistData R98 extension
-SystemInfoAssistData-R98-ExpOTD ::= SEQUENCE {
-	systemInfoAssistListR98-ExpOTD 	SeqOfSystemInfoAssistBTS-R98-ExpOTD
-}
-
--- SeqOfSystemInfoAssistBTS-R98-ExpOTD index refer to SeqOfSystemInfoAssistBTS
--- If the index exceeds the SegOfSystemInfoAssistBTS range or if there is other
--- inconsistencies between the BTS indices, the MS shall apply protocol
--- error cause incorrectData
-SeqOfSystemInfoAssistBTS-R98-ExpOTD ::= SEQUENCE (SIZE(1..32)) OF SystemInfoAssistBTS-R98-ExpOTD
-
--- whether n.th is present or not ?
-SystemInfoAssistBTS-R98-ExpOTD ::= CHOICE {
-	notPresent		NULL,
-	present			AssistBTSData-R98-ExpOTD
-}
-
--- This element completes AssistBTSData IE
-AssistBTSData-R98-ExpOTD ::= SEQUENCE {
-	expectedOTD				ExpectedOTD,
-	expOTDuncertainty		ExpOTDUncertainty	-- Uncertainty of expected OTD
-}
-
--- Expected OTD value between nbor base station and reference BTS
--- at MS's current estimated location.
-ExpectedOTD ::= INTEGER (0..1250)
--- The ExpectedOTD value 1250 shall not be encoded by the transmitting entity and
--- shall be treated by the receiving entity as 0.
--- Uncertainty of Exptected OTD in bits
-ExpOTDUncertainty ::= INTEGER(0..7)
-
--- Release 98 extensions
-
-GPSReferenceTimeUncertainty ::= INTEGER (0 .. 127) -- Coding according to Annex
-
-GPSTimeAssistanceMeasurements ::= SEQUENCE {
- referenceFrameMSB INTEGER (0 .. 63), -- MSB of frame number
- gpsTowSubms INTEGER (0 .. 9999) OPTIONAL, -- in units of 100ns, for MS based AGPS
- deltaTow INTEGER (0 .. 127) OPTIONAL, -- for MS assisted AGPS
- gpsReferenceTimeUncertainty GPSReferenceTimeUncertainty OPTIONAL
-}
-
-Rel-98-MsrPosition-Rsp-Extension ::= SEQUENCE {
-
-	-- First extension to Release 98
-	rel-98-Ext-MeasureInfo	SEQUENCE {
-		otd-MeasureInfo-R98-Ext	OTD-MeasureInfo-R98-Ext		OPTIONAL
-	},
-	..., 
- timeAssistanceMeasurements GPSTimeAssistanceMeasurements OPTIONAL 
- -- Further R98 extensions here
-}
-
--- This is an addition to OTD-MeasureInfo element defined in original message,
--- If OTD-MeasureInfo is absent, or if one or more OTD-MsrElementRest are present
--- OTD-MeasureInfo-R98-Ext shall be absent.
--- OTD-MeasureInfo-R98-Ext
-OTD-MeasureInfo-R98-Ext ::= SEQUENCE {
-	-- Measurement info elements
-	otdMsrFirstSets-R98-Ext		OTD-MsrElementFirst-R98-Ext
-}
-
--- OTD measurement information Ext for the first set only
-OTD-MsrElementFirst-R98-Ext ::= SEQUENCE {
-	-- additional measured neighbors in OTD measurements
-	otd-FirstSetMsrs-R98-Ext 	SeqOfOTD-FirstSetMsrs-R98-Ext 	OPTIONAL
-}
-SeqOfOTD-FirstSetMsrs-R98-Ext ::= SEQUENCE (SIZE(1..5)) OF OTD-FirstSetMsrs
-
-Rel-5-MsrPosition-Rsp-Extension ::= SEQUENCE {
-
-	extended-reference	Extended-reference 	OPTIONAL,
-	-- The extended-reference shall be included by the MS if and only if previously
-	-- received from the SMLC in a Measure Position Request. When included, the value sent
-	-- by the MS shall equal the value received from the SMLC.
-
-	-- extension to Release 5, for RRLP pseudo-segmentation here
-	otd-MeasureInfo-5-Ext	OTD-MeasureInfo-5-Ext	OPTIONAL,
-	ulPseudoSegInd			UlPseudoSegInd			OPTIONAL,	-- Included when uplink RRLP
-	-- Pseudo-segmentation is used, not included when no uplink pseudo-segmentation is used
-	...
-					-- Possibly more extensions for Release 5 here later
-}
-
-Extended-reference ::= SEQUENCE {
-	smlc-code			INTEGER (0..63),
-	transaction-ID		INTEGER (0..262143)
-}
-
-OTD-MeasureInfo-5-Ext ::= SeqOfOTD-MsrElementRest
-	-- if more than one measurement sets are present this element is repeated
-	-- NumberOfSets - 1 (-1 = first set) combined in OTD-MeasureInfo-5-Ext and
-	-- OTD-MeasureInfo (e.g. if NumberOfSets is 3, then one otdMsrRestSets may
-	-- be sent in OTD-MeasureInfo-5-Ext and one in OTD-MeasureInfo)
-
--- First part of Uplink RRLP Pseudo-segmentation indication, possibly more may be defined
--- in the future for segmentation with more than two segments.
-UlPseudoSegInd ::= ENUMERATED {
-	firstOfMany (0),
-	secondOfMany(1)
-}
-
-Rel5-MsrPosition-Req-Extension ::= SEQUENCE {
-	extended-reference			Extended-reference,
-	...
-	-- Possibly more extensions for Release 5 here later
-}
-
-Rel5-AssistanceData-Extension ::= SEQUENCE {
-	extended-reference			Extended-reference,
-	...
-
--- Possibly more extensions for Release 5 here later
-}
-
-Rel-5-ProtocolError-Extension::= SEQUENCE {
-	extended-reference			Extended-reference 	OPTIONAL,
-	-- The extended-reference shall be included by the MS if and only if previously
-	-- received from the SMLC.
-	-- When included, the value sent by the MS shall equal the value received from the SMLC.
-	...
-
-	-- Possibly more extensions for Release 5 here later
-}
-
--- Release 7 Extensions here
-
-Rel7-MsrPosition-Req-Extension ::= SEQUENCE {
-velocityRequested		 NULL		 OPTIONAL,
- ganssPositionMethod GANSSPositioningMethod OPTIONAL,
- ganss-AssistData GANSS-AssistData OPTIONAL,
- ganssCarrierPhaseMeasurementRequest NULL OPTIONAL,
- ganssTODGSMTimeAssociationMeasurementRequest NULL OPTIONAL,
-requiredResponseTime	RequiredResponseTime	OPTIONAL,
-	...
-	-- Further Release 7 extentions here
-}
-
--- additional satellite systems may be added in future versions of the protocol
-GANSSPositioningMethod ::= BIT STRING {
-	gps (0),
-	galileo (1)} (SIZE (2..16))
-
-GANSS-AssistData ::= SEQUENCE {
-	ganss-controlHeader	GANSS-ControlHeader
-}
-
-GANSS-ControlHeader ::= SEQUENCE {
- ganssCommonAssistData GANSSCommonAssistData OPTIONAL,
- ganssGenericAssistDataList SeqOfGANSSGenericAssistDataElement OPTIONAL
-}
-
--- GANSS Common Assistance Data Elements
-GANSSCommonAssistData ::= SEQUENCE {
-	ganssReferenceTime		 GANSSReferenceTime		 OPTIONAL,
-	ganssRefLocation			GANSSRefLocation		 OPTIONAL,
-	ganssIonosphericModel		GANSSIonosphericModel	 OPTIONAL,
-	...
-}
-
--- List of GANSS Generic Assistance Data Elements, up to 8 GANSS
-SeqOfGANSSGenericAssistDataElement ::= SEQUENCE (SIZE (1..8)) OF GANSSGenericAssistDataElement
-
--- GANSS Generic Assistance Data Elements
-GANSSGenericAssistDataElement ::= SEQUENCE {
- ganssID INTEGER (0..7) OPTIONAL, -- Coding according to Annex
- ganssTimeModel SeqOfGANSSTimeModel OPTIONAL,
-	ganssDiffCorrections		 GANSSDiffCorrections	 OPTIONAL,
-	ganssNavigationModel		 GANSSNavModel OPTIONAL,
-	ganssRealTimeIntegrity	 GANSSRealTimeIntegrity	 OPTIONAL,
-	ganssDataBitAssist			 GANSSDataBitAssist		 OPTIONAL,
-	ganssRefMeasurementAssist	 GANSSRefMeasurementAssist OPTIONAL,
- ganssAlmanacModel GANSSAlmanacModel OPTIONAL,
- ganssUTCModel GANSSUTCModel OPTIONAL,
-	...
-}
-
--- GANSS COMMON ASSISTANCE DATA ELEMENTS
-
--- GANSS Reference Time IE
-GANSSReferenceTime ::= SEQUENCE {
-	ganssRefTimeInfo			 GANSSRefTimeInfo,
-	ganssTOD-GSMTimeAssociation GANSSTOD-GSMTimeAssociation OPTIONAL
-}
-
--- GANSS Reference Time includes GANSS TOD, GANSS Day, uncertainty
-GANSSRefTimeInfo ::= SEQUENCE {
-	ganssDay			 INTEGER(0 .. 8191) OPTIONAL,
- ganssTOD GANSSTOD,
-	ganssTODUncertainty	 GANSSTODUncertainty OPTIONAL,
- ganssTimeID INTEGER (0 .. 7) OPTIONAL
-}
-
--- GANSS TOD integer seconds
-GANSSTOD ::= INTEGER (0 .. 86399)
-
--- GANSS TOD uncertainty
-GANSSTODUncertainty ::= INTEGER (0 .. 127) -- Coding according to Annex
-
--- GANSS TOD-GSM Time association 
-GANSSTOD-GSMTimeAssociation ::= SEQUENCE {
-	bcchCarrier		BCCHCarrier,	-- BCCH carrier
-	bsic			BSIC,			-- BSIC
-	frameNumber		FrameNumber,
-	timeSlot		TimeSlot,
-	bitNumber		BitNumber,
- frameDrift FrameDrift OPTIONAL
-}
-
--- Frame drift
-FrameDrift ::= INTEGER(-64 .. 63)
-
--- GANSS Reference Location IE
-GANSSRefLocation ::= SEQUENCE {
-	threeDLocation			Ext-GeographicalInformation
-}
-
--- GANSS Ionospheric Model IE
--- GANSS Ionospheric Model consists of NeQuick model parameters and storm flags
-
-GANSSIonosphericModel ::= SEQUENCE {
- ganssIonoModel GANSSIonosphereModel,
- ganssIonoStormFlags GANSSIonoStormFlags OPTIONAL,
- ...
-}
-
--- GANSS ionosphere model. Coding according to Annex 
-GANSSIonosphereModel ::= SEQUENCE {
- ai0 INTEGER (0 .. 4095),
- ai1 INTEGER (0 .. 4095),
- ai2 INTEGER (0 .. 4095)
-}
-
--- GANSS ionosphere storm flags
-GANSSIonoStormFlags ::= SEQUENCE {
-	ionoStormFlag1	INTEGER (0 .. 1),
-	ionoStormFlag2	INTEGER (0 .. 1),
-	ionoStormFlag3	INTEGER (0 .. 1),
-	ionoStormFlag4	INTEGER (0 .. 1),
-	ionoStormFlag5	INTEGER (0 .. 1)
-}
-
--- GANSS GENERIC ASSISTANCE DATA ELEMENTS
-
--- GANSS Time Model IE consists of time offset and first and second order parameters to relate GNSS
--- specific system time to selected time reference
-SeqOfGANSSTimeModel ::= SEQUENCE (SIZE(1..7)) OF GANSSTimeModelElement
-
-GANSSTimeModelElement ::= SEQUENCE {
-	ganssTimeModelRefTime		INTEGER(0 .. 65535),
-	tA0		 TA0,
-	tA1		 TA1 OPTIONAL,
-	tA2		 TA2 OPTIONAL,
- gnssTOID INTEGER (0 .. 7),
- weekNumber INTEGER (0 .. 8191) OPTIONAL 
-}
-
--- GANSS time model parameter A0
-TA0 ::= INTEGER (-2147483648 .. 2147483647)
-
--- GANSS time model parameter A1
-TA1 ::= INTEGER (-8388608 .. 8388607)
-
--- GANSS time model parameter A2
-TA2 ::= INTEGER (-64 .. 63)
-
--- DGANSS Corrections IE
-GANSSDiffCorrections ::= SEQUENCE {
-	dganssRefTime		INTEGER (0 .. 119),	 -- DGANSS reference time
-
-	-- N_SGN_TYPE can be read from number of elements of sgnTypeList
-	sgnTypeList		 SeqOfSgnTypeElement
-}
-
-SeqOfSgnTypeElement ::= SEQUENCE (SIZE (1..3)) OF SgnTypeElement -- max three signals per GNSS
-
--- DGANSS signal type element, once per GNSS signal type included in DGANSS
-SgnTypeElement ::= SEQUENCE {
-	ganssSignalID		 GANSSSignalID OPTIONAL, -- signal type identity
- ganssStatusHealth INTEGER (0 .. 7),
-	-- N_SGN can be read from number of elements of dganssSgnList
- dganssSgnList SeqOfDGANSSSgnElement
-}
-
-GANSSSignalID ::= INTEGER (0 .. 3)	-- Coding according to Annex
-SeqOfDGANSSSgnElement ::= SEQUENCE (SIZE (1..16)) OF DGANSSSgnElement
-
--- number of correction for signals
-DGANSSSgnElement ::= SEQUENCE {
-	svID		 SVID, -- Satellite identity
-
---- Sequence number for GANSS Navigation Model that matches the DGANSS correction set
-	iod 			INTEGER (0 .. 1023),
-
-	-- User Differential Range Error
-	udre			INTEGER (0..3),		
-
-	-- Pseudo Range Correction, range is
-	-- -655.04 - +655.04,
-	pseudoRangeCor	INTEGER (-2047..2047), 	
-
-	-- Pseudo Range Rate Correction, range is
-	-- -4.064 - +4.064,
-	rangeRateCor	INTEGER (-127..127)
-}
-
-SVID ::= INTEGER (0 .. 63)	-- Coding according to Annex
-
--- GANSS Navigation Model IE
-GANSSNavModel ::= SEQUENCE {
- nonBroadcastIndFlag INTEGER (0 .. 1),
- toeMSB INTEGER (0 .. 31) OPTIONAL, -- 5 MSB of toe and toc 
- eMSB INTEGER (0 .. 127) OPTIONAL,
- sqrtAMBS INTEGER (0 .. 63) OPTIONAL,
-	ganssSatelliteList SeqOfGANSSSatelliteElement
-}
-
-SeqOfGANSSSatelliteElement ::= SEQUENCE (SIZE(1..32)) OF GANSSSatelliteElement
-
-GANSSSatelliteElement ::= SEQUENCE {
-	svID SVID,
- svHealth INTEGER (-7 .. 13), -- Coding according to Annex
- iod INTEGER (0 .. 1023), -- Coding according to Annex
- ganssClockModel GANSSClockModel, 
- ganssOrbitModel GANSSOrbitModel, 
- ...
-}
-
--- GANSS orbit model for the GNSS satellite according to the choice
-GANSSOrbitModel ::= CHOICE {
-	keplerianSet	 NavModel-KeplerianSet,	
- ...
-}
-
--- Navigation model in Keplerian parameters
-NavModel-KeplerianSet ::= SEQUENCE {
- keplerToeLSB INTEGER (0 .. 511), -- 9LSB are given in GANSSNavigationModel
-	keplerW			 INTEGER (-2147483648..2147483647),
-	keplerDeltaN	 INTEGER (-32768..32767),
-	keplerM0		 INTEGER (-2147483648..2147483647),
-	keplerOmegaDot	 INTEGER (-8388608..8388607),
-	keplerELSB 	 INTEGER (0..33554431),
-	keplerIDot		 INTEGER (-8192..8191),
-	keplerAPowerHalfLSB INTEGER (0.. 67108863),
-	keplerI0		 INTEGER (-2147483648..2147483647),
-	keplerOmega0 INTEGER (-2147483648..2147483647),
-	keplerCrs		 INTEGER (-32768..32767),
-	keplerCis		 INTEGER (-32768..32767),
-	keplerCus		 INTEGER (-32768..32767),
-	keplerCrc		 INTEGER (-32768..32767),
-	keplerCic		 INTEGER (-32768..32767),
-	keplerCuc		 INTEGER (-32768..32767)
-}
-
--- GANSS clock model for the GNSS satellite according to the choice
-GANSSClockModel ::= CHOICE {
-	standardClockModelList	 SeqOfStandardClockModelElement,	
- ...
-}
-
-SeqOfStandardClockModelElement ::= SEQUENCE (SIZE(1..2)) OF StandardClockModelElement
-
-StandardClockModelElement ::= SEQUENCE {
- stanClockTocLSB INTEGER (0 .. 511), -- 9LSB of time of clock
- stanClockAF2 INTEGER (-2048 .. 2047), 
- stanClockAF1 INTEGER (-131072 .. 131071), 
- stanClockAF0 INTEGER (-134217728 .. 134217727),
- stanClockTgd INTEGER (-512 .. 511) OPTIONAL,
- stanModelID INTEGER (0 .. 1) OPTIONAL,
- ...
-} 
-
--- GANSS Real-Time Integrity IE
-GANSSRealTimeIntegrity ::= SEQUENCE {
- -- list of bad signals
- -- NBS can be read from number of elements in SeqOf-BadSignalSet
- ganssBadSignalList SeqOfBadSignalElement
-}
-
-SeqOfBadSignalElement ::= SEQUENCE (SIZE(1..16)) OF BadSignalElement
-
-BadSignalElement ::= SEQUENCE {
- badSVID SVID, -- Coding according to Annex
- badSignalID INTEGER (0 .. 3) OPTIONAL -- Coding according to Annex
-}
-
-
--- GANSS Data Bit Assistance IE
-GANSSDataBitAssist ::= SEQUENCE {
- ganssTOD INTEGER (0 .. 59),
- svID SVID,
- ganssDataTypeID INTEGER (0 .. 2), -- Coding according to Annex
- -- list of navigation data bits
- -- N_BIT can be read from number of elements in SeqOf-DataBits
- ganssDataBits SeqOf-GANSSDataBits
-}
-
-SeqOf-GANSSDataBits ::= SEQUENCE (SIZE(1 .. 1024)) OF GANSSDataBit
-GANSSDataBit ::= INTEGER(0 .. 1)
-
--- GANSS Reference Measurement Assistance IE
--- Code and Doppler assistance from the network. 
-GANSSRefMeasurementAssist ::= SEQUENCE {
- ganssSignalID INTEGER (0 .. 3) OPTIONAL, -- Coding according to Annex
- ganssRefMeasAssitList SeqOfGANSSRefMeasurementElement
-}
-
-SeqOfGANSSRefMeasurementElement ::= SEQUENCE (SIZE(1 .. 16)) OF GANSSRefMeasurementElement
-
-GANSSRefMeasurementElement ::= SEQUENCE {
- svID SVID,
-	-- Doppler 0th order term,
-	-- -1024 m/s to 1023.5 m/s with 0.5 m/s resolution)
-	doppler0				INTEGER (-2048 .. 2047),	-- Coding according to Annex
-	additionalDoppler		AdditionalDopplerFields	 OPTIONAL,
-	codePhase				INTEGER (0 .. 1022),	 -- Code Phase in ms
-	intCodePhase			INTEGER (0 .. 127),	 -- Integer Code Phase in ms
-	codePhaseSearchWindow	INTEGER (0 .. 31),	 -- Code Phase Search Window, see Annex
-	additionalAngle			AddionalAngleFields		 OPTIONAL,
- ...
-}
-
-AdditionalDopplerFields ::= SEQUENCE {
-	-- Doppler 1st order term, -0.2 - +0.1 m/s2
-	doppler1				INTEGER (0..63),
-	dopplerUncertainty		INTEGER (0..4)
-}
-
--- GANSS Almanac Model IE
-GANSSAlmanacModel ::= SEQUENCE {
- weekNumber INTEGER (0 .. 255),
- svIDMask SVIDMASK,
- toa INTEGER (0 .. 255) OPTIONAL,
- ioda INTEGER (0 .. 3) OPTIONAL,
- ganssAlmanacList SeqOfGANSSAlmanacElement
-}
-
--- SV ID Mask, LSB for ID 1 and MSB for ID 36
-SVIDMASK ::= BIT STRING (SIZE (1..36))
-
-SeqOfGANSSAlmanacElement ::= SEQUENCE (SIZE(1 .. 36)) OF GANSSAlmanacElement
-
--- GANSS Almanac Model 
-GANSSAlmanacElement ::= CHOICE {
-	keplerianAlmanacSet	 Almanac-KeplerianSet,	
- ...
-}
-
--- Almanac parameters according to Keplerian parameters
-Almanac-KeplerianSet ::= SEQUENCE {
- 	kepAlmanacE			 INTEGER (0 .. 2047),
-	kepAlmanacDeltaI		INTEGER (-1024 .. 1023),
-	kepAlmanacOmegaDot		INTEGER (-1024 .. 1023),
- kepSVHealth INTEGER (0 .. 15), -- Coding according to Annex
-	kepAlmanacAPowerHalf	INTEGER (-65536 .. 65535),
-	kepAlmanacOmega0		INTEGER (-32768 .. 32767),
-	kepAlmanacW			 INTEGER (-32768 .. 32767),
-	kepAlmanacM0			INTEGER (-32768 .. 32767),
-	kepAlmanacAF0			INTEGER (-8192 .. 8191),
-	kepAlmanacAF1			INTEGER (-1024..1023)
-}
-
--- GANSS Universal Time Coordinate Model
-GANSSUTCModel ::= SEQUENCE {
-	ganssUtcA1			INTEGER (-8388608..8388607),
-	ganssUtcA0			INTEGER (-2147483648..2147483647),
-	ganssUtcTot			INTEGER (0..255),
-	ganssUtcWNt			INTEGER (0..255),
-	ganssUtcDeltaTls	INTEGER (-128..127),
-	ganssUtcWNlsf		INTEGER (0..255),
-	ganssUtcDN			INTEGER (-128..127),
-	ganssUtcDeltaTlsf	INTEGER (-128..127)
-}
-
---Required Measurement Request Response Time, range is 1 to 128 seconds. 
-RequiredResponseTime ::= INTEGER  (1..128)
-
-Rel-7-MsrPosition-Rsp-Extension ::= SEQUENCE {
-
-	velEstimate 	VelocityEstimate OPTIONAL,
- -- Horizontal Velocity
- -- Horizontal with Vertical Velocity
- -- Horizontal Velocity with Uncertainty
- -- Horizontal with Vertical Velocity and Uncertainty
- ganssLocationInfo GANSSLocationInfo OPTIONAL,
- ganssMeasureInfo GANSSMeasureInfo OPTIONAL,
-	...
--- Further Release 7 extensions here
-}
-
--- GANSS Location Information contains location estimate, time stamp with uncertainty 
--- and optionally Reference Frame field
-GANSSLocationInfo ::= SEQUENCE {
- referenceFrame ReferenceFrame OPTIONAL, -- Reference Frame Number
- ganssTODm GANSSTODm OPTIONAL, -- GNSS TOD modulo
- ganssTODFrac INTEGER (0 .. 16384) OPTIONAL, -- Coding according to Annex
-	ganssTODUncertainty GANSSTODUncertainty OPTIONAL, -- Coding according to Annex
- ganssTimeID INTEGER (0 .. 3) OPTIONAL, -- Coding according to Annex
-	fixType			 FixType,
- posData PositionData,
- stationaryIndication INTEGER(0 .. 1) OPTIONAL, -- '0' if moving or motion not known 
-	-- Possible shapes carried in posEstimate are
-	-- ellipsoid point,
-	-- ellipsoid point with uncertainty circle
-	-- ellipsoid point with uncertainty ellipse
-	-- ellipsoid point with altitude and uncertainty ellipsoid
-	posEstimate		 Ext-GeographicalInformation,
- ...
-}
-
-PositionData ::= BIT STRING {
- e-otd(0),
-	gps (1),
-	galileo (2) } (SIZE (3..16))
-
-
--- GANSS TOD modulo 1 hour
-GANSSTODm ::= INTEGER (0 .. 3599999)
-
-ReferenceFrame ::= SEQUENCE {
- referenceFN INTEGER (0 .. 65535),
-	-- Note that applicable range for referenceFN is 0 - 42431
- referenceFNMSB INTEGER (0 .. 63) OPTIONAL -- MSB of Reference Frame Number
-}
-
-
-
--- GANSS Measurement Information 
-GANSSMeasureInfo ::= SEQUENCE {
-	-- Measurement info elements
-	-- user has to make sure that in this element is number of elements
-	-- defined in reference BTS identity
- ganssMsrSetList SeqOfGANSS-MsrSetElement
-}
-SeqOfGANSS-MsrSetElement ::= SEQUENCE (SIZE(1..3)) OF GANSS-MsrSetElement
-
--- GANSS measurement information 1-3 times in a message
-GANSS-MsrSetElement ::= SEQUENCE {
- referenceFrame ReferenceFrame OPTIONAL, -- Reference Frame Number
- ganssTODm GANSSTODm OPTIONAL, -- GANSS TOD modulo
- deltaGNASSTOD INTEGER (0 .. 127) OPTIONAL,
-	ganssTODUncertainty GANSSTODUncertainty OPTIONAL, -- Coding accoring to Annex
-
- --N_SGN_TYPE can be read from number of elements of SeqOfGANSS-SgnTypeElement
- ganss-SgnTypeList SeqOfGANSS-SgnTypeElement
-}
-
--- Measurements can be returned up to 6 different signal types 
-SeqOfGANSS-SgnTypeElement ::= SEQUENCE (SIZE(1..6)) OF GANSS-SgnTypeElement
-
-GANSS-SgnTypeElement ::= SEQUENCE {
-	ganssSignalID		INTEGER (0 .. 15), -- Coding accroding to Annex
- --N_SGN can be read from number of elements of SeqOfGANSS-SgnElement
- ganss-SgnList SeqOfGANSS-SgnElement
-}
-
--- Measurements can be returned up to 16 per signal types 
-SeqOfGANSS-SgnElement ::= SEQUENCE (SIZE(1..16)) OF GANSS-SgnElement
-
-
-GANSS-SgnElement ::= SEQUENCE {
- svID SVID,
- cNo INTEGER (0 .. 63),
- mpathDet MpathIndic, -- Coding according to Annex
- carrierQualityInd INTEGER (0 .. 3) OPTIONAL, -- Coding according to Annex
- codePhase INTEGER (0 .. 2097151),
- integerCodePhase INTEGER (0 .. 63) OPTIONAL,
- codePhaseRMSError INTEGER (0..63), -- Coding accoring to Annex
- doppler INTEGER (-32768 .. 32767) OPTIONAL,
- adr INTEGER (0 .. 33554431) OPTIONAL
-}
-
-Rel7-AssistanceData-Extension ::= SEQUENCE {
- ganss-AssistData GANSS-AssistData OPTIONAL,
- ganssCarrierPhaseMeasurementRequest NULL OPTIONAL,
- ganssTODGSMTimeAssociationMeasurementRequest NULL OPTIONAL,
-	...
--- Possibly more extensions for Release 7 here
-}
-
-END
diff --git a/rrlp-ephemeris/asn1/RRLP-Messages.asn b/rrlp-ephemeris/asn1/RRLP-Messages.asn
deleted file mode 100644
index 79140e2..0000000
--- a/rrlp-ephemeris/asn1/RRLP-Messages.asn
+++ /dev/null
@@ -1,38 +0,0 @@
--- RRLP-Messages.asn
--- $Id$
--- Taken from 3GPP TS 44.031 V7.4.0 (2007-03)
--- http://www.3gpp.org/ftp/Specs/archive/44_series/44.031/44031-740.zip/44031-740.doc
---
--- 3.1 General Format of RRLP Message
---
-
-RRLP-Messages
--- { RRLP-messages }
-
-DEFINITIONS AUTOMATIC TAGS ::=
-
-BEGIN
-
-IMPORTS
-	MsrPosition-Req, MsrPosition-Rsp, AssistanceData,
-	ProtocolError
-FROM
-	RRLP-Components 	-- { RRLP-Components }
-;
-
-PDU ::= SEQUENCE {
-	referenceNumber			INTEGER (0..7),
-	component				RRLP-Component
-}
-
-RRLP-Component ::= CHOICE {
-	msrPositionReq			MsrPosition-Req,
-	msrPositionRsp			MsrPosition-Rsp,
-	assistanceData			AssistanceData,
-	assistanceDataAck		NULL,
-	protocolError			ProtocolError,
-	...
-
-}
-
-END
diff --git a/rrlp-ephemeris/asn1/patch-rrlp-components.diff b/rrlp-ephemeris/asn1/patch-rrlp-components.diff
deleted file mode 100644
index a5e55ae..0000000
--- a/rrlp-ephemeris/asn1/patch-rrlp-components.diff
+++ /dev/null
@@ -1,36 +0,0 @@
---- RRLP-Components.asn	2009-10-26 22:10:44.000000000 +0100
-+++ RRLP-Components.asn	2009-10-26 22:10:44.000000000 +0100
-@@ -18,16 +18,16 @@
- 	Ext-GeographicalInformation, VelocityEstimate
- FROM
- 	MAP-LCS-DataTypes {
--	ccitt identified-organization (4) etsi (0) mobileDomain (0)
--	gsm-Network (1) modules (3) map-LCS-DataTypes (25) version5 (5)}
-+	itu-t identified-organization (4) etsi (0) mobileDomain (0)
-+	gsm-Network (1) modules (3) map-LCS-DataTypes (25) version11 (11)}
- 
- 	ExtensionContainer
- FROM MAP-ExtensionDataTypes {
--	ccitt identified-organization (4) etsi (0) mobileDomain (0)
--	gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version4 (4)}
-+	itu-t identified-organization (4) etsi (0) mobileDomain (0)
-+	gsm-Network (1) modules (3) map-ExtensionDataTypes (21) version11 (11)}
- ;
- 
- -- Add here other ASN.1 definitions presented below
- -- in chapters 4 and 5.
- 
-@@ -305,11 +305,11 @@
- SystemInfoIndex ::= INTEGER (1..32)
- 
- CellIDAndLAC ::= SEQUENCE {
--	referenceLAC	LAC,				-- Location area code
-+	referenceLAC	LACID,				-- Location area code
- 	referenceCI		CellID				-- Cell identity
- }
- CellID ::= INTEGER (0..65535)
--LAC ::= INTEGER (0..65535)
-+LACID ::= INTEGER (0..65535)
- 
- -- OTD-MeasureInfo
- OTD-MeasureInfo ::= SEQUENCE {
diff --git a/rrlp-ephemeris/asn1c_patches/00_add_enumerated_verbose.diff b/rrlp-ephemeris/asn1c_patches/00_add_enumerated_verbose.diff
deleted file mode 100644
index 64c22a3..0000000
--- a/rrlp-ephemeris/asn1c_patches/00_add_enumerated_verbose.diff
+++ /dev/null
@@ -1,56 +0,0 @@
-Index: skeletons/NativeEnumerated.c
-===================================================================
---- skeletons/NativeEnumerated.c	(revision 1407)
-+++ skeletons/NativeEnumerated.c	(working copy)
-@@ -22,7 +22,7 @@
- 	"ENUMERATED",			/* The ASN.1 type is still ENUMERATED */
- 	"ENUMERATED",
- 	NativeInteger_free,
--	NativeInteger_print,
-+	NativeEnumerated_print,
- 	asn_generic_no_constraint,
- 	NativeInteger_decode_ber,
- 	NativeInteger_encode_der,
-@@ -205,3 +205,30 @@
- 	_ASN_ENCODED_OK(er);
- }
- 
-+int
-+NativeEnumerated_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
-+	asn_app_consume_bytes_f *cb, void *app_key) {
-+	asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
-+	const long *native = (const long *)sptr;
-+	char scratch[256];
-+	int ret;
-+
-+	(void)td;	/* Unused argument */
-+	(void)ilevel;	/* Unused argument */
-+
-+	if(native) {
-+		const asn_INTEGER_enum_map_t *map = INTEGER_map_value2enum(specs, *native);
-+		if (map && map->enum_len && map->enum_name) {
-+			ret = snprintf(scratch, sizeof(scratch),
-+				"%s", map->enum_name);
-+		} else {
-+			ret = snprintf(scratch, sizeof(scratch),
-+				(specs && specs->field_unsigned)
-+				? "%lu" : "%ld", *native);
-+		}
-+		assert(ret > 0 && (size_t)ret < sizeof(scratch));
-+		return (cb(scratch, ret, app_key) < 0) ? -1 : 0;
-+	} else {
-+		return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
-+	}
-+}
-Index: skeletons/NativeEnumerated.h
-===================================================================
---- skeletons/NativeEnumerated.h	(revision 1407)
-+++ skeletons/NativeEnumerated.h	(working copy)
-@@ -24,6 +24,7 @@
- xer_type_encoder_f NativeEnumerated_encode_xer;
- per_type_decoder_f NativeEnumerated_decode_uper;
- per_type_encoder_f NativeEnumerated_encode_uper;
-+asn_struct_print_f NativeEnumerated_print;
- 
- #ifdef __cplusplus
- }
diff --git a/rrlp-ephemeris/asn1c_patches/01_fix_per_encoding_dieter.diff b/rrlp-ephemeris/asn1c_patches/01_fix_per_encoding_dieter.diff
deleted file mode 100644
index a09c201..0000000
--- a/rrlp-ephemeris/asn1c_patches/01_fix_per_encoding_dieter.diff
+++ /dev/null
@@ -1,17 +0,0 @@
-Index: skeletons/per_support.c
-===================================================================
---- skeletons/per_support.c	(revision 1407)
-+++ skeletons/per_support.c	(working copy)
-@@ -336,7 +336,12 @@
- 		buf[3] = bits;
- 	else {
- 		ASN_DEBUG("->[PER out split %d]", obits);
-+#if 1 // Dieter
-+		po->nboff -= obits; // undo incrementation from a few lines above
-+		per_put_few_bits(po, bits >> (obits - 24), 24); // shift according to the rest of the bits 
-+#else		
- 		per_put_few_bits(po, bits >> 8, 24);
-+#endif
- 		per_put_few_bits(po, bits, obits - 24);
- 		ASN_DEBUG("<-[PER out split %d]", obits);
- 	}
diff --git a/rrlp-ephemeris/data.ubx b/rrlp-ephemeris/data.ubx
deleted file mode 100644
index 07cdddc..0000000
--- a/rrlp-ephemeris/data.ubx
+++ /dev/null
Binary files differ
diff --git a/rrlp-ephemeris/get-test-data.sh b/rrlp-ephemeris/get-test-data.sh
deleted file mode 100755
index 169f43c..0000000
--- a/rrlp-ephemeris/get-test-data.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh
-
-DEV=$1
-OUTF=$2
-
-# Change mode
-echo -en "\$PUBX,41,1,0001,0001,9600,0*14\r\n" > ${DEV}
-
-# Wait a little
-sleep 2
-
-# Start dump
-echo -en "\xb5\x62\x01\x02\x00\x00\x03\x0a" | \
-	socat -t5 ${DEV},b9600,raw,clocal=1,echo=0 - > ${OUTF}
-echo -en "\xb5\x62\x0b\x10\x00\x00\x1b\x5c" | \
-	socat -t10 ${DEV},b9600,raw,clocal=1,echo=0 - >> ${OUTF}
-
diff --git a/rrlp-ephemeris/gpl-2.0.txt b/rrlp-ephemeris/gpl-2.0.txt
deleted file mode 100644
index d511905..0000000
--- a/rrlp-ephemeris/gpl-2.0.txt
+++ /dev/null
@@ -1,339 +0,0 @@
-		    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.
diff --git a/rrlp-ephemeris/gpl-3.0.txt b/rrlp-ephemeris/gpl-3.0.txt
deleted file mode 100644
index 94a9ed0..0000000
--- a/rrlp-ephemeris/gpl-3.0.txt
+++ /dev/null
@@ -1,674 +0,0 @@
-                    GNU GENERAL PUBLIC LICENSE
-                       Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                            Preamble
-
-  The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
-  The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works.  By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.  We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors.  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
-them 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 prevent others from denying you
-these rights or asking you to surrender the rights.  Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received.  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.
-
-  Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
-  For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software.  For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
-  Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so.  This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software.  The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable.  Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products.  If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
-  Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary.  To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                       TERMS AND CONDITIONS
-
-  0. Definitions.
-
-  "This License" refers to version 3 of the GNU General Public License.
-
-  "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
-  "The Program" refers to any copyrightable work licensed under this
-License.  Each licensee is addressed as "you".  "Licensees" and
-"recipients" may be individuals or organizations.
-
-  To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy.  The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
-  A "covered work" means either the unmodified Program or a work based
-on the Program.
-
-  To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy.  Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
-  To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies.  Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
-  An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License.  If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
-  1. Source Code.
-
-  The "source code" for a work means the preferred form of the work
-for making modifications to it.  "Object code" means any non-source
-form of a work.
-
-  A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
-  The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form.  A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
-  The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities.  However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work.  For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
-  The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
-  The Corresponding Source for a work in source code form is that
-same work.
-
-  2. Basic Permissions.
-
-  All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met.  This License explicitly affirms your unlimited
-permission to run the unmodified Program.  The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work.  This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
-  You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force.  You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright.  Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
-  Conveying under any other circumstances is permitted solely under
-the conditions stated below.  Sublicensing is not allowed; section 10
-makes it unnecessary.
-
-  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-  No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
-  When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
-  4. Conveying Verbatim Copies.
-
-  You may convey 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;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
-  You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
-  5. Conveying Modified Source Versions.
-
-  You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
-    a) The work must carry prominent notices stating that you modified
-    it, and giving a relevant date.
-
-    b) The work must carry prominent notices stating that it is
-    released under this License and any conditions added under section
-    7.  This requirement modifies the requirement in section 4 to
-    "keep intact all notices".
-
-    c) You must license the entire work, as a whole, under this
-    License to anyone who comes into possession of a copy.  This
-    License will therefore apply, along with any applicable section 7
-    additional terms, to the whole of the work, and all its parts,
-    regardless of how they are packaged.  This License gives no
-    permission to license the work in any other way, but it does not
-    invalidate such permission if you have separately received it.
-
-    d) If the work has interactive user interfaces, each must display
-    Appropriate Legal Notices; however, if the Program has interactive
-    interfaces that do not display Appropriate Legal Notices, your
-    work need not make them do so.
-
-  A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit.  Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
-  6. Conveying Non-Source Forms.
-
-  You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
-    a) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by the
-    Corresponding Source fixed on a durable physical medium
-    customarily used for software interchange.
-
-    b) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by a
-    written offer, valid for at least three years and valid for as
-    long as you offer spare parts or customer support for that product
-    model, to give anyone who possesses the object code either (1) a
-    copy of the Corresponding Source for all the software in the
-    product that is covered by this License, on a durable physical
-    medium customarily used for software interchange, for a price no
-    more than your reasonable cost of physically performing this
-    conveying of source, or (2) access to copy the
-    Corresponding Source from a network server at no charge.
-
-    c) Convey individual copies of the object code with a copy of the
-    written offer to provide the Corresponding Source.  This
-    alternative is allowed only occasionally and noncommercially, and
-    only if you received the object code with such an offer, in accord
-    with subsection 6b.
-
-    d) Convey the object code by offering access from a designated
-    place (gratis or for a charge), and offer equivalent access to the
-    Corresponding Source in the same way through the same place at no
-    further charge.  You need not require recipients to copy the
-    Corresponding Source along with the object code.  If the place to
-    copy the object code is a network server, the Corresponding Source
-    may be on a different server (operated by you or a third party)
-    that supports equivalent copying facilities, provided you maintain
-    clear directions next to the object code saying where to find the
-    Corresponding Source.  Regardless of what server hosts the
-    Corresponding Source, you remain obligated to ensure that it is
-    available for as long as needed to satisfy these requirements.
-
-    e) Convey the object code using peer-to-peer transmission, provided
-    you inform other peers where the object code and Corresponding
-    Source of the work are being offered to the general public at no
-    charge under subsection 6d.
-
-  A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
-  A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling.  In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage.  For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product.  A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
-  "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source.  The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
-  If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information.  But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
-  The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed.  Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
-  Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
-  7. Additional Terms.
-
-  "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law.  If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
-  When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it.  (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.)  You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
-  Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
-    a) Disclaiming warranty or limiting liability differently from the
-    terms of sections 15 and 16 of this License; or
-
-    b) Requiring preservation of specified reasonable legal notices or
-    author attributions in that material or in the Appropriate Legal
-    Notices displayed by works containing it; or
-
-    c) Prohibiting misrepresentation of the origin of that material, or
-    requiring that modified versions of such material be marked in
-    reasonable ways as different from the original version; or
-
-    d) Limiting the use for publicity purposes of names of licensors or
-    authors of the material; or
-
-    e) Declining to grant rights under trademark law for use of some
-    trade names, trademarks, or service marks; or
-
-    f) Requiring indemnification of licensors and authors of that
-    material by anyone who conveys the material (or modified versions of
-    it) with contractual assumptions of liability to the recipient, for
-    any liability that these contractual assumptions directly impose on
-    those licensors and authors.
-
-  All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10.  If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term.  If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
-  If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
-  Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
-  8. Termination.
-
-  You may not propagate or modify a covered work except as expressly
-provided under this License.  Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
-  However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
-  Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
-  Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License.  If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
-  9. Acceptance Not Required for Having Copies.
-
-  You are not required to accept this License in order to receive or
-run a copy of the Program.  Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance.  However,
-nothing other than this License grants you permission to propagate or
-modify any covered work.  These actions infringe copyright if you do
-not accept this License.  Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
-  10. Automatic Licensing of Downstream Recipients.
-
-  Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License.  You are not responsible
-for enforcing compliance by third parties with this License.
-
-  An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations.  If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
-  You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License.  For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
-  11. Patents.
-
-  A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based.  The
-work thus licensed is called the contributor's "contributor version".
-
-  A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version.  For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
-  Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
-  In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement).  To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
-  If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients.  "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
-  If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
-  A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License.  You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
-  Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
-  12. No Surrender of Others' Freedom.
-
-  If 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 convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all.  For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
-  13. Use with the GNU Affero General Public License.
-
-  Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work.  The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
-  14. Revised Versions of this License.
-
-  The Free Software Foundation may publish revised and/or new versions of
-the GNU 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 that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation.  If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
-  If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
-  Later license versions may give you additional or different
-permissions.  However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
-  15. Disclaimer of Warranty.
-
-  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.
-
-  16. Limitation of Liability.
-
-  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-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.
-
-  17. Interpretation of Sections 15 and 16.
-
-  If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
-                     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
-state 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 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/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
-  If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
-    <program>  Copyright (C) <year>  <name of author>
-    This program 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, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
-  You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
-
-  The GNU 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.  But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/rrlp-ephemeris/gps.c b/rrlp-ephemeris/gps.c
deleted file mode 100644
index c235748..0000000
--- a/rrlp-ephemeris/gps.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * gps.c
- *
- * A few utility functions to deal with low level GPS data
- *
- *
- * Copyright (C) 2009  Sylvain Munaut <tnt@246tNt.com>
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include "gps.h"
-
-
-#define GET_FIELD_U(w, nb, pos) (((w) >> (pos)) & ((1<<(nb))-1))
-#define GET_FIELD_S(w, nb, pos) (((int)((w) << (32-(nb)-(pos)))) >> (32-(nb)))
-
-/*
- * Unpacks GPS Subframe 1,2,3 payloads (3 * 8 words)
- *
- * Note: eph->sv_id is not filled here since not present in those subframes
- *
- * (no parity bit checking is done, only the lower 24 bits of each word
- *  are used)
- */
-int
-gps_unpack_sf123(uint32_t *sf, struct gps_ephemeris_sv *eph)
-{
-	uint32_t *sf1 = &sf[0];
-	uint32_t *sf2 = &sf[8];
-	uint32_t *sf3 = &sf[16];
-
-	int iode1, iode2;
-
-	eph->week_no	= GET_FIELD_U(sf1[0], 10, 14);
-	eph->code_on_l2	= GET_FIELD_U(sf1[0],  2, 12);
-	eph->sv_ura	= GET_FIELD_U(sf1[0],  4,  8);
-	eph->sv_health	= GET_FIELD_U(sf1[0],  6,  2);
-	eph->l2_p_flag	= GET_FIELD_U(sf1[1],  1, 23);
-	eph->t_gd	= GET_FIELD_S(sf1[4],  8,  0);
-	eph->iodc	= (GET_FIELD_U(sf1[0],  2,  0) << 8) | \
-	                   GET_FIELD_U(sf1[5],  8, 16);
-	eph->t_oc	= GET_FIELD_U(sf1[5], 16,  0);
-	eph->a_f2	= GET_FIELD_S(sf1[6],  8, 16);
-	eph->a_f1	= GET_FIELD_S(sf1[6], 16,  0);
-	eph->a_f0	= GET_FIELD_S(sf1[7], 22,  2);
-
-	iode1		= GET_FIELD_U(sf2[0],  8, 16);
-	eph->c_rs	= GET_FIELD_S(sf2[0], 16,  0);
-	eph->delta_n	= GET_FIELD_S(sf2[1], 16,  8);
-	eph->m_0	= (GET_FIELD_S(sf2[1],  8,  0) << 24) | \
-	                   GET_FIELD_U(sf2[2], 24,  0);
-	eph->c_uc	= GET_FIELD_S(sf2[3], 16,  8);
-	eph->e		= (GET_FIELD_U(sf2[3],  8,  0) << 24) | \
-	                   GET_FIELD_U(sf2[4], 24,  0);
-	eph->c_us	= GET_FIELD_S(sf2[5], 16,  8);
-	eph->a_powhalf	= (GET_FIELD_U(sf2[5],  8,  0) << 24) | \
-	                   GET_FIELD_U(sf2[6], 24,  0);
-	eph->t_oe	= GET_FIELD_U(sf2[7], 16,  8);
-	eph->fit_flag	= GET_FIELD_U(sf2[7],  1,  7);
-
-	eph->c_ic	= GET_FIELD_S(sf3[0], 16,  8);
-	eph->omega_0	= (GET_FIELD_S(sf3[0],  8,  0) << 24) | \
-	                   GET_FIELD_U(sf3[1], 24,  0);
-	eph->c_is	= GET_FIELD_S(sf3[2], 16,  8);
-	eph->i_0	= (GET_FIELD_S(sf3[2],  8,  0) << 24) | \
-	                   GET_FIELD_U(sf3[3], 24,  0);
-	eph->c_rc	= GET_FIELD_S(sf3[4], 16,  8);
-	eph->w		= (GET_FIELD_S(sf3[4],  8,  0) << 24) | \
-	                   GET_FIELD_U(sf3[5], 24,  0);
-	eph->omega_dot	= GET_FIELD_S(sf3[6], 24,  0);
-	iode2		= GET_FIELD_U(sf3[7],  8, 16);
-	eph->idot	= GET_FIELD_S(sf3[7], 14,  2);
-
-	eph->_rsvd1	= GET_FIELD_U(sf1[1], 23,  0);
-	eph->_rsvd2	= GET_FIELD_U(sf1[2], 24,  0);
-	eph->_rsvd3	= GET_FIELD_U(sf1[3], 24,  0);
-	eph->_rsvd4	= GET_FIELD_U(sf1[4], 16,  8);
-	eph->aodo	= GET_FIELD_U(sf2[7],  5,  2);
-
-	/* Check & cross-validate iodc[7:0], iode1, iode2 */
-	if ((iode1 != iode2) || (iode1 != (eph->iodc & 0xff)))
-		return -1;
-
-	return 0;
-}
-
-
-/*
- * Unpacks GPS Subframe 4 or 5 Almanac pages payload (8 words)
- *
- * (no parity bit checking is done, only the lower 24 bits of each word
- *  are used)
- */
-int
-gps_unpack_sf45_almanac(uint32_t *sf, struct gps_almanac_sv *alm)
-{
-	alm->sv_id      = GET_FIELD_U(sf[0],  6, 16);
-
-	alm->e		= GET_FIELD_U(sf[0], 16,  0);
-	alm->t_oa	= GET_FIELD_U(sf[1],  8, 16);
-	alm->ksii	= GET_FIELD_S(sf[1], 16,  0);
-	alm->omega_dot	= GET_FIELD_S(sf[2], 16,  8);
-	alm->sv_health	= GET_FIELD_U(sf[2],  8,  0);
-	alm->a_powhalf	= GET_FIELD_U(sf[3], 24,  0);
-	alm->omega_0	= GET_FIELD_S(sf[4], 24,  0);
-	alm->w		= GET_FIELD_S(sf[5], 24,  0);
-	alm->m_0	= GET_FIELD_S(sf[6], 24,  0);
-	alm->a_f0	= (GET_FIELD_S(sf[7], 8, 16) << 3) | \
-	                   GET_FIELD_U(sf[7], 3,  2);
-	alm->a_f1	= GET_FIELD_S(sf[7], 11,  5);
-
-	return 0;
-}
-
diff --git a/rrlp-ephemeris/gps.h b/rrlp-ephemeris/gps.h
deleted file mode 100644
index 241b9d7..0000000
--- a/rrlp-ephemeris/gps.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * gps.h
- *
- * Header to deal with low level GPS data
- *
- *
- * Copyright (C) 2009  Sylvain Munaut <tnt@246tNt.com>
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GPS_H__
-#define __GPS_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdint.h>
-
-
-#define MAX_SV	64
-
-
-/* Ionosperic model data */
-struct gps_ionosphere_model {
-			/* #bits  Scale factor  Effective  Units            */
-			/*           (LSB)       range                      */
-
-	int alpha_0;	/* s 8       2^-30                 seconds          */
-	int alpha_1;	/* s 8       2^-27                 s / semi-circles */
-	int alpha_2;	/* s 8       2^-24                 s / (semi-circles)^2 */
-	int alpha_3;	/* s 8       2^-24                 s / (semi-circles)^3 */
-	int beta_0;	/* s 8       2^11                  seconds          */
-	int beta_1;	/* s 8       2^14                  s / semi-circles */
-	int beta_2;	/* s 8       2^16                  s / (semi-circles)^2 */
-	int beta_3;	/* s 8       2^16                  s / (semi-circles)^3 */
-};
-
-
-/* UTC model data */
-struct gps_utc_model {
-			/* #bits  Scale factor  Effective  Units            */
-			/*           (LSB)       range                      */
-
-	int a0;		/* s 32      2^-30                 seconds          */
-	int a1;		/* s 24      2^-50                 seconds / seconds */
-	int delta_t_ls;	/* s  8      1                     seconds          */
-	int t_ot;	/* u  8      2^12       602,112    seconds          */
-	int wn_t;	/* u  8      1                     weeks            */
-	int wn_lsf;	/* u  8      1                     weeks            */
-	int dn;		/* u  8      1                7    days             */
-	int delta_t_lsf;/* s  8      1                     seconds          */
-};
-
-
-/* Almanach data */
-struct gps_almanac_sv {
-	int sv_id;
-	int sv_health;
-
-			/* #bits  Scale factor  Effective  Units            */
-			/*           (LSB)       range                      */
-
-	int e;		/* u 16      2^-21                                  */
-	int t_oa;	/* u  8      2^12       602,112    seconds          */
-	int ksii;	/* s 16      2^-19                 semi-circles     */
-	int omega_dot;	/* s 16      2^-38                 semi-circles / s */
-	int a_powhalf;	/* u 24      2^-11                 meters           */
-	int omega_0;	/* s 24      2^-23                 semi-circles     */
-	int w;		/* s 24      2^-23                 semi-circles     */
-	int m_0;	/* s 24      2^-23                 semi-circles     */
-	int a_f0;	/* s 11      2^-20                 seconds          */
-	int a_f1;	/* s 11      2^-38                 seconds / seconds */
-};
-
-struct gps_almanac {
-	int wna;
-	int n_sv;
-	struct gps_almanac_sv svs[MAX_SV];
-};
-
-
-/* Ephemeris data */
-struct gps_ephemeris_sv {
-	int sv_id;
-
-			/* #bits  Scale factor  Effective  Units            */
-			/*           (LSB)       range                      */
-
-	int code_on_l2;	/* u  2      1                     /                */
-	int week_no;	/* u 10      1                     week             */
-	int l2_p_flag;	/* u  1      1                     /                */
-	int sv_ura;	/* u  4      /                     /                */
-	int sv_health;	/* u  6      /                     /                */
-	int t_gd;	/* s  8      2^-31                 seconds          */
-	int iodc;	/* u 10      /                     /                */
-	int t_oc;	/* u 16      2^4        604,784    seconds          */
-	int a_f2;	/* s  8      2^-55                 sec / sec^2      */
-	int a_f1;	/* s 16      2^-43                 sec / sec        */
-	int a_f0;	/* s 22      2^-31                 seconds          */
-
-	int c_rs;	/* s 16      2^-5                  meters           */
-	int delta_n;	/* s 16      2^-43                 semi-circles / s */
-	int m_0;	/* s 32      2^-31                 semi-circles     */
-	int c_uc;	/* s 16      2^-29                 radians          */
-	unsigned int e;	/* u 32      2^-33      0.03       /                */
-	int c_us;	/* s 16      2^-29                 radians          */
-	unsigned int a_powhalf; /* u 32  2^-19             meters^(1/2)     */
-	int t_oe;	/* u 16      2^4        604,784    seconds          */
-	int fit_flag;	/* u  1      /                     /                */
-
-	int c_ic;	/* s 16      2^-29                 radians          */
-	int omega_0;	/* s 32      2^-31                 semi-circles     */
-	int c_is;	/* s 16      2^-29                 radians          */
-	int i_0;	/* s 32      2^-31                 semi-circles     */
-	int c_rc;	/* s 16      2^-5                  meters           */
-	int w;		/* s 32      2^-31                 semi-circles     */
-	int omega_dot;	/* s 24      2^-43                 semi-circles / s */
-	int idot;	/* s 14      2^-43                 semi-circles / s */
-
-	int _rsvd1;	/* 23 bits */
-	int _rsvd2;	/* 24 bits */
-	int _rsvd3;	/* 24 bits */
-	int _rsvd4;	/* 16 bits */
-	int aodo;	/* 8 bits  Not sure it needs to be here ... */
-};
-
-struct gps_ephemeris {
-	int n_sv;
-	struct gps_ephemeris_sv svs[MAX_SV];
-};
-
-
-/* Reference position */
-struct gps_ref_pos {	/* WSG84 ellipsoid */
-	double latitude;	/* deg */
-	double longitude;	/* deg */
-	double altitude;	/* m above ellipsoid */
-};
-
-
-/* Reference time */
-struct gps_ref_time {
-	int wn;			/* GPS week number */
-	double tow;		/* in seconds */
-};
-
-
-/* All assist data */
-#define GPS_FIELD_IONOSPHERE	(1<<0)
-#define GPS_FIELD_UTC		(1<<1)
-#define GPS_FIELD_ALMANAC	(1<<2)
-#define GPS_FIELD_EPHEMERIS	(1<<3)
-#define GPS_FIELD_REFPOS	(1<<4)
-#define GPS_FIELD_REFTIME	(1<<5)
-
-struct gps_assist_data {
-	int fields;
-	struct gps_ionosphere_model	ionosphere;
-	struct gps_utc_model		utc;
-	struct gps_almanac		almanac;
-	struct gps_ephemeris		ephemeris;
-	struct gps_ref_pos		ref_pos;
-	struct gps_ref_time		ref_time;
-};
-
-
-/* GPS Subframe utility methods (see gps.c for details) */
-int gps_unpack_sf123(uint32_t *sf, struct gps_ephemeris_sv *eph);
-int gps_unpack_sf45_almanac(uint32_t *sf, struct gps_almanac_sv *alm);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __GPS_H__ */
-
diff --git a/rrlp-ephemeris/main.c b/rrlp-ephemeris/main.c
deleted file mode 100644
index bb025a2..0000000
--- a/rrlp-ephemeris/main.c
+++ /dev/null
@@ -1,99 +0,0 @@
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "gps.h"
-#include "ubx.h"
-#include "ubx-parse.h"
-#include "rrlp.h"
-
-static int
-do_ubx_read(struct gps_assist_data *gps, const char *filename)
-{
-	int rv, fd, i;
-	struct stat st;
-	void *buf;
-
-	/* Load file */
-	fd = open(filename, O_RDONLY);
-	if (fd < 0)
-		return -1;
-
-	rv = fstat(fd, &st);
-	if (rv < 0) {
-		close(fd);
-		return -1;
-	}
-
-	buf = malloc(st.st_size);
-	if (!buf) {
-		close(fd);
-		return -1;
-	}
-
-	rv = read(fd, buf, st.st_size);
-	if (rv != st.st_size) {
-		free(buf);
-		close(fd);
-		return -1;
-	}
-
-	/* Parse each message */
-	for (i=0; i<st.st_size;) {
-		int rv;
-		rv = ubx_msg_dispatch(ubx_parse_dt, buf + i, st.st_size - i, gps);
-		if (rv < 0)
-			i++;	/* Invalid message: try one byte later */
-		else
-			i += rv;
-	}
-
-	/* Done */
-	free(buf);
-	close(fd);
-
-	return 0;
-}
-
-static int
-do_rrlp(struct gps_assist_data *gps)
-{
-	struct rrlp_assist_req ar;
-	void *pdus[64];
-	int len[64];
-	int i, rv;
-
-	char *test = "\x28\x00\x80\x10\x01\x32\x00\x19\x4F\x07\x15\x04";
-
-	rrlp_decode_assistance_request(&ar, test, 12);
-	printf("%08x %016llx\n", ar.req_elems, (long long unsigned) ar.eph_svs);
-
-	ar.req_elems = -1;
-	ar.eph_svs = -1LL;
-	rv = rrlp_gps_assist_pdus(gps, &ar, pdus, len, 64);
-	printf("%d\n", rv);
-	for (i=0; i<rv; i++) {
-		printf("%p %d\n", pdus[i], len[i]);
-	}
-	return 0;
-}
-
-int main(int argc, char *argv[])
-{
-	struct gps_assist_data gps;
-	int rv;
-
-	memset(&gps, 0x00, sizeof(gps));
-
-	rv = do_ubx_read(&gps, "data.ubx");
-	
-	rv = do_rrlp(&gps);
-
-	return 0;
-}
-
diff --git a/rrlp-ephemeris/rrlp.c b/rrlp-ephemeris/rrlp.c
deleted file mode 100644
index e60c3ab..0000000
--- a/rrlp-ephemeris/rrlp.c
+++ /dev/null
@@ -1,648 +0,0 @@
-/*
- * rrlp.c
- *
- * RRLP implementation
- *
- *
- * Copyright (C) 2009  Sylvain Munaut <tnt@246tNt.com>
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include <errno.h>
-#include <math.h>
-
-#include "gps.h"
-#include "rrlp.h"
-
-#include <PDU.h>
-#include <GPS-AssistData.h>
-#include <NavigationModel.h>
-#include <IonosphericModel.h>
-#include <UTCModel.h>
-#include <Almanac.h>
-#include <RefLocation.h>
-#include <ReferenceTime.h>
-
-
-/* ------------------------------------------------------------------------ */
-/* RRLP Assistance request decoding                                         */
-/* ---------------------------------------------------------------------{{{ */
-/* Decode and validate the assistance data request messages.
- * See section 10.10 of
- *  . ETSI TS 149 031 V8.1.0 (2009-01)
- *  . 3GPP TS 49.031 version 8.1.0 Release 8
- */
-
-/* Packed structure from 49.031 spec (RGA = Request GPS Assistance) */
-
-#define RRLP_RGA0_ALMANAC	(1<<0)
-#define RRLP_RGA0_UTC_MODEL	(1<<1)
-#define RRLP_RGA0_IONO_MODEL	(1<<2)
-#define RRLP_RGA0_NAV_MODEL	(1<<3)
-#define RRLP_RGA0_DGPS		(1<<4)
-#define RRLP_RGA0_REF_LOC	(1<<5)
-#define RRLP_RGA0_REF_TIME	(1<<6)
-#define RRLP_RGA0_ACQ_ASSIST	(1<<7)
-
-#define RRLP_RGA1_REALTIME_INT	(1<<0)
-#define RRLP_RGA1_EPH_EXT	(1<<1)
-#define RRLP_RGA1_EPH_EXT_CHECK	(1<<2)
-
-struct rrlp_rga_hdr {
-	uint8_t items0;
-	uint8_t items1;
-} __attribute__((packed));
-
-struct rrlp_rga_eph_sv {
-	uint8_t sv_id;		/* [7:6] reserved, [5:0] sv_id */
-	uint8_t iode;		/* latest eph in the MS memory in hours */
-} __attribute__((packed));
-
-struct rrlp_rga_eph {
-	uint8_t wn_hi;		/* [7:6] = wn[9:8] */
-	uint8_t wn_lo;		/* wn[7:0] */
-	uint8_t toe;		/* latest eph in the MS memory in hours */
-	uint8_t nsat_tmtoe;	/* [7:4] nstat, [3:0] T-Toe limit */
-	struct rrlp_rga_eph_sv svs[0];
-} __attribute__((packed));
-
-struct rrlp_rga_eph_ext {
-	uint8_t validity;	/* in 4 hours units */
-} __attribute__((packed));
-
-struct rrlp_rga_eph_ext_check {
-		/* weeks are in gps week modulo 4 */
-	uint8_t wn_begin_end;	/* [7:4] begin, [3:0] end */
-	uint8_t tow_begin;
-	uint8_t tow_end;
-} __attribute__((packed));
-
-
-/* Parsing function */
-
-int
-rrlp_decode_assistance_request(
-	struct rrlp_assist_req *ar,
-	void *req, int req_len)
-{
-	struct rrlp_rga_hdr *hdr = NULL;
-	struct rrlp_rga_eph *eph = NULL;
-	struct rrlp_rga_eph_ext *eph_ext = NULL;
-	struct rrlp_rga_eph_ext_check *eph_ext_check = NULL;
-	int p = 0;
-
-	/* Reset */
-	ar->req_elems = 0;
-	ar->eph_svs = 0;
-
-	/* Parse message */
-	hdr = req;
-	p += sizeof(struct rrlp_rga_hdr);
-	if (p > req_len)
-		return -1;
-
-	if (hdr->items0 & RRLP_RGA0_NAV_MODEL) {
-		eph = req + p;
-		p += sizeof(struct rrlp_rga_eph);
-		if (p > req_len)
-			return -1;
-		p += (eph->nsat_tmtoe >> 4) * sizeof(struct rrlp_rga_eph_sv);
-		if (p > req_len)
-			return -1;
-	}
-
-	if (hdr->items1 & RRLP_RGA1_EPH_EXT) {
-		eph_ext = req + p;
-		p += sizeof(struct rrlp_rga_eph_ext);
-		if (p > req_len)
-			return -1;
-	}
-
-	if (hdr->items1 & RRLP_RGA1_EPH_EXT_CHECK) {
-		eph_ext_check = req + p;
-		p += sizeof(struct rrlp_rga_eph_ext_check);
-		if (p > req_len)
-			return -1;
-	}
-
-	if (p != req_len)
-		return -2; /* not all bytes consumed ??? */
-
-	/* Print a warning for unsupported requests */
-	if ((eph_ext != NULL) ||
-	    (eph_ext_check != NULL) ||
-	    (hdr->items0 & (RRLP_RGA0_DGPS | RRLP_RGA0_ACQ_ASSIST)) ||
-	    (hdr->items1 & RRLP_RGA1_REALTIME_INT)) {
-		fprintf(stderr, "[w] Unsupported assistance data requested, ignored ...\n");
-	}
-
-	/* Copy the request */
-	if (hdr->items0 & RRLP_RGA0_ALMANAC)
-		ar->req_elems |= RRLP_AR_ALMANAC;
-
-	if (hdr->items0 & RRLP_RGA0_UTC_MODEL)
-		ar->req_elems |= RRLP_AR_UTC_MODEL;
-
-	if (hdr->items0 & RRLP_RGA0_IONO_MODEL)
-		ar->req_elems |= RRLP_AR_IONO_MODEL;
-
-	if (hdr->items0 & RRLP_RGA0_REF_LOC)
-		ar->req_elems |= RRLP_AR_REF_LOC;
-
-	if (hdr->items0 & RRLP_RGA0_REF_TIME)
-		ar->req_elems |= RRLP_AR_REF_TIME;
-
-	if (hdr->items0 & RRLP_RGA0_NAV_MODEL) {
-		int i, n_svs = eph->nsat_tmtoe >> 4;
-		ar->req_elems |= RRLP_AR_EPHEMERIS;
-		for (i=0; i<n_svs; i++)
-			ar->eph_svs |= (1ULL << (eph->svs[i].sv_id - 1));
-	}
-
-	return 0;
-}
-
-/* }}} */
-
-
-/* ------------------------------------------------------------------------ */
-/* RRLP elements fill                                                       */
-/* ---------------------------------------------------------------------{{{ */
-
-	/* Helpers */
-
-static void
-_ts_23_032_store_latitude(double lat, uint8_t *b)
-{
-	uint32_t x;
-	x = (uint32_t) floor(fabs(lat/90.0) * ((double)(1<<23)));
-	if (x >= (1<<23))
-		x = (1<<23) - 1;
-	if (lat < 0.0)
-		x |= (1<<23);
-	b[0] = (x >> 16) & 0xff;
-	b[1] = (x >>  8) & 0xff;
-	b[2] =  x        & 0xff;
-}
-
-static void
-_ts_23_032_store_longitude(double lon, uint8_t *b)
-{
-	int32_t x;
-	x = floor((lon/360.0) * ((double)(1<<24)));
-	if (x >= (1<<23))
-		x = 0x007fffff;
-	else if (x < -(1<<23))
-		x = 0x00800000;
-	b[0] = (x >> 16) & 0xff;
-	b[1] = (x >>  8) & 0xff;
-	b[2] =  x        & 0xff;
-}
-
-static void
-_ts_23_032_store_altitude(double alt, uint8_t *b)
-{
-	int alt_i = (int)fabs(alt);
-	b[0] = ((alt_i >> 8) & 0x7f) | (alt<0.0 ? 0x80 : 0x00);
-	b[1] = alt_i & 0xff;
-}
-
-
-	/* Fill methods */
-
-static void
-_rrlp_fill_navigation_model_element(
-	struct NavModelElement *rrlp_nme,
-	struct gps_ephemeris_sv *gps_eph_sv)
-{
-	struct UncompressedEphemeris *rrlp_eph;
-
-	rrlp_nme->satStatus.present = SatStatus_PR_newSatelliteAndModelUC;
-	rrlp_nme->satelliteID = gps_eph_sv->sv_id;
-
-	rrlp_eph = &rrlp_nme->satStatus.choice.newSatelliteAndModelUC;
-
-	rrlp_eph->ephemCodeOnL2   = gps_eph_sv->code_on_l2;
-	rrlp_eph->ephemURA        = gps_eph_sv->sv_ura;
-	rrlp_eph->ephemSVhealth   = gps_eph_sv->sv_health;
-	rrlp_eph->ephemIODC       = gps_eph_sv->iodc;
-	rrlp_eph->ephemL2Pflag    = gps_eph_sv->l2_p_flag;
-	rrlp_eph->ephemTgd        = gps_eph_sv->t_gd;
-	rrlp_eph->ephemToc        = gps_eph_sv->t_oc;
-	rrlp_eph->ephemAF2        = gps_eph_sv->a_f2;
-	rrlp_eph->ephemAF1        = gps_eph_sv->a_f1;
-	rrlp_eph->ephemAF0        = gps_eph_sv->a_f0;
-	rrlp_eph->ephemCrs        = gps_eph_sv->c_rs;
-	rrlp_eph->ephemDeltaN     = gps_eph_sv->delta_n;
-	rrlp_eph->ephemM0         = gps_eph_sv->m_0;
-	rrlp_eph->ephemCuc        = gps_eph_sv->c_uc;
-	rrlp_eph->ephemE          = gps_eph_sv->e;
-	rrlp_eph->ephemCus        = gps_eph_sv->c_us;
-	rrlp_eph->ephemAPowerHalf = gps_eph_sv->a_powhalf;
-	rrlp_eph->ephemToe        = gps_eph_sv->t_oe;
-	rrlp_eph->ephemFitFlag    = gps_eph_sv->fit_flag;
-	rrlp_eph->ephemAODA       = gps_eph_sv->aodo;
-	rrlp_eph->ephemCic        = gps_eph_sv->c_ic;
-	rrlp_eph->ephemOmegaA0    = gps_eph_sv->omega_0;
-	rrlp_eph->ephemCis        = gps_eph_sv->c_is;
-	rrlp_eph->ephemI0         = gps_eph_sv->i_0;
-	rrlp_eph->ephemCrc        = gps_eph_sv->c_rc;
-	rrlp_eph->ephemW          = gps_eph_sv->w;
-	rrlp_eph->ephemOmegaADot  = gps_eph_sv->omega_dot;
-	rrlp_eph->ephemIDot       = gps_eph_sv->idot;
-
-	rrlp_eph->ephemSF1Rsvd.reserved1 = gps_eph_sv->_rsvd1;
-	rrlp_eph->ephemSF1Rsvd.reserved2 = gps_eph_sv->_rsvd2;
-	rrlp_eph->ephemSF1Rsvd.reserved3 = gps_eph_sv->_rsvd3;
-	rrlp_eph->ephemSF1Rsvd.reserved4 = gps_eph_sv->_rsvd4;
-}
-
-static void
-_rrlp_fill_almanac_element(
-	struct AlmanacElement *rrlp_ae,
-	struct gps_almanac_sv *gps_alm_sv)
-{
-	rrlp_ae->satelliteID = gps_alm_sv->sv_id;
-
-	rrlp_ae->almanacE          = gps_alm_sv->e;
-	rrlp_ae->alamanacToa       = gps_alm_sv->t_oa;
-	rrlp_ae->almanacKsii       = gps_alm_sv->ksii;
-	rrlp_ae->almanacOmegaDot   = gps_alm_sv->omega_dot;
-	rrlp_ae->almanacSVhealth   = gps_alm_sv->sv_health;
-	rrlp_ae->almanacAPowerHalf = gps_alm_sv->a_powhalf;
-	rrlp_ae->almanacOmega0     = gps_alm_sv->omega_0;
-	rrlp_ae->almanacW          = gps_alm_sv->w;
-	rrlp_ae->almanacM0         = gps_alm_sv->m_0;
-	rrlp_ae->almanacAF0        = gps_alm_sv->a_f0;
-	rrlp_ae->almanacAF1        = gps_alm_sv->a_f1;
-
-}
-
-static void
-_rrlp_fill_ionospheric_model(
-	struct IonosphericModel *rrlp_iono,
-	struct gps_ionosphere_model *gps_iono)
-{
-	rrlp_iono->alfa0 = gps_iono->alpha_0;
-	rrlp_iono->alfa1 = gps_iono->alpha_1;
-	rrlp_iono->alfa2 = gps_iono->alpha_2;
-	rrlp_iono->alfa3 = gps_iono->alpha_3;
-	rrlp_iono->beta0 = gps_iono->beta_0;
-	rrlp_iono->beta1 = gps_iono->beta_1;
-	rrlp_iono->beta2 = gps_iono->beta_2;
-	rrlp_iono->beta3 = gps_iono->beta_3;
-}
-
-static void
-_rrlp_fill_utc_model(
-	struct UTCModel *rrlp_utc,
-	struct gps_utc_model *gps_utc)
-{
-	rrlp_utc->utcA1        = gps_utc->a1;
-	rrlp_utc->utcA0        = gps_utc->a0;
-	rrlp_utc->utcTot       = gps_utc->t_ot;
-	rrlp_utc->utcWNt       = gps_utc->wn_t & 0xff;
-	rrlp_utc->utcDeltaTls  = gps_utc->delta_t_ls;
-	rrlp_utc->utcWNlsf     = gps_utc->wn_lsf & 0xff;
-	rrlp_utc->utcDN        = gps_utc->dn;
-	rrlp_utc->utcDeltaTlsf = gps_utc->delta_t_lsf;
-}
-
-/* }}} */
-
-
-/* ------------------------------------------------------------------------ */
-/* RRLP Assistance PDU Generation                                           */
-/* ---------------------------------------------------------------------{{{ */
-
-struct PDU *
-_rrlp_create_gps_assist_pdu(int refnum, struct GPS_AssistData **o_gps_ad)
-{
-	struct PDU *pdu;
-	struct GPS_AssistData *gps_ad;
-
-	pdu = calloc(1, sizeof(*pdu));
-	if (!pdu)
-		return NULL;
-
-	gps_ad = calloc(1, sizeof(*gps_ad));
-	if (!gps_ad) {
-		free(pdu);
-		return NULL;
-	}
-
-	if (o_gps_ad)
-		*o_gps_ad = gps_ad;
-
-	pdu->referenceNumber = refnum;
-	pdu->component.present = RRLP_Component_PR_assistanceData;
-	pdu->component.choice.assistanceData.gps_AssistData = gps_ad;
-
-	return pdu;
-}
-
-static int
-_rrlp_add_ionospheric_model(
-	struct GPS_AssistData *rrlp_gps_ad,
-	struct gps_assist_data *gps_ad)
-{
-	struct IonosphericModel *rrlp_iono;
-
-	if (!(gps_ad->fields & GPS_FIELD_IONOSPHERE))
-		return -EINVAL;
-
-	rrlp_iono = calloc(1, sizeof(*rrlp_iono));
-	if (!rrlp_iono)
-		return -ENOMEM;
-	rrlp_gps_ad->controlHeader.ionosphericModel = rrlp_iono;
-
-	_rrlp_fill_ionospheric_model(rrlp_iono, &gps_ad->ionosphere);
-
-	return 0;
-}
-
-static int
-_rrlp_add_utc_model(
-	struct GPS_AssistData *rrlp_gps_ad,
-	struct gps_assist_data *gps_ad)
-{
-	struct UTCModel *rrlp_utc;
-
-	if (!(gps_ad->fields & GPS_FIELD_UTC))
-		return -EINVAL;
-
-	rrlp_utc = calloc(1, sizeof(*rrlp_utc));
-	if (!rrlp_utc)
-		return -ENOMEM;
-	rrlp_gps_ad->controlHeader.utcModel = rrlp_utc;
-
-	_rrlp_fill_utc_model(rrlp_utc, &gps_ad->utc);
-
-	return 0;
-}
-
-static int
-_rrlp_add_reference_location(
-	struct GPS_AssistData *rrlp_gps_ad,
-	struct gps_assist_data *gps_ad)
-{
-	struct RefLocation *rrlp_refloc;
-	uint8_t *b;
-
-	if (!(gps_ad->fields & GPS_FIELD_REFPOS))
-		return -EINVAL;
-
-	rrlp_refloc = calloc(1, sizeof(*rrlp_refloc));
-	if (!rrlp_refloc)
-		return -ENOMEM;
-	rrlp_gps_ad->controlHeader.refLocation = rrlp_refloc;
-
-	b = malloc(9);
-
-	b[0] = 0x80; /* Ellipsoid Point with altitude */
-	_ts_23_032_store_latitude(gps_ad->ref_pos.latitude, &b[1]);
-	_ts_23_032_store_longitude(gps_ad->ref_pos.longitude, &b[4]);
-	_ts_23_032_store_altitude(gps_ad->ref_pos.altitude, &b[7]);
-
-	rrlp_refloc->threeDLocation.buf = b;
-	rrlp_refloc->threeDLocation.size = 9;
-
-	return 0;
-}
-
-static int
-_rrlp_add_reference_time(
-	struct GPS_AssistData *rrlp_gps_ad,
-	struct gps_assist_data *gps_ad)
-{
-	struct ReferenceTime *rrlp_reftime;
-
-	if (!(gps_ad->fields & GPS_FIELD_REFTIME))
-		return -EINVAL;
-
-	rrlp_reftime = calloc(1, sizeof(*rrlp_reftime));
-	if (!rrlp_reftime)
-		return -ENOMEM;
-	rrlp_gps_ad->controlHeader.referenceTime = rrlp_reftime;
-
-	rrlp_reftime->gpsTime.gpsWeek   = gps_ad->ref_time.wn & 0x3ff; /* 10b */
-	rrlp_reftime->gpsTime.gpsTOW23b =
-		((int)floor(gps_ad->ref_time.tow / 0.08)) & 0x7fffff;  /* 23b */
-
-	return 0;
-}
-
-static int
-_rrlp_add_almanac(
-	struct GPS_AssistData *rrlp_gps_ad,
-	struct gps_assist_data *gps_ad, int *start, int count)
-{
-	int i;
-	struct Almanac *rrlp_alm;
-	struct gps_almanac *gps_alm = &gps_ad->almanac;
-
-	if (!(gps_ad->fields & GPS_FIELD_ALMANAC))
-		return -EINVAL;
-
-	rrlp_alm = calloc(1, sizeof(*rrlp_alm));
-	if (!rrlp_alm)
-		return -ENOMEM;
-	rrlp_gps_ad->controlHeader.almanac = rrlp_alm;
-
-	rrlp_alm->alamanacWNa = gps_alm->wna;
-	if (count == -1)
-		count = gps_alm->n_sv - *start;
-	for (i=*start; (i<*start+count) && (i<gps_alm->n_sv); i++) {
-		struct AlmanacElement *ae;
-		ae = calloc(1, sizeof(*ae));
-		if (!ae)
-			return -ENOMEM;
-		_rrlp_fill_almanac_element(ae, &gps_alm->svs[i]);
-		ASN_SEQUENCE_ADD(&rrlp_alm->almanacList.list, ae);
-	}
-
-	*start = i;
-
-	return i < gps_alm->n_sv;
-}
-
-static int
-_rrlp_add_ephemeris(
-	struct GPS_AssistData *rrlp_gps_ad,
-	struct gps_assist_data *gps_ad, int *start, int count, uint64_t mask)
-{
-	int i, j;
-	struct NavigationModel *rrlp_nav;
-	struct gps_ephemeris *gps_eph = &gps_ad->ephemeris;
-
-	if (!(gps_ad->fields & GPS_FIELD_EPHEMERIS))
-		return -EINVAL;
-
-	rrlp_nav = calloc(1, sizeof(*rrlp_nav));
-	if (!rrlp_nav)
-		return -ENOMEM;
-	rrlp_gps_ad->controlHeader.navigationModel = rrlp_nav;
-
-	if (count == -1)
-		count = gps_eph->n_sv - *start;
-	for (i=*start,j=0; (j<count) && (i<gps_eph->n_sv); i++) {
-		if (!(mask & (1ULL<<(gps_eph->svs[i].sv_id-1))))
-			continue;
-		struct NavModelElement *nme;
-		nme = calloc(1, sizeof(*nme));
-		if (!nme)
-			return -ENOMEM;
-		_rrlp_fill_navigation_model_element(nme, &gps_eph->svs[i]);
-		ASN_SEQUENCE_ADD(&rrlp_nav->navModelList.list, nme);
-		j++;
-	}
-
-	*start = i;
-
-	return i < gps_eph->n_sv;
-}
-
-
-#define MAX_PDUS 64
-
-int
-rrlp_gps_assist_pdus(
-	struct gps_assist_data *gps_ad, struct rrlp_assist_req *req,
-	void **o_pdu, int *o_len, int o_max_pdus)
-{
-	struct PDU *lst_pdu[MAX_PDUS];
-	int lst_cnt = 0;
-
-	struct PDU *rrlp_pdu = NULL;
-	struct GPS_AssistData *rrlp_gps_ad = NULL;
-	uint32_t re = req->req_elems;
-	int i, rv = 0;
-
-	/* IonosphericModel, UTCModel, RefLocation, ReferenceTime */
-	if (re & (RRLP_AR_IONO_MODEL |
-	          RRLP_AR_UTC_MODEL |
-	          RRLP_AR_REF_TIME |
-	          RRLP_AR_REF_LOC))
-	{
-		int pdu_has_data = 0;
-
-		rrlp_pdu = _rrlp_create_gps_assist_pdu(1, &rrlp_gps_ad);
-		if (!rrlp_pdu) {
-			rv = -ENOMEM;
-			goto error;
-		}
-
-		if (re & RRLP_AR_IONO_MODEL)
-			if (!_rrlp_add_ionospheric_model(rrlp_gps_ad, gps_ad))
-				pdu_has_data = 1;
-
-		if (re & RRLP_AR_UTC_MODEL)
-			if (!_rrlp_add_utc_model(rrlp_gps_ad, gps_ad))
-				pdu_has_data = 1;
-
-		if (re & RRLP_AR_REF_TIME)
-			if (!_rrlp_add_reference_time(rrlp_gps_ad, gps_ad))
-				pdu_has_data = 1;
-
-		if (re & RRLP_AR_REF_LOC)
-			if (!_rrlp_add_reference_location(rrlp_gps_ad, gps_ad))
-				pdu_has_data = 1;
-
-		if (pdu_has_data) {
-			lst_pdu[lst_cnt++] = rrlp_pdu;
-			rrlp_pdu = NULL;
-		}
-	}
-
-	/* Almanac */
-	if (re & RRLP_AR_ALMANAC) {
-		i = 0;
-		do {
-			if (!(gps_ad->fields & GPS_FIELD_ALMANAC))
-				break;
-
-			if (!rrlp_pdu) {
-				rrlp_pdu = _rrlp_create_gps_assist_pdu(1, &rrlp_gps_ad);
-				if (!rrlp_pdu) {
-					rv = -ENOMEM;
-					goto error;
-				}
-			}
-
-			rv = _rrlp_add_almanac(rrlp_gps_ad, gps_ad, &i, 10);
-			if (rv < 0)
-				goto error;
-
-			lst_pdu[lst_cnt++] = rrlp_pdu;
-			rrlp_pdu = NULL;
-		} while (rv);
-	}
-
-	/* Ephemeris */
-	if (re & RRLP_AR_EPHEMERIS) {
-		i = 0;
-		do {
-			if (!(gps_ad->fields & GPS_FIELD_EPHEMERIS))
-				break;
-
-			if (!rrlp_pdu) {
-				rrlp_pdu = _rrlp_create_gps_assist_pdu(1, &rrlp_gps_ad);
-				if (!rrlp_pdu) {
-					rv = -ENOMEM;
-					goto error;
-				}
-			}
-
-			rv = _rrlp_add_ephemeris(rrlp_gps_ad, gps_ad, &i, 2, req->eph_svs);
-
-			lst_pdu[lst_cnt++] = rrlp_pdu;
-			rrlp_pdu = NULL;
-
-		} while (rv);
-	}
-
-	/* Serialize & Release all PDUs */
-	for (i=0; i<lst_cnt && i<o_max_pdus; i++) {
-		/* Pseudo segmentation flags */
-		MoreAssDataToBeSent_t *mad = calloc(1, sizeof(*mad));
-		*mad = (i == (lst_cnt-1)) ?
-				MoreAssDataToBeSent_noMoreMessages :
-				MoreAssDataToBeSent_moreMessagesOnTheWay;
-		lst_pdu[i]->component.choice.assistanceData.moreAssDataToBeSent = mad;
-
-		/* Serialization */
-		// asn_fprint(stdout, &asn_DEF_PDU, lst_pdu[i]);
-		rv = uper_encode_to_new_buffer(&asn_DEF_PDU, NULL, lst_pdu[i], &o_pdu[i]);
-		if (rv < 0)
-			goto error;
-		o_len[i] = rv;
-	}
-
-	rv = lst_cnt;
-
-	/* Release ASN.1 objects */
-error:
-	if (rrlp_pdu)
-		asn_DEF_PDU.free_struct(&asn_DEF_PDU, (void*)rrlp_pdu, 0);
-
-	for (i=0; i<lst_cnt; i++)
-		asn_DEF_PDU.free_struct(&asn_DEF_PDU, lst_pdu[i], 0);
-
-	return rv;
-}
-
-/* }}} */
-
diff --git a/rrlp-ephemeris/rrlp.h b/rrlp-ephemeris/rrlp.h
deleted file mode 100644
index a5e4344..0000000
--- a/rrlp-ephemeris/rrlp.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * rrlp.h
- *
- * RRLP Header
- *
- *
- * Copyright (C) 2009  Sylvain Munaut <tnt@246tNt.com>
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __RRLP_H__
-#define __RRLP_H__
-
-#include <stdint.h>
-
-#include "gps.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* Our internal simplified structure for requests */
-
-#define RRLP_AR_REF_LOC		(1<<0)
-#define RRLP_AR_REF_TIME	(1<<1)
-#define RRLP_AR_UTC_MODEL	(1<<2)
-#define RRLP_AR_IONO_MODEL	(1<<3)
-#define RRLP_AR_ALMANAC		(1<<4)
-#define RRLP_AR_EPHEMERIS	(1<<5)
-
-struct rrlp_assist_req {
-	uint32_t req_elems;
-	uint64_t eph_svs;
-};
-
-
-/* Methods */
-int rrlp_decode_assistance_request(struct rrlp_assist_req *ar,
-	void *req, int req_len);
-
-int rrlp_gps_assist_pdus(
-	struct gps_assist_data *gps_ad, struct rrlp_assist_req *req,
-	void **o_pdu, int *o_len, int o_max_pdus);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __RRLP_H__ */
-
diff --git a/rrlp-ephemeris/ubx-parse.c b/rrlp-ephemeris/ubx-parse.c
deleted file mode 100644
index c3d0f70..0000000
--- a/rrlp-ephemeris/ubx-parse.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * ubx-parse.c
- *
- * Implementation of parsing code converting UBX messages to GPS assist
- * data
- *
- *
- * Copyright (C) 2009  Sylvain Munaut <tnt@246tNt.com>
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-
-#include "gps.h"
-#include "ubx.h"
-#include "ubx-parse.h"
-
-
-/* Helpers */
-
-static int
-float_to_fixedpoint(float f, int sf)
-{
-	if (sf < 0) {
-		while (sf++ < 0)
-			f *= 2.0f;
-	} else {
-		while (sf-- > 0)
-			f *= 0.5f;
-	}
-
-	return (int)f;
-}
-
-static inline int
-double_to_fixedpoint(double d, int sf)
-{
-	if (sf < 0) {
-		while (sf++ < 0)
-			d *= 2.0;
-	} else {
-		while (sf-- > 0)
-			d *= 0.5;
-	}
-
-	return (int)d;
-}
-
-
-/* UBX message parsing to fill gps assist data */
-
-static void
-_ubx_msg_parse_nav_posllh(struct ubx_hdr *hdr, void *pl, int pl_len, void *ud)
-{
-	struct ubx_nav_posllh *nav_posllh = pl;
-	struct gps_assist_data *gps = ud;
-
-	//printf("[.] NAV_POSLLH\n");
-
-	gps->fields |= GPS_FIELD_REFPOS;
-
-	gps->ref_pos.latitude  = (double)(nav_posllh->lat) * 1e-7;
-	gps->ref_pos.longitude = (double)(nav_posllh->lon) * 1e-7;
-	gps->ref_pos.altitude  = (double)(nav_posllh->height) * 1e-3;
-}
-
-static void
-_ubx_msg_parse_aid_ini(struct ubx_hdr *hdr, void *pl, int pl_len, void *ud)
-{
-	struct ubx_aid_ini *aid_ini = pl;
-	struct gps_assist_data *gps = ud;
-
-	//printf("[.] AID_INI\n");
-
-	/* Extract info for "Reference Time" */
-	gps->fields |= GPS_FIELD_REFTIME;
-
-	gps->ref_time.wn = aid_ini->wn;
-	gps->ref_time.tow = (double)aid_ini->tow * 1e-3;
-
-	// FIXME: We could extract ref position as well but we need it in
-	//        WGS84 geodetic coordinates and it's provided as ecef, so
-	//        we need a lot of math ...
-}
-
-static void
-_ubx_msg_parse_aid_hui(struct ubx_hdr *hdr, void *pl, int pl_len, void *ud)
-{
-	struct ubx_aid_hui *aid_hui = pl;
-	struct gps_assist_data *gps = ud;
-
-	//printf("[.] AID_HUI\n");
-
-	if (aid_hui->flags & 0x2) { /* UTC parameters valid */
-		struct gps_utc_model *utc = &gps->utc;
-
-		gps->fields |= GPS_FIELD_UTC;
-
-		utc->a0          = double_to_fixedpoint(aid_hui->utc_a0, -30);
-		utc->a1          = double_to_fixedpoint(aid_hui->utc_a1, -50);
-		utc->delta_t_ls  = aid_hui->utc_ls;
-		utc->t_ot        = aid_hui->utc_tot >> 12;
-		utc->wn_t        = aid_hui->utc_wnt;
-		utc->wn_lsf      = aid_hui->utc_wnf;
-		utc->dn          = aid_hui->utc_dn;
-		utc->delta_t_lsf = aid_hui->utc_lsf;
-	}
-
-	if (aid_hui->flags & 0x04) { /* Klobuchar parameters valid */
-		struct gps_ionosphere_model *iono = &gps->ionosphere;
-
-		gps->fields |= GPS_FIELD_IONOSPHERE;
-
-		iono->alpha_0 = float_to_fixedpoint(aid_hui->klob_a0, -30);
-		iono->alpha_1 = float_to_fixedpoint(aid_hui->klob_a1, -27);
-		iono->alpha_2 = float_to_fixedpoint(aid_hui->klob_a2, -24);
-		iono->alpha_3 = float_to_fixedpoint(aid_hui->klob_a3, -24);
-		iono->beta_0 = float_to_fixedpoint(aid_hui->klob_b0, 11);
-		iono->beta_1 = float_to_fixedpoint(aid_hui->klob_b1, 14);
-		iono->beta_2 = float_to_fixedpoint(aid_hui->klob_b2, 16);
-		iono->beta_3 = float_to_fixedpoint(aid_hui->klob_b3, 16);
-	}
-}
-
-static void
-_ubx_msg_parse_aid_alm(struct ubx_hdr *hdr, void *pl, int pl_len, void *ud)
-{
-	struct ubx_aid_alm *aid_alm = pl;
-	struct gps_assist_data *gps = ud;
-
-	//printf("[.] AID_ALM %d - %d\n", aid_alm->sv_id, aid_alm->gps_week);
-
-	if (aid_alm->gps_week) {
-		gps->fields |= GPS_FIELD_ALMANAC;
-		gps->almanac.wna = aid_alm->gps_week & 0xff;
-		gps_unpack_sf45_almanac(aid_alm->alm_words, &gps->almanac.svs[gps->almanac.n_sv++]);
-	}
-}
-
-static void
-_ubx_msg_parse_aid_eph(struct ubx_hdr *hdr, void *pl, int pl_len, void *ud)
-{
-	struct ubx_aid_eph *aid_eph = pl;
-	struct gps_assist_data *gps = ud;
-
-	//printf("[.] AID_EPH %d - %s\n", aid_eph->sv_id, aid_eph->present ? "present" : "not present");
-
-	if (aid_eph->present) {
-		int i = gps->ephemeris.n_sv++;
-		gps->fields |= GPS_FIELD_EPHEMERIS;
-		gps->ephemeris.svs[i].sv_id = aid_eph->sv_id;
-		gps_unpack_sf123(aid_eph->eph_words, &gps->ephemeris.svs[i]);
-	}
-}
-
-
-/* Dispatch table */
-struct ubx_dispatch_entry ubx_parse_dt[] = {
-	UBX_DISPATCH(NAV, POSLLH, _ubx_msg_parse_nav_posllh),
-	UBX_DISPATCH(AID, INI, _ubx_msg_parse_aid_ini),
-	UBX_DISPATCH(AID, HUI, _ubx_msg_parse_aid_hui),
-	UBX_DISPATCH(AID, ALM, _ubx_msg_parse_aid_alm),
-	UBX_DISPATCH(AID, EPH, _ubx_msg_parse_aid_eph),
-};
-
diff --git a/rrlp-ephemeris/ubx-parse.h b/rrlp-ephemeris/ubx-parse.h
deleted file mode 100644
index 621475d..0000000
--- a/rrlp-ephemeris/ubx-parse.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * ubx-parse.h
- *
- * Header for parsing code converting UBX messages to GPS assist data
- *
- *
- * Copyright (C) 2009  Sylvain Munaut <tnt@246tNt.com>
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __UBX_PARSE_H__
-#define __UBX_PARSE_H__
-
-
-#include "gps.h"
-#include "ubx.h"
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* Dispatch table */
-extern struct ubx_dispatch_entry ubx_parse_dt[];
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __UBX_PARSE_H__ */
-
diff --git a/rrlp-ephemeris/ubx.c b/rrlp-ephemeris/ubx.c
deleted file mode 100644
index 83dd1f0..0000000
--- a/rrlp-ephemeris/ubx.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * ubx.c
- *
- * Implementation of generic UBX helpers
- *
- *
- * Copyright (C) 2009  Sylvain Munaut <tnt@246tNt.com>
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-
-#include "ubx.h"
-
-
-static void
-ubx_checksum(uint8_t *data, int len, uint8_t *cksum)
-{
-	int i;
-	uint8_t ck0 = 0, ck1 = 0;
-	for (i=0; i<len; i++) {
-		ck0 += data[i];
-		ck1 += ck0;
-	}
-	cksum[0] = ck0;
-	cksum[1] = ck1;
-}
-
-
-static ubx_msg_handler_t
-ubx_find_handler(struct ubx_dispatch_entry *dt, uint8_t msg_class, uint8_t msg_id)
-{
-	while (dt->handler) {
-		if ((dt->msg_class == msg_class) && (dt->msg_id == msg_id))
-			return dt->handler;
-		dt++;
-	}
-	return NULL;
-}
-
-
-int
-ubx_msg_dispatch(struct ubx_dispatch_entry *dt,
-                 void *msg, int len, void *userdata)
-{
-	struct ubx_hdr *hdr = msg;
-	uint8_t cksum[2], *cksum_ptr;
-	ubx_msg_handler_t h;
-
-	if ((hdr->sync[0] != UBX_SYNC0) || (hdr->sync[1] != UBX_SYNC1)) {
-		fprintf(stderr, "[!] Invalid sync bytes\n");
-		return -1;
-	}
-
-	ubx_checksum(msg + 2, sizeof(struct ubx_hdr) + hdr->payload_len - 2, cksum);
-	cksum_ptr = msg + (sizeof(struct ubx_hdr) + hdr->payload_len);
-	if ((cksum_ptr[0] != cksum[0]) || (cksum_ptr[1] != cksum[1])) {
-		fprintf(stderr, "[!] Invalid checksum\n");
-		return -1;
-	}
-
-	h = ubx_find_handler(dt, hdr->msg_class, hdr->msg_id);
-	if (h)
-		h(hdr, msg + sizeof(struct ubx_hdr), hdr->payload_len, userdata);
-
-	return sizeof(struct ubx_hdr) + hdr->payload_len + 2;
-}
-
diff --git a/rrlp-ephemeris/ubx.h b/rrlp-ephemeris/ubx.h
deleted file mode 100644
index 8264386..0000000
--- a/rrlp-ephemeris/ubx.h
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * ubx.h
- *
- * Header for UBX related stuff
- *
- *
- * Copyright (C) 2009  Sylvain Munaut <tnt@246tNt.com>
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __UBX_H__
-#define __UBX_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdint.h>
-
-/* Constants used in UBX */
-
-	/* Sync bytes (two first bytes of each message) */
-#define UBX_SYNC0		0xb5
-#define UBX_SYNC1		0x62
-
-	/* UBX messages classes */
-#define UBX_CLASS_NAV		0x01
-#define UBX_CLASS_RXM		0x02
-#define UBX_CLASS_INF		0x04
-#define UBX_CLASS_ACK		0x05
-#define UBX_CLASS_CFG		0x06
-#define UBX_CLASS_UPD		0x09
-#define UBX_CLASS_MON		0x0a
-#define UBX_CLASS_AID		0x0b
-#define UBX_CLASS_TIM		0x0d
-
-	/* UBX messages type ID (by class) */
-#define UBX_NAV_POSECEF		0x01
-#define UBX_NAV_POSLLH		0x02
-#define UBX_NAV_STATUS		0x03
-#define UBX_NAV_DOP		0x04
-#define UBX_NAV_SOL		0x06
-#define UBX_NAV_POSUTM		0x08
-#define UBX_NAV_VELECEF		0x11
-#define UBX_NAV_VELNED		0x12
-#define UBX_NAV_TIMEGPS		0x20
-#define UBX_NAV_TIMEUTC		0x21
-#define UBX_NAV_CLOCK		0x22
-#define UBX_NAV_SVINFO		0x30
-#define UBX_NAV_DGPS		0x31
-#define UBX_NAV_SBAS		0x32
-#define UBX_NAV_EKFSTATUS	0x40
-
-#define UBX_RXM_RAW		0x10
-#define UBX_RXM_SFRB		0x11
-#define UBX_RXM_SVSI		0x20
-#define UBX_RXM_SVSI_GPS	0x20
-#define UBX_RXM_ALM		0x30
-#define UBX_RXM_EPH		0x31
-#define UBX_RXM_POSREQ		0x40
-
-#define UBX_INF_ERROR		0x00
-#define UBX_INF_WARNING		0x01
-#define UBX_INF_NOTICE		0x02
-#define UBX_INF_TEST		0x03
-#define UBX_INF_DEBUG		0x04
-#define UBX_INF_USER		0x07
-
-#define UBX_ACK_NAK		0x00
-#define UBX_ACK_ACK		0x01
-
-#define UBX_CFG_PRT		0x00
-#define UBX_CFG_USB		0x1b
-#define UBX_CFG_MSG		0x01
-#define UBX_CFG_NMEA		0x17
-#define UBX_CFG_RATE		0x08
-#define UBX_CFG_CFG		0x09
-#define UBX_CFG_TP		0x07
-#define UBX_CFG_NAV2		0x1a
-#define UBX_CFG_DAT		0x06
-#define UBX_CFG_INF		0x02
-#define UBX_CFG_RST		0x04
-#define UBX_CFG_RXM		0x11
-#define UBX_CFG_ANT		0x13
-#define UBX_CFG_FXN		0x0e
-#define UBX_CFG_SBAS		0x16
-#define UBX_CFG_LIC		0x80
-#define UBX_CFG_TM		0x10
-#define UBX_CFG_TM2		0x19
-#define UBX_CFG_TMODE		0x1d
-#define UBX_CFG_EKF		0x12
-
-#define UBX_UPD_DOWNL		0x01
-#define UBX_UPD_UPLOAD		0x02
-#define UBX_UPD_EXEC		0x03
-#define UBX_UPD_MEMCPY		0x04
-
-#define UBX_MON_SCHD		0x01
-#define UBX_MON_IO		0x02
-#define UBX_MON_IPC		0x03
-#define UBX_MON_VER		0x04
-#define UBX_MON_EXCEPT		0x05
-#define UBX_MON_MSGPP		0x06
-#define UBX_MON_RXBUF		0x07
-#define UBX_MON_TXBUF		0x08
-#define UBX_MON_HW		0x09
-#define UBX_MON_USB		0x0a
-
-#define UBX_AID_REQ		0x00
-#define UBX_AID_INI		0x01
-#define UBX_AID_HUI		0x02
-#define UBX_AID_DATA		0x10
-#define UBX_AID_ALM		0x30
-#define UBX_AID_EPH		0x31
-
-#define UBX_TIM_TP		0x01
-#define UBX_TIM_TM		0x02
-#define UBX_TIM_TM2		0x03
-#define UBX_TIM_SVIN		0x04
-
-
-/* Header */
-struct ubx_hdr {
-        uint8_t  sync[2];
-        uint8_t  msg_class;
-        uint8_t  msg_id;
-        uint16_t payload_len;
-} __attribute__((packed));
-
-
-/* Payload formats (some of them) */
-struct ubx_nav_posllh {
-	uint32_t itow;
-	int32_t  lon;	/* scaling 1e-7 */
-	int32_t  lat;	/* scaling 1e-7 */
-	int32_t  height;/* mm */
-	int32_t  hsl;	/* mm */
-	uint32_t hacc;	/* mm */
-	uint32_t vacc;	/* mm */
-} __attribute__((packed));
-
-struct ubx_aid_ini {
-	int32_t  x;
-	int32_t  y;
-	int32_t  z;
-	uint32_t posacc;
-	uint16_t tm_cfg;
-	uint16_t wn;
-	uint32_t tow;
-	int32_t  tow_ns;
-	uint32_t tacc_ms;
-	uint32_t tacc_ns;
-	int32_t  clkd;
-	uint32_t clkdacc;
-	uint32_t flags;
-} __attribute__((packed));
-
-struct ubx_aid_hui {
-	uint32_t health;
-	double   utc_a1;
-	double   utc_a0;
-	int32_t  utc_tot;
-	int16_t  utc_wnt;
-	int16_t  utc_ls;
-	int16_t  utc_wnf;
-	int16_t  utc_dn;
-	int16_t  utc_lsf;
-	int16_t  utc_spare;
-	float    klob_a0;
-	float    klob_a1;
-	float    klob_a2;
-	float    klob_a3;
-	float    klob_b0;
-	float    klob_b1;
-	float    klob_b2;
-	float    klob_b3;
-	uint32_t flags;
-} __attribute__((packed));
-
-struct ubx_aid_alm {
-	uint32_t sv_id;
-	uint32_t gps_week;
-	uint32_t alm_words[8];	/* Present only if 'gps_week' != 0 */
-} __attribute__((packed));
-
-struct ubx_aid_eph {
-	uint32_t sv_id;
-	uint32_t present;
-	uint32_t eph_words[24];	/* Present only if 'present' != 0 */
-} __attribute__((packed));
-
-
-/* Message handler */
-typedef void (*ubx_msg_handler_t)(
-	struct ubx_hdr *hdr, void *payload, int payload_len, void *userdata);
-
-struct ubx_dispatch_entry {
-	uint8_t msg_class;
-	uint8_t msg_id;
-	ubx_msg_handler_t handler;
-};
-
-#define UBX_DISPATCH(kls,id,hdl) {		\
-	.msg_class = UBX_CLASS_ ## kls ,	\
-	.msg_id = UBX_ ## kls ## _ ## id,	\
-	.handler = (hdl),			\
-}
-
-
-/* Methods */
-int ubx_msg_dispatch(struct ubx_dispatch_entry *dt,
-                     void *msg, int len, void *userdata);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __UBX_H__ */
-
diff --git a/wireshark/abis_oml.patch b/wireshark/abis_oml.patch
index 9f06b4d..b9248dc 100644
--- a/wireshark/abis_oml.patch
+++ b/wireshark/abis_oml.patch
@@ -1,8 +1,21 @@
-Index: wireshark/epan/dissectors/Makefile.common
-===================================================================
---- wireshark.orig/epan/dissectors/Makefile.common
-+++ wireshark/epan/dissectors/Makefile.common
-@@ -474,6 +474,7 @@
+From b659280ff645354bb55529b05114419b9f0efd6f Mon Sep 17 00:00:00 2001
+From: Holger Hans Peter Freyther <zecke@selfish.org>
+Date: Mon, 19 Apr 2010 13:23:51 +0800
+Subject: [PATCH 1/2] Add the Abis OML patch.
+
+---
+ epan/dissectors/Makefile.common       |    1 +
+ epan/dissectors/packet-gsm_abis_oml.c | 1405 +++++++++++++++++++++++++++++++++
+ epan/dissectors/packet-gsm_abis_oml.h |  800 +++++++++++++++++++
+ 3 files changed, 2206 insertions(+), 0 deletions(-)
+ create mode 100644 epan/dissectors/packet-gsm_abis_oml.c
+ create mode 100644 epan/dissectors/packet-gsm_abis_oml.h
+
+diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common
+index b18f42e..115fa09 100644
+--- a/epan/dissectors/Makefile.common
++++ b/epan/dissectors/Makefile.common
+@@ -485,6 +485,7 @@ DISSECTOR_SRC = \
  	packet-gsm_a_gm.c		\
  	packet-gsm_a_rp.c		\
  	packet-gsm_a_rr.c	\
@@ -12,10 +25,10 @@
  	packet-gsm_bssmap_le.c	\
 diff --git a/epan/dissectors/packet-gsm_abis_oml.c b/epan/dissectors/packet-gsm_abis_oml.c
 new file mode 100644
-index 0000000..2de9dca
+index 0000000..0f16f18
 --- /dev/null
 +++ b/epan/dissectors/packet-gsm_abis_oml.c
-@@ -0,0 +1,1382 @@
+@@ -0,0 +1,1405 @@
 +/* packet-abis_oml.c
 + * Routines for packet dissection of GSM A-bis over IP (3GPP TS 12.21)
 + * Copyright 2009 by Harald Welte <laforge@gnumonks.org>
@@ -57,6 +70,8 @@
 +#include "packet-gsm_abis_oml.h"
 +#include "packet-gsm_a_common.h"
 +
++#include <stdio.h>
++
 +/* initialize the protocol and registered fields */
 +static int proto_abis_oml = -1;
 +
@@ -132,7 +147,7 @@
 +static int ett_oml_fom_att = -1;
 +
 +/* Decode things as nanoBTS traces */
-+static gboolean global_oml_use_nano_bts = FALSE;
++static gboolean global_oml_use_nano_bts = TRUE;
 +
 +static proto_tree *top_tree;
 +
@@ -598,6 +613,22 @@
 +	{ NM_IPACC_TR_IE_FREQ_ERR,	"Frequency Error" },
 +};
 +
++static const struct tlv_def *
++find_tlv_tag(guint8 tag)
++{
++	const struct tlv_def *specific;
++
++	if (global_oml_use_nano_bts)
++		specific = &nm_att_tlvdef_ipa.def[tag];
++	else
++		specific = &nm_att_tlvdev_bs11.def[tag];
++
++	if (specific->type != TLV_TYPE_UNKNOWN)
++		return specific;
++
++	return &nm_att_tlvdef_base.def[tag];
++}
++
 +/* Parse the ip.access specific BCCH Information IE embedded into the Test
 + * Report IE */
 +static gint
@@ -682,7 +713,9 @@
 +ipacc_tr_ie_chan_usage(tvbuff_t *tvb, proto_tree *att_tree, int offset)
 +{
 +	while (tvb_reported_length_remaining(tvb, offset) != 0) {
-+		guint16 result = tvb_get_ntohs(tvb, offset);
++		guint16 result;
++
++		result = tvb_get_ntohs(tvb, offset);
 +		proto_tree_add_uint(att_tree, hf_attr_ipa_tr_arfcn,
 +				    tvb, offset, 2, result);
 +		proto_tree_add_uint(att_tree, hf_attr_ipa_tr_rxlev,
@@ -702,11 +735,13 @@
 +			    1, FALSE);
 +
 +	while (tvb_reported_length_remaining(tvb, offset) != 0) {
-+		guint8 ie = tvb_get_guint8(tvb, offset);
-+		guint16 len = tvb_get_ntohs(tvb, offset+1);
++		guint8 ie;
++		guint16 len;
 +		proto_item *ti;
 +		proto_tree *att_tree;
 +
++		ie = tvb_get_guint8(tvb, offset);
++		len = tvb_get_ntohs(tvb, offset+1);
 +		ti = proto_tree_add_item(tree, hf_oml_ipa_tres_attr_tag, tvb,
 +					 offset++, 1, FALSE);
 +		att_tree = proto_item_add_subtree(ti, ett_oml_fom_att);
@@ -749,7 +784,7 @@
 +		tvbuff_t *sub_tvb;
 +
 +		tag = tvb_get_guint8(tvb, offset);
-+		tdef = &nm_att_tlvdef.def[tag];
++		tdef = find_tlv_tag(tag);
 +
 +		switch (tdef->type) {
 +		case TLV_TYPE_FIXED:
@@ -778,6 +813,7 @@
 +			len = tvb_get_guint8(tvb, offset+1) << 8 |
 +						tvb_get_guint8(tvb, offset+2);
 +			break;
++		case TLV_TYPE_UNKNOWN: /* fall through */
 +		default:
 +			hlen = len_len = len = 0;
 +			DISSECTOR_ASSERT_NOT_REACHED();
@@ -1398,11 +1434,12 @@
 +	abis_oml_handle = create_dissector_handle(dissect_abis_oml, proto_abis_oml);
 +	dissector_add("lapd.gsm.sapi", LAPD_GSM_SAPI_OM_PROC, abis_oml_handle);
 +}
-Index: wireshark/epan/dissectors/packet-gsm_abis_oml.h
-===================================================================
+diff --git a/epan/dissectors/packet-gsm_abis_oml.h b/epan/dissectors/packet-gsm_abis_oml.h
+new file mode 100644
+index 0000000..bdc414d
 --- /dev/null
-+++ wireshark/epan/dissectors/packet-gsm_abis_oml.h
-@@ -0,0 +1,786 @@
++++ b/epan/dissectors/packet-gsm_abis_oml.h
+@@ -0,0 +1,800 @@
 +/* 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 */
 +
@@ -2013,6 +2050,7 @@
 +
 +/* From openbsc/include/openbsc/tlv.h */
 +enum tlv_type {
++	TLV_TYPE_UNKNOWN,
 +	TLV_TYPE_FIXED,
 +	TLV_TYPE_T,
 +	TLV_TYPE_TV,
@@ -2061,7 +2099,7 @@
 +};
 +
 +/* From openbsc/src/abis_nm.c */
-+static const struct tlv_definition nm_att_tlvdef = {
++static const struct tlv_definition nm_att_tlvdef_base = {
 +	.def = {
 +		[NM_ATT_ABIS_CHANNEL] =		{ TLV_TYPE_FIXED, 3 },
 +		[NM_ATT_ADD_INFO] =		{ TLV_TYPE_TL16V, 0 },
@@ -2084,7 +2122,6 @@
 +		[NM_ATT_GSM_TIME] =		{ TLV_TYPE_FIXED, 2 },
 +		[NM_ATT_HSN] =			{ TLV_TYPE_TV, 0 },
 +		[NM_ATT_HW_CONFIG] =		{ TLV_TYPE_TL16V, 0 },
-+		//BS11 [NM_ATT_HW_DESC] =		{ TLV_TYPE_TL16V, 0 },
 +		[NM_ATT_HW_DESC] =		{ TLV_TYPE_TLV, 0 },
 +		[NM_ATT_INTAVE_PARAM] =		{ TLV_TYPE_TV, 0 },
 +		[NM_ATT_INTERF_BOUND] =		{ TLV_TYPE_FIXED, 6 },
@@ -2128,8 +2165,15 @@
 +		[NM_ATT_OUTST_ALARM] =		{ TLV_TYPE_TV, 0 },
 +		[NM_ATT_FILE_DATA] =		{ TLV_TYPE_TL16V, 0 },
 +		[NM_ATT_MEAS_RES] =		{ TLV_TYPE_TL16V, 0 },
-+#if 0
-+		/* BS11 specifics */
++
++	},
++};
++
++/* BS11 specifics */
++static const struct tlv_definition nm_att_tlvdev_bs11 = {
++	.def = {
++		/* a difference.. */
++		[NM_ATT_HW_DESC] =		{ TLV_TYPE_TL16V, 0 },
 +		[NM_ATT_BS11_ESN_FW_CODE_NO] =	{ TLV_TYPE_TLV, 0 },
 +		[NM_ATT_BS11_ESN_HW_CODE_NO] =	{ TLV_TYPE_TLV, 0 },
 +		[NM_ATT_BS11_ESN_PCB_SERIAL] =	{ TLV_TYPE_TLV, 0 },
@@ -2154,8 +2198,12 @@
 +		[NM_ATT_BS11_CCLK_ACCURACY] =	{ TLV_TYPE_TV, 0 },
 +		[NM_ATT_BS11_CCLK_TYPE] =	{ TLV_TYPE_TV, 0 },
 +		[0x95] =			{ TLV_TYPE_FIXED, 2 },
-+#endif
-+		/* ip.access specifics */
++	},
++};
++
++/* ip.access specifics */
++static const struct tlv_definition nm_att_tlvdef_ipa = {
++	.def = {
 +		[NM_ATT_IPACC_DST_IP] =		{ TLV_TYPE_FIXED, 4 },
 +		[NM_ATT_IPACC_DST_IP_PORT] =	{ TLV_TYPE_FIXED, 2 },
 +		[NM_ATT_IPACC_PRIM_OML_CFG] =	{ TLV_TYPE_TL16V, 0 },
@@ -2185,8 +2233,13 @@
 +		[NM_ATT_IPACC_CODING_SCHEMES] =	{ TLV_TYPE_TL16V, 0 },
 +		[NM_ATT_IPACC_RLC_CFG_2] =	{ TLV_TYPE_TL16V, 0 },
 +		[NM_ATT_IPACC_RLC_CFG_3] =	{ TLV_TYPE_TL16V, 0 },
++		[NM_ATT_IPACC_PAGING_CFG] =	{ TLV_TYPE_FIXED, 2 },
 +		[NM_ATT_IPACC_FILE_DATA] =	{ TLV_TYPE_TL16V, 0 },
++		[NM_ATT_IPACC_CGI] = 		{ TLV_TYPE_TL16V, 0 },
 +	},
 +};
 +
 +#endif /* _NM_H */
+-- 
+1.7.0.1
+
diff --git a/wireshark/rsl-ipaccess.patch b/wireshark/rsl-ipaccess.patch
index 36c09c5..29220b8 100644
--- a/wireshark/rsl-ipaccess.patch
+++ b/wireshark/rsl-ipaccess.patch
@@ -1,16 +1,25 @@
-Index: wireshark/epan/dissectors/packet-rsl.c
-===================================================================
---- wireshark.orig/epan/dissectors/packet-rsl.c	2009-10-21 23:03:41.000000000 +0200
-+++ wireshark/epan/dissectors/packet-rsl.c	2009-10-22 10:02:51.000000000 +0200
+From 8f35d623641dbba90e6186604c11e892bf515ecc Mon Sep 17 00:00:00 2001
+From: Holger Hans Peter Freyther <zecke@selfish.org>
+Date: Mon, 19 Apr 2010 13:32:58 +0800
+Subject: [PATCH 2/2] RSL patch
+
+---
+ epan/dissectors/packet-rsl.c |  522 +++++++++++++++++++++++++++++++++++++++++-
+ 1 files changed, 515 insertions(+), 7 deletions(-)
+
+diff --git a/epan/dissectors/packet-rsl.c b/epan/dissectors/packet-rsl.c
+index b10a671..a455cf3 100644
+--- a/epan/dissectors/packet-rsl.c
++++ b/epan/dissectors/packet-rsl.c
 @@ -2,6 +2,7 @@
   * Routines for Radio Signalling Link (RSL) dissection.
   *
   * Copyright 2007, Anders Broman <anders.broman@ericsson.com>
 + * Copyright 2009, Harald Welte <laforge@gnumonks.org>
   *
-  * $Id: packet-rsl.c 29944 2009-09-16 13:39:37Z morriss $
+  * $Id$
   *
-@@ -44,6 +45,8 @@
+@@ -42,6 +43,8 @@
  #include <epan/lapd_sapi.h>
  
  #include "packet-gsm_a_common.h"
@@ -19,7 +28,7 @@
  
  /* Initialize the protocol and registered fields */
  static int proto_rsl		= -1;
-@@ -117,6 +120,24 @@
+@@ -115,6 +118,24 @@ static int hf_rsl_emlpp_prio		= -1;
  static int hf_rsl_rtd				= -1;
  static int hf_rsl_delay_ind			= -1;
  static int hf_rsl_tfo				= -1;
@@ -44,7 +53,7 @@
  
  /* Initialize the subtree pointers */
  static int ett_rsl = -1;
-@@ -174,6 +195,15 @@
+@@ -172,6 +193,15 @@ static int ett_ie_cause = -1;
  static int ett_ie_meas_res_no = -1;
  static int ett_ie_message_id = -1;
  static int ett_ie_sys_info_type = -1;
@@ -60,7 +69,7 @@
  
  proto_tree *top_tree;
  dissector_handle_t gsm_a_ccch_handle;
-@@ -209,8 +239,11 @@
+@@ -207,8 +237,11 @@ static const value_string rsl_msg_disc_vals[] = {
  	{  0x06,		"Common Channel Management messages" },
  	{  0x08,		"TRX Management messages" },
  	{  0x16,		"Location Services messages" },
@@ -72,7 +81,7 @@
  /*
   * 9.2 MESSAGE TYPE
   */
-@@ -277,6 +310,49 @@
+@@ -275,6 +308,49 @@ static const value_string rsl_msg_disc_vals[] = {
  	/* 	0 1 - - - - - - Location Services messages: */
  #define RSL_MSG_LOC_INF					65	/* 8.7.1 */
  
@@ -90,16 +99,16 @@
 +#define RSL_MSG_TYPE_IPAC_PDCH_DEACT_ACK 0x4c
 +#define RSL_MSG_TYPE_IPAC_PDCH_DEACT_NACK 0x4d
 +
-+#define RSL_MSG_TYPE_IPAC_BIND		0x70
-+#define RSL_MSG_TYPE_IPAC_BIND_ACK	0x71
-+#define RSL_MSG_TYPE_IPAC_BIND_NACK	0x72
-+#define RSL_MSG_TYPE_IPAC_CONNECT	0x73
-+#define RSL_MSG_TYPE_IPAC_CONNECT_ACK	0x74
-+#define RSL_MSG_TYPE_IPAC_CONNECT_NACK	0x75
-+#define RSL_MSG_TYPE_IPAC_DISC_IND	0x76
-+#define RSL_MSG_TYPE_IPAC_DISC		0x77
-+#define RSL_MSG_TYPE_IPAC_DISC_ACK	0x78
-+#define RSL_MSG_TYPE_IPAC_DISC_NACK	0x79
++#define RSL_MSG_TYPE_IPAC_CRCX		0x70
++#define RSL_MSG_TYPE_IPAC_CRCX_ACK	0x71
++#define RSL_MSG_TYPE_IPAC_CRCX_NACK	0x72
++#define RSL_MSG_TYPE_IPAC_MDCX		0x73
++#define RSL_MSG_TYPE_IPAC_MDCX_ACK	0x74
++#define RSL_MSG_TYPE_IPAC_MDCX_NACK	0x75
++#define RSL_MSG_TYPE_IPAC_DLCX_IND	0x76
++#define RSL_MSG_TYPE_IPAC_DLCX		0x77
++#define RSL_MSG_TYPE_IPAC_DLCX_ACK	0x78
++#define RSL_MSG_TYPE_IPAC_DLCX_NACK	0x79
 +
 +#define RSL_IE_IPAC_SRTP_CONFIG		0xe0
 +#define RSL_IE_IPAC_PROXY_UDP		0xe1
@@ -122,7 +131,7 @@
  
  static const value_string rsl_msg_type_vals[] = {
  	  /* 	0 0 0 0 - - - - Radio Link Layer Management messages: */
-@@ -339,6 +415,26 @@
+@@ -337,6 +413,26 @@ static const value_string rsl_msg_type_vals[] = {
  	{  0x3f,	"TFO MODification REQuest" },					/* 8.4.31 */
  	/* 	0 1 - - - - - - Location Services messages: */
  	{  0x41,	"Location Information" },						/* 8.7.1 */
@@ -149,7 +158,7 @@
  	{ 0,		NULL }
  };
  
-@@ -372,10 +468,10 @@ static const value_string rsl_msg_type_vals[] = {
+@@ -370,10 +466,10 @@ static const value_string rsl_msg_type_vals[] = {
  #define RSL_IE_MESSAGE_ID		28
  
  #define RSL_IE_SYS_INFO_TYPE	30
@@ -164,7 +173,7 @@
  #define RSL_IE_FULL_IMM_ASS_INF			35
  #define RSL_IE_SMSCB_INF				36
  #define RSL_IE_FULL_MS_TIMING_OFFSET	37
-@@ -478,6 +574,24 @@
+@@ -476,6 +572,24 @@ static const value_string rsl_ie_type_vals[] = {
  			Not used
  
  	*/
@@ -189,7 +198,7 @@
  	{ 0,			NULL }
  };
  
-@@ -514,6 +628,96 @@
+@@ -512,6 +626,96 @@ static const value_string rsl_ch_no_Cbits_vals[] = {
  	{ 0,			NULL }
  };
  
@@ -286,7 +295,7 @@
  /* 9.3.1 Channel number			9.3.1	M TV 2 */
  static int
  dissect_rsl_ie_ch_no(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gboolean is_mandatory)
-@@ -2044,7 +2248,6 @@
+@@ -2042,7 +2246,6 @@ dissect_rsl_ie_err_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
  	proto_item_set_len(ti, length+2);
  
  	proto_tree_add_item(ie_tree, hf_rsl_ie_length, tvb, offset, 1, FALSE);
@@ -294,7 +303,7 @@
  
  	/* Received Message */
  	offset = dissct_rsl_msg(tvb, pinfo, ie_tree, offset);
-@@ -2909,12 +3112,183 @@
+@@ -2907,12 +3110,184 @@ dissect_rsl_ie_tfo_transp_cont(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree
  }
  
  static int
@@ -310,16 +319,16 @@
 +
 +#if 0
 +	switch (msg_type) {
-+	case RSL_MSG_TYPE_IPAC_BIND:
-+	case RSL_MSG_TYPE_IPAC_BIND_ACK:
-+	case RSL_MSG_TYPE_IPAC_BIND_NACK:
-+	case RSL_MSG_TYPE_IPAC_CONNECT:
-+	case RSL_MSG_TYPE_IPAC_CONNECT_ACK:
-+	case RSL_MSG_TYPE_IPAC_CONNECT_NACK:
-+	case RSL_MSG_TYPE_IPAC_DISC_IND:
-+	case RSL_MSG_TYPE_IPAC_DISC:
-+	case RSL_MSG_TYPE_IPAC_DISC_ACK:
-+	case RSL_MSG_TYPE_IPAC_DISC_NACK:
++	case RSL_MSG_TYPE_IPAC_CRCX:
++	case RSL_MSG_TYPE_IPAC_CRCX_ACK:
++	case RSL_MSG_TYPE_IPAC_CRCX_NACK:
++	case RSL_MSG_TYPE_IPAC_MDCX:
++	case RSL_MSG_TYPE_IPAC_MDCX_ACK:
++	case RSL_MSG_TYPE_IPAC_MDCX_NACK:
++	case RSL_MSG_TYPE_IPAC_DLCX_IND:
++	case RSL_MSG_TYPE_IPAC_DLCX:
++	case RSL_MSG_TYPE_IPAC_DLCX_ACK:
++	case RSL_MSG_TYPE_IPAC_DLCX_NACK:
 +	case RSL_MSG_TYPE_IPAC_PDCH_ACT:
 +	case RSL_MSG_TYPE_IPAC_PDCH_ACT_ACK:
 +	case RSL_MSG_TYPE_IPAC_PDCH_ACT_NACK:
@@ -449,7 +458,7 @@
 +	}
 +
 +	switch (msg_type) {
-+	case RSL_MSG_TYPE_IPAC_BIND_ACK:
++	case RSL_MSG_TYPE_IPAC_CRCX_ACK:
 +		/* Notify the RTP and RTCP dissectors about a new RTP stream */
 +		src_addr.type = AT_IPv4;
 +		src_addr.len = 4;
@@ -480,7 +489,7 @@
  	offset++;
  
  	switch (msg_type){
-@@ -3482,6 +3856,18 @@
+@@ -3480,6 +3855,18 @@ dissct_rsl_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
  		/* LLP APDU 9.3.58 M LV 2-N */
  		offset = dissect_rsl_ie_llp_apdu(tvb, pinfo, tree, offset, TRUE);
  		break;
@@ -499,7 +508,7 @@
  	default:
  		break;
  	}
-@@ -3489,6 +3875,40 @@
+@@ -3487,6 +3874,40 @@ dissct_rsl_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
  	return offset;
  
  }
@@ -540,7 +549,7 @@
  static void
  dissect_rsl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
  {
-@@ -3516,7 +3936,6 @@
+@@ -3514,7 +3935,6 @@ dissect_rsl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
  		/* 9.1 Message discriminator */
  		proto_tree_add_item(rsl_tree, hf_rsl_msg_dsc, tvb, offset, 1, FALSE);
  		proto_tree_add_item(rsl_tree, hf_rsl_T_bit, tvb, offset, 1, FALSE);
@@ -548,7 +557,7 @@
  
  		offset = dissct_rsl_msg(tvb, pinfo, rsl_tree, offset);
  
-@@ -3886,6 +4305,86 @@
+@@ -3884,6 +4304,86 @@ void proto_register_rsl(void)
  			FT_UINT8, BASE_DEC, VALS(rsl_emlpp_prio_vals), 0x03,
  			NULL, HFILL }
  		},
@@ -635,7 +644,7 @@
  	};
  	static gint *ett[] = {
  		&ett_rsl,
-@@ -3943,6 +4442,14 @@
+@@ -3941,6 +4441,14 @@ void proto_register_rsl(void)
  		&ett_ie_meas_res_no,
  		&ett_ie_message_id,
  		&ett_ie_sys_info_type,
@@ -650,3 +659,6 @@
  	};
  
  	/* Register the protocol name and description */
+-- 
+1.7.0.1
+