Merge branch 'on-waves/mgcp'
diff --git a/libosmocore/.gitignore b/libosmocore/.gitignore
deleted file mode 100644
index 06904fa..0000000
--- a/libosmocore/.gitignore
+++ /dev/null
@@ -1,30 +0,0 @@
-Makefile
-Makefile.in
-.deps
-.libs
-*.o
-*.lo
-*.la
-*.pc
-aclocal.m4
-m4/*.m4
-autom4te.cache
-config.h*
-config.sub
-config.log
-config.status
-config.guess
-configure
-depcomp
-missing
-ltmain.sh
-install-sh
-stamp-h1
-libtool
-
-.tarball-version
-.version
-
-tests/sms/sms_test
-tests/timer/timer_test
-
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 fde0102..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 logging.h gsm0808.h rate_ctr.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/gsm0808.h b/libosmocore/include/osmocore/gsm0808.h
deleted file mode 100644
index a40713f..0000000
--- a/libosmocore/include/osmocore/gsm0808.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* (C) 2009,2010 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009,2010 by On-Waves
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-#ifndef OSMOCORE_GSM0808_H
-#define OSMOCORE_GSM0808_H
-
-#include "tlv.h"
-
-struct msgb;
-
-struct msgb *gsm0808_create_layer3(struct msgb *msg, uint16_t netcode, uint16_t countrycode, int lac, int ci);
-struct msgb *gsm0808_create_reset(void);
-struct msgb *gsm0808_create_clear_complete(void);
-struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id);
-struct msgb *gsm0808_create_cipher_reject(uint8_t cause);
-struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark, uint8_t length);
-struct msgb *gsm0808_create_sapi_reject(uint8_t link_id);
-struct msgb *gsm0808_create_assignment_completed(struct gsm_lchan *lchan, uint8_t rr_cause,
-						 uint8_t chosen_channel, uint8_t encr_alg_id,
-						 uint8_t speech_mode);
-struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause);
-
-const struct tlv_definition *gsm0808_att_tlvdef();
-
-#endif
diff --git a/libosmocore/include/osmocore/gsm48.h b/libosmocore/include/osmocore/gsm48.h
deleted file mode 100644
index be9fbbd..0000000
--- a/libosmocore/include/osmocore/gsm48.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef _OSMOCORE_GSM48_H
-#define _OSMOCORE_GSM48_H
-
-#include <osmocore/tlv.h>
-#include <osmocore/protocol/gsm_04_08.h>
-#include <osmocore/gsm48_ie.h>
-
-/* A parsed GPRS routing area */
-struct gprs_ra_id {
-	uint16_t	mnc;
-	uint16_t	mcc;
-	uint16_t	lac;
-	uint8_t		rac;
-};
-
-extern const struct tlv_definition gsm48_att_tlvdef;
-const char *gsm48_cc_state_name(uint8_t state);
-const char *gsm48_cc_msg_name(uint8_t msgtype);
-const char *rr_cause_name(uint8_t cause);
-
-void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc,
-			uint16_t mnc, uint16_t lac);
-int gsm48_generate_mid_from_tmsi(uint8_t *buf, uint32_t tmsi);
-int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi);
-
-/* Convert Mobile Identity (10.5.1.4) to string */
-int gsm48_mi_to_string(char *string, const int str_len,
-			const uint8_t *mi, const int mi_len);
-
-/* Parse Routeing Area Identifier */
-void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf);
-int gsm48_construct_ra(uint8_t *buf, const struct gprs_ra_id *raid);
-
-#endif
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 51e9f2e..0000000
--- a/libosmocore/include/osmocore/gsm_utils.h
+++ /dev/null
@@ -1,103 +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>
-
-#define ADD_MODULO(sum, delta, modulo) do {	\
-	if ((sum += delta) >= modulo)		\
-		sum -= modulo;			\
-	} while (0)
-
-#define GSM_MAX_FN	(26*51*2048)
-
-struct gsm_time {
-	uint32_t	fn;	/* FN count */
-	uint16_t	t1;	/* FN div (26*51) */
-	uint8_t		t2;	/* FN modulo 26 */
-	uint8_t		t3;	/* FN modulo 51 */
-	uint8_t		tc;
-};
-
-enum gsm_band {
-	GSM_BAND_850	= 1,
-	GSM_BAND_900	= 2,
-	GSM_BAND_1800	= 4,
-	GSM_BAND_1900	= 8,
-	GSM_BAND_450	= 0x10,
-	GSM_BAND_480	= 0x20,
-	GSM_BAND_750	= 0x40,
-	GSM_BAND_810	= 0x80,
-};
-
-const char *gsm_band_name(enum gsm_band band);
-enum gsm_band gsm_band_parse(const char *mhz);
-
-int gsm_7bit_decode(char *decoded, const uint8_t *user_data, uint8_t length);
-int gsm_7bit_encode(uint8_t *result, const char *data);
-
-int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm);
-int ms_pwr_dbm(enum gsm_band band, uint8_t lvl);
-
-/* According to TS 08.05 Chapter 8.1.4 */
-int rxlev2dbm(uint8_t rxlev);
-uint8_t dbm2rxlev(int dbm);
-
-/* According to GSM 04.08 Chapter 10.5.2.29 */
-static inline int rach_max_trans_val2raw(int val) { return (val >> 1) & 3; }
-static inline int rach_max_trans_raw2val(int raw) {
-	const int tbl[4] = { 1, 2, 4, 7 };
-	return tbl[raw & 3];
-}
-
-#define	ARFCN_PCS	0x8000
-#define	ARFCN_UPLINK	0x4000
-
-enum gsm_band gsm_arfcn2band(uint16_t arfcn);
-
-/* Convert an ARFCN to the frequency in MHz * 10 */
-uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink);
-
-/* Convert from frame number to GSM time */
-void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn);
-
-/* Convert from GSM time to frame number */
-uint32_t gsm_gsmtime2fn(struct gsm_time *time);
-
-/* GSM TS 03.03 Chapter 2.6 */
-enum gprs_tlli_tyoe {
-	TLLI_LOCAL,
-	TLLI_FOREIGN,
-	TLLI_RANDOM,
-	TLLI_AUXILIARY,
-	TLLI_RESERVED,
-};
-
-/* TS 03.03 Chapter 2.6 */
-int gprs_tlli_type(uint32_t tlli);
-
-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/logging.h b/libosmocore/include/osmocore/logging.h
deleted file mode 100644
index 2e82959..0000000
--- a/libosmocore/include/osmocore/logging.h
+++ /dev/null
@@ -1,135 +0,0 @@
-#ifndef _OSMOCORE_LOGGING_H
-#define _OSMOCORE_LOGGING_H
-
-#include <stdio.h>
-#include <stdint.h>
-#include <osmocore/linuxlist.h>
-
-#define LOG_MAX_CATEGORY	32
-#define LOG_MAX_CTX		8
-#define LOG_MAX_FILTERS	8
-
-#define DEBUG
-
-#ifdef DEBUG
-#define DEBUGP(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 0, fmt, ## args)
-#define DEBUGPC(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 1, fmt, ## args)
-#else
-#define DEBUGP(xss, fmt, args...)
-#define DEBUGPC(ss, fmt, args...)
-#endif
-
-#define static_assert(exp, name) typedef int dummy##name [(exp) ? 1 : -1];
-
-char *hexdump(const unsigned char *buf, int len);
-void logp(unsigned int subsys, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
-
-/* new logging interface */
-#define LOGP(ss, level, fmt, args...) \
-	logp2(ss, level, __FILE__, __LINE__, 0, fmt, ##args)
-#define LOGPC(ss, level, fmt, args...) \
-	logp2(ss, level, __FILE__, __LINE__, 1, fmt, ##args)
-
-/* different levels */
-#define LOGL_DEBUG	1	/* debugging information */
-#define LOGL_INFO	3
-#define LOGL_NOTICE	5	/* abnormal/unexpected condition */
-#define LOGL_ERROR	7	/* error condition, requires user action */
-#define LOGL_FATAL	8	/* fatal, program aborted */
-
-#define LOG_FILTER_ALL	0x0001
-
-struct log_category {
-	uint8_t loglevel;
-	uint8_t enabled;
-};
-
-struct log_info_cat {
-	const char *name;
-	const char *color;
-	const char *description;
-	uint8_t loglevel;
-	uint8_t enabled;
-};
-
-/* log context information, passed to filter */
-struct log_context {
-	void *ctx[LOG_MAX_CTX+1];
-};
-
-struct log_target;
-
-typedef int log_filter(const struct log_context *ctx,
-		       struct log_target *target);
-
-struct log_info {
-	/* filter callback function */
-	log_filter *filter_fn;
-
-	/* per-category information */
-	const struct log_info_cat *cat;
-	unsigned int num_cat;
-};
-
-struct log_target {
-        struct llist_head entry;
-
-	int filter_map;
-	void *filter_data[LOG_MAX_FILTERS+1];
-
-	struct log_category categories[LOG_MAX_CATEGORY+1];
-	uint8_t loglevel;
-	int use_color:1;
-	int print_timestamp:1;
-
-	union {
-		struct {
-			FILE *out;
-		} tgt_stdout;
-
-		struct {
-			int priority;
-		} tgt_syslog;
-
-		struct {
-			void *vty;
-		} tgt_vty;
-	};
-
-        void (*output) (struct log_target *target, const char *string);
-};
-
-/* use the above macros */
-void logp2(unsigned int subsys, unsigned int level, char *file,
-	   int line, int cont, const char *format, ...)
-				__attribute__ ((format (printf, 6, 7)));
-void log_init(const struct log_info *cat);
-
-/* context management */
-void log_reset_context(void);
-int log_set_context(uint8_t ctx, void *value);
-
-/* filter on the targets */
-void log_set_all_filter(struct log_target *target, int);
-
-void log_set_use_color(struct log_target *target, int);
-void log_set_print_timestamp(struct log_target *target, int);
-void log_set_log_level(struct log_target *target, int log_level);
-void log_parse_category_mask(struct log_target *target, const char* mask);
-int log_parse_level(const char *lvl);
-const char *log_level_str(unsigned int lvl);
-int log_parse_category(const char *category);
-void log_set_category_filter(struct log_target *target, int category,
-			       int enable, int level);
-
-/* management of the targets */
-struct log_target *log_target_create(void);
-struct log_target *log_target_create_stderr(void);
-void log_add_target(struct log_target *target);
-void log_del_target(struct log_target *target);
-
-/* Gernerate command argument strings for VTY use */
-const char *log_vty_category_string(struct log_info *info);
-const char *log_vty_level_string(struct log_info *info);
-
-#endif /* _OSMOCORE_LOGGING_H */
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 2841dc5..0000000
--- a/libosmocore/include/osmocore/msgb.h
+++ /dev/null
@@ -1,165 +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 msgb {
-	struct llist_head list;
-
-	/* Part of which TRX logical channel we were received / transmitted */
-	/* FIXME: move them into the control buffer */
-	struct gsm_bts_trx *trx;
-	struct gsm_lchan *lchan;
-
-	/* the Layer1 header (if any) */
-	unsigned char *l1h;
-	/* the A-bis layer 2 header: OML, RSL(RLL), NS */
-	unsigned char *l2h;
-	/* the layer 3 header. For OML: FOM; RSL: 04.08; GPRS: BSSGP */
-	unsigned char *l3h;
-	/* the layer 4 header */
-	unsigned char *l4h;
-
-	/* the 'control buffer', large enough to contain 5 pointers */
-	unsigned long cb[5];
-
-	uint16_t data_len;
-	uint16_t len;
-
-	unsigned char *head;
-	unsigned char *tail;
-	unsigned char *data;
-	unsigned char _data[0];
-};
-
-extern struct msgb *msgb_alloc(uint16_t size, const char *name);
-extern void msgb_free(struct msgb *m);
-extern void msgb_enqueue(struct llist_head *queue, struct msgb *msg);
-extern struct msgb *msgb_dequeue(struct llist_head *queue);
-extern void msgb_reset(struct msgb *m);
-
-#define msgb_l1(m)	((void *)(m->l1h))
-#define msgb_l2(m)	((void *)(m->l2h))
-#define msgb_l3(m)	((void *)(m->l3h))
-#define msgb_sms(m)	((void *)(m->l4h))
-
-static inline unsigned int msgb_l1len(const struct msgb *msgb)
-{
-	return msgb->tail - (uint8_t *)msgb_l1(msgb);
-}
-
-static inline unsigned int msgb_l2len(const struct msgb *msgb)
-{
-	return msgb->tail - (uint8_t *)msgb_l2(msgb);
-}
-
-static inline unsigned int msgb_l3len(const struct msgb *msgb)
-{
-	return msgb->tail - (uint8_t *)msgb_l3(msgb);
-}
-
-static inline unsigned int msgb_headlen(const struct msgb *msgb)
-{
-	return msgb->len - msgb->data_len;
-}
-static inline unsigned char *msgb_put(struct msgb *msgb, unsigned int len)
-{
-	unsigned char *tmp = msgb->tail;
-	msgb->tail += len;
-	msgb->len += len;
-	return tmp;
-}
-static inline void msgb_put_u8(struct msgb *msgb, uint8_t word)
-{
-	uint8_t *space = msgb_put(msgb, 1);
-	space[0] = word & 0xFF;
-}
-static inline void msgb_put_u16(struct msgb *msgb, uint16_t word)
-{
-	uint8_t *space = msgb_put(msgb, 2);
-	space[0] = word >> 8 & 0xFF;
-	space[1] = word & 0xFF;
-}
-static inline void msgb_put_u32(struct msgb *msgb, uint32_t word)
-{
-	uint8_t *space = msgb_put(msgb, 4);
-	space[0] = word >> 24 & 0xFF;
-	space[1] = word >> 16 & 0xFF;
-	space[2] = word >> 8 & 0xFF;
-	space[3] = word & 0xFF;
-}
-static inline unsigned char *msgb_get(struct msgb *msgb, unsigned int len)
-{
-	unsigned char *tmp = msgb->data;
-	msgb->data += len;
-	msgb->len -= len;
-	return tmp;
-}
-static inline uint8_t msgb_get_u8(struct msgb *msgb)
-{
-	uint8_t *space = msgb_get(msgb, 1);
-	return space[0];
-}
-static inline uint16_t msgb_get_u16(struct msgb *msgb)
-{
-	uint8_t *space = msgb_get(msgb, 2);
-	return space[0] << 8 | space[1];
-}
-static inline uint32_t msgb_get_u32(struct msgb *msgb)
-{
-	uint8_t *space = msgb_get(msgb, 4);
-	return space[0] << 24 | space[1] << 16 | space[2] << 8 | space[3];
-}
-static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len)
-{
-	msgb->data -= len;
-	msgb->len += len;
-	return msgb->data;
-}
-static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len)
-{
-	msgb->len -= len;
-	return msgb->data += len;
-}
-static inline int msgb_tailroom(const struct msgb *msgb)
-{
-	return (msgb->head + msgb->data_len) - msgb->tail;
-}
-
-/* increase the headroom of an empty msgb, reducing the tailroom */
-static inline void msgb_reserve(struct msgb *msg, int len)
-{
-	msg->data += len;
-	msg->tail += len;
-}
-
-static inline struct msgb *msgb_alloc_headroom(int size, int headroom,
-						const char *name)
-{
-	struct msgb *msg = msgb_alloc(size, name);
-	if (msg)
-		msgb_reserve(msg, headroom);
-	return msg;
-}
-
-#endif /* _MSGB_H */
diff --git a/libosmocore/include/osmocore/protocol/Makefile.am b/libosmocore/include/osmocore/protocol/Makefile.am
deleted file mode 100644
index 557950e..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 gsm_08_08.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 1a112a0..0000000
--- a/libosmocore/include/osmocore/protocol/gsm_04_08.h
+++ /dev/null
@@ -1,751 +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_MM_CONNECTION_PEND	2 /* see 10.5.4.6 */
-#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
-
-/* Chapter 10.4.4.15 */
-struct gsm48_ra_id {
-	uint8_t digits[3];	/* MCC + MNC BCD digits */
-	uint16_t lac;		/* Location Area Code */
-	uint8_t rac;		/* Routing Area Code */
-} __attribute__ ((packed));
-
-
-
-#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_08.h b/libosmocore/include/osmocore/protocol/gsm_08_08.h
deleted file mode 100644
index 6b8f935..0000000
--- a/libosmocore/include/osmocore/protocol/gsm_08_08.h
+++ /dev/null
@@ -1,303 +0,0 @@
-/* From GSM08.08 */
-
-#ifndef GSM_0808_H
-#define GSM_0808_H
-
-#include <stdlib.h>
-
-/*
- * this is from GSM 03.03 CGI but is copied in GSM 08.08
- * in § 3.2.2.27 for Cell Identifier List
- */
-enum CELL_IDENT {
-	CELL_IDENT_WHOLE_GLOBAL		= 0,
-	CELL_IDENT_LAC_AND_CI		= 1,
-	CELL_IDENT_CI			= 2,
-	CELL_IDENT_NO_CELL		= 3,
-	CELL_IDENT_LAI_AND_LAC		= 4,
-	CELL_IDENT_LAC			= 5,
-	CELL_IDENT_BSS			= 6,
-	CELL_IDENT_UTRAN_PLMN_LAC_RNC	= 8,
-	CELL_IDENT_UTRAN_RNC		= 9,
-	CELL_IDENT_UTRAN_LAC_RNC	= 10,
-};
-
-
-/* GSM 08.06 § 6.3 */
-enum BSSAP_MSG_TYPE {
-	BSSAP_MSG_BSS_MANAGEMENT    = 0x0,
-	BSSAP_MSG_DTAP		    = 0x1,
-};
-
-struct bssmap_header {
-	uint8_t type;
-	uint8_t length;
-} __attribute__((packed));
-
-struct dtap_header {
-	uint8_t type;
-	uint8_t link_id;
-	uint8_t length;
-} __attribute__((packed));
-
-
-enum BSS_MAP_MSG_TYPE {
-	BSS_MAP_MSG_RESERVED_0		= 0,
-
-	/* ASSIGNMENT MESSAGES */
-	BSS_MAP_MSG_ASSIGMENT_RQST	= 1,
-	BSS_MAP_MSG_ASSIGMENT_COMPLETE	= 2,
-	BSS_MAP_MSG_ASSIGMENT_FAILURE	= 3,
-
-	/*  HANDOVER MESSAGES */
-	BSS_MAP_MSG_HANDOVER_RQST		= 16,
-	BSS_MAP_MSG_HANDOVER_REQUIRED		= 17,
-	BSS_MAP_MSG_HANDOVER_RQST_ACKNOWLEDGE= 18,
-	BSS_MAP_MSG_HANDOVER_CMD		= 19,
-	BSS_MAP_MSG_HANDOVER_COMPLETE		= 20,
-	BSS_MAP_MSG_HANDOVER_SUCCEEDED		= 21,
-	BSS_MAP_MSG_HANDOVER_FAILURE		= 22,
-	BSS_MAP_MSG_HANDOVER_PERFORMED		= 23,
-	BSS_MAP_MSG_HANDOVER_CANDIDATE_ENQUIRE	= 24,
-	BSS_MAP_MSG_HANDOVER_CANDIDATE_RESPONSE	= 25,
-	BSS_MAP_MSG_HANDOVER_REQUIRED_REJECT	= 26,
-	BSS_MAP_MSG_HANDOVER_DETECT		= 27,
-
-	/* RELEASE MESSAGES */
-	BSS_MAP_MSG_CLEAR_CMD		= 32,
-	BSS_MAP_MSG_CLEAR_COMPLETE		= 33,
-	BSS_MAP_MSG_CLEAR_RQST		= 34,
-	BSS_MAP_MSG_RESERVED_1			= 35,
-	BSS_MAP_MSG_RESERVED_2			= 36,
-	BSS_MAP_MSG_SAPI_N_REJECT		= 37,
-	BSS_MAP_MSG_CONFUSION			= 38,
-
-	/* OTHER CONNECTION RELATED MESSAGES */
-	BSS_MAP_MSG_SUSPEND			= 40,
-	BSS_MAP_MSG_RESUME			= 41,
-	BSS_MAP_MSG_CONNECTION_ORIENTED_INFORMATION = 42,
-	BSS_MAP_MSG_PERFORM_LOCATION_RQST	= 43,
-	BSS_MAP_MSG_LSA_INFORMATION		= 44,
-	BSS_MAP_MSG_PERFORM_LOCATION_RESPONSE	= 45,
-	BSS_MAP_MSG_PERFORM_LOCATION_ABORT	= 46,
-	BSS_MAP_MSG_COMMON_ID			= 47,
-
-	/* GENERAL MESSAGES */
-	BSS_MAP_MSG_RESET			= 48,
-	BSS_MAP_MSG_RESET_ACKNOWLEDGE		= 49,
-	BSS_MAP_MSG_OVERLOAD			= 50,
-	BSS_MAP_MSG_RESERVED_3			= 51,
-	BSS_MAP_MSG_RESET_CIRCUIT		= 52,
-	BSS_MAP_MSG_RESET_CIRCUIT_ACKNOWLEDGE	= 53,
-	BSS_MAP_MSG_MSC_INVOKE_TRACE		= 54,
-	BSS_MAP_MSG_BSS_INVOKE_TRACE		= 55,
-	BSS_MAP_MSG_CONNECTIONLESS_INFORMATION	= 58,
-
-	/* TERRESTRIAL RESOURCE MESSAGES */
-	BSS_MAP_MSG_BLOCK			= 64,
-	BSS_MAP_MSG_BLOCKING_ACKNOWLEDGE	= 65,
-	BSS_MAP_MSG_UNBLOCK			= 66,
-	BSS_MAP_MSG_UNBLOCKING_ACKNOWLEDGE	= 67,
-	BSS_MAP_MSG_CIRCUIT_GROUP_BLOCK		= 68,
-	BSS_MAP_MSG_CIRCUIT_GROUP_BLOCKING_ACKNOWLEDGE	= 69,
-	BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCK	= 70,
-	BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCKING_ACKNOWLEDGE = 71,
-	BSS_MAP_MSG_UNEQUIPPED_CIRCUIT		= 72,
-	BSS_MAP_MSG_CHANGE_CIRCUIT		= 78,
-	BSS_MAP_MSG_CHANGE_CIRCUIT_ACKNOWLEDGE	= 79,
-
-	/* RADIO RESOURCE MESSAGES */
-	BSS_MAP_MSG_RESOURCE_RQST		= 80,
-	BSS_MAP_MSG_RESOURCE_INDICATION		= 81,
-	BSS_MAP_MSG_PAGING			= 82,
-	BSS_MAP_MSG_CIPHER_MODE_CMD		= 83,
-	BSS_MAP_MSG_CLASSMARK_UPDATE		= 84,
-	BSS_MAP_MSG_CIPHER_MODE_COMPLETE	= 85,
-	BSS_MAP_MSG_QUEUING_INDICATION		= 86,
-	BSS_MAP_MSG_COMPLETE_LAYER_3		= 87,
-	BSS_MAP_MSG_CLASSMARK_RQST		= 88,
-	BSS_MAP_MSG_CIPHER_MODE_REJECT		= 89,
-	BSS_MAP_MSG_LOAD_INDICATION		= 90,
-
-	/* VGCS/VBS */
-	BSS_MAP_MSG_VGCS_VBS_SETUP		= 4,
-	BSS_MAP_MSG_VGCS_VBS_SETUP_ACK		= 5,
-	BSS_MAP_MSG_VGCS_VBS_SETUP_REFUSE	= 6,
-	BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RQST	= 7,
-	BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RESULT	= 28,
-	BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_FAILURE	= 29,
-	BSS_MAP_MSG_VGCS_VBS_QUEUING_INDICATION	= 30,
-	BSS_MAP_MSG_UPLINK_RQST		= 31,
-	BSS_MAP_MSG_UPLINK_RQST_ACKNOWLEDGE	= 39,
-	BSS_MAP_MSG_UPLINK_RQST_CONFIRMATION	= 73,
-	BSS_MAP_MSG_UPLINK_RELEASE_INDICATION	= 74,
-	BSS_MAP_MSG_UPLINK_REJECT_CMD	= 75,
-	BSS_MAP_MSG_UPLINK_RELEASE_CMD	= 76,
-	BSS_MAP_MSG_UPLINK_SEIZED_CMD	= 77,
-};
-
-enum GSM0808_IE_CODING {
-	GSM0808_IE_CIRCUIT_IDENTITY_CODE	= 1,
-	GSM0808_IE_RESERVED_0			= 2,
-	GSM0808_IE_RESOURCE_AVAILABLE		= 3,
-	GSM0808_IE_CAUSE			= 4,
-	GSM0808_IE_CELL_IDENTIFIER		= 5,
-	GSM0808_IE_PRIORITY			= 6,
-	GSM0808_IE_LAYER_3_HEADER_INFORMATION	= 7,
-	GSM0808_IE_IMSI				= 8,
-	GSM0808_IE_TMSI				= 9,
-	GSM0808_IE_ENCRYPTION_INFORMATION	= 10,
-	GSM0808_IE_CHANNEL_TYPE			= 11,
-	GSM0808_IE_PERIODICITY			= 12,
-	GSM0808_IE_EXTENDED_RESOURCE_INDICATOR	= 13,
-	GSM0808_IE_NUMBER_OF_MSS		= 14,
-	GSM0808_IE_RESERVED_1			= 15,
-	GSM0808_IE_RESERVED_2			= 16,
-	GSM0808_IE_RESERVED_3			= 17,
-	GSM0808_IE_CLASSMARK_INFORMATION_T2	= 18,
-	GSM0808_IE_CLASSMARK_INFORMATION_T3	= 19,
-	GSM0808_IE_INTERFERENCE_BAND_TO_USE	= 20,
-	GSM0808_IE_RR_CAUSE			= 21,
-	GSM0808_IE_RESERVED_4			= 22,
-	GSM0808_IE_LAYER_3_INFORMATION		= 23,
-	GSM0808_IE_DLCI				= 24,
-	GSM0808_IE_DOWNLINK_DTX_FLAG		= 25,
-	GSM0808_IE_CELL_IDENTIFIER_LIST		= 26,
-	GSM0808_IE_RESPONSE_RQST		= 27,
-	GSM0808_IE_RESOURCE_INDICATION_METHOD	= 28,
-	GSM0808_IE_CLASSMARK_INFORMATION_TYPE_1	= 29,
-	GSM0808_IE_CIRCUIT_IDENTITY_CODE_LIST	= 30,
-	GSM0808_IE_DIAGNOSTIC			= 31,
-	GSM0808_IE_LAYER_3_MESSAGE_CONTENTS	= 32,
-	GSM0808_IE_CHOSEN_CHANNEL		= 33,
-	GSM0808_IE_TOTAL_RESOURCE_ACCESSIBLE	= 34,
-	GSM0808_IE_CIPHER_RESPONSE_MODE		= 35,
-	GSM0808_IE_CHANNEL_NEEDED		= 36,
-	GSM0808_IE_TRACE_TYPE			= 37,
-	GSM0808_IE_TRIGGERID			= 38,
-	GSM0808_IE_TRACE_REFERENCE		= 39,
-	GSM0808_IE_TRANSACTIONID		= 40,
-	GSM0808_IE_MOBILE_IDENTITY		= 41,
-	GSM0808_IE_OMCID			= 42,
-	GSM0808_IE_FORWARD_INDICATOR		= 43,
-	GSM0808_IE_CHOSEN_ENCR_ALG		= 44,
-	GSM0808_IE_CIRCUIT_POOL			= 45,
-	GSM0808_IE_CIRCUIT_POOL_LIST		= 46,
-	GSM0808_IE_TIME_INDICATION		= 47,
-	GSM0808_IE_RESOURCE_SITUATION		= 48,
-	GSM0808_IE_CURRENT_CHANNEL_TYPE_1	= 49,
-	GSM0808_IE_QUEUEING_INDICATOR		= 50,
-	GSM0808_IE_SPEECH_VERSION		= 64,
-	GSM0808_IE_ASSIGNMENT_REQUIREMENT	= 51,
-	GSM0808_IE_TALKER_FLAG			= 53,
-	GSM0808_IE_CONNECTION_RELEASE_RQSTED	= 54,
-	GSM0808_IE_GROUP_CALL_REFERENCE		= 55,
-	GSM0808_IE_EMLPP_PRIORITY		= 56,
-	GSM0808_IE_CONFIG_EVO_INDI		= 57,
-	GSM0808_IE_OLD_BSS_TO_NEW_BSS_INFORMATION	= 58,
-	GSM0808_IE_LSA_IDENTIFIER		= 59,
-	GSM0808_IE_LSA_IDENTIFIER_LIST		= 60,
-	GSM0808_IE_LSA_INFORMATION		= 61,
-	GSM0808_IE_LCS_QOS			= 62,
-	GSM0808_IE_LSA_ACCESS_CTRL_SUPPR	= 63,
-	GSM0808_IE_LCS_PRIORITY			= 67,
-	GSM0808_IE_LOCATION_TYPE		= 68,
-	GSM0808_IE_LOCATION_ESTIMATE		= 69,
-	GSM0808_IE_POSITIONING_DATA		= 70,
-	GSM0808_IE_LCS_CAUSE			= 71,
-	GSM0808_IE_LCS_CLIENT_TYPE		= 72,
-	GSM0808_IE_APDU				= 73,
-	GSM0808_IE_NETWORK_ELEMENT_IDENTITY	= 74,
-	GSM0808_IE_GPS_ASSISTANCE_DATA		= 75,
-	GSM0808_IE_DECIPHERING_KEYS		= 76,
-	GSM0808_IE_RETURN_ERROR_RQST		= 77,
-	GSM0808_IE_RETURN_ERROR_CAUSE		= 78,
-	GSM0808_IE_SEGMENTATION			= 79,
-	GSM0808_IE_SERVICE_HANDOVER		= 80,
-	GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_UMTS	= 81,
-	GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_CDMA2000= 82,
-	GSM0808_IE_RESERVED_5			= 65,
-	GSM0808_IE_RESERVED_6			= 66,
-};
-
-enum gsm0808_cause {
-	GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE			= 0,
-	GSM0808_CAUSE_RADIO_INTERFACE_FAILURE				= 1,
-	GSM0808_CAUSE_UPLINK_QUALITY					= 2,
-	GSM0808_CAUSE_UPLINK_STRENGTH					= 3,
-	GSM0808_CAUSE_DOWNLINK_QUALITY					= 4,
-	GSM0808_CAUSE_DOWNLINK_STRENGTH					= 5,
-	GSM0808_CAUSE_DISTANCE						= 6,
-	GSM0808_CAUSE_O_AND_M_INTERVENTION				= 7,
-	GSM0808_CAUSE_RESPONSE_TO_MSC_INVOCATION			= 8,
-	GSM0808_CAUSE_CALL_CONTROL					= 9,
-	GSM0808_CAUSE_RADIO_INTERFACE_FAILURE_REVERSION			= 10,
-	GSM0808_CAUSE_HANDOVER_SUCCESSFUL				= 11,
-	GSM0808_CAUSE_BETTER_CELL					= 12,
-	GSM0808_CAUSE_DIRECTED_RETRY					= 13,
-	GSM0808_CAUSE_JOINED_GROUP_CALL_CHANNEL				= 14,
-	GSM0808_CAUSE_TRAFFIC						= 15,
-	GSM0808_CAUSE_EQUIPMENT_FAILURE					= 32,
-	GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE			= 33,
-	GSM0808_CAUSE_RQSTED_TERRESTRIAL_RESOURCE_UNAVAILABLE	= 34,
-	GSM0808_CAUSE_CCCH_OVERLOAD					= 35,
-	GSM0808_CAUSE_PROCESSOR_OVERLOAD				= 36,
-	GSM0808_CAUSE_BSS_NOT_EQUIPPED					= 37,
-	GSM0808_CAUSE_MS_NOT_EQUIPPED					= 38,
-	GSM0808_CAUSE_INVALID_CELL					= 39,
-	GSM0808_CAUSE_TRAFFIC_LOAD					= 40,
-	GSM0808_CAUSE_PREEMPTION					= 41,
-	GSM0808_CAUSE_RQSTED_TRANSCODING_RATE_ADAPTION_UNAVAILABLE	= 48,
-	GSM0808_CAUSE_CIRCUIT_POOL_MISMATCH				= 49,
-	GSM0808_CAUSE_SWITCH_CIRCUIT_POOL				= 50,
-	GSM0808_CAUSE_RQSTED_SPEECH_VERSION_UNAVAILABLE		= 51,
-	GSM0808_CAUSE_LSA_NOT_ALLOWED					= 52,
-	GSM0808_CAUSE_CIPHERING_ALGORITHM_NOT_SUPPORTED			= 64,
-	GSM0808_CAUSE_TERRESTRIAL_CIRCUIT_ALREADY_ALLOCATED		= 80,
-	GSM0808_CAUSE_INVALID_MESSAGE_CONTENTS				= 81,
-	GSM0808_CAUSE_INFORMATION_ELEMENT_OR_FIELD_MISSING		= 82,
-	GSM0808_CAUSE_INCORRECT_VALUE					= 83,
-	GSM0808_CAUSE_UNKNOWN_MESSAGE_TYPE				= 84,
-	GSM0808_CAUSE_UNKNOWN_INFORMATION_ELEMENT			= 85,
-	GSM0808_CAUSE_PROTOCOL_ERROR_BETWEEN_BSS_AND_MSC		= 96,
-};
-
-/* GSM 08.08 3.2.2.11 Channel Type */
-enum gsm0808_chan_indicator {
-	GSM0808_CHAN_SPEECH = 1,
-	GSM0808_CHAN_DATA   = 2,
-	GSM0808_CHAN_SIGN   = 3,
-};
-
-enum gsm0808_chan_rate_type_data {
-	GSM0808_DATA_FULL_BM	= 0x8,
-	GSM0808_DATA_HALF_LM	= 0x9,
-	GSM0808_DATA_FULL_RPREF	= 0xa,
-	GSM0808_DATA_HALF_PREF	= 0xb,
-	GSM0808_DATA_FULL_PREF_NO_CHANGE	= 0x1a,
-	GSM0808_DATA_HALF_PREF_NO_CHANGE	= 0x1b,
-	GSM0808_DATA_MULTI_MASK	= 0x20,
-	GSM0808_DATA_MULTI_MASK_NO_CHANGE	= 0x30,
-};
-
-enum gsm0808_chan_rate_type_speech {
-	GSM0808_SPEECH_FULL_BM	= 0x8,
-	GSM0808_SPEECH_HALF_LM	= 0x9,
-	GSM0808_SPEECH_FULL_PREF= 0xa,
-	GSM0808_SPEECH_HALF_PREF= 0xb,
-	GSM0808_SPEECH_FULL_PREF_NO_CHANGE	= 0x1a,
-	GSM0808_SPEECH_HALF_PREF_NO_CHANGE	= 0x1b,
-	GSM0808_SPEECH_PERM	= 0xf,
-	GSM0808_SPEECH_PERM_NO_CHANGE = 0x1f,
-};
-
-enum gsm0808_permitted_speech {
-	GSM0808_PERM_FR1	= 0x01,
-	GSM0808_PERM_FR2	= 0x11,
-	GSM0808_PERM_FR3	= 0x21,
-	GSM0808_PERM_HR1	= GSM0808_PERM_FR1 | 0x4,
-	GSM0808_PERM_HR2	= GSM0808_PERM_FR2 | 0x4,
-	GSM0808_PERM_HR3	= GSM0808_PERM_FR3 | 0x4,
-};
-
-#endif
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/rate_ctr.h b/libosmocore/include/osmocore/rate_ctr.h
deleted file mode 100644
index 88c9de5..0000000
--- a/libosmocore/include/osmocore/rate_ctr.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef _RATE_CTR_H
-#define _RATE_CTR_H
-
-#include <stdint.h>
-
-#include <osmocore/linuxlist.h>
-
-#define RATE_CTR_INTV_NUM	4
-
-enum rate_ctr_intv {
-	RATE_CTR_INTV_SEC,
-	RATE_CTR_INTV_MIN,
-	RATE_CTR_INTV_HOUR,
-	RATE_CTR_INTV_DAY,
-};
-
-/* for each of the intervals, we keep the following values */
-struct rate_ctr_per_intv {
-	uint64_t last;
-	uint64_t rate;
-};
-
-/* for each actual value, we keep the following data */
-struct rate_ctr {
-	uint64_t current;
-	struct rate_ctr_per_intv intv[RATE_CTR_INTV_NUM];
-};
-
-struct rate_ctr_desc {
-	const char *name;
-	const char *description;
-};
-
-/* Describe a counter group class */
-struct rate_ctr_group_desc {
-	/* The prefix to the name of all counters in this group */
-	char *group_name_prefix;
-	/* The human-readable description of the group */
-	char *group_description;
-	/* The number of counters in this group */
-	unsigned int num_ctr;
-	/* Pointer to array of counter names */
-	struct rate_ctr_desc *ctr_desc;
-};
-
-/* One instance of a counter group class */
-struct rate_ctr_group {
-	/* Linked list of all counter groups in the system */
-	struct llist_head list;
-	/* Pointer to the counter group class */
-	const struct rate_ctr_group_desc *desc;
-	/* The index of this ctr_group within its class */
-	unsigned int idx;
-	/* Actual counter structures below */
-	struct rate_ctr ctr[0];
-};
-
-/* Allocate a new group of counters according to description */
-struct rate_ctr_group *rate_ctr_group_alloc(void *ctx,
-					    const struct rate_ctr_group_desc *desc,
-					    unsigned int idx);
-
-/* Free the memory for the specified group of counters */
-void rate_ctr_group_free(struct rate_ctr_group *grp);
-
-/* Add a number to the counter */
-void rate_ctr_add(struct rate_ctr *ctr, int inc);
-
-/* Increment the counter by 1 */
-static inline void rate_ctr_inc(struct rate_ctr *ctr)
-{
-	rate_ctr_add(ctr, 1);
-}
-
-/* Initialize the counter module */
-int rate_ctr_init(void *tall_ctx);
-
-struct vty;
-void vty_out_rate_ctr_group(struct vty *vty, const char *prefix,
-			    struct rate_ctr_group *ctrg);
-#endif /* RATE_CTR_H */
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 ef244c3..0000000
--- a/libosmocore/include/osmocore/write_queue.h
+++ /dev/null
@@ -1,46 +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);
-	int (*except_cb)(struct bsc_fd *fd);
-};
-
-void write_queue_init(struct write_queue *queue, int max_length);
-void write_queue_clear(struct write_queue *queue);
-int write_queue_enqueue(struct write_queue *queue, struct msgb *data);
-int write_queue_bfd_cb(struct bsc_fd *fd, unsigned int what);
-
-#endif
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 ce063d0..0000000
--- a/libosmocore/src/Makefile.am
+++ /dev/null
@@ -1,17 +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 \
-			 logging.c gsm0808.c rate_ctr.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/gsm0808.c b/libosmocore/src/gsm0808.c
deleted file mode 100644
index 7a7eb3a..0000000
--- a/libosmocore/src/gsm0808.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/* (C) 2009,2010 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009,2010 by On-Waves
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <osmocore/gsm0808.h>
-#include <osmocore/protocol/gsm_08_08.h>
-#include <osmocore/gsm48.h>
-
-#include <arpa/inet.h>
-
-#define BSSMAP_MSG_SIZE 512
-#define BSSMAP_MSG_HEADROOM 128
-
-struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc, uint16_t cc, int lac, int _ci)
-{
-	uint8_t *data;
-	uint16_t *ci;
-	struct msgb* msg;
-	struct gsm48_loc_area_id *lai;
-
-	msg  = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
-				   "bssmap cmpl l3");
-	if (!msg)
-		return NULL;
-
-	/* create the bssmap header */
-	msg->l3h = msgb_put(msg, 2);
-	msg->l3h[0] = 0x0;
-
-	/* create layer 3 header */
-	data = msgb_put(msg, 1);
-	data[0] = BSS_MAP_MSG_COMPLETE_LAYER_3;
-
-	/* create the cell header */
-	data = msgb_put(msg, 3);
-	data[0] = GSM0808_IE_CELL_IDENTIFIER;
-	data[1] = 1 + sizeof(*lai) + 2;
-	data[2] = CELL_IDENT_WHOLE_GLOBAL;
-
-	lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
-	gsm48_generate_lai(lai, cc, nc, lac);
-
-	ci = (uint16_t *) msgb_put(msg, 2);
-	*ci = htons(_ci);
-
-	/* copy the layer3 data */
-	data = msgb_put(msg, msgb_l3len(msg_l3) + 2);
-	data[0] = GSM0808_IE_LAYER_3_INFORMATION;
-	data[1] = msgb_l3len(msg_l3);
-	memcpy(&data[2], msg_l3->l3h, data[1]);
-
-	/* update the size */
-	msg->l3h[1] = msgb_l3len(msg) - 2;
-
-	return msg;
-}
-
-struct msgb *gsm0808_create_reset(void)
-{
-	struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
-					       "bssmap: reset");
-	if (!msg)
-		return NULL;
-
-	msg->l3h = msgb_put(msg, 6);
-	msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
-	msg->l3h[1] = 0x04;
-	msg->l3h[2] = 0x30;
-	msg->l3h[3] = 0x04;
-	msg->l3h[4] = 0x01;
-	msg->l3h[5] = 0x20;
-	return msg;
-}
-
-struct msgb *gsm0808_create_clear_complete(void)
-{
-	struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
-					       "bssmap: clear complete");
-	if (!msg)
-		return NULL;
-
-	msg->l3h = msgb_put(msg, 3);
-	msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
-	msg->l3h[1] = 1;
-	msg->l3h[2] = BSS_MAP_MSG_CLEAR_COMPLETE;
-
-	return msg;
-}
-
-struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id)
-{
-	struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
-					       "cipher-complete");
-	if (!msg)
-		return NULL;
-
-        /* send response with BSS override for A5/1... cheating */
-	msg->l3h = msgb_put(msg, 3);
-	msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
-	msg->l3h[1] = 0xff;
-	msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_COMPLETE;
-
-	/* include layer3 in case we have at least two octets */
-	if (layer3 && msgb_l3len(layer3) > 2) {
-		msg->l4h = msgb_put(msg, msgb_l3len(layer3) + 2);
-		msg->l4h[0] = GSM0808_IE_LAYER_3_MESSAGE_CONTENTS;
-		msg->l4h[1] = msgb_l3len(layer3);
-		memcpy(&msg->l4h[2], layer3->l3h, msgb_l3len(layer3));
-	}
-
-	/* and the optional BSS message */
-	msg->l4h = msgb_put(msg, 2);
-	msg->l4h[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
-	msg->l4h[1] = alg_id;
-
-	/* update the size */
-	msg->l3h[1] = msgb_l3len(msg) - 2;
-	return msg;
-}
-
-struct msgb *gsm0808_create_cipher_reject(uint8_t cause)
-{
-	struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
-					       "bssmap: clear complete");
-	if (!msg)
-		return NULL;
-
-	msg->l3h = msgb_put(msg, 3);
-	msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
-	msg->l3h[1] = 2;
-	msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_REJECT;
-	msg->l3h[3] = cause;
-
-	return msg;
-}
-
-struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark_data, uint8_t length)
-{
-	struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
-					       "classmark-update");
-	if (!msg)
-		return NULL;
-
-	msg->l3h = msgb_put(msg, 3);
-	msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
-	msg->l3h[1] = 0xff;
-	msg->l3h[2] = BSS_MAP_MSG_CLASSMARK_UPDATE;
-
-	msg->l4h = msgb_put(msg, length);
-	memcpy(msg->l4h, classmark_data, length);
-
-	/* update the size */
-	msg->l3h[1] = msgb_l3len(msg) - 2;
-	return msg;
-}
-
-struct msgb *gsm0808_create_sapi_reject(uint8_t link_id)
-{
-	struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
-					       "bssmap: sapi 'n' reject");
-	if (!msg)
-		return NULL;
-
-	msg->l3h = msgb_put(msg, 5);
-	msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
-	msg->l3h[1] = 3;
-	msg->l3h[2] = BSS_MAP_MSG_SAPI_N_REJECT;
-	msg->l3h[3] = link_id;
-	msg->l3h[4] = GSM0808_CAUSE_BSS_NOT_EQUIPPED;
-
-	return msg;
-}
-
-struct msgb *gsm0808_create_assignment_completed(struct gsm_lchan *lchan, uint8_t rr_cause,
-						 uint8_t chosen_channel, uint8_t encr_alg_id,
-						 uint8_t speech_mode)
-{
-	uint8_t *data;
-
-	struct msgb *msg = msgb_alloc(35, "bssmap: ass compl");
-	if (!msg)
-		return NULL;
-
-	msg->l3h = msgb_put(msg, 3);
-	msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
-	msg->l3h[1] = 0xff;
-	msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_COMPLETE;
-
-	/* write 3.2.2.22 */
-	data = msgb_put(msg, 2);
-	data[0] = GSM0808_IE_RR_CAUSE;
-	data[1] = rr_cause;
-
-	/* write cirtcuit identity  code 3.2.2.2 */
-	/* write cell identifier 3.2.2.17 */
-	/* write chosen channel 3.2.2.33 when BTS picked it */
-	data = msgb_put(msg, 2);
-	data[0] = GSM0808_IE_CHOSEN_CHANNEL;
-	data[1] = chosen_channel;
-
-	/* write chosen encryption algorithm 3.2.2.44 */
-	data = msgb_put(msg, 2);
-	data[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
-	data[1] = encr_alg_id;
-
-	/* write circuit pool 3.2.2.45 */
-	/* write speech version chosen: 3.2.2.51 when BTS picked it */
-	if (speech_mode != 0) {
-		data = msgb_put(msg, 2);
-		data[0] = GSM0808_IE_SPEECH_VERSION;
-		data[1] = speech_mode;
-	}
-
-	/* write LSA identifier 3.2.2.15 */
-
-
-	/* update the size */
-	msg->l3h[1] = msgb_l3len(msg) - 2;
-	return msg;
-}
-
-struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause)
-{
-	uint8_t *data;
-	struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
-					       "bssmap: ass fail");
-	if (!msg)
-		return NULL;
-
-	msg->l3h = msgb_put(msg, 6);
-	msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
-	msg->l3h[1] = 0xff;
-	msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE;
-	msg->l3h[3] = GSM0808_IE_CAUSE;
-	msg->l3h[4] = 1;
-	msg->l3h[5] = cause;
-
-	/* RR cause 3.2.2.22 */
-	if (rr_cause) {
-		data = msgb_put(msg, 2);
-		data[0] = GSM0808_IE_RR_CAUSE;
-		data[1] = *rr_cause;
-	}
-
-	/* Circuit pool 3.22.45 */
-	/* Circuit pool list 3.2.2.46 */
-
-	/* update the size */
-	msg->l3h[1] = msgb_l3len(msg) - 2;
-	return msg;
-}
-
-static const struct tlv_definition bss_att_tlvdef = {
-	.def = {
-		[GSM0808_IE_IMSI]		    = { TLV_TYPE_TLV },
-		[GSM0808_IE_TMSI]		    = { TLV_TYPE_TLV },
-		[GSM0808_IE_CELL_IDENTIFIER_LIST]   = { TLV_TYPE_TLV },
-		[GSM0808_IE_CHANNEL_NEEDED]	    = { TLV_TYPE_TV },
-		[GSM0808_IE_EMLPP_PRIORITY]	    = { TLV_TYPE_TV },
-		[GSM0808_IE_CHANNEL_TYPE]	    = { TLV_TYPE_TLV },
-		[GSM0808_IE_PRIORITY]		    = { TLV_TYPE_TLV },
-		[GSM0808_IE_CIRCUIT_IDENTITY_CODE]  = { TLV_TYPE_TV },
-		[GSM0808_IE_DOWNLINK_DTX_FLAG]	    = { TLV_TYPE_TV },
-		[GSM0808_IE_INTERFERENCE_BAND_TO_USE] = { TLV_TYPE_TV },
-		[GSM0808_IE_CLASSMARK_INFORMATION_T2] = { TLV_TYPE_TLV },
-		[GSM0808_IE_GROUP_CALL_REFERENCE]   = { TLV_TYPE_TLV },
-		[GSM0808_IE_TALKER_FLAG]	    = { TLV_TYPE_T },
-		[GSM0808_IE_CONFIG_EVO_INDI]	    = { TLV_TYPE_TV },
-		[GSM0808_IE_LSA_ACCESS_CTRL_SUPPR]  = { TLV_TYPE_TV },
-		[GSM0808_IE_SERVICE_HANDOVER]	    = { TLV_TYPE_TV},
-		[GSM0808_IE_ENCRYPTION_INFORMATION] = { TLV_TYPE_TLV },
-		[GSM0808_IE_CIPHER_RESPONSE_MODE]   = { TLV_TYPE_TV },
-	},
-};
-
-const struct tlv_definition *gsm0808_att_tlvdef()
-{
-	return &bss_att_tlvdef;
-}
diff --git a/libosmocore/src/gsm48.c b/libosmocore/src/gsm48.c
deleted file mode 100644
index d957aef..0000000
--- a/libosmocore/src/gsm48.c
+++ /dev/null
@@ -1,353 +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[33] = {
-	"NULL",
-	"INITIATED",
-	"MM_CONNECTION_PEND",
-	"MO_CALL_PROC",
-	"CALL_DELIVERED",
-	"illegal state 5",
-	"CALL_PRESENT",
-	"CALL_RECEIVED",
-	"CONNECT_REQUEST",
-	"MO_TERM_CALL_CONF",
-	"ACTIVE",
-	"DISCONNECT_REQ",
-	"DISCONNECT_IND",
-	"illegal state 13",
-	"illegal state 14",
-	"illegal state 15",
-	"illegal state 16",
-	"illegal state 17",
-	"illegal state 18",
-	"RELEASE_REQ",
-	"illegal state 20",
-	"illegal state 21",
-	"illegal state 22",
-	"illegal state 23",
-	"illegal state 24",
-	"illegal state 25",
-	"MO_ORIG_MODIFY",
-	"MO_TERM_MODIFY",
-	"CONNECT_IND",
-	"illegal state 29",
-	"illegal state 30",
-	"illegal state 31",
-};
-
-const char *gsm48_cc_state_name(uint8_t state)
-{
-	if (state < ARRAY_SIZE(cc_state_names))
-		return cc_state_names[state];
-
-	return "invalid";
-}
-
-static const struct value_string cc_msg_names[] = {
-	{ GSM48_MT_CC_ALERTING,		"ALERTING" },
-	{ GSM48_MT_CC_CALL_PROC,	"CALL_PROC" },
-	{ GSM48_MT_CC_PROGRESS,		"PROGRESS" },
-	{ GSM48_MT_CC_ESTAB,		"ESTAB" },
-	{ GSM48_MT_CC_SETUP,		"SETUP" },
-	{ GSM48_MT_CC_ESTAB_CONF,	"ESTAB_CONF" },
-	{ GSM48_MT_CC_CONNECT,		"CONNECT" },
-	{ GSM48_MT_CC_CALL_CONF,	"CALL_CONF" },
-	{ GSM48_MT_CC_START_CC,		"START_CC" },
-	{ GSM48_MT_CC_RECALL,		"RECALL" },
-	{ GSM48_MT_CC_EMERG_SETUP,	"EMERG_SETUP" },
-	{ GSM48_MT_CC_CONNECT_ACK,	"CONNECT_ACK" },
-	{ GSM48_MT_CC_USER_INFO,	"USER_INFO" },
-	{ GSM48_MT_CC_MODIFY_REJECT,	"MODIFY_REJECT" },
-	{ GSM48_MT_CC_MODIFY,		"MODIFY" },
-	{ GSM48_MT_CC_HOLD,		"HOLD" },
-	{ GSM48_MT_CC_HOLD_ACK,		"HOLD_ACK" },
-	{ GSM48_MT_CC_HOLD_REJ,		"HOLD_REJ" },
-	{ GSM48_MT_CC_RETR,		"RETR" },
-	{ GSM48_MT_CC_RETR_ACK,		"RETR_ACK" },
-	{ GSM48_MT_CC_RETR_REJ,		"RETR_REJ" },
-	{ GSM48_MT_CC_MODIFY_COMPL,	"MODIFY_COMPL" },
-	{ GSM48_MT_CC_DISCONNECT,	"DISCONNECT" },
-	{ GSM48_MT_CC_RELEASE_COMPL,	"RELEASE_COMPL" },
-	{ GSM48_MT_CC_RELEASE,		"RELEASE" },
-	{ GSM48_MT_CC_STOP_DTMF,	"STOP_DTMF" },
-	{ GSM48_MT_CC_STOP_DTMF_ACK,	"STOP_DTMF_ACK" },
-	{ GSM48_MT_CC_STATUS_ENQ,	"STATUS_ENQ" },
-	{ GSM48_MT_CC_START_DTMF,	"START_DTMF" },
-	{ GSM48_MT_CC_START_DTMF_ACK,	"START_DTMF_ACK" },
-	{ GSM48_MT_CC_START_DTMF_REJ,	"START_DTMF_REJ" },
-	{ GSM48_MT_CC_CONG_CTRL,	"CONG_CTRL" },
-	{ GSM48_MT_CC_FACILITY,		"FACILITY" },
-	{ GSM48_MT_CC_STATUS,		"STATUS" },
-	{ GSM48_MT_CC_NOTIFY,		"NOTFIY" },
-	{ 0,				NULL }
-};
-
-const char *gsm48_cc_msg_name(uint8_t msgtype)
-{
-	return get_value_string(cc_msg_names, msgtype);
-}
-
-const char *rr_cause_name(uint8_t cause)
-{
-	return get_value_string(rr_cause_names, cause);
-}
-
-static void to_bcd(uint8_t *bcd, uint16_t val)
-{
-	bcd[2] = val % 10;
-	val = val / 10;
-	bcd[1] = val % 10;
-	val = val / 10;
-	bcd[0] = val % 10;
-	val = val / 10;
-}
-
-void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc,
-			uint16_t mnc, uint16_t lac)
-{
-	uint8_t bcd[3];
-
-	to_bcd(bcd, mcc);
-	lai48->digits[0] = bcd[0] | (bcd[1] << 4);
-	lai48->digits[1] = bcd[2];
-
-	to_bcd(bcd, mnc);
-	/* FIXME: do we need three-digit MNC? See Table 10.5.3 */
-#if 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];
-}
-
-/* Convert Mobile Identity (10.5.1.4) to string */
-int gsm48_mi_to_string(char *string, const int str_len, const uint8_t *mi,
-		       const int mi_len)
-{
-	int i;
-	uint8_t mi_type;
-	char *str_cur = string;
-	uint32_t tmsi;
-
-	mi_type = mi[0] & GSM_MI_TYPE_MASK;
-
-	switch (mi_type) {
-	case GSM_MI_TYPE_NONE:
-		break;
-	case GSM_MI_TYPE_TMSI:
-		/* Table 10.5.4.3, reverse generate_mid_from_tmsi */
-		if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
-			memcpy(&tmsi, &mi[1], 4);
-			tmsi = ntohl(tmsi);
-			return snprintf(string, str_len, "%u", tmsi);
-		}
-		break;
-	case GSM_MI_TYPE_IMSI:
-	case GSM_MI_TYPE_IMEI:
-	case GSM_MI_TYPE_IMEISV:
-		*str_cur++ = bcd2char(mi[0] >> 4);
-
-                for (i = 1; i < mi_len; i++) {
-			if (str_cur + 2 >= string + str_len)
-				return str_cur - string;
-			*str_cur++ = bcd2char(mi[i] & 0xf);
-			/* skip last nibble in last input byte when GSM_EVEN */
-			if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
-				*str_cur++ = bcd2char(mi[i] >> 4);
-		}
-		break;
-	default:
-		break;
-	}
-	*str_cur++ = '\0';
-
-	return str_cur - string;
-}
-
-void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf)
-{
-	raid->mcc = (buf[0] & 0xf) * 100;
-	raid->mcc += (buf[0] >> 4) * 10;
-	raid->mcc += (buf[1] & 0xf) * 1;
-
-	/* I wonder who came up with the stupidity of encoding the MNC
-	 * differently depending on how many digits its decimal number has! */
-	if ((buf[1] >> 4) == 0xf) {
-		raid->mnc = (buf[2] & 0xf) * 10;
-		raid->mnc += (buf[2] >> 4) * 1;
-	} else {
-		raid->mnc = (buf[2] & 0xf) * 100;
-		raid->mnc += (buf[2] >> 4) * 10;
-		raid->mnc += (buf[1] >> 4) * 1;
-	}
-
-	raid->lac = ntohs(*(uint16_t *)(buf + 3));
-	raid->rac = buf[5];
-}
-
-int gsm48_construct_ra(uint8_t *buf, const struct gprs_ra_id *raid)
-{
-	uint16_t mcc = raid->mcc;
-	uint16_t mnc = raid->mnc;
-
-	buf[0] = ((mcc / 100) % 10) | (((mcc / 10) % 10) << 4);
-	buf[1] = (mcc % 10);
-
-	/* I wonder who came up with the stupidity of encoding the MNC
-	 * differently depending on how many digits its decimal number has! */
-	if (mnc < 100) {
-		buf[1] |= 0xf0;
-		buf[2] = ((mnc / 10) % 10) | ((mnc % 10) << 4);
-	} else {
-		buf[1] |= (mnc % 10) << 4;
-		buf[2] = ((mnc / 100) % 10) | (((mcc / 10) % 10) << 4);
-	}
-
-	*(uint16_t *)(buf+3) = htons(raid->lac);
-
-	buf[5] = raid->rac;
-
-	return 6;
-}
diff --git a/libosmocore/src/gsm48_ie.c b/libosmocore/src/gsm48_ie.c
deleted file mode 100644
index 3c2a1f7..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) 2009-2010 by Andreas Eversberg
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-
-#include <stdint.h>
-#include <string.h>
-#include <errno.h>
-
-#include <osmocore/utils.h>
-#include <osmocore/msgb.h>
-#include <osmocore/tlv.h>
-#include <osmocore/mncc.h>
-#include <osmocore/protocol/gsm_04_08.h>
-
-static const char bcd_num_digits[] = {
-	'0', '1', '2', '3', '4', '5', '6', '7',
-	'8', '9', '*', '#', 'a', 'b', 'c', '\0'
-};
-
-/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */
-int gsm48_decode_bcd_number(char *output, int output_len,
-			    const uint8_t *bcd_lv, int h_len)
-{
-	uint8_t in_len = bcd_lv[0];
-	int i;
-
-	for (i = 1 + h_len; i <= in_len; i++) {
-		/* lower nibble */
-		output_len--;
-		if (output_len <= 1)
-			break;
-		*output++ = bcd_num_digits[bcd_lv[i] & 0xf];
-
-		/* higher nibble */
-		output_len--;
-		if (output_len <= 1)
-			break;
-		*output++ = bcd_num_digits[bcd_lv[i] >> 4];
-	}
-	if (output_len >= 1)
-		*output++ = '\0';
-
-	return 0;
-}
-
-/* convert a single ASCII character to call-control BCD */
-static int asc_to_bcd(const char asc)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) {
-		if (bcd_num_digits[i] == asc)
-			return i;
-	}
-	return -EINVAL;
-}
-
-/* convert a ASCII phone number to 'called/calling/connect party BCD number' */
-int gsm48_encode_bcd_number(uint8_t *bcd_lv, uint8_t max_len,
-		      int h_len, const char *input)
-{
-	int in_len = strlen(input);
-	int i;
-	uint8_t *bcd_cur = bcd_lv + 1 + h_len;
-
-	/* two digits per byte, plus type byte */
-	bcd_lv[0] = in_len/2 + h_len;
-	if (in_len % 2)
-		bcd_lv[0]++;
-
-	if (bcd_lv[0] > max_len)
-		return -EIO;
-
-	for (i = 0; i < in_len; i++) {
-		int rc = asc_to_bcd(input[i]);
-		if (rc < 0)
-			return rc;
-		if (i % 2 == 0)
-			*bcd_cur = rc;
-		else
-			*bcd_cur++ |= (rc << 4);
-	}
-	/* append padding nibble in case of odd length */
-	if (i % 2)
-		*bcd_cur++ |= 0xf0;
-
-	/* return how many bytes we used */
-	return (bcd_cur - bcd_lv);
-}
-
-/* decode 'bearer capability' */
-int gsm48_decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
-			     const uint8_t *lv)
-{
-	uint8_t in_len = lv[0];
-	int i, s;
-
-	if (in_len < 1)
-		return -EINVAL;
-
-	bcap->speech_ver[0] = -1; /* end of list, of maximum 7 values */
-
-	/* octet 3 */
-	bcap->transfer = lv[1] & 0x07;
-	bcap->mode = (lv[1] & 0x08) >> 3;
-	bcap->coding = (lv[1] & 0x10) >> 4;
-	bcap->radio = (lv[1] & 0x60) >> 5;
-
-	if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) {
-		i = 1;
-		s = 0;
-		while(!(lv[i] & 0x80)) {
-			i++; /* octet 3a etc */
-			if (in_len < i)
-				return 0;
-			bcap->speech_ver[s++] = lv[i] & 0x0f;
-			bcap->speech_ver[s] = -1; /* end of list */
-			if (i == 2) /* octet 3a */
-				bcap->speech_ctm = (lv[i] & 0x20) >> 5;
-			if (s == 7) /* maximum speech versions + end of list */
-				return 0;
-		}
-	} else {
-		i = 1;
-		while (!(lv[i] & 0x80)) {
-			i++; /* octet 3a etc */
-			if (in_len < i)
-				return 0;
-			/* ignore them */
-		}
-		/* FIXME: implement OCTET 4+ parsing */
-	}
-
-	return 0;
-}
-
-/* encode 'bearer capability' */
-int gsm48_encode_bearer_cap(struct msgb *msg, int lv_only,
-			     const struct gsm_mncc_bearer_cap *bcap)
-{
-	uint8_t lv[32 + 1];
-	int i = 1, s;
-
-	lv[1] = bcap->transfer;
-	lv[1] |= bcap->mode << 3;
-	lv[1] |= bcap->coding << 4;
-	lv[1] |= bcap->radio << 5;
-
-	if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) {
-		for (s = 0; bcap->speech_ver[s] >= 0; s++) {
-			i++; /* octet 3a etc */
-			lv[i] = bcap->speech_ver[s];
-			if (i == 2) /* octet 3a */
-				lv[i] |= bcap->speech_ctm << 5;
-		}
-		lv[i] |= 0x80; /* last IE of octet 3 etc */
-	} else {
-		/* FIXME: implement OCTET 4+ encoding */
-	}
-
-	lv[0] = i;
-	if (lv_only)
-		msgb_lv_put(msg, lv[0], lv+1);
-	else
-		msgb_tlv_put(msg, GSM48_IE_BEARER_CAP, lv[0], lv+1);
-
-	return 0;
-}
-
-/* decode 'call control cap' */
-int gsm48_decode_cccap(struct gsm_mncc_cccap *ccap, const uint8_t *lv)
-{
-	uint8_t in_len = lv[0];
-
-	if (in_len < 1)
-		return -EINVAL;
-
-	/* octet 3 */
-	ccap->dtmf = lv[1] & 0x01;
-	ccap->pcp = (lv[1] & 0x02) >> 1;
-
-	return 0;
-}
-
-/* encode 'call control cap' */
-int gsm48_encode_cccap(struct msgb *msg,
-			const struct gsm_mncc_cccap *ccap)
-{
-	uint8_t lv[2];
-
-	lv[0] = 1;
-	lv[1] = 0;
-	if (ccap->dtmf)
-		lv [1] |= 0x01;
-	if (ccap->pcp)
-		lv [1] |= 0x02;
-
-	msgb_tlv_put(msg, GSM48_IE_CC_CAP, lv[0], lv+1);
-
-	return 0;
-}
-
-/* decode 'called party BCD number' */
-int gsm48_decode_called(struct gsm_mncc_number *called,
-			 const uint8_t *lv)
-{
-	uint8_t in_len = lv[0];
-
-	if (in_len < 1)
-		return -EINVAL;
-
-	/* octet 3 */
-	called->plan = lv[1] & 0x0f;
-	called->type = (lv[1] & 0x70) >> 4;
-
-	/* octet 4..N */
-	gsm48_decode_bcd_number(called->number, sizeof(called->number), lv, 1);
-
-	return 0;
-}
-
-/* encode 'called party BCD number' */
-int gsm48_encode_called(struct msgb *msg,
-			 const struct gsm_mncc_number *called)
-{
-	uint8_t lv[18];
-	int ret;
-
-	/* octet 3 */
-	lv[1] = called->plan;
-	lv[1] |= called->type << 4;
-
-	/* octet 4..N, octet 2 */
-	ret = gsm48_encode_bcd_number(lv, sizeof(lv), 1, called->number);
-	if (ret < 0)
-		return ret;
-
-	msgb_tlv_put(msg, GSM48_IE_CALLED_BCD, lv[0], lv+1);
-
-	return 0;
-}
-
-/* decode callerid of various IEs */
-int gsm48_decode_callerid(struct gsm_mncc_number *callerid,
-			 const uint8_t *lv)
-{
-	uint8_t in_len = lv[0];
-	int i = 1;
-
-	if (in_len < 1)
-		return -EINVAL;
-
-	/* octet 3 */
-	callerid->plan = lv[1] & 0x0f;
-	callerid->type = (lv[1] & 0x70) >> 4;
-
-	/* octet 3a */
-	if (!(lv[1] & 0x80)) {
-		callerid->screen = lv[2] & 0x03;
-		callerid->present = (lv[2] & 0x60) >> 5;
-		i = 2;
-	}
-
-	/* octet 4..N */
-	gsm48_decode_bcd_number(callerid->number, sizeof(callerid->number), lv, i);
-
-	return 0;
-}
-
-/* encode callerid of various IEs */
-int gsm48_encode_callerid(struct msgb *msg, int ie, int max_len,
-			   const struct gsm_mncc_number *callerid)
-{
-	uint8_t lv[max_len - 1];
-	int h_len = 1;
-	int ret;
-
-	/* octet 3 */
-	lv[1] = callerid->plan;
-	lv[1] |= callerid->type << 4;
-
-	if (callerid->present || callerid->screen) {
-		/* octet 3a */
-		lv[2] = callerid->screen;
-		lv[2] |= callerid->present << 5;
-		lv[2] |= 0x80;
-		h_len++;
-	} else
-		lv[1] |= 0x80;
-
-	/* octet 4..N, octet 2 */
-	ret = gsm48_encode_bcd_number(lv, sizeof(lv), h_len, callerid->number);
-	if (ret < 0)
-		return ret;
-
-	msgb_tlv_put(msg, ie, lv[0], lv+1);
-
-	return 0;
-}
-
-/* decode 'cause' */
-int gsm48_decode_cause(struct gsm_mncc_cause *cause,
-			const uint8_t *lv)
-{
-	uint8_t in_len = lv[0];
-	int i;
-
-	if (in_len < 2)
-		return -EINVAL;
-
-	cause->diag_len = 0;
-
-	/* octet 3 */
-	cause->location = lv[1] & 0x0f;
-	cause->coding = (lv[1] & 0x60) >> 5;
-
-	i = 1;
-	if (!(lv[i] & 0x80)) {
-		i++; /* octet 3a */
-		if (in_len < i+1)
-			return 0;
-		cause->rec = 1;
-		cause->rec_val = lv[i] & 0x7f;
-	}
-	i++;
-
-	/* octet 4 */
-	cause->value = lv[i] & 0x7f;
-	i++;
-
-	if (in_len < i) /* no diag */
-		return 0;
-
-	if (in_len - (i-1) > 32) /* maximum 32 octets */
-		return 0;
-
-	/* octet 5-N */
-	memcpy(cause->diag, lv + i, in_len - (i-1));
-	cause->diag_len = in_len - (i-1);
-
-	return 0;
-}
-
-/* encode 'cause' */
-int gsm48_encode_cause(struct msgb *msg, int lv_only,
-			const struct gsm_mncc_cause *cause)
-{
-	uint8_t lv[32+4];
-	int i;
-
-	if (cause->diag_len > 32)
-		return -EINVAL;
-
-	/* octet 3 */
-	lv[1] = cause->location;
-	lv[1] |= cause->coding << 5;
-
-	i = 1;
-	if (cause->rec) {
-		i++; /* octet 3a */
-		lv[i] = cause->rec_val;
-	}
-	lv[i] |= 0x80; /* end of octet 3 */
-
-	/* octet 4 */
-	i++;
-	lv[i] = 0x80 | cause->value;
-
-	/* octet 5-N */
-	if (cause->diag_len) {
-		memcpy(lv + i, cause->diag, cause->diag_len);
-		i += cause->diag_len;
-	}
-
-	lv[0] = i;
-	if (lv_only)
-		msgb_lv_put(msg, lv[0], lv+1);
-	else
-		msgb_tlv_put(msg, GSM48_IE_CAUSE, lv[0], lv+1);
-
-	return 0;
-}
-
-/* decode 'calling number' */
-int gsm48_decode_calling(struct gsm_mncc_number *calling,
-			 const uint8_t *lv)
-{
-	return gsm48_decode_callerid(calling, lv);
-}
-
-/* encode 'calling number' */
-int gsm48_encode_calling(struct msgb *msg, 
-			  const struct gsm_mncc_number *calling)
-{
-	return gsm48_encode_callerid(msg, GSM48_IE_CALLING_BCD, 14, calling);
-}
-
-/* decode 'connected number' */
-int gsm48_decode_connected(struct gsm_mncc_number *connected,
-			 const uint8_t *lv)
-{
-	return gsm48_decode_callerid(connected, lv);
-}
-
-/* encode 'connected number' */
-int gsm48_encode_connected(struct msgb *msg,
-			    const struct gsm_mncc_number *connected)
-{
-	return gsm48_encode_callerid(msg, GSM48_IE_CONN_BCD, 14, connected);
-}
-
-/* decode 'redirecting number' */
-int gsm48_decode_redirecting(struct gsm_mncc_number *redirecting,
-			 const uint8_t *lv)
-{
-	return gsm48_decode_callerid(redirecting, lv);
-}
-
-/* encode 'redirecting number' */
-int gsm48_encode_redirecting(struct msgb *msg,
-			      const struct gsm_mncc_number *redirecting)
-{
-	return gsm48_encode_callerid(msg, GSM48_IE_REDIR_BCD, 19, redirecting);
-}
-
-/* decode 'facility' */
-int gsm48_decode_facility(struct gsm_mncc_facility *facility,
-			   const uint8_t *lv)
-{
-	uint8_t in_len = lv[0];
-
-	if (in_len < 1)
-		return -EINVAL;
-
-	if (in_len > sizeof(facility->info))
-		return -EINVAL;
-
-	memcpy(facility->info, lv+1, in_len);
-	facility->len = in_len;
-
-	return 0;
-}
-
-/* encode 'facility' */
-int gsm48_encode_facility(struct msgb *msg, int lv_only,
-			   const struct gsm_mncc_facility *facility)
-{
-	uint8_t lv[GSM_MAX_FACILITY + 1];
-
-	if (facility->len < 1 || facility->len > GSM_MAX_FACILITY)
-		return -EINVAL;
-
-	memcpy(lv+1, facility->info, facility->len);
-	lv[0] = facility->len;
-	if (lv_only)
-		msgb_lv_put(msg, lv[0], lv+1);
-	else
-		msgb_tlv_put(msg, GSM48_IE_FACILITY, lv[0], lv+1);
-
-	return 0;
-}
-
-/* decode 'notify' */
-int gsm48_decode_notify(int *notify, const uint8_t *v)
-{
-	*notify = v[0] & 0x7f;
-
-	return 0;
-}
-
-/* encode 'notify' */
-int gsm48_encode_notify(struct msgb *msg, int notify)
-{
-	msgb_v_put(msg, notify | 0x80);
-
-	return 0;
-}
-
-/* decode 'signal' */
-int gsm48_decode_signal(int *signal, const uint8_t *v)
-{
-	*signal = v[0];
-
-	return 0;
-}
-
-/* encode 'signal' */
-int gsm48_encode_signal(struct msgb *msg, int signal)
-{
-	msgb_tv_put(msg, GSM48_IE_SIGNAL, signal);
-
-	return 0;
-}
-
-/* decode 'keypad' */
-int gsm48_decode_keypad(int *keypad, const uint8_t *lv)
-{
-	uint8_t in_len = lv[0];
-
-	if (in_len < 1)
-		return -EINVAL;
-
-	*keypad = lv[1] & 0x7f;
-
-	return 0;
-}
-
-/* encode 'keypad' */
-int gsm48_encode_keypad(struct msgb *msg, int keypad)
-{
-	msgb_tv_put(msg, GSM48_IE_KPD_FACILITY, keypad);
-
-	return 0;
-}
-
-/* decode 'progress' */
-int gsm48_decode_progress(struct gsm_mncc_progress *progress,
-			   const uint8_t *lv)
-{
-	uint8_t in_len = lv[0];
-
-	if (in_len < 2)
-		return -EINVAL;
-
-	progress->coding = (lv[1] & 0x60) >> 5;
-	progress->location = lv[1] & 0x0f;
-	progress->descr = lv[2] & 0x7f;
-
-	return 0;
-}
-
-/* encode 'progress' */
-int gsm48_encode_progress(struct msgb *msg, int lv_only,
-			   const struct gsm_mncc_progress *p)
-{
-	uint8_t lv[3];
-
-	lv[0] = 2;
-	lv[1] = 0x80 | ((p->coding & 0x3) << 5) | (p->location & 0xf);
-	lv[2] = 0x80 | (p->descr & 0x7f);
-	if (lv_only)
-		msgb_lv_put(msg, lv[0], lv+1);
-	else
-		msgb_tlv_put(msg, GSM48_IE_PROGR_IND, lv[0], lv+1);
-
-	return 0;
-}
-
-/* decode 'user-user' */
-int gsm48_decode_useruser(struct gsm_mncc_useruser *uu,
-			   const uint8_t *lv)
-{
-	uint8_t in_len = lv[0];
-	char *info = uu->info;
-	int info_len = sizeof(uu->info);
-	int i;
-
-	if (in_len < 1)
-		return -EINVAL;
-
-	uu->proto = lv[1];
-
-	for (i = 2; i <= in_len; i++) {
-		info_len--;
-		if (info_len <= 1)
-			break;
-		*info++ = lv[i];
-	}
-	if (info_len >= 1)
-		*info++ = '\0';
-
-	return 0;
-}
-
-/* encode 'useruser' */
-int gsm48_encode_useruser(struct msgb *msg, int lv_only,
-			   const struct gsm_mncc_useruser *uu)
-{
-	uint8_t lv[GSM_MAX_USERUSER + 2];
-
-	if (strlen(uu->info) > GSM_MAX_USERUSER)
-		return -EINVAL;
-
-	lv[0] = 1 + strlen(uu->info);
-	lv[1] = uu->proto;
-	memcpy(lv + 2, uu->info, strlen(uu->info));
-	if (lv_only)
-		msgb_lv_put(msg, lv[0], lv+1);
-	else
-		msgb_tlv_put(msg, GSM48_IE_USER_USER, lv[0], lv+1);
-
-	return 0;
-}
-
-/* decode 'ss version' */
-int gsm48_decode_ssversion(struct gsm_mncc_ssversion *ssv,
-			    const uint8_t *lv)
-{
-	uint8_t in_len = lv[0];
-
-	if (in_len < 1 || in_len < sizeof(ssv->info))
-		return -EINVAL;
-
-	memcpy(ssv->info, lv + 1, in_len);
-	ssv->len = in_len;
-
-	return 0;
-}
-
-/* encode 'ss version' */
-int gsm48_encode_ssversion(struct msgb *msg,
-			   const struct gsm_mncc_ssversion *ssv)
-{
-	uint8_t lv[GSM_MAX_SSVERSION + 1];
-
-	if (ssv->len > GSM_MAX_SSVERSION)
-		return -EINVAL;
-
-	lv[0] = ssv->len;
-	memcpy(lv + 1, ssv->info, ssv->len);
-	msgb_tlv_put(msg, GSM48_IE_SS_VERS, lv[0], lv+1);
-
-	return 0;
-}
-
-/* decode 'more data' does not require a function, because it has no value */
-
-/* encode 'more data' */
-int gsm48_encode_more(struct msgb *msg)
-{
-	uint8_t *ie;
-
-	ie = msgb_put(msg, 1);
-	ie[0] = GSM48_IE_MORE_DATA;
-
-	return 0;
-}
-
diff --git a/libosmocore/src/gsm_utils.c b/libosmocore/src/gsm_utils.c
deleted file mode 100644
index b392fd3..0000000
--- a/libosmocore/src/gsm_utils.c
+++ /dev/null
@@ -1,376 +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));
-}
-
-/* TS 03.03 Chapter 2.6 */
-int gprs_tlli_type(uint32_t tlli)
-{
-	if ((tlli & 0xc0000000) == 0xc0000000)
-		return TLLI_LOCAL;
-	else if ((tlli & 0xc0000000) == 0x80000000)
-		return TLLI_FOREIGN;
-	else if ((tlli & 0xf8000000) == 0x78000000)
-		return TLLI_RANDOM;
-	else if ((tlli & 0xf8000000) == 0x70000000)
-		return TLLI_AUXILIARY;
-
-	return TLLI_RESERVED;
-}
diff --git a/libosmocore/src/logging.c b/libosmocore/src/logging.c
deleted file mode 100644
index e72a6e2..0000000
--- a/libosmocore/src/logging.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/* Debugging/Logging support code */
-
-/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
- * (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include "../config.h"
-
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#include <time.h>
-#include <errno.h>
-
-#include <osmocore/talloc.h>
-#include <osmocore/utils.h>
-#include <osmocore/logging.h>
-
-static const struct log_info *log_info;
-
-static struct log_context log_context;
-static void *tall_log_ctx = NULL;
-static LLIST_HEAD(target_list);
-
-static const struct value_string loglevel_strs[] = {
-	{ 0,		"EVERYTHING" },
-	{ LOGL_DEBUG,	"DEBUG" },
-	{ LOGL_INFO,	"INFO" },
-	{ LOGL_NOTICE,	"NOTICE" },
-	{ LOGL_ERROR,	"ERROR" },
-	{ LOGL_FATAL,	"FATAL" },
-	{ 0, NULL },
-};
-
-int log_parse_level(const char *lvl)
-{
-	return get_string_value(loglevel_strs, lvl);
-}
-
-const char *log_level_str(unsigned int lvl)
-{
-	return get_value_string(loglevel_strs, lvl);
-}
-
-int log_parse_category(const char *category)
-{
-	int i;
-
-	for (i = 0; i < log_info->num_cat; ++i) {
-		if (!strcasecmp(log_info->cat[i].name+1, category))
-			return i;
-	}
-
-	return -EINVAL;
-}
-
-/*
- * Parse the category mask.
- * The format can be this: category1:category2:category3
- * or category1,2:category2,3:...
- */
-void log_parse_category_mask(struct log_target* target, const char *_mask)
-{
-	int i = 0;
-	char *mask = strdup(_mask);
-	char *category_token = NULL;
-
-	/* Disable everything to enable it afterwards */
-	for (i = 0; i < ARRAY_SIZE(target->categories); ++i)
-		target->categories[i].enabled = 0;
-
-	category_token = strtok(mask, ":");
-	do {
-		for (i = 0; i < log_info->num_cat; ++i) {
-			char* colon = strstr(category_token, ",");
-			int length = strlen(category_token);
-
-			if (colon)
-			    length = colon - category_token;
-
-			if (strncasecmp(log_info->cat[i].name, category_token,
-					length) == 0) {
-				int level = 0;
-
-				if (colon)
-					level = atoi(colon+1);
-
-				target->categories[i].enabled = 1;
-				target->categories[i].loglevel = level;
-			}
-		}
-	} while ((category_token = strtok(NULL, ":")));
-
-	free(mask);
-}
-
-static const char* color(int subsys)
-{
-	if (subsys < log_info->num_cat)
-		return log_info->cat[subsys].color;
-
-	return NULL;
-}
-
-static void _output(struct log_target *target, unsigned int subsys,
-		    char *file, int line, int cont, const char *format,
-		    va_list ap)
-{
-	char col[30];
-	char sub[30];
-	char tim[30];
-	char buf[4096];
-	char final[4096];
-
-	/* prepare the data */
-	col[0] = '\0';
-	sub[0] = '\0';
-	tim[0] = '\0';
-	buf[0] = '\0';
-
-	/* are we using color */
-	if (target->use_color) {
-		const char *c = color(subsys);
-		if (c) {
-			snprintf(col, sizeof(col), "%s", color(subsys));
-			col[sizeof(col)-1] = '\0';
-		}
-	}
-	vsnprintf(buf, sizeof(buf), format, ap);
-	buf[sizeof(buf)-1] = '\0';
-
-	if (!cont) {
-		if (target->print_timestamp) {
-			char *timestr;
-			time_t tm;
-			tm = time(NULL);
-			timestr = ctime(&tm);
-			timestr[strlen(timestr)-1] = '\0';
-			snprintf(tim, sizeof(tim), "%s ", timestr);
-			tim[sizeof(tim)-1] = '\0';
-		}
-		snprintf(sub, sizeof(sub), "<%4.4x> %s:%d ", subsys, file, line);
-		sub[sizeof(sub)-1] = '\0';
-	}
-
-	snprintf(final, sizeof(final), "%s%s%s%s\033[0;m", col, tim, sub, buf);
-	final[sizeof(final)-1] = '\0';
-	target->output(target, final);
-}
-
-
-static void _logp(unsigned int subsys, int level, char *file, int line,
-		  int cont, const char *format, va_list ap)
-{
-	struct log_target *tar;
-
-	llist_for_each_entry(tar, &target_list, entry) {
-		struct log_category *category;
-		int output = 0;
-
-		category = &tar->categories[subsys];
-		/* subsystem is not supposed to be logged */
-		if (!category->enabled)
-			continue;
-
-		/* Check the global log level */
-		if (tar->loglevel != 0 && level < tar->loglevel)
-			continue;
-
-		/* Check the category log level */
-		if (tar->loglevel == 0 && category->loglevel != 0 &&
-		    level < category->loglevel)
-			continue;
-
-		/* Apply filters here... if that becomes messy we will
-		 * need to put filters in a list and each filter will
-		 * say stop, continue, output */
-		if ((tar->filter_map & LOG_FILTER_ALL) != 0)
-			output = 1;
-		else if (log_info->filter_fn)
-			output = log_info->filter_fn(&log_context,
-						       tar);
-
-		if (output) {
-			/* FIXME: copying the va_list is an ugly
-			 * workaround against a bug hidden somewhere in
-			 * _output.  If we do not copy here, the first
-			 * call to _output() will corrupt the va_list
-			 * contents, and any further _output() calls
-			 * with the same va_list will segfault */
-			va_list bp;
-			va_copy(bp, ap);
-			_output(tar, subsys, file, line, cont, format, bp);
-			va_end(bp);
-		}
-	}
-}
-
-void logp(unsigned int subsys, char *file, int line, int cont,
-	  const char *format, ...)
-{
-	va_list ap;
-
-	va_start(ap, format);
-	_logp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
-	va_end(ap);
-}
-
-void logp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
-{
-	va_list ap;
-
-	va_start(ap, format);
-	_logp(subsys, level, file, line, cont, format, ap);
-	va_end(ap);
-}
-
-static char hexd_buff[4096];
-
-char *hexdump(const unsigned char *buf, int len)
-{
-	int i;
-	char *cur = hexd_buff;
-
-	hexd_buff[0] = 0;
-	for (i = 0; i < len; i++) {
-		int len_remain = sizeof(hexd_buff) - (cur - hexd_buff);
-		int rc = snprintf(cur, len_remain, "%02x ", buf[i]);
-		if (rc <= 0)
-			break;
-		cur += rc;
-	}
-	hexd_buff[sizeof(hexd_buff)-1] = 0;
-	return hexd_buff;
-}
-
-void log_add_target(struct log_target *target)
-{
-	llist_add_tail(&target->entry, &target_list);
-}
-
-void log_del_target(struct log_target *target)
-{
-	llist_del(&target->entry);
-}
-
-void log_reset_context(void)
-{
-	memset(&log_context, 0, sizeof(log_context));
-}
-
-int log_set_context(uint8_t ctx_nr, void *value)
-{
-	if (ctx_nr > LOG_MAX_CTX)
-		return -EINVAL;
-
-	log_context.ctx[ctx_nr] = value;
-
-	return 0;
-}
-
-void log_set_all_filter(struct log_target *target, int all)
-{
-	if (all)
-		target->filter_map |= LOG_FILTER_ALL;
-	else
-		target->filter_map &= ~LOG_FILTER_ALL;
-}
-
-void log_set_use_color(struct log_target *target, int use_color)
-{
-	target->use_color = use_color;
-}
-
-void log_set_print_timestamp(struct log_target *target, int print_timestamp)
-{
-	target->print_timestamp = print_timestamp;
-}
-
-void log_set_log_level(struct log_target *target, int log_level)
-{
-	target->loglevel = log_level;
-}
-
-void log_set_category_filter(struct log_target *target, int category,
-			       int enable, int level)
-{
-	if (category >= log_info->num_cat)
-		return;
-	target->categories[category].enabled = !!enable;
-	target->categories[category].loglevel = level;
-}
-
-/* since C89/C99 says stderr is a macro, we can safely do this! */
-#ifdef stderr
-static void _stderr_output(struct log_target *target, const char *log)
-{
-	fprintf(target->tgt_stdout.out, "%s", log);
-	fflush(target->tgt_stdout.out);
-}
-#endif
-
-struct log_target *log_target_create(void)
-{
-	struct log_target *target;
-	unsigned int i;
-
-	target = talloc_zero(tall_log_ctx, struct log_target);
-	if (!target)
-		return NULL;
-
-	INIT_LLIST_HEAD(&target->entry);
-
-	/* initialize the per-category enabled/loglevel from defaults */
-	for (i = 0; i < log_info->num_cat; i++) {
-		struct log_category *cat = &target->categories[i];
-		cat->enabled = log_info->cat[i].enabled;
-		cat->loglevel = log_info->cat[i].loglevel;
-	}
-
-	/* global settings */
-	target->use_color = 1;
-	target->print_timestamp = 0;
-
-	/* global log level */
-	target->loglevel = 0;
-	return target;
-}
-
-struct log_target *log_target_create_stderr(void)
-{
-/* since C89/C99 says stderr is a macro, we can safely do this! */
-#ifdef stderr
-	struct log_target *target;
-
-	target = log_target_create();
-	if (!target)
-		return NULL;
-
-	target->tgt_stdout.out = stderr;
-	target->output = _stderr_output;
-	return target;
-#else
-	return NULL;
-#endif /* stderr */
-}
-
-const char *log_vty_level_string(struct log_info *info)
-{
-	const struct value_string *vs;
-	unsigned int len = 3; /* ()\0 */
-	char *str;
-
-	for (vs = loglevel_strs; vs->value || vs->str; vs++)
-		len += strlen(vs->str) + 1;
-
-	str = talloc_zero_size(NULL, len);
-	if (!str)
-		return NULL;
-
-	str[0] = '(';
-	for (vs = loglevel_strs; vs->value || vs->str; vs++) {
-		strcat(str, vs->str);
-		strcat(str, "|");
-	}
-	str[strlen(str)-1] = ')';
-
-	return str;
-}
-
-const char *log_vty_category_string(struct log_info *info)
-{
-	unsigned int len = 3;	/* "()\0" */
-	unsigned int i;
-	char *str;
-
-	for (i = 0; i < info->num_cat; i++)
-		len += strlen(info->cat[i].name) + 1;
-
-	str = talloc_zero_size(NULL, len);
-	if (!str)
-		return NULL;
-
-	str[0] = '(';
-	for (i = 0; i < info->num_cat; i++) {
-		strcat(str, info->cat[i].name+1);
-		strcat(str, "|");
-	}
-	str[strlen(str)-1] = ')';
-
-	return str;
-}
-
-void log_init(const struct log_info *cat)
-{
-	tall_log_ctx = talloc_named_const(NULL, 1, "logging");
-	log_info = cat;
-}
diff --git a/libosmocore/src/msgb.c b/libosmocore/src/msgb.c
deleted file mode 100644
index a60e2ff..0000000
--- a/libosmocore/src/msgb.c
+++ /dev/null
@@ -1,90 +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->trx = NULL;
-	msg->lchan = NULL;
-	msg->l2h = NULL;
-	msg->l3h = NULL;
-	msg->l4h = NULL;
-
-	memset(&msg->cb, 0, sizeof(msg->cb));
-}
diff --git a/libosmocore/src/rate_ctr.c b/libosmocore/src/rate_ctr.c
deleted file mode 100644
index e48c779..0000000
--- a/libosmocore/src/rate_ctr.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/* utility routines for keeping conters about events and the event rates */
-
-/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <stdint.h>
-#include <inttypes.h>
-#include <string.h>
-
-#include <osmocore/linuxlist.h>
-#include <osmocore/talloc.h>
-#include <osmocore/timer.h>
-#include <osmocore/rate_ctr.h>
-
-static LLIST_HEAD(rate_ctr_groups);
-
-static void *tall_rate_ctr_ctx;
-
-struct rate_ctr_group *rate_ctr_group_alloc(void *ctx,
-					    const struct rate_ctr_group_desc *desc,
-					    unsigned int idx)
-{
-	unsigned int size;
-	struct rate_ctr_group *group;
-
-	size = sizeof(struct rate_ctr_group) +
-			desc->num_ctr * sizeof(struct rate_ctr);
-
-	if (!ctx)
-		ctx = tall_rate_ctr_ctx;
-
-	group = talloc_zero_size(ctx, size);
-	if (!group)
-		return NULL;
-
-	group->desc = desc;
-	group->idx = idx;
-
-	llist_add(&group->list, &rate_ctr_groups);
-
-	return group;
-}
-
-void rate_ctr_group_free(struct rate_ctr_group *grp)
-{
-	llist_del(&grp->list);
-	talloc_free(grp);
-}
-
-void rate_ctr_add(struct rate_ctr *ctr, int inc)
-{
-	ctr->current += inc;
-}
-
-static void interval_expired(struct rate_ctr *ctr, enum rate_ctr_intv intv)
-{
-	/* calculate rate over last interval */
-	ctr->intv[intv].rate = ctr->current - ctr->intv[intv].last;
-	/* save current counter for next interval */
-	ctr->intv[intv].last = ctr->current;
-}
-
-static struct timer_list rate_ctr_timer;
-static uint64_t timer_ticks;
-
-/* The one-second interval has expired */
-static void rate_ctr_group_intv(struct rate_ctr_group *grp)
-{
-	unsigned int i;
-
-	for (i = 0; i < grp->desc->num_ctr; i++) {
-		struct rate_ctr *ctr = &grp->ctr[i];
-
-		interval_expired(ctr, RATE_CTR_INTV_SEC);
-		if ((timer_ticks % 60) == 0)
-			interval_expired(ctr, RATE_CTR_INTV_MIN);
-		if ((timer_ticks % (60*60)) == 0)
-			interval_expired(ctr, RATE_CTR_INTV_HOUR);
-		if ((timer_ticks % (24*60*60)) == 0)
-			interval_expired(ctr, RATE_CTR_INTV_DAY);
-	}
-}
-
-static void rate_ctr_timer_cb(void *data)
-{
-	struct rate_ctr_group *ctrg;
-
-	/* Increment number of ticks before we calculate intervals,
-	 * as a counter value of 0 would already wrap all counters */
-	timer_ticks++;
-
-	llist_for_each_entry(ctrg, &rate_ctr_groups, list)
-		rate_ctr_group_intv(ctrg);
-
-	bsc_schedule_timer(&rate_ctr_timer, 1, 0);
-}
-
-int rate_ctr_init(void *tall_ctx)
-{
-	tall_rate_ctr_ctx = tall_ctx;
-	rate_ctr_timer.cb = rate_ctr_timer_cb;
-	bsc_schedule_timer(&rate_ctr_timer, 1, 0);
-
-	return 0;
-}
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 2f6afa7..0000000
--- a/libosmocore/src/select.c
+++ /dev/null
@@ -1,131 +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 */
-		/* this seems to happen with the last element of the list as well */
-		if (unregistered_count >= 1)
-			goto restart;
-	}
-	return work;
-}
-
-#endif /* _HAVE_SYS_SELECT_H */
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 618a8c0..0000000
--- a/libosmocore/src/write_queue.c
+++ /dev/null
@@ -1,88 +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_EXCEPT)
-		queue->except_cb(fd);
-
-	if (what & BSC_FD_WRITE) {
-		struct msgb *msg;
-
-		fd->when &= ~BSC_FD_WRITE;
-		msg = msgb_dequeue(&queue->msg_queue);
-		if (!msg)
-			return -1;
-
-		--queue->current_length;
-		queue->write_cb(fd, msg);
-		msgb_free(msg);
-
-		if (!llist_empty(&queue->msg_queue))
-			fd->when |= BSC_FD_WRITE;
-	}
-
-	return 0;
-}
-
-void write_queue_init(struct write_queue *queue, int max_length)
-{
-	queue->max_length = max_length;
-	queue->current_length = 0;
-	queue->read_cb = NULL;
-	queue->write_cb = NULL;
-	queue->bfd.cb = write_queue_bfd_cb;
-	INIT_LLIST_HEAD(&queue->msg_queue);
-}
-
-int write_queue_enqueue(struct write_queue *queue, struct msgb *data)
-{
-//	if (queue->current_length + 1 >= queue->max_length)
-//		LOGP(DMSC, LOGL_ERROR, "The queue is full. Dropping not yet implemented.\n");
-
-	++queue->current_length;
-	msgb_enqueue(&queue->msg_queue, data);
-	queue->bfd.when |= BSC_FD_WRITE;
-
-	return 0;
-}
-
-void write_queue_clear(struct write_queue *queue)
-{
-	while (!llist_empty(&queue->msg_queue)) {
-		struct msgb *msg = msgb_dequeue(&queue->msg_queue);
-		msgb_free(msg);
-	}
-
-	queue->current_length = 0;
-	queue->bfd.when &= ~BSC_FD_WRITE;
-}
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/configure.in b/openbsc/configure.in
index 66d4ee1..ef95920 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.6)
+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,16 +49,17 @@
     openbsc.pc
     libsccp.pc
     include/openbsc/Makefile
-    include/vty/Makefile
     include/sccp/Makefile
     include/Makefile
     src/Makefile
     src/ipaccess/Makefile
     src/gprs/Makefile
+    src/nat/Makefile
     tests/Makefile
     tests/debug/Makefile
     tests/gsm0408/Makefile
     tests/db/Makefile
     tests/channel/Makefile
     tests/sccp/Makefile
+    tests/bsc-nat/Makefile
     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/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 afb62de..465b21a 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -1,14 +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 \
-		 vty.h \
-		crc24.h gprs_bssgp.h gprs_llc.h gprs_ns.h \
-		gb_proxy.h gprs_sgsn.h gsm_04_08_gprs.h sgsn.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 bsc_msc.h bsc_nat.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 c20e4e1..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 */
@@ -170,4 +172,7 @@
 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 8e6774d..e87f430 100644
--- a/openbsc/include/openbsc/abis_rsl.h
+++ b/openbsc/include/openbsc/abis_rsl.h
@@ -68,7 +68,7 @@
 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);
 
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
index 51e344f..7747ada 100644
--- a/openbsc/include/openbsc/bsc_api.h
+++ b/openbsc/include/openbsc/bsc_api.h
@@ -1,6 +1,28 @@
 /* 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);
+int gsm0808_page(struct gsm_bts *bts, unsigned int page_group,
+		 unsigned int mi_len, uint8_t *mi, int chan_type);
+
+#endif
diff --git a/openbsc/include/openbsc/bsc_msc.h b/openbsc/include/openbsc/bsc_msc.h
new file mode 100644
index 0000000..faf6faa
--- /dev/null
+++ b/openbsc/include/openbsc/bsc_msc.h
@@ -0,0 +1,51 @@
+/* Routines to talk to the MSC using the IPA Protocol */
+/*
+ * (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.
+ *
+ */
+
+#ifndef BSC_MSC_H
+#define BSC_MSC_H
+
+#include <osmocore/write_queue.h>
+#include <osmocore/timer.h>
+
+struct bsc_msc_connection {
+	struct write_queue write_queue;
+	int is_connected;
+	int is_authenticated;
+	const char *ip;
+	int port;
+	int prio;
+
+	void (*connection_loss) (struct bsc_msc_connection *);
+	void (*connected) (struct bsc_msc_connection *);
+	struct timer_list reconnect_timer;
+	struct timer_list timeout_timer;
+};
+
+struct bsc_msc_connection *bsc_msc_create(const char *ip, int port, int prio);
+int bsc_msc_connect(struct bsc_msc_connection *);
+void bsc_msc_schedule_connect(struct bsc_msc_connection *);
+
+void bsc_msc_lost(struct bsc_msc_connection *);
+
+struct msgb *bsc_msc_id_get_resp(const char *token);
+
+#endif
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
new file mode 100644
index 0000000..cb0f761
--- /dev/null
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -0,0 +1,338 @@
+/*
+ * (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.
+ *
+ */
+
+#ifndef BSC_NAT_H
+#define BSC_NAT_H
+
+#include "mgcp.h"
+
+#include <sys/types.h>
+#include <sccp/sccp_types.h>
+
+#include <osmocore/select.h>
+#include <osmocore/msgb.h>
+#include <osmocore/timer.h>
+#include <osmocore/write_queue.h>
+#include <osmocore/statistics.h>
+
+#include <regex.h>
+
+#define DIR_BSC 1
+#define DIR_MSC 2
+
+#define NAT_IPAC_PROTO_MGCP	0xfc
+
+struct bsc_nat;
+
+enum {
+	NAT_CON_TYPE_NONE,
+	NAT_CON_TYPE_LU,
+	NAT_CON_TYPE_CM_SERV_REQ,
+	NAT_CON_TYPE_PAG_RESP,
+	NAT_CON_TYPE_LOCAL_REJECT,
+	NAT_CON_TYPE_OTHER,
+};
+
+/*
+ * For the NAT we will need to analyze and later patch
+ * the received message. This would require us to parse
+ * the IPA and SCCP header twice. Instead of doing this
+ * we will have one analyze structure and have the patching
+ * and filter operate on the same structure.
+ */
+struct bsc_nat_parsed {
+	/* ip access prototype */
+	int ipa_proto;
+
+	/* source local reference */
+	struct sccp_source_reference *src_local_ref;
+
+	/* destination local reference */
+	struct sccp_source_reference *dest_local_ref;
+
+	/* called ssn number */
+	int called_ssn;
+
+	/* calling ssn number */
+	int calling_ssn;
+
+	/* sccp message type */
+	int sccp_type;
+
+	/* bssap type, e.g. 0 for BSS Management */
+	int bssap;
+
+	/* the gsm0808 message type */
+	int gsm_type;
+};
+
+/*
+ * Per BSC data structure
+ */
+struct bsc_connection {
+	struct llist_head list_entry;
+
+	/* do we know anything about this BSC? */
+	int authenticated;
+
+	/* the fd we use to communicate */
+	struct write_queue write_queue;
+
+	/* the BSS associated */
+	struct bsc_config *cfg;
+
+	/* a timeout node */
+	struct timer_list id_timeout;
+
+	/* pong timeout */
+	struct timer_list ping_timeout;
+	struct timer_list pong_timeout;
+
+	/* a back pointer */
+	struct bsc_nat *nat;
+};
+
+/*
+ * Per SCCP source local reference patch table. It needs to
+ * be updated on new SCCP connections, connection confirm and reject,
+ * and on the loss of the BSC connection.
+ */
+struct sccp_connections {
+	struct llist_head list_entry;
+
+	struct bsc_connection *bsc;
+
+	struct sccp_source_reference real_ref;
+	struct sccp_source_reference patched_ref;
+	struct sccp_source_reference remote_ref;
+	int has_remote_ref;
+
+	/* status */
+	int con_type;
+	int con_local;
+
+	/* GSM audio handling. That is 32 * multiplex + ts */
+	int crcx;
+	int msc_timeslot;
+	int bsc_timeslot;
+
+	/* timeout handling */
+	struct timespec creation_time;
+};
+
+/**
+ * Stats per BSC
+ */
+struct bsc_config_stats {
+	struct {
+		struct counter *conn;
+		struct counter *calls;
+	} sccp;
+
+	struct {
+		struct counter *reconn;
+	} net;
+};
+
+/**
+ * One BSC entry in the config
+ */
+struct bsc_config {
+	struct llist_head entry;
+
+	char *token;
+	unsigned int lac;
+	int nr;
+
+	char *description;
+
+	/* imsi white and blacklist */
+	char *acc_lst_name;
+
+	int forbid_paging;
+
+	/* backpointer */
+	struct bsc_nat *nat;
+
+	struct bsc_config_stats stats;
+};
+
+/**
+ * BSCs point of view of endpoints
+ */
+struct bsc_endpoint {
+	/* the pending transaction id */
+	char *transaction_id;
+	/* the bsc we are talking to */
+	struct bsc_connection *bsc;
+};
+
+/**
+ * Statistic for the nat.
+ */
+struct bsc_nat_statistics {
+	struct {
+		struct counter *conn;
+		struct counter *calls;
+	} sccp;
+
+	struct {
+		struct counter *reconn;
+                struct counter *auth_fail;
+	} bsc;
+
+	struct {
+		struct counter *reconn;
+	} msc;
+};
+
+struct bsc_nat_acc_lst {
+	struct llist_head list;
+
+	/* the name of the list */
+	const char *name;
+	struct llist_head fltr_list;
+};
+
+struct bsc_nat_acc_lst_entry {
+	struct llist_head list;
+
+	/* the filter */
+	char *imsi_allow;
+	regex_t imsi_allow_re;
+	char *imsi_deny;
+	regex_t imsi_deny_re;
+};
+
+/**
+ * the structure of the "nat" network
+ */
+struct bsc_nat {
+	/* active SCCP connections that need patching */
+	struct llist_head sccp_connections;
+
+	/* active BSC connections that need patching */
+	struct llist_head bsc_connections;
+
+	/* access lists */
+	struct llist_head access_lists;
+
+	/* known BSC's */
+	struct llist_head bsc_configs;
+	int num_bsc;
+	int bsc_ip_tos;
+
+	/* MGCP config */
+	struct mgcp_config *mgcp_cfg;
+	struct write_queue mgcp_queue;
+	u_int8_t mgcp_msg[4096];
+	int mgcp_length;
+
+	/* msc things */
+	char *msc_ip;
+	int msc_port;
+	int first_contact;
+	struct bsc_msc_connection *msc_con;
+	char *token;
+
+	/* timeouts */
+	int auth_timeout;
+	int ping_timeout;
+	int pong_timeout;
+
+	struct bsc_endpoint *bsc_endpoints;
+
+	/* filter */
+	char *acc_lst_name;
+
+	/* statistics */
+	struct bsc_nat_statistics stats;
+};
+
+/* create and init the structures */
+struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token, unsigned int lac);
+struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num);
+struct bsc_nat *bsc_nat_alloc(void);
+struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat);
+void bsc_nat_set_msc_ip(struct bsc_nat *bsc, const char *ip);
+
+void sccp_connection_destroy(struct sccp_connections *);
+void bsc_close_connection(struct bsc_connection *);
+
+const char *bsc_con_type_to_string(int type);
+
+/**
+ * parse the given message into the above structure
+ */
+struct bsc_nat_parsed *bsc_nat_parse(struct msgb *msg);
+
+/**
+ * filter based on IP Access header in both directions
+ */
+int bsc_nat_filter_ipa(int direction, struct msgb *msg, struct bsc_nat_parsed *parsed);
+int bsc_nat_vty_init(struct bsc_nat *nat);
+struct bsc_connection *bsc_nat_find_bsc(struct bsc_nat *nat, struct msgb *msg, int *_lac);
+
+/**
+ * Content filtering.
+ */
+int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg,
+			   struct bsc_nat_parsed *, int *con_type);
+
+/**
+ * SCCP patching and handling
+ */
+struct sccp_connections *create_sccp_src_ref(struct bsc_connection *bsc, struct bsc_nat_parsed *parsed);
+int update_sccp_src_ref(struct sccp_connections *sccp, struct bsc_nat_parsed *parsed);
+void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed);
+struct sccp_connections *patch_sccp_src_ref_to_bsc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
+struct sccp_connections *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat_parsed *, struct bsc_connection *);
+
+/**
+ * MGCP/Audio handling
+ */
+int bsc_write_mgcp(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length);
+int bsc_mgcp_assign(struct sccp_connections *, struct msgb *msg);
+void bsc_mgcp_init(struct sccp_connections *);
+void bsc_mgcp_dlcx(struct sccp_connections *);
+void bsc_mgcp_free_endpoints(struct bsc_nat *nat);
+int bsc_mgcp_nat_init(struct bsc_nat *nat);
+
+struct sccp_connections *bsc_mgcp_find_con(struct bsc_nat *, int endpoint_number);
+struct msgb *bsc_mgcp_rewrite(char *input, int length, const char *ip, int port);
+void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg);
+
+void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc);
+int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60]);
+int bsc_mgcp_extract_ci(const char *resp);
+
+
+int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int id);
+
+/* IMSI allow/deny handling */
+void bsc_parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv);
+struct bsc_nat_acc_lst *bsc_nat_acc_lst_find(struct bsc_nat *nat, const char *name);
+struct bsc_nat_acc_lst *bsc_nat_acc_lst_get(struct bsc_nat *nat, const char *name);
+void bsc_nat_acc_lst_delete(struct bsc_nat_acc_lst *lst);
+
+struct bsc_nat_acc_lst_entry *bsc_nat_acc_lst_entry_create(struct bsc_nat_acc_lst *);
+
+#endif
diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h
index d4f5858..bbbe536 100644
--- a/openbsc/include/openbsc/chan_alloc.h
+++ b/openbsc/include/openbsc/chan_alloc.h
@@ -23,6 +23,8 @@
 
 #include "gsm_subscriber.h"
 
+struct gsm_subscriber_connection;
+
 /* Special allocator for C0 of BTS */
 struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts,
 				   enum gsm_phys_chan_config pchan);
@@ -34,11 +36,8 @@
 /* Regular physical channel (TS) */
 void ts_free(struct gsm_bts_trx_ts *ts);
 
-/* Find an allocated channel */
-struct gsm_lchan *lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr);
-
 /* Find an allocated channel for a specified subscriber */
-struct gsm_lchan *lchan_for_subscr(struct gsm_subscriber *subscr);
+struct gsm_subscriber_connection *connection_for_subscr(struct gsm_subscriber *subscr);
 
 /* Allocate a logical channel (SDCCH, TCH, ...) */
 struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type);
diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h
index 1782efb..2a521f0 100644
--- a/openbsc/include/openbsc/db.h
+++ b/openbsc/include/openbsc/db.h
@@ -44,14 +44,14 @@
 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);
diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h
index 65fd0bb..eb290e4 100644
--- a/openbsc/include/openbsc/debug.h
+++ b/openbsc/include/openbsc/debug.h
@@ -32,6 +32,9 @@
 	DGPRS,
 	DNS,
 	DBSSGP,
+	DLLC,
+	DSNDCP,
+	DNAT,
 	Debug_LastEntry,
 };
 
@@ -40,15 +43,27 @@
 #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_ALL = 1 << 0,
 	LOG_FILTER_IMSI = 1 << 1,
+	LOG_FILTER_NSVC = 1 << 2,
+	LOG_FILTER_BVC  = 1 << 3,
 };
 
+/* we don't need a header dependency for this... */
+struct gprs_nsvc;
+struct bssgp_bvc_ctx;
+
 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;
 
diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h
index db236b5..18ded22 100644
--- a/openbsc/include/openbsc/gb_proxy.h
+++ b/openbsc/include/openbsc/gb_proxy.h
@@ -6,18 +6,11 @@
 #include <osmocore/msgb.h>
 
 #include <openbsc/gprs_ns.h>
-#include <vty/command.h>
+#include <osmocom/vty/command.h>
 
 struct gbproxy_config {
 	/* parsed from config file */
-	u_int32_t nsip_listen_ip;
-	u_int16_t nsip_listen_port;
-
-	u_int32_t nsip_sgsn_ip;
-	u_int16_t nsip_sgsn_port;
-
 	u_int16_t nsip_sgsn_nsei;
-	u_int16_t nsip_sgsn_nsvci;
 
 	/* misc */
 	struct gprs_ns_inst *nsi;
@@ -39,4 +32,8 @@
 
 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
index d3ccb12..e432cf7 100644
--- a/openbsc/include/openbsc/gprs_bssgp.h
+++ b/openbsc/include/openbsc/gprs_bssgp.h
@@ -3,6 +3,10 @@
 
 #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 */
@@ -149,9 +153,44 @@
 
 /* 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>
 
-extern int gprs_bssgp_rcvmsg(struct msgb *msg);
+/* 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 */
@@ -160,4 +199,34 @@
 	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
index 5a6682d..0ddb518 100644
--- a/openbsc/include/openbsc/gprs_llc.h
+++ b/openbsc/include/openbsc/gprs_llc.h
@@ -2,6 +2,7 @@
 #define _GPRS_LLC_H
 
 #include <stdint.h>
+#include <openbsc/gprs_sgsn.h>
 
 /* Section 4.7 LLC Layer Structure */
 enum gprs_llc_sapi {
@@ -26,7 +27,123 @@
 	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);
-int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command);
+
+/* 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
index 4ccf4c7..953c364 100644
--- a/openbsc/include/openbsc/gprs_ns.h
+++ b/openbsc/include/openbsc/gprs_ns.h
@@ -107,6 +107,7 @@
 enum gprs_ns_ll {
 	GPRS_NS_LL_UDP,
 	GPRS_NS_LL_E1,
+	GPRS_NS_LL_FR_GRE,
 };
 
 enum gprs_ns_evt {
@@ -130,15 +131,18 @@
 
 	uint16_t timeout[NS_TIMERS_COUNT];
 
-	/* which link-layer are we based on? */
-	enum gprs_ns_ll ll;
-
-	union {
-		/* NS-over-IP specific bits */
-		struct {
-			struct bsc_fd fd;
-		} nsip;
-	};
+	/* 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 {
@@ -168,10 +172,16 @@
 
 	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;
 	};
 };
 
@@ -181,15 +191,11 @@
 /* Destroy a NS protocol instance */
 void gprs_ns_destroy(struct gprs_ns_inst *nsi);
 
-/* Listen for incoming GPRS packets */
-int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port);
+/* Listen for incoming GPRS packets via NS/UDP */
+int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi);
 
 struct sockaddr_in;
 
-/* main entry point, here incoming NS frames enter */
-int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg,
-		   struct sockaddr_in *saddr);
-
 /* main function for higher layers (BSSGP) to send NS messages */
 int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg);
 
@@ -197,8 +203,8 @@
 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 */
-int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port);
+/* 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,
@@ -208,8 +214,19 @@
 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
index bdc0b1c..0801150 100644
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -2,6 +2,15 @@
 #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 {
@@ -16,6 +25,34 @@
 	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
@@ -28,6 +65,7 @@
 	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 */
@@ -63,42 +101,18 @@
 	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;
-};
+	unsigned int		T;		/* Txxxx number */
+	unsigned int		num_T_exp;	/* number of consecutive T expirations */
 
-enum pdp_ctx_state {
-	PDP_STAE_NONE,
-};
-
-enum pdp_type {
-	PDP_TYPE_NONE,
-};
-
-struct sgsn_pdp_ctx {
-	struct llist_head	list;
-
-	unsigned int		id;
-	enum pdp_ctx_state	state;
-	enum pdp_type		type;
-	uint32_t		addresss;
-	char 			*apn_subscribed;
-	char 			*apn_used;
-	uint16_t		nsapi;
-	uint8_t			ti;	/* transaction identifier */
-	uint32_t		ggsn_in_use;
-	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;
+	enum gprs_t3350_mode	t3350_mode;
+	uint8_t			t3370_id_type;
 };
 
 /* look-up a SGSN MM context based on TLLI + RAI */
@@ -111,4 +125,86 @@
 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 74dcbe5..11bca54 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -11,6 +11,7 @@
 struct gsm_subscriber;
 struct gsm_network;
 struct gsm_trans;
+struct gsm_subscriber_connection;
 
 #define GSM48_ALLOC_SIZE	1024
 #define GSM48_ALLOC_HEADROOM	128
@@ -23,19 +24,18 @@
 
 /* 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_auth_req(struct gsm_lchan *lchan, u_int8_t *rand, int key_seq);
-int gsm48_tx_mm_auth_rej(struct gsm_lchan *lchan);
-int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans);
-
+int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn);
+int gsm48_tx_mm_auth_req(struct gsm_subscriber_connection *conn, u_int8_t *rand, int key_seq);
+int gsm48_tx_mm_auth_rej(struct gsm_subscriber_connection *conn);
 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,
+int gsm48_send_rr_app_info(struct gsm_subscriber_connection *conn, u_int8_t apdu_id,
 			   u_int8_t apdu_len, const u_int8_t *apdu);
 int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, u_int8_t power_class);
 int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan,
@@ -52,12 +52,15 @@
 		      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);
 int gsm48_rx_rr_modif_ack(struct msgb *msg);
 int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg);
 
+struct msgb *gsm48_create_mm_serv_rej(enum gsm48_reject_value value);
+struct msgb *gsm48_create_loc_upd_rej(uint8_t cause);
 
 #endif
diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h
index 344b277..baa513b 100644
--- a/openbsc/include/openbsc/gsm_04_08_gprs.h
+++ b/openbsc/include/openbsc/gsm_04_08_gprs.h
@@ -2,6 +2,7 @@
 #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
@@ -46,6 +47,15 @@
 #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
@@ -53,13 +63,17 @@
 #define GPRS_UPD_T_PERIODIC		3
 
 enum gsm48_gprs_ie_mm {
-	GSM48_IE_GMM_TIMER_READY	= 0x17, /* 10.5.7.3 */
+	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_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 {
@@ -72,6 +86,11 @@
 	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 */
@@ -344,7 +363,4 @@
 
 int gprs_tlli_type(uint32_t tlli);
 
-struct gsm_bts *gsm48_bts_by_ra_id(struct gsm_network *net,
-				   const uint8_t *buf, unsigned int len);
-
 #endif /* _GSM48_GPRS_H */
diff --git a/openbsc/include/openbsc/gsm_04_11.h b/openbsc/include/openbsc/gsm_04_11.h
index 8127af1..61eaffd 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 */
@@ -23,9 +25,7 @@
 
 struct msgb;
 
-int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id);
-
-int gsm411_send_sms_lchan(struct gsm_subscriber_connection *conn, struct gsm_sms *sms);
+int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn, struct msgb *msg, u_int8_t link_id);
 
 struct gsm_sms *sms_alloc(void);
 void sms_free(struct gsm_sms *sms);
@@ -33,4 +33,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 91527c9..f3f4ed3 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 {
@@ -104,6 +105,14 @@
 #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,
@@ -150,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 {
@@ -175,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 */
@@ -192,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? */
@@ -205,6 +229,7 @@
 	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 */
 };
 
@@ -220,6 +245,7 @@
 	 * 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;
@@ -256,6 +282,8 @@
 	} encr;
 
 	struct timer_list T3101;
+	struct timer_list T3111;
+	struct timer_list error_timer;
 
 	/* AMR bits */
 	struct gsm48_multi_rate_conf mr_conf;
@@ -322,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;
@@ -428,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 */
@@ -623,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;
@@ -644,6 +677,7 @@
 	struct {
 		enum rrlp_mode mode;
 	} rrlp;
+	int msc_prio;
 };
 
 #define SMS_HDR_SIZE	128
diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h
index 0653996..527056b 100644
--- a/openbsc/include/openbsc/gsm_subscriber.h
+++ b/openbsc/include/openbsc/gsm_subscriber.h
@@ -82,7 +82,7 @@
 struct gsm_subscriber *subscr_get_by_id(struct gsm_network *net,
 					unsigned long long id);
 int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason);
-void subscr_put_channel(struct gsm_lchan *lchan);
+void subscr_put_channel(struct gsm_subscriber_connection *conn);
 void subscr_get_channel(struct gsm_subscriber *subscr,
                         int type, gsm_cbfn *cbfn, void *param);
 
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/sgsn.h b/openbsc/include/openbsc/sgsn.h
index 2dc53c1..eccfdea 100644
--- a/openbsc/include/openbsc/sgsn.h
+++ b/openbsc/include/openbsc/sgsn.h
@@ -6,16 +6,32 @@
 #include <osmocore/msgb.h>
 
 #include <openbsc/gprs_ns.h>
+#include <openbsc/gprs_sgsn.h>
 
 struct sgsn_config {
 	/* parsed from config file */
-	u_int32_t nsip_listen_ip;
-	u_int16_t nsip_listen_port;
+
+	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 */
 
@@ -27,4 +43,23 @@
 /* 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/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 b8c36b6..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 <openbsc/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 log_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/vty.h b/openbsc/include/openbsc/vty.h
index f1b1148..3346a2c 100644
--- a/openbsc/include/openbsc/vty.h
+++ b/openbsc/include/openbsc/vty.h
@@ -1,10 +1,37 @@
 #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 openbsc_vty_add_cmds(void);
+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,
+	NAT_NODE,
+	BSC_NODE,
+};
+
 #endif
diff --git a/openbsc/include/sccp/sccp.h b/openbsc/include/sccp/sccp.h
index 604a2ac..84ae914 100644
--- a/openbsc/include/sccp/sccp.h
+++ b/openbsc/include/sccp/sccp.h
@@ -148,6 +148,11 @@
 u_int32_t sccp_src_ref_to_int(struct sccp_source_reference *ref);
 struct sccp_source_reference sccp_src_ref_from_int(u_int32_t);
 
+struct msgb *sccp_create_refuse(struct sccp_source_reference *src_ref, int cause, uint8_t *data, int length);
+struct msgb *sccp_create_cc(struct sccp_source_reference *src_ref, struct sccp_source_reference *dst_ref);
+struct msgb *sccp_create_rlsd(struct sccp_source_reference *src_ref, struct sccp_source_reference *dst_ref, int cause);
+struct msgb *sccp_create_dt1(struct sccp_source_reference *dst_ref, uint8_t *data, uint8_t len);
+
 /**
  * Below this are helper functions and structs for parsing SCCP messages
  */
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 c9467a9..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(void *ctx, size_t);
-
-/* Free all data in the buffer. */
-void buffer_reset(struct buffer *);
-
-/* This function first calls buffer_reset to release all buffered data.
-   Then it frees the struct buffer itself. */
-void buffer_free(struct buffer *);
-
-/* Add the given data to the end of the buffer. */
-extern void buffer_put(struct buffer *, const void *, size_t);
-/* Add a single character to the end of the buffer. */
-extern void buffer_putc(struct buffer *, u_char);
-/* Add a NUL-terminated string to the end of the buffer. */
-extern void buffer_putstr(struct buffer *, const char *);
-
-/* Combine all accumulated (and unflushed) data inside the buffer into a
-   single NUL-terminated string allocated using XMALLOC(MTYPE_TMP).  Note
-   that this function does not alter the state of the buffer, so the data
-   is still inside waiting to be flushed. */
-char *buffer_getstr(struct buffer *);
-
-/* Returns 1 if there is no pending data in the buffer.  Otherwise returns 0. */
-int buffer_empty(struct buffer *);
-
-typedef enum {
-	/* An I/O error occurred.  The buffer should be destroyed and the
-	   file descriptor should be closed. */
-	BUFFER_ERROR = -1,
-
-	/* The data was written successfully, and the buffer is now empty
-	   (there is no pending data waiting to be flushed). */
-	BUFFER_EMPTY = 0,
-
-	/* There is pending data in the buffer waiting to be flushed.  Please
-	   try flushing the buffer when select indicates that the file descriptor
-	   is writeable. */
-	BUFFER_PENDING = 1
-} buffer_status_t;
-
-/* Try to write this data to the file descriptor.  Any data that cannot
-   be written immediately is added to the buffer queue. */
-extern buffer_status_t buffer_write(struct buffer *, int fd,
-				    const void *, size_t);
-
-/* This function attempts to flush some (but perhaps not all) of
-   the queued data to the given file descriptor. */
-extern buffer_status_t buffer_flush_available(struct buffer *, int fd);
-
-/* The following 2 functions (buffer_flush_all and buffer_flush_window)
-   are for use in lib/vty.c only.  They should not be used elsewhere. */
-
-/* Call buffer_flush_available repeatedly until either all data has been
-   flushed, or an I/O error has been encountered, or the operation would
-   block. */
-extern buffer_status_t buffer_flush_all(struct buffer *, int fd);
-
-/* Attempt to write enough data to the given fd to fill a window of the
-   given width and height (and remove the data written from the buffer).
-
-   If !no_more, then a message saying " --More-- " is appended.
-   If erase is true, then first overwrite the previous " --More-- " message
-   with spaces.
-
-   Any write error (including EAGAIN or EINTR) will cause this function
-   to return -1 (because the logic for handling the erase and more features
-   is too complicated to retry the write later).
-*/
-extern buffer_status_t buffer_flush_window(struct buffer *, int fd, int width,
-					   int height, int erase, int no_more);
-
-#endif				/* _ZEBRA_BUFFER_H */
diff --git a/openbsc/include/vty/command.h b/openbsc/include/vty/command.h
deleted file mode 100644
index 1b6e0a7..0000000
--- a/openbsc/include/vty/command.h
+++ /dev/null
@@ -1,386 +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,
-	GBPROXY_NODE,
-	SGSN_NODE,
-	NS_NODE,
-};
-
-/* Node which has some commands and prompt string and configuration
-   function pointer . */
-struct cmd_node {
-	/* Node index. */
-	enum node_type node;
-
-	/* Prompt character at vty interface. */
-	const char *prompt;
-
-	/* Is this node's configuration goes to vtysh ? */
-	int vtysh;
-
-	/* Node's configuration write function */
-	int (*func) (struct vty *);
-
-	/* Vector of this node's command list. */
-	vector cmd_vector;
-};
-
-enum {
-	CMD_ATTR_DEPRECATED = 1,
-	CMD_ATTR_HIDDEN,
-};
-
-/* Structure of command element. */
-struct cmd_element {
-	const char *string;	/* Command specification by string. */
-	int (*func) (struct cmd_element *, struct vty *, int, const char *[]);
-	const char *doc;	/* Documentation of this command. */
-	int daemon;		/* Daemon to which this command belong. */
-	vector strvec;		/* Pointing out each description vector. */
-	unsigned int cmdsize;	/* Command index count. */
-	char *config;		/* Configuration string */
-	vector subconfig;	/* Sub configuration string */
-	u_char attr;		/* Command attributes */
-};
-
-/* Command description structure. */
-struct desc {
-	const char *cmd;	/* Command string. */
-	const char *str;	/* Command's description. */
-};
-
-/* Return value of the commands. */
-#define CMD_SUCCESS              0
-#define CMD_WARNING              1
-#define CMD_ERR_NO_MATCH         2
-#define CMD_ERR_AMBIGUOUS        3
-#define CMD_ERR_INCOMPLETE       4
-#define CMD_ERR_EXEED_ARGC_MAX   5
-#define CMD_ERR_NOTHING_TODO     6
-#define CMD_COMPLETE_FULL_MATCH  7
-#define CMD_COMPLETE_MATCH       8
-#define CMD_COMPLETE_LIST_MATCH  9
-#define CMD_SUCCESS_DAEMON      10
-
-/* Argc max counts. */
-#define CMD_ARGC_MAX   25
-
-/* Turn off these macros when uisng cpp with extract.pl */
-#ifndef VTYSH_EXTRACT_PL
-
-/* helper defines for end-user DEFUN* macros */
-#define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \
-  static struct cmd_element cmdname = \
-  { \
-    .string = cmdstr, \
-    .func = funcname, \
-    .doc = helpstr, \
-    .attr = attrs, \
-    .daemon = dnum, \
-  };
-
-/* global (non static) cmd_element */
-#define gDEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \
-  struct cmd_element cmdname = \
-  { \
-    .string = cmdstr, \
-    .func = funcname, \
-    .doc = helpstr, \
-    .attr = attrs, \
-    .daemon = dnum, \
-  };
-
-#define DEFUN_CMD_FUNC_DECL(funcname) \
-  static int funcname (struct cmd_element *, struct vty *, int, const char *[]); \
-
-#define DEFUN_CMD_FUNC_TEXT(funcname) \
-  static int funcname \
-    (struct cmd_element *self, struct vty *vty, int argc, const char *argv[])
-
-/* DEFUN for vty command interafce. Little bit hacky ;-). */
-#define DEFUN(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_FUNC_DECL(funcname) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \
-  DEFUN_CMD_FUNC_TEXT(funcname)
-
-/* global (non static) cmd_element */
-#define gDEFUN(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_FUNC_DECL(funcname) \
-  gDEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \
-  DEFUN_CMD_FUNC_TEXT(funcname)
-
-#define DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
-  DEFUN_CMD_FUNC_DECL(funcname) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \
-  DEFUN_CMD_FUNC_TEXT(funcname)
-
-#define DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
-
-#define DEFUN_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED) \
-
-/* DEFUN_NOSH for commands that vtysh should ignore */
-#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN(funcname, cmdname, cmdstr, helpstr)
-
-/* DEFSH for vtysh. */
-#define DEFSH(daemon, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, 0, daemon) \
-
-/* DEFUN + DEFSH */
-#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_FUNC_DECL(funcname) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon) \
-  DEFUN_CMD_FUNC_TEXT(funcname)
-
-/* DEFUN + DEFSH with attributes */
-#define DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, attr) \
-  DEFUN_CMD_FUNC_DECL(funcname) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, daemon) \
-  DEFUN_CMD_FUNC_TEXT(funcname)
-
-#define DEFUNSH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \
-  DEFUNSH_ATTR (daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
-
-#define DEFUNSH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \
-  DEFUNSH_ATTR (daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED)
-
-/* ALIAS macro which define existing command's alias. */
-#define ALIAS(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0)
-
-/* global (non static) cmd_element */
-#define gALIAS(funcname, cmdname, cmdstr, helpstr) \
-  gDEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0)
-
-#define ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0)
-
-#define ALIAS_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, 0)
-
-#define ALIAS_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, 0)
-
-#define ALIAS_SH(daemon, funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon)
-
-#define ALIAS_SH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, daemon)
-
-#define ALIAS_SH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, daemon)
-
-#endif				/* VTYSH_EXTRACT_PL */
-
-/* Some macroes */
-#define CMD_OPTION(S)   ((S[0]) == '[')
-#define CMD_VARIABLE(S) (((S[0]) >= 'A' && (S[0]) <= 'Z') || ((S[0]) == '<'))
-#define CMD_VARARG(S)   ((S[0]) == '.')
-#define CMD_RANGE(S)	((S[0] == '<'))
-
-#define CMD_IPV4(S)	   ((strcmp ((S), "A.B.C.D") == 0))
-#define CMD_IPV4_PREFIX(S) ((strcmp ((S), "A.B.C.D/M") == 0))
-#define CMD_IPV6(S)        ((strcmp ((S), "X:X::X:X") == 0))
-#define CMD_IPV6_PREFIX(S) ((strcmp ((S), "X:X::X:X/M") == 0))
-
-/* Common descriptions. */
-#define SHOW_STR "Show running system information\n"
-#define IP_STR "IP information\n"
-#define IPV6_STR "IPv6 information\n"
-#define NO_STR "Negate a command or set its defaults\n"
-#define CLEAR_STR "Reset functions\n"
-#define RIP_STR "RIP information\n"
-#define BGP_STR "BGP information\n"
-#define OSPF_STR "OSPF information\n"
-#define NEIGHBOR_STR "Specify neighbor router\n"
-#define DEBUG_STR "Debugging functions (see also 'undebug')\n"
-#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n"
-#define ROUTER_STR "Enable a routing process\n"
-#define AS_STR "AS number\n"
-#define MBGP_STR "MBGP information\n"
-#define MATCH_STR "Match values from routing table\n"
-#define SET_STR "Set values in destination routing protocol\n"
-#define OUT_STR "Filter outgoing routing updates\n"
-#define IN_STR  "Filter incoming routing updates\n"
-#define V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)\n"
-#define OSPF6_NUMBER_STR "Specify by number\n"
-#define INTERFACE_STR "Interface infomation\n"
-#define IFNAME_STR "Interface name(e.g. ep0)\n"
-#define IP6_STR "IPv6 Information\n"
-#define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n"
-#define OSPF6_ROUTER_STR "Enable a routing process\n"
-#define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n"
-#define SECONDS_STR "<1-65535> Seconds\n"
-#define ROUTE_STR "Routing Table\n"
-#define PREFIX_LIST_STR "Build a prefix list\n"
-#define OSPF6_DUMP_TYPE_LIST \
-"(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)"
-#define ISIS_STR "IS-IS information\n"
-#define AREA_TAG_STR "[area tag]\n"
-
-#define CONF_BACKUP_EXT ".sav"
-
-/* IPv4 only machine should not accept IPv6 address for peer's IP
-   address.  So we replace VTY command string like below. */
-#ifdef HAVE_IPV6
-#define NEIGHBOR_CMD       "neighbor (A.B.C.D|X:X::X:X) "
-#define NO_NEIGHBOR_CMD    "no neighbor (A.B.C.D|X:X::X:X) "
-#define NEIGHBOR_ADDR_STR  "Neighbor address\nIPv6 address\n"
-#define NEIGHBOR_CMD2      "neighbor (A.B.C.D|X:X::X:X|WORD) "
-#define NO_NEIGHBOR_CMD2   "no neighbor (A.B.C.D|X:X::X:X|WORD) "
-#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
-#else
-#define NEIGHBOR_CMD       "neighbor A.B.C.D "
-#define NO_NEIGHBOR_CMD    "no neighbor A.B.C.D "
-#define NEIGHBOR_ADDR_STR  "Neighbor address\n"
-#define NEIGHBOR_CMD2      "neighbor (A.B.C.D|WORD) "
-#define NO_NEIGHBOR_CMD2   "no neighbor (A.B.C.D|WORD) "
-#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor tag\n"
-#endif				/* HAVE_IPV6 */
-
-/* Prototypes. */
-void install_node(struct cmd_node *, int (*)(struct vty *));
-void install_default(enum node_type);
-void install_element(enum node_type, struct cmd_element *);
-void install_element_ve(struct cmd_element *cmd);
-void sort_node();
-
-/* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated
-   string with a space between each element (allocated using
-   XMALLOC(MTYPE_TMP)).  Returns NULL if shift >= argc. */
-char *argv_concat(const char **argv, int argc, int shift);
-
-vector cmd_make_strvec(const char *);
-void cmd_free_strvec(vector);
-vector cmd_describe_command();
-char **cmd_complete_command();
-const char *cmd_prompt(enum node_type);
-int config_from_file(struct vty *, FILE *);
-enum node_type node_parent(enum node_type);
-int cmd_execute_command(vector, struct vty *, struct cmd_element **, int);
-int cmd_execute_command_strict(vector, struct vty *, struct cmd_element **);
-void config_replace_string(struct cmd_element *, char *, ...);
-void cmd_init(int);
-
-/* Export typical functions. */
-extern struct cmd_element config_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 177c410..2c92a86 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -1,44 +1,45 @@
 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)
 
 # build current directory before building gprs
-SUBDIRS = . ipaccess gprs
+SUBDIRS = . ipaccess gprs nat
 
 sbin_PROGRAMS = bsc_hack bs11_config isdnsync bsc_mgcp
-noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a
-noinst_HEADERS = vty/cardshell.h
+noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a libmgcp.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 socket.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 bsc_api.c
+		bts_unknown.c bsc_version.c bsc_api.c bsc_vty.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 \
-		telnet_interface.c vty_interface_cmds.c vty/utils.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)
+libmgcp_a_SOURCES = mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgcp/mgcp_vty.c
+
+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
 
 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
-bsc_mgcp_LDADD = libvty.a
+bsc_mgcp_SOURCES = mgcp/mgcp_main.c debug.c
+bsc_mgcp_LDADD = libvty.a libmgcp.a $(LIBOSMOVTY_LIBS)
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c
index 09285bd..6837305 100644
--- a/openbsc/src/abis_nm.c
+++ b/openbsc/src/abis_nm.c
@@ -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) {
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 53b2982..451c80d 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -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,14 +752,15 @@
    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);
 
 	/* FIXME: start some timer in case we don't receive a REL ACK ? */
 
@@ -811,7 +846,7 @@
 	LOGPC(DRSL, LOGL_NOTICE, "\n");
 	/* FIXME: only free it after channel release ACK */
 	counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rf_fail);
-	return rsl_rf_chan_release(msg->lchan);
+	return rsl_rf_chan_release(msg->lchan, 1);
 }
 
 static void print_meas_rep_uni(struct gsm_meas_rep_unidir *mru,
@@ -983,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));
-		rsl_lchan_set_state(msg->lchan, 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:
@@ -1079,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 */
@@ -1252,12 +1298,28 @@
 
 	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);
+		return rsl_rf_chan_release(msg->lchan, 1);
 	}
 
 	return 0;
 }
 
+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,
@@ -1309,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);
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 8f6de8a..44cef0a 100644
--- a/openbsc/src/bs11_config.c
+++ b/openbsc/src/bs11_config.c
@@ -830,6 +830,7 @@
 	}
 }
 
+extern int bts_model_bs11_init(void);
 int main(int argc, char **argv)
 {
 	struct gsm_network *gsmnet;
diff --git a/openbsc/src/bsc_api.c b/openbsc/src/bsc_api.c
index b504752..28fc324 100644
--- a/openbsc/src/bsc_api.c
+++ b/openbsc/src/bsc_api.c
@@ -1,6 +1,8 @@
 /* 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
  *
@@ -21,13 +23,118 @@
  */
 
 #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;
-	return rsl_data_request(msg, link_id);
+
+	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);
+	}
+}
+
+int gsm0808_page(struct gsm_bts *bts, unsigned int page_group, unsigned int mi_len,
+		 uint8_t *mi, int chan_type)
+{
+	return rsl_paging_cmd(bts, page_group, mi_len, mi, chan_type);
+}
+
+/* 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 a50d4ab..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 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) {
@@ -151,9 +144,7 @@
 			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,10 +198,20 @@
 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;
 
+	vty_info.copyright = openbsc_copyright;
+
 	log_init(&log_info);
 	tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
 	talloc_ctx_init();
@@ -227,9 +228,17 @@
 	/* enable filters */
 	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);
diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c
index 77446a2..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,7 +27,8 @@
 #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>
@@ -419,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;
@@ -441,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 =
@@ -456,7 +457,7 @@
 		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);
@@ -465,7 +466,7 @@
 		bts = container_of(obj, struct gsm_bts, gprs.nse);
 		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));
@@ -479,7 +480,7 @@
 		bts = container_of(obj, struct gsm_bts, gprs.cell);
 		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));
@@ -981,6 +982,8 @@
 {
 	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) {
@@ -1002,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;
@@ -1062,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;
 
@@ -1072,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_msc.c b/openbsc/src/bsc_msc.c
new file mode 100644
index 0000000..42b4c20
--- /dev/null
+++ b/openbsc/src/bsc_msc.c
@@ -0,0 +1,270 @@
+/* Routines to talk to the MSC using the IPA Protocol */
+/*
+ * (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_msc.h>
+#include <openbsc/debug.h>
+#include <openbsc/ipaccess.h>
+
+#include <osmocore/write_queue.h>
+#include <osmocore/talloc.h>
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+static void connection_loss(struct bsc_msc_connection *con)
+{
+	struct bsc_fd *fd;
+
+	fd = &con->write_queue.bfd;
+
+	close(fd->fd);
+	fd->fd = -1;
+	fd->cb = write_queue_bfd_cb;
+	fd->when = 0;
+
+	con->is_connected = 0;
+	con->connection_loss(con);
+}
+
+static void msc_con_timeout(void *_con)
+{
+	struct bsc_msc_connection *con = _con;
+
+	LOGP(DMSC, LOGL_ERROR, "MSC Connection timeout.\n");
+	bsc_msc_lost(con);
+}
+
+static int bsc_msc_except(struct bsc_fd *bfd)
+{
+	struct write_queue *wrt;
+	struct bsc_msc_connection *con;
+
+	LOGP(DMSC, LOGL_ERROR, "Exception on the BFD. Closing down.\n");
+
+	wrt = container_of(bfd, struct write_queue, bfd);
+	con = container_of(wrt, struct bsc_msc_connection, write_queue);
+
+	connection_loss(con);
+	return 0;
+}
+
+/* called in the case of a non blocking connect */
+static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
+{
+	int rc;
+	int val;
+	struct bsc_msc_connection *con;
+	struct write_queue *queue;
+
+	socklen_t len = sizeof(val);
+
+	if ((what & BSC_FD_WRITE) == 0) {
+		LOGP(DMSC, LOGL_ERROR, "Callback but not readable.\n");
+		return -1;
+	}
+
+	queue = container_of(fd, struct write_queue, bfd);
+	con = container_of(queue, struct bsc_msc_connection, write_queue);
+
+	/* check the socket state */
+	rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len);
+	if (rc != 0) {
+		LOGP(DMSC, LOGL_ERROR, "getsockopt for the MSC socket failed.\n");
+		goto error;
+	}
+	if (val != 0) {
+		LOGP(DMSC, LOGL_ERROR, "Not connected to the MSC: %d\n", val);
+		goto error;
+	}
+
+
+	/* go to full operation */
+	fd->cb = write_queue_bfd_cb;
+	fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
+
+	con->is_connected = 1;
+	bsc_del_timer(&con->timeout_timer);
+	LOGP(DMSC, LOGL_NOTICE, "(Re)Connected to the MSC.\n");
+	if (con->connected)
+		con->connected(con);
+	return 0;
+
+error:
+	bsc_unregister_fd(fd);
+	connection_loss(con);
+	return -1;
+}
+static void setnonblocking(struct bsc_fd *fd)
+{
+	int flags;
+
+	flags = fcntl(fd->fd, F_GETFL);
+	if (flags < 0) {
+		perror("fcntl get failed");
+		close(fd->fd);
+		fd->fd = -1;
+		return;
+	}
+
+	flags |= O_NONBLOCK;
+	flags = fcntl(fd->fd, F_SETFL, flags);
+	if (flags < 0) {
+		perror("fcntl get failed");
+		close(fd->fd);
+		fd->fd = -1;
+		return;
+	}
+}
+
+int bsc_msc_connect(struct bsc_msc_connection *con)
+{
+	struct bsc_fd *fd;
+	struct sockaddr_in sin;
+	int on = 1, ret;
+
+	LOGP(DMSC, LOGL_NOTICE, "Attempting to connect MSC at %s:%d\n", con->ip, con->port);
+
+	con->is_connected = 0;
+
+	fd = &con->write_queue.bfd;
+	fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	fd->data = NULL;
+	fd->priv_nr = 1;
+
+	if (fd->fd < 0) {
+		perror("Creating TCP socket failed");
+		return fd->fd;
+	}
+
+	/* make it non blocking */
+	setnonblocking(fd);
+
+	/* set the socket priority */
+	ret = setsockopt(fd->fd, IPPROTO_IP, IP_TOS,
+			 &con->prio, sizeof(con->prio));
+	if (ret != 0)
+		LOGP(DMSC, LOGL_ERROR, "Failed to set prio to %d. %s\n",
+		     con->prio, strerror(errno));
+
+	memset(&sin, 0, sizeof(sin));
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(con->port);
+	inet_aton(con->ip, &sin.sin_addr);
+
+	setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+	ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin));
+
+	if (ret == -1 && errno == EINPROGRESS) {
+		LOGP(DMSC, LOGL_ERROR, "MSC Connection in progress\n");
+		fd->when = BSC_FD_WRITE;
+		fd->cb = msc_connection_connect;
+		con->timeout_timer.cb = msc_con_timeout;
+		con->timeout_timer.data = con;
+		bsc_schedule_timer(&con->timeout_timer, 20, 0);
+	} else if (ret < 0) {
+		perror("Connection failed");
+		connection_loss(con);
+		return ret;
+	} else {
+		fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
+		fd->cb = write_queue_bfd_cb;
+		con->is_connected = 1;
+		if (con->connected)
+			con->connected(con);
+	}
+
+	ret = bsc_register_fd(fd);
+	if (ret < 0) {
+		perror("Registering the fd failed");
+		close(fd->fd);
+		return ret;
+	}
+
+	return ret;
+}
+
+struct bsc_msc_connection *bsc_msc_create(const char *ip, int port, int prio)
+{
+	struct bsc_msc_connection *con;
+
+	con = talloc_zero(NULL, struct bsc_msc_connection);
+	if (!con) {
+		LOGP(DMSC, LOGL_FATAL, "Failed to create the MSC connection.\n");
+		return NULL;
+	}
+
+	con->ip = ip;
+	con->port = port;
+	con->prio = prio;
+	write_queue_init(&con->write_queue, 100);
+	con->write_queue.except_cb = bsc_msc_except;
+	return con;
+}
+
+void bsc_msc_lost(struct bsc_msc_connection *con)
+{
+	write_queue_clear(&con->write_queue);
+	bsc_unregister_fd(&con->write_queue.bfd);
+	connection_loss(con);
+}
+
+static void reconnect_msc(void *_msc)
+{
+	struct bsc_msc_connection *con = _msc;
+
+	LOGP(DMSC, LOGL_NOTICE, "Attempting to reconnect to the MSC.\n");
+	bsc_msc_connect(con);
+}
+
+void bsc_msc_schedule_connect(struct bsc_msc_connection *con)
+{
+	LOGP(DMSC, LOGL_NOTICE, "Attempting to reconnect to the MSC.\n");
+	con->reconnect_timer.cb = reconnect_msc;
+	con->reconnect_timer.data = con;
+	bsc_schedule_timer(&con->reconnect_timer, 5, 0);
+}
+
+struct msgb *bsc_msc_id_get_resp(const char *token)
+{
+	struct msgb *msg;
+
+	if (!token) {
+		LOGP(DMSC, LOGL_ERROR, "No token specified.\n");
+		return NULL;
+	}
+
+	msg = msgb_alloc_headroom(4096, 128, "id resp");
+	if (!msg) {
+		LOGP(DMSC, LOGL_ERROR, "Failed to create the message.\n");
+		return NULL;
+	}
+
+	msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
+	msgb_l16tv_put(msg, strlen(token) + 1,
+			IPAC_IDTAG_UNITNAME, (u_int8_t *) token);
+	return msg;
+}
\ No newline at end of file
diff --git a/openbsc/src/bsc_rll.c b/openbsc/src/bsc_rll.c
index 9a4f5aa..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;
@@ -55,7 +56,6 @@
 
 	conn = &rllr->lchan->conn;
 	llist_del(&rllr->list);
-	put_subscr_con(conn);
 	rllr->cb(rllr->lchan, rllr->link_id, rllr->data, type);
 	talloc_free(rllr);
 }
@@ -88,7 +88,6 @@
 		link_id |= 0x40;
 
 	conn = &lchan->conn;
-	use_subscr_con(conn);
 	rllr->lchan = lchan;
 	rllr->link_id = link_id;
 	rllr->cb = cb;
@@ -120,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 90%
rename from openbsc/src/vty_interface.c
rename to openbsc/src/bsc_vty.c
index 2799706..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,11 +39,11 @@
 #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[] = {
@@ -94,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;
@@ -159,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;
@@ -193,6 +210,8 @@
 		bts->cell_identity,
 		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),
@@ -231,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) {
@@ -294,6 +313,9 @@
 	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);
@@ -352,6 +374,8 @@
 
 	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,
@@ -401,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)
@@ -411,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);
@@ -456,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,
@@ -480,7 +509,7 @@
 	"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;
@@ -546,7 +575,7 @@
 	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;
@@ -706,7 +735,7 @@
 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;
@@ -924,7 +953,7 @@
 	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;
 
@@ -955,7 +984,7 @@
       cfg_net_cmd,
       "network", NETWORK_STR)
 {
-	vty->index = gsmnet;
+	vty->index = gsmnet_from_vty(vty);
 	vty->node = GSMNET_NODE;
 
 	return CMD_SUCCESS;
@@ -967,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;
@@ -977,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;
@@ -987,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);
 
@@ -1000,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);
 
@@ -1018,6 +1055,7 @@
 	"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;
 
@@ -1029,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;
@@ -1037,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;
@@ -1047,8 +1091,11 @@
 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;
 }
@@ -1062,6 +1109,8 @@
 	"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;
@@ -1071,6 +1120,8 @@
       "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;
@@ -1085,6 +1136,7 @@
 	"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 "
@@ -1107,6 +1159,7 @@
 	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;
 }
@@ -1116,6 +1169,7 @@
 	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;
 }
@@ -1125,6 +1179,7 @@
 	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;
 }
@@ -1134,6 +1189,7 @@
 	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;
 }
@@ -1143,6 +1199,7 @@
 	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;
 }
@@ -1152,6 +1209,7 @@
 	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;
 }
@@ -1163,6 +1221,7 @@
       "Configure GSM Timers\n"					\
       doc)							\
 {								\
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);	\
 	int value = atoi(argv[0]);				\
 								\
 	if (value < 0 || value > 65535) {			\
@@ -1180,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.")
@@ -1195,6 +1254,7 @@
       "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;
 
@@ -1216,6 +1276,7 @@
 	}
 
 	vty->index = bts;
+	vty->index_sub = &bts->description;
 	vty->node = BTS_NODE;
 
 	return CMD_SUCCESS;
@@ -1679,7 +1740,18 @@
 }
 
 #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	""
+#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>",
@@ -1763,6 +1835,7 @@
 		return CMD_WARNING;
 
 	vty->index = trx;
+	vty->index_sub = &trx->description;
 	vty->node = TRX_NODE;
 
 	return CMD_SUCCESS;
@@ -1770,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]);
@@ -1916,21 +1989,53 @@
 	return CMD_SUCCESS;
 }
 
-extern int bsc_vty_init_extra(struct gsm_network *net);
-
-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;
 
+	conn = (struct telnet_connection *) vty->priv;
+	if (!conn->dbg) {
+		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	log_set_imsi_filter(conn->dbg, argv[0]);
+	return CMD_SUCCESS;
+}
+
+extern int bsc_vty_init_extra(void);
+extern const char *openbsc_copyright;
+
+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);
@@ -1938,11 +2043,13 @@
 
 	install_element_ve(&show_paging_cmd);
 
-	openbsc_vty_add_cmds();
+	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);
@@ -1975,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);
@@ -2010,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);
@@ -2020,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 107abdc..d6e4ff1 100644
--- a/openbsc/src/chan_alloc.c
+++ b/openbsc/src/chan_alloc.c
@@ -338,6 +338,8 @@
 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;
@@ -363,7 +365,7 @@
 
 	DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan));
 	rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
-	rsl_release_request(lchan, 0);
+	rsl_release_request(lchan, 0, 0);
 	return 1;
 }
 
@@ -376,7 +378,7 @@
 		bsc_schedule_timer(&lchan->conn.release_timer, LCHAN_RELEASE_TIMEOUT);
 }
 
-struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) {
+static struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) {
 	struct gsm_bts_trx *trx;
 	int ts_no, lchan_no;
 
@@ -394,7 +396,7 @@
 	return NULL;
 }
 
-struct gsm_lchan *lchan_for_subscr(struct gsm_subscriber *subscr)
+struct gsm_subscriber_connection *connection_for_subscr(struct gsm_subscriber *subscr)
 {
 	struct gsm_bts *bts;
 	struct gsm_network *net = subscr->net;
@@ -403,7 +405,7 @@
 	llist_for_each_entry(bts, &net->bts_list, list) {
 		lchan = lchan_find(bts, subscr);
 		if (lchan)
-			return lchan;
+			return &lchan->conn;
 	}
 
 	return NULL;
diff --git a/openbsc/src/common_vty.c b/openbsc/src/common_vty.c
new file mode 100644
index 0000000..ffa676d
--- /dev/null
+++ b/openbsc/src/common_vty.c
@@ -0,0 +1,185 @@
+/* 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 <openbsc/bsc_nat.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;
+	case NAT_NODE:
+		vty->node = CONFIG_NODE;
+		vty->index = NULL;
+		break;
+	case BSC_NODE:
+		vty->node = NAT_NODE;
+		{
+			struct bsc_config *bsc_config = vty->index;
+			vty->index = bsc_config->nat;
+		}
+		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 BSC_NODE:
+		vty->node = NAT_NODE;
+		{
+			struct bsc_config *bsc_config = vty->index;
+			vty->index = bsc_config->nat;
+		}
+		break;
+	case MGCP_NODE:
+	case GBPROXY_NODE:
+	case SGSN_NODE:
+	case NS_NODE:
+	case BSSGP_NODE:
+	case NAT_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 57a7863..72e6bd3 100644
--- a/openbsc/src/db.c
+++ b/openbsc/src/db.c
@@ -132,17 +132,15 @@
 		"timestamp TIMESTAMP NOT NULL, "
 		"value INTEGER NOT NULL, "
 		"name TEXT NOT NULL, "
-		"index INTEGER NOT NULL "
+		"idx INTEGER NOT NULL "
 		")",
 	"CREATE TABLE IF NOT EXISTS AuthKeys ("
-		"id INTEGER PRIMARY KEY AUTOINCREMENT, "
-		"subscriber_id INTEGER UNIQUE NOT NULL, "
+		"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, "
@@ -350,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;
@@ -379,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;
@@ -402,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;
@@ -435,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;
@@ -488,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;
@@ -499,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)
@@ -511,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;
@@ -526,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, "
@@ -537,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",
@@ -1202,7 +1200,7 @@
 
 	result = dbi_conn_queryf(conn,
 		"Insert INTO RateCounters "
-		"(timestamp,name,index,value) VALUES "
+		"(timestamp,name,idx,value) VALUES "
 		"(datetime('now'),%s.%s,%u,%"PRIu64")",
 		q_prefix, q_name, ctrg->idx, ctrg->ctr[num].current);
 
diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c
index 9218f64..c701f50 100644
--- a/openbsc/src/debug.c
+++ b/openbsc/src/debug.c
@@ -154,33 +154,58 @@
 	[DNS] = {
 		.name = "DNS",
 		.description = "GPRS Network Service (NS)",
-		.enabled = 1, .loglevel = LOGL_DEBUG,
+		.enabled = 1, .loglevel = LOGL_INFO,
 	},
 	[DBSSGP] = {
 		.name = "DBSSGP",
 		.description = "GPRS BSS Gateway Protocol (BSSGP)",
 		.enabled = 1, .loglevel = LOGL_DEBUG,
 	},
-};
-
-enum log_ctxt {
-	CTX_SUBSCRIBER,
+	[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,
+	},
+	[DNAT] = {
+		.name = "DNAT",
+		.description = "GSM 08.08 NAT/Multipkexer",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
 };
 
 enum log_filter {
 	_FLT_ALL = LOG_FILTER_ALL,	/* libosmocore */
 	FLT_IMSI = 1,
+	FLT_NSVC = 2,
+	FLT_BVC  = 3,
 };
 
 static int filter_fn(const struct log_context *ctx,
 		     struct log_target *tar)
 {
-	struct gsm_subscriber *subscr = ctx->ctx[CTX_SUBSCRIBER];
+	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;
 }
 
@@ -201,3 +226,25 @@
 		target->filter_data[FLT_IMSI] = NULL;
 	}
 }
+
+void log_set_nsvc_filter(struct log_target *target, struct gprs_nsvc *nsvc)
+{
+	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 log_set_bvc_filter(struct log_target *target, struct bssgp_bvc_ctx *bctx)
+{
+	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/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am
index 88c358a..30b45f6 100644
--- a/openbsc/src/gprs/Makefile.am
+++ b/openbsc/src/gprs/Makefile.am
@@ -1,18 +1,25 @@
 INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
-AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS)
-AM_LDFLAGS = $(LIBOSMOCORE_LIBS)
+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
-noinst_LIBRARIES = libsgsn.a
+else
+sbin_PROGRAMS = osmo-gbproxy
+endif
 
-libsgsn_a_SOURCES = gprs_ns.c gprs_bssgp.c gprs_llc.c gsm_04_08_gprs.c \
-		crc24.c gprs_sgsn.c gprs_bssgp_util.c
+
+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 \
-			gprs_ns.c gprs_ns_vty.c gprs_bssgp_util.c \
 			$(top_srcdir)/src/socket.c $(top_srcdir)/src/debug.c
-osmo_gbproxy_LDADD = $(top_builddir)/src/libvty.a
+osmo_gbproxy_LDADD = libgb.a $(top_builddir)/src/libvty.a
 
-osmo_sgsn_SOURCES = sgsn_main.c sgsn_vty.c gprs_ns_vty.c \
+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 = $(top_builddir)/src/libvty.a libsgsn.a
+osmo_sgsn_LDADD = libgb.a $(top_builddir)/src/libvty.a -lgtp
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c
index 5fbf9bf..a95929b 100644
--- a/openbsc/src/gprs/gb_proxy.c
+++ b/openbsc/src/gprs/gb_proxy.c
@@ -122,16 +122,38 @@
 /* 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 header */
-	memcpy(new_msg, msg, sizeof(*new_msg));
 	/* copy data */
-	memcpy(new_msg->data, msg->data, new_msg->data_len);
+	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;
 }
@@ -320,11 +342,11 @@
 	} 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->bvci);
+			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->bvci);
+			peer ? peer->bvci : -1);
 	} else
 		LOGPC(DGPRS, LOGL_INFO, "\n");
 
@@ -507,6 +529,18 @@
 	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)
@@ -555,7 +589,7 @@
 }
 
 
-#include <vty/command.h>
+#include <osmocom/vty/command.h>
 
 gDEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy",
        SHOW_STR "Display information about the Gb proxy")
@@ -567,14 +601,16 @@
 		struct gprs_ra_id raid;
 		gsm48_parse_ra(&raid, peer->ra);
 
-		vty_out(vty, "NSEI %5u, NS-VC %5u, PTP-BVCI %u, "
-			"RAC %u-%u-%u-%u%s",
+		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, VTY_NEWLINE);
-		if (nsvc->nsi->ll == GPRS_NS_LL_UDP)
-			vty_out(vty, "  remote address %s:%u%s",
+			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
index fc8f164..32bbe38 100644
--- a/openbsc/src/gprs/gb_proxy_main.c
+++ b/openbsc/src/gprs/gb_proxy_main.c
@@ -42,10 +42,12 @@
 #include <openbsc/debug.h>
 #include <openbsc/gprs_ns.h>
 #include <openbsc/gprs_bssgp.h>
-#include <openbsc/telnet_interface.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 */
@@ -56,15 +58,13 @@
 
 void *tall_bsc_ctx;
 
-const char *openbsc_version = "Osmocom NSIP Proxy " PACKAGE_VERSION;
 const char *openbsc_copyright =
 	"Copyright (C) 2010 Harald Welte and On-Waves\n"
-	"Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\n"
-	"Dieter Spaar, Andreas Eversberg, Holger Freyther\n\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;
 
@@ -116,13 +116,86 @@
 	}
 }
 
+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;
-	struct log_target *stderr_target;
-	struct sockaddr_in sin;
 	int rc;
 
 	tall_bsc_ctx = talloc_named_const(NULL, 0, "nsip_proxy");
@@ -139,8 +212,18 @@
 	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);
-	telnet_init(&dummy_network, 4246);
+
+	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) {
@@ -157,14 +240,28 @@
 		exit(2);
 	}
 
-	nsip_listen(bssgp_nsi, gbcfg.nsip_listen_port);
+	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);
+	}
 
-	/* 'establish' the outgoing connection to the SGSN */
-	sin.sin_family = AF_INET;
-	sin.sin_port = htons(gbcfg.nsip_sgsn_port);
-	sin.sin_addr.s_addr = htonl(gbcfg.nsip_sgsn_ip);
-	nsip_connect(bssgp_nsi, &sin, gbcfg.nsip_sgsn_nsei,
-			gbcfg.nsip_sgsn_nsvci);
+	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);
@@ -174,15 +271,3 @@
 
 	exit(0);
 }
-
-struct gsm_network;
-int bsc_vty_init(struct gsm_network *dummy)
-{
-	cmd_init(1);
-	vty_init();
-
-	openbsc_vty_add_cmds();
-        gbproxy_vty_init();
-	return 0;
-}
-
diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c
index e1cf97e..7b6d2da 100644
--- a/openbsc/src/gprs/gb_proxy_vty.c
+++ b/openbsc/src/gprs/gb_proxy_vty.c
@@ -29,9 +29,10 @@
 #include <openbsc/debug.h>
 #include <openbsc/gb_proxy.h>
 #include <openbsc/gprs_ns.h>
+#include <openbsc/vty.h>
 
-#include <vty/command.h>
-#include <vty/vty.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/vty.h>
 
 static struct gbproxy_config *g_cfg = NULL;
 
@@ -46,25 +47,9 @@
 
 static int config_write_gbproxy(struct vty *vty)
 {
-	struct in_addr ia;
-
 	vty_out(vty, "gbproxy%s", VTY_NEWLINE);
 
-	if (g_cfg->nsip_listen_ip) {
-		ia.s_addr = htonl(g_cfg->nsip_listen_ip);
-		vty_out(vty, " nsip bss local ip %s%s", inet_ntoa(ia),
-			VTY_NEWLINE);
-	}
-	vty_out(vty, " nsip bss local port %u%s", g_cfg->nsip_listen_port,
-		VTY_NEWLINE);
-	ia.s_addr = htonl(g_cfg->nsip_sgsn_ip);
-	vty_out(vty, " nsip sgsn remote ip %s%s", inet_ntoa(ia),
-		VTY_NEWLINE);
-	vty_out(vty, " nsip sgsn remote port %u%s", g_cfg->nsip_sgsn_port,
-		VTY_NEWLINE);
-	vty_out(vty, " nsip sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei,
-		VTY_NEWLINE);
-	vty_out(vty, " nsip sgsn nsvci %u%s", g_cfg->nsip_sgsn_nsvci,
+	vty_out(vty, " sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei,
 		VTY_NEWLINE);
 
 	return CMD_SUCCESS;
@@ -79,58 +64,9 @@
 	return CMD_SUCCESS;
 }
 
-DEFUN(cfg_nsip_bss_local_ip,
-      cfg_nsip_bss_local_ip_cmd,
-      "nsip bss local ip A.B.C.D",
-      "Set the IP address on which we listen for BSS connects")
-{
-	struct in_addr ia;
-
-	inet_aton(argv[0], &ia);
-	g_cfg->nsip_listen_ip = ntohl(ia.s_addr);
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nsip_bss_local_port,
-      cfg_nsip_bss_local_port_cmd,
-      "nsip bss local port <0-65534>",
-      "Set the UDP port on which we listen for BSS connects")
-{
-	unsigned int port = atoi(argv[0]);
-
-	g_cfg->nsip_listen_port = port;
-	return CMD_SUCCESS;
-}
-
-
-DEFUN(cfg_nsip_sgsn_ip,
-      cfg_nsip_sgsn_ip_cmd,
-      "nsip sgsn remote ip A.B.C.D",
-      "Set the IP of the SGSN to which the proxy shall connect")
-{
-	struct in_addr ia;
-
-	inet_aton(argv[0], &ia);
-	g_cfg->nsip_sgsn_ip = ntohl(ia.s_addr);
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nsip_sgsn_port,
-      cfg_nsip_sgsn_port_cmd,
-      "nsip sgsn remote port <0-65534>",
-      "Set the UDP port of the SGSN to which the proxy shall connect")
-{
-	unsigned int port = atoi(argv[0]);
-
-	g_cfg->nsip_sgsn_port = port;
-	return CMD_SUCCESS;
-}
-
 DEFUN(cfg_nsip_sgsn_nsei,
       cfg_nsip_sgsn_nsei_cmd,
-      "nsip sgsn nsei <0-65534>",
+      "sgsn nsei <0-65534>",
       "Set the NSEI to be used in the connection with the SGSN")
 {
 	unsigned int port = atoi(argv[0]);
@@ -139,17 +75,6 @@
 	return CMD_SUCCESS;
 }
 
-DEFUN(cfg_nsip_sgsn_nsvci,
-      cfg_nsip_sgsn_nsvci_cmd,
-      "nsip sgsn nsvci <0-65534>",
-      "Set the NSVCI to be used in the connection with the SGSN")
-{
-	unsigned int port = atoi(argv[0]);
-
-	g_cfg->nsip_sgsn_nsvci = port;
-	return CMD_SUCCESS;
-}
-
 int gbproxy_vty_init(void)
 {
 	install_element_ve(&show_gbproxy_cmd);
@@ -157,12 +82,9 @@
 	install_element(CONFIG_NODE, &cfg_gbproxy_cmd);
 	install_node(&gbproxy_node, config_write_gbproxy);
 	install_default(GBPROXY_NODE);
-	install_element(GBPROXY_NODE, &cfg_nsip_bss_local_ip_cmd);
-	install_element(GBPROXY_NODE, &cfg_nsip_bss_local_port_cmd);
-	install_element(GBPROXY_NODE, &cfg_nsip_sgsn_ip_cmd);
-	install_element(GBPROXY_NODE, &cfg_nsip_sgsn_port_cmd);
+	install_element(GBPROXY_NODE, &ournode_exit_cmd);
+	install_element(GBPROXY_NODE, &ournode_end_cmd);
 	install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd);
-	install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsvci_cmd);
 
 	return 0;
 }
@@ -172,7 +94,7 @@
 	int 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;
diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c
index 9fdfd32..0ec873c 100644
--- a/openbsc/src/gprs/gprs_bssgp.c
+++ b/openbsc/src/gprs/gprs_bssgp.c
@@ -18,6 +18,9 @@
  * 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>
@@ -28,6 +31,7 @@
 #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>
@@ -35,38 +39,46 @@
 #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
 
-/* The per-BTS context that we keep on the SGSN side of the BSSGP link */
-struct bssgp_bts_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 bvc_state;
-
-	/* 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;
+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 LLIST_HEAD(bts_ctxts);
+
+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_bts_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid)
+struct bssgp_bvc_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid)
 {
-	struct bssgp_bts_ctx *bctx;
+	struct bssgp_bvc_ctx *bctx;
 
-	llist_for_each_entry(bctx, &bts_ctxts, list) {
+	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;
@@ -75,27 +87,30 @@
 }
 
 /* Find a BTS context based on BVCI+NSEI tuple */
-struct bssgp_bts_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei)
+struct bssgp_bvc_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei)
 {
-	struct bssgp_bts_ctx *bctx;
+	struct bssgp_bvc_ctx *bctx;
 
-	llist_for_each_entry(bctx, &bts_ctxts, list) {
+	llist_for_each_entry(bctx, &bssgp_bvc_ctxts, list) {
 		if (bctx->nsei == nsei && bctx->bvci == bvci)
 			return bctx;
 	}
 	return NULL;
 }
 
-struct bssgp_bts_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei)
+struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei)
 {
-	struct bssgp_bts_ctx *ctx;
+	struct bssgp_bvc_ctx *ctx;
 
-	ctx = talloc_zero(bssgp_tall_ctx, struct bssgp_bts_ctx);
+	ctx = talloc_zero(bssgp_tall_ctx, struct bssgp_bvc_ctx);
 	if (!ctx)
 		return NULL;
 	ctx->bvci = bvci;
 	ctx->nsei = nsei;
-	llist_add(&ctx->list, &bts_ctxts);
+	/* 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;
 }
@@ -116,6 +131,96 @@
 	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 */
@@ -128,13 +233,13 @@
 static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp,	
 			      uint16_t ns_bvci)
 {
-	struct bssgp_bts_ctx *bctx;
+	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));
-	DEBUGPC(DBSSGP, "BVCI=%u, cause=%s\n", 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 */
@@ -142,11 +247,14 @@
 	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 RESET BVCI=%u "
+			LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u RESET "
 				"missing mandatory IE\n", bvci);
 			return -EINVAL;
 		}
@@ -164,90 +272,200 @@
 	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)
+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);
-	int data_len = msgb_bssgp_len(msg) - sizeof(*budh);
-	struct tlv_parsed tp;
-	int rc;
-
-	DEBUGP(DBSSGP, "BSSGP UL-UD\n");
 
 	/* extract TLLI and parse TLV IEs */
 	msgb_tlli(msg) = ntohl(budh->tlli);
-	rc = bssgp_tlv_parse(&tp, budh->data, data_len);
+
+	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))
-		return -EIO;
-
-	/* FIXME: lookup bssgp_bts_ctx based on BVCI + NSEI */
+	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) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU);
-	msgb_bcid(msg) = TLVP_VAL(&tp, BSSGP_IE_CELL_ID);
+	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);
+	return gprs_llc_rcvmsg(msg, tp);
 }
 
-static int bssgp_rx_suspend(struct msgb *msg)
+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);
-	int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
-	struct tlv_parsed tp;
+	struct gprs_ra_id raid;
+	uint32_t tlli;
 	int rc;
 
-	DEBUGP(DBSSGP, "BSSGP SUSPEND\n");
+	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);
+	}
 
-	rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
+	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 rc;
+		return bssgp_tx_suspend_nack(msgb_nsei(msg), tlli, NULL);
 
-	if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) ||
-	    !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
-		return -EIO;
+	bssgp_tx_suspend_ack(msgb_nsei(msg), tlli, &raid, 0);
 
-	/* FIXME: pass the SUSPEND request to GMM */
-	/* SEND SUSPEND_ACK or SUSPEND_NACK */
+	return 0;
 }
 
-static int bssgp_rx_resume(struct msgb *msg)
+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);
-	int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
-	struct tlv_parsed tp;
+	struct gprs_ra_id raid;
+	uint32_t tlli;
+	uint8_t suspend_ref;
 	int rc;
 
-	DEBUGP(DBSSGP, "BSSGP RESUME\n");
+	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);
+	}
 
-	rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
+	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 rc;
+		return bssgp_tx_resume_nack(msgb_nsei(msg), tlli, &raid,
+					    NULL);
 
-	if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) ||
-	    !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA) ||
-	    !TLVP_PRESENT(&tp, BSSGP_IE_SUSPEND_REF_NR))
-		return -EIO;
-
-	/* FIXME: pass the RESUME request to GMM */
-	/* SEND RESUME_ACK or RESUME_NACK */
+	bssgp_tx_resume_ack(msgb_nsei(msg), tlli, &raid);
+	return 0;
 }
 
-static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp)
+
+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 FC BVC\n");
+	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))
+	    !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 */
 
@@ -256,133 +474,168 @@
 				   msgb_bvci(msg));
 }
 
-/* We expect msgb_bssgph() to point to the BSSGP header */
-int gprs_bssgp_rcvmsg(struct msgb *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);
-	struct tlv_parsed tp;
 	uint8_t pdu_type = bgph->pdu_type;
-	int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
-	uint16_t bvci;	/* PTP BVCI */
-	uint16_t ns_bvci = msgb_bvci(msg);
 	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)
-		rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
+	/* 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);
+		rc = bssgp_rx_ul_ud(msg, tp, bctx);
 		break;
 	case BSSGP_PDUT_RA_CAPABILITY:
 		/* BSS requests RA capability or IMSI */
-		DEBUGP(DBSSGP, "BSSGP RA CAPABILITY UPDATE\n");
+		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 RADIO STATUS\n");
+		DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx RADIO STATUS\n", bctx->bvci);
 		/* BSS informs us of some exception */
-		/* FIXME: notify GMM */
-		break;
-	case BSSGP_PDUT_SUSPEND:
-		/* MS wants to suspend */
-		rc = bssgp_rx_suspend(msg);
-		break;
-	case BSSGP_PDUT_RESUME:
-		/* MS wants to resume */
-		rc = bssgp_rx_resume(msg);
-		break;
-	case BSSGP_PDUT_FLUSH_LL:
-		/* BSS informs MS has moved to one cell to other cell */
-		DEBUGP(DBSSGP, "BSSGP FLUSH LL\n");
-		/* FIXME: notify GMM */
-		/* Send FLUSH_LL_ACK */
-		break;
-	case BSSGP_PDUT_LLC_DISCARD:
-		/* BSS informs that some LLC PDU's have been discarded */
-		DEBUGP(DBSSGP, "BSSGP LLC DISCARDED\n");
-		/* FIXME: notify GMM */
+		/* 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);
+		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 FC MS\n");
+		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_BVC_BLOCK:
-		/* BSS tells us that BVC shall be blocked */
-		DEBUGP(DBSSGP, "BSSGP BVC BLOCK ");
-		if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) ||
-		    !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE))
-			goto err_mand_ie;
-		bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
-		DEBUGPC(DBSSGP, "BVCI=%u, cause=%s\n", bvci,
-			bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE)));
-		/* We always acknowledge the BLOCKing */
-		rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK,
-					  msgb_nsei(msg), bvci, ns_bvci);
-		break;
-	case BSSGP_PDUT_BVC_UNBLOCK:
-		/* BSS tells us that BVC shall be unblocked */
-		DEBUGP(DBSSGP, "BSSGP BVC UNBLOCK ");
-		if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI))
-			goto err_mand_ie;
-		bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
-		DEBUGPC(DBSSGP, "BVCI=%u\n", bvci);
-		/* We always acknowledge the unBLOCKing */
-		rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK,
-					  msgb_nsei(msg), bvci, ns_bvci);
-		break;
-	case BSSGP_PDUT_BVC_RESET:
-		/* BSS tells us that BVC init is required */
-		DEBUGP(DBSSGP, "BSSGP BVC RESET ");
-		if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) ||
-		    !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE))
-			goto err_mand_ie;
-		rc = bssgp_rx_bvc_reset(msg, &tp, ns_bvci);
-		break;
 	case BSSGP_PDUT_STATUS:
 		/* Some exception has occurred */
-		/* FIXME: notify GMM */
+		/* 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 PDU type 0x%02x not [yet] implemented\n",
-			pdu_type);
+		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_ACK:
-	case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK:
-	case BSSGP_PDUT_FLOW_CONTROL_MS_ACK:
+	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 PDU type 0x%02x only exists in DL\n",
-			pdu_type);
+		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 PDU type 0x%02x unknown\n", pdu_type);
+		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;
 	}
 
@@ -391,30 +644,85 @@
 	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)
+int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx)
 {
-	struct bssgp_bts_ctx *bctx;
+	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, 0x21 };
+	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 < 2) {
+	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)
+	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;
@@ -426,11 +734,41 @@
 		llc_pdu_tlv[1] = msg_len >> 8;
 		llc_pdu_tlv[2] = msg_len & 0xff;
 	} else {
-		llc_pdu_tlv[1] = msg_len & 0x3f;
+		llc_pdu_tlv[1] = msg_len & 0x7f;
 		llc_pdu_tlv[1] |= 0x80;
 	}
 
-	/* FIXME: optional elements */
+	/* 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);
@@ -442,7 +780,73 @@
 	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
index d9b5175..e760252 100644
--- a/openbsc/src/gprs/gprs_bssgp_util.c
+++ b/openbsc/src/gprs/gprs_bssgp_util.c
@@ -101,7 +101,8 @@
 	struct bssgp_normal_hdr *bgph =
 			(struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
 
-	DEBUGPC(DBSSGP, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause));
+	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;
 
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
index 9c75a3d..54f06f9 100644
--- a/openbsc/src/gprs/gprs_llc.c
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -30,73 +30,125 @@
 
 #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 4.5.2 Logical Link States + Annex C.2 */
-enum gprs_llc_ll_state {
-	GPRS_LLS_UNASSIGNED	= 1,	/* No TLLI yet */
-	GPRS_LLS_ASSIGNED_ADM	= 2,	/* TLLI assigned */
-	GPRS_LLS_LOCAL_EST	= 3,	/* Local Establishment */
-	GPRS_LLS_REMOTE_EST	= 4,	/* Remote Establishment */
-	GPRS_LLS_ABM		= 5,
-	GPRS_LLS_LOCAL_REL	= 6,	/* Local Release */
-	GPRS_LLS_TIMER_REC 	= 7,	/* Timer Recovery */
+/* 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,
+	},
 };
 
-/* Section 4.7.1: Logical Link Entity: One per DLCI (TLLI + SAPI) */
-struct gprs_llc_lle {
-	struct llist_head list;
-	struct timer_list t200;
-	struct timer_list t201;	/* wait for acknowledgement */
-
-	enum gprs_llc_ll_state state;
-
-	uint32_t tlli;
-	uint32_t sapi;
-
-	uint8_t v_sent;
-	uint8_t v_ack;
-	uint8_t v_recv;
-
-	unsigned int n200;
-	unsigned int retrans_ctr;
-
-	/* over which BSSGP BTS ctx do we need to transmit */
-	uint16_t bvci;
-	uint16_t nsei;
-};
-
-static LLIST_HEAD(gprs_llc_lles);
+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, uint32_t sapi)
+static struct gprs_llc_lle *lle_by_tlli_sapi(uint32_t tlli, uint8_t sapi)
 {
-	struct gprs_llc_lle *lle;
+	struct gprs_llc_llme *llme;
 
-	llist_for_each_entry(lle, &gprs_llc_lles, list) {
-		if (lle->tlli == tlli && lle->sapi == sapi)
-			return lle;
+	llist_for_each_entry(llme, &gprs_llc_llmes, list) {
+		if (llme->tlli == tlli || llme->old_tlli == tlli)
+			return &llme->lle[sapi];
 	}
 	return NULL;
 }
 
-static struct gprs_llc_lle *lle_alloc(uint32_t tlli, uint32_t sapi)
+static void lle_init(struct gprs_llc_llme *llme, uint8_t sapi)
 {
-	struct gprs_llc_lle *lle;
+	struct gprs_llc_lle *lle = &llme->lle[sapi];
 
-	lle = talloc_zero(llc_tall_ctx, struct gprs_llc_lle);
-	if (!lle)
+	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;
 
-	lle->tlli = tlli;
-	lle->sapi = sapi;
-	lle->state = GPRS_LLS_UNASSIGNED;
-	llist_add(&lle->list, &gprs_llc_lles);
+	llme->tlli = tlli;
+	llme->state = GPRS_LLMS_UNASSIGNED;
 
-	return lle;
+	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 {
@@ -111,6 +163,23 @@
 	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 {
@@ -149,20 +218,20 @@
 
 	/* 8.5.1.3: Expiry of T200 */
 
-	if (lle->retrans_ctr >= lle->n200) {
+	if (lle->retrans_ctr >= lle->params.n200) {
 		/* FIXME: LLGM-STATUS-IND, LL-RELEASE-IND/CNF */
-		lle->state = GPRS_LLS_ASSIGNED_ADM;
+		lle->state = GPRS_LLES_ASSIGNED_ADM;
 	}
 
 	switch (lle->state) {
-	case GPRS_LLS_LOCAL_EST:
-		/* retransmit SABM */
-		/* re-start T200 */
+	case GPRS_LLES_LOCAL_EST:
+		/* FIXME: retransmit SABM */
+		/* FIXME: re-start T200 */
 		lle->retrans_ctr++;
 		break;
-	case GPRS_LLS_LOCAL_REL:
-		/* retransmit DISC */
-		/* re-start T200 */
+	case GPRS_LLES_LOCAL_REL:
+		/* FIXME: retransmit DISC */
+		/* FIXME: re-start T200 */
 		lle->retrans_ctr++;
 		break;
 	}
@@ -173,9 +242,9 @@
 {
 	struct gprs_llc_lle *lle = data;
 
-	if (lle->retrans_ctr < lle->n200) {
-		/* transmit apropriate supervisory frame (8.6.4.1) */
-		/* set timer T201 */
+	if (lle->retrans_ctr < lle->params.n200) {
+		/* FIXME: transmit apropriate supervisory frame (8.6.4.1) */
+		/* FIXME: set timer T201 */
 		lle->retrans_ctr++;
 	}
 }
@@ -213,22 +282,24 @@
 
 	/* Identifiers passed down: (BVCI, NSEI) */
 
-	return gprs_bssgp_tx_dl_ud(msg);
+	/* 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->tlli;
-	msgb_bvci(msg) = lle->bvci;
-	msgb_nsei(msg) = lle->nsei;
+	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)
+int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
+		   void *mmctx)
 {
 	struct gprs_llc_lle *lle;
 	uint8_t *fcs, *llch;
@@ -240,11 +311,25 @@
 
 	/* look-up or create the LL Entity for this (TLLI, SAPI) tuple */
 	lle = lle_by_tlli_sapi(msgb_tlli(msg), sapi);
-	if (!lle)
-		lle = lle_alloc(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->bvci = msgb_bvci(msg);
-	lle->nsei = msgb_nsei(msg);
+	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;
@@ -272,22 +357,23 @@
 
 	/* Identifiers passed down: (BVCI, NSEI) */
 
-	return gprs_bssgp_tx_dl_ud(msg);
+	/* Send BSSGP-DL-UNITDATA.req */
+	return gprs_bssgp_tx_dl_ud(msg, mmctx);
 }
 
-static int gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph)
+static void gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph)
 {
-	DEBUGP(DGPRS, "LLC SAPI=%u %c %c FCS=0x%06x(%s) ",
+	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(DGPRS, "CMD=%u ", gph->cmd);
+		DEBUGPC(DLLC, "CMD=%s ", get_value_string(llc_cmd_strs, gph->cmd));
 
 	if (gph->data)
-		DEBUGPC(DGPRS, "DATA ");
+		DEBUGPC(DLLC, "DATA ");
 
-	DEBUGPC(DGPRS, "\n");
+	DEBUGPC(DLLC, "\n");
 }
 static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph,
 			   struct gprs_llc_lle *lle)
@@ -295,26 +381,26 @@
 	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_LLS_ASSIGNED_ADM) {
+		if (lle->state == GPRS_LLES_ASSIGNED_ADM) {
 			/* start re-establishment (8.7.1) */
 		}
-		lle->state = GPRS_LLS_REMOTE_EST;
+		lle->state = GPRS_LLES_REMOTE_EST;
 		/* FIXME: Send UA */
-		lle->state = GPRS_LLS_ABM;
+		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_LLS_ASSIGNED_ADM;
+		lle->state = GPRS_LLES_ASSIGNED_ADM;
 		break;
 	case GPRS_LLC_UA: /* Section 6.4.1.3 */
-		if (lle->state == GPRS_LLS_LOCAL_EST)
-			lle->state = GPRS_LLS_ABM;
+		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_LLS_LOCAL_EST)
-			lle->state = GPRS_LLS_ASSIGNED_ADM;
+		if (lle->state == GPRS_LLES_LOCAL_EST)
+			lle->state = GPRS_LLES_ASSIGNED_ADM;
 		break;
 	case GPRS_LLC_FRMR: /* Section 6.4.1.5 */
 		break;
@@ -329,6 +415,15 @@
 			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;
@@ -336,7 +431,7 @@
 
 /* parse a GPRS LLC header, also check for invalid frames */
 static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
-			      const uint8_t *llc_hdr, int len)
+			      uint8_t *llc_hdr, int len)
 {
 	uint8_t *ctrl = llc_hdr+1;
 	int is_sack = 0;
@@ -437,6 +532,7 @@
 		}
 	} 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;
 
@@ -491,6 +587,12 @@
 	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) */
@@ -504,42 +606,81 @@
 
 	/* Identifiers from DOWN: NSEI, BVCI, TLLI */
 
-	rc = gprs_llc_hdr_parse(&llhp, lh, TLVP_LEN(tv, BSSGP_IE_LLC_PDU));
-	/* FIXME */
-
+	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);
-	/* allocate a new LLE if needed */
-	if (!lle)
-		lle = lle_alloc(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->bvci = msgb_bvci(msg);
-	lle->nsei = msgb_nsei(msg);
+	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);
-	/* FIXME */
+	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:
-			rc = gsm0408_gprs_rcvmsg(msg);
+			/* send LL_UNITDATA_IND to GMM */
+			rc = gsm0408_gprs_rcvmsg(msg, lle->llme);
 			break;
-		case GPRS_SAPI_TOM2:
-		case GPRS_SAPI_TOM8:
-			/* FIXME */
 		case GPRS_SAPI_SNDCP3:
 		case GPRS_SAPI_SNDCP5:
 		case GPRS_SAPI_SNDCP9:
 		case GPRS_SAPI_SNDCP11:
-			/* FIXME */
+			/* 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(DGPRS, LOGL_NOTICE, "Unsupported SAPI %u\n", llhp.sapi);
+			LOGP(DLLC, LOGL_NOTICE, "Unsupported SAPI %u\n", llhp.sapi);
 			rc = -EINVAL;
 			break;
 		}
@@ -547,3 +688,51 @@
 
 	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
index dc12953..3db1d67 100644
--- a/openbsc/src/gprs/gprs_ns.c
+++ b/openbsc/src/gprs/gprs_ns.c
@@ -69,8 +69,8 @@
 #include <openbsc/signal.h>
 #include <openbsc/gprs_ns.h>
 #include <openbsc/gprs_bssgp.h>
-
-#define NS_ALLOC_SIZE	1024
+#include <openbsc/gprs_ns_frgre.h>
+#include <openbsc/socket.h>
 
 static const struct tlv_definition ns_att_tlvdef = {
 	.def = {
@@ -108,8 +108,7 @@
 };
 
 /* Lookup struct gprs_nsvc based on NSVCI */
-static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi,
-					uint16_t 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) {
@@ -150,6 +149,8 @@
 {
 	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 */
@@ -205,21 +206,27 @@
 }
 
 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->nsi->ll) {
+	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->nsi->ll);
+		LOGP(DNS, LOGL_ERROR, "unsupported NS linklayer %u\n", nsvc->ll);
 		msgb_free(msg);
 		ret = -EIO;
 		break;
@@ -229,9 +236,11 @@
 
 static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type)
 {
-	struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS");
+	struct msgb *msg = gprs_ns_msgb_alloc();
 	struct gprs_ns_hdr *nsh;
 
+	log_set_context(BSC_CTX_NSVC, nsvc);
+
 	if (!msg)
 		return -ENOMEM;
 
@@ -245,11 +254,13 @@
 
 int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause)
 {
-	struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS");
+	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;
 
@@ -271,16 +282,18 @@
 int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause,
 		      uint16_t bvci, struct msgb *orig_msg)
 {
-	struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS");
+	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_INFO, "NSEI=%u Tx NS STATUS (NSVCI=%u, cause=%s)\n",
+	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));
@@ -317,10 +330,12 @@
 
 int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause)
 {
-	struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS");
+	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;
 
@@ -343,6 +358,7 @@
 
 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);
 
@@ -351,6 +367,7 @@
 
 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);
 
@@ -359,6 +376,7 @@
 
 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);
 
@@ -383,6 +401,7 @@
 	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);
@@ -400,6 +419,7 @@
 	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);
@@ -449,10 +469,11 @@
 /* Section 9.2.6 */
 static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc)
 {
-	struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS");
+	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;
 
@@ -486,6 +507,7 @@
 			"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",
@@ -540,9 +562,16 @@
 	uint8_t cause;
 	int rc;
 
-	LOGP(DNS, LOGL_INFO, "NSEI=%u NS STATUS ", nsvc->nsei);
+	LOGP(DNS, LOGL_NOTICE, "NSEI=%u Rx NS STATUS ", nsvc->nsei);
 
-	rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0);
+	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");
@@ -550,7 +579,7 @@
 	}
 
 	cause = *TLVP_VAL(&tp, NS_IE_CAUSE);
-	LOGPC(DNS, LOGL_INFO, "cause=%s\n", gprs_ns_cause_str(cause));
+	LOGPC(DNS, LOGL_NOTICE, "cause=%s\n", gprs_ns_cause_str(cause));
 
 	return 0;
 }
@@ -564,7 +593,13 @@
 	uint16_t *nsvci, *nsei;
 	int rc;
 
-	rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0);
+	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) ||
@@ -588,7 +623,8 @@
 	nsvc->nsvci = ntohs(*nsvci);
 
 	/* start the test procedure */
-	nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE);
+	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 */
@@ -608,7 +644,13 @@
 
 	nsvc->state |= NSE_S_BLOCKED;
 
-	rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0);
+	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)) {
@@ -628,7 +670,7 @@
 
 /* main entry point, here incoming NS frames enter */
 int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg,
-		   struct sockaddr_in *saddr)
+		   struct sockaddr_in *saddr, enum gprs_ns_ll ll)
 {
 	struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
 	struct gprs_nsvc *nsvc;
@@ -639,10 +681,17 @@
 	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),
@@ -650,12 +699,22 @@
 			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), 0, 0);
+				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)) {
@@ -669,15 +728,19 @@
 		 * 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));
-			nsvc = nsvc_create(nsi, 0xffff);
 		}
 		/* 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));
@@ -694,9 +757,7 @@
 			rc = gprs_ns_tx_alive_ack(nsvc);
 		break;
 	case NS_PDUT_ALIVE_ACK:
-		/* stop Tns-alive */
-		bsc_del_timer(&nsvc->timer);
-		/* start Tns-test */
+		/* 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 */
@@ -720,13 +781,13 @@
 		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->remote_end_is_sgsn) {
+		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_ALIVE);
 		}
+		/* 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 */
@@ -797,7 +858,7 @@
 static struct msgb *read_nsip_msg(struct bsc_fd *bfd, int *error,
 				  struct sockaddr_in *saddr)
 {
-	struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Abis/IP/GPRS-NS");
+	struct msgb *msg = gprs_ns_msgb_alloc();
 	int ret = 0;
 	socklen_t saddr_len = sizeof(*saddr);
 
@@ -806,7 +867,7 @@
 		return NULL;
 	}
 
-	ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0,
+	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",
@@ -836,7 +897,7 @@
 	if (!msg)
 		return error;
 
-	error = gprs_ns_rcvmsg(nsi, msg, &saddr);
+	error = gprs_ns_rcvmsg(nsi, msg, &saddr, GPRS_NS_LL_UDP);
 
 	msgb_free(msg);
 
@@ -849,7 +910,7 @@
 	return -EIO;
 }
 
-int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg)
+static int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg)
 {
 	int rc;
 	struct gprs_ns_inst *nsi = nsvc->nsi;
@@ -876,24 +937,38 @@
 	return rc;
 }
 
-extern int make_sock(struct bsc_fd *bfd, int proto, uint16_t port,
-		     int (*cb)(struct bsc_fd *fd, unsigned int what));
-
 /* Listen for incoming GPRS packets */
-int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port)
+int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi)
 {
 	int ret;
 
-	ret = make_sock(&nsi->nsip.fd, IPPROTO_UDP, udp_port, nsip_fd_cb);
+	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->ll = GPRS_NS_LL_UDP;
 	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,
@@ -909,18 +984,6 @@
 	nsvc->nsvci = nsvci;
 	nsvc->remote_end_is_sgsn = 1;
 
-	/* Initiate a RESET procedure */
-	/* Mark NS-VC locally as blocked and dead */
-	nsvc->state = NSE_S_BLOCKED;
-	/* Send NS-RESET PDU */
-	if (gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION) < 0) {
-		LOGP(DNS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n",
-			nsei);
-	}
-	/* Start Tns-reset */
-	nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET);
-
+	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
index 8f0628a..e395df7 100644
--- a/openbsc/src/gprs/gprs_ns_vty.c
+++ b/openbsc/src/gprs/gprs_ns_vty.c
@@ -37,9 +37,12 @@
 #include <openbsc/signal.h>
 #include <openbsc/gprs_ns.h>
 #include <openbsc/gprs_bssgp.h>
+#include <openbsc/vty.h>
 
-#include <vty/vty.h>
-#include <vty/command.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;
 
@@ -66,6 +69,7 @@
 {
 	struct gprs_nsvc *nsvc;
 	unsigned int i;
+	struct in_addr ia;
 
 	vty_out(vty, "ns%s", VTY_NEWLINE);
 
@@ -77,7 +81,10 @@
 		vty_out(vty, " nse %u remote-role %s%s",
 			nsvc->nsei, nsvc->remote_end_is_sgsn ? "sgsn" : "bss",
 			VTY_NEWLINE);
-		if (nsvc->nsi->ll == GPRS_NS_LL_UDP) {
+		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),
@@ -85,6 +92,19 @@
 			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;
 		}
 	}
 
@@ -93,6 +113,23 @@
 			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;
 }
 
@@ -104,25 +141,40 @@
 	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;
-		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->nsi->ll == GPRS_NS_LL_UDP)
-			vty_out(vty, ", %15s:%u",
-				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);
+		dump_nse(vty, nsvc, stats);
 	}
 }
 
@@ -144,7 +196,36 @@
 	return CMD_SUCCESS;
 }
 
-#define NSE_CMD_STR "NS Entity\n" "NS Entity ID (NSEI)\n"
+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>",
@@ -207,11 +288,68 @@
 		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
@@ -238,7 +376,7 @@
 
 DEFUN(cfg_no_nse, cfg_no_nse_cmd,
 	"no nse <0-65535>",
-	"Delete NS Entity\n"
+	"Delete Persistent NS Entity\n"
 	"Delete " NSE_CMD_STR)
 {
 	uint16_t nsei = atoi(argv[0]);
@@ -250,7 +388,13 @@
 		return CMD_WARNING;
 	}
 
-	nsvc_delete(nsvc);
+	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;
 }
@@ -271,22 +415,157 @@
 	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
index ba46719..9a76cee 100644
--- a/openbsc/src/gprs/gprs_sgsn.c
+++ b/openbsc/src/gprs/gprs_sgsn.c
@@ -25,13 +25,55 @@
 #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>
 
-static LLIST_HEAD(sgsn_mm_ctxts);
+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)
@@ -45,12 +87,25 @@
 					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;
 }
 
@@ -59,7 +114,8 @@
 	struct sgsn_mm_ctx *ctx;
 
 	llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
-		if (p_tmsi == ctx->p_tmsi)
+		if (p_tmsi == ctx->p_tmsi ||
+		    (ctx->p_tmsi_old && ctx->p_tmsi_old == p_tmsi))
 			return ctx;
 	}
 	return NULL;
@@ -81,16 +137,168 @@
 struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
 					const struct gprs_ra_id *raid)
 {
-	struct sgsn_mm_ctx *ctx = talloc_zero(NULL, struct sgsn_mm_ctx);
+	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
index 0d1a390..8433326 100644
--- a/openbsc/src/gprs/gprs_sndcp.c
+++ b/openbsc/src/gprs/gprs_sndcp.c
@@ -1,6 +1,7 @@
 /* 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
  *
@@ -32,6 +33,7 @@
 #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 {
@@ -41,10 +43,14 @@
 	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;
-	uint8_t dcomp;
-};
+	uint8_t pcomp:4;
+	uint8_t dcomp:4;
+} __attribute__((packed));
 
 struct sndcp_udata_hdr {
 	/* octet 3 */
@@ -52,19 +58,578 @@
 	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,
 };
 
-/* Entry point for the LL-UNITDATA.indication */
-int sndcp_unitdata_ind(struct msgb *msg, uint8_t sapi, uint8_t *hdr, uint8_t len)
-{
-	struct sndcp_udata_hdr *suh;
-	uint16_t npdu;
 
-	if (suh->type == 0) {
-		LOGP(DGPRS, LOGL_ERROR, "SN-DATA PDU at unitdata_ind() function\n");
+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;
 	}
 
-	npdu = (suh->npdu_high << 8) | suh->npdu_low;
+	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/gsm_04_08_gprs.c b/openbsc/src/gprs/gsm_04_08_gprs.c
deleted file mode 100644
index 4a42113..0000000
--- a/openbsc/src/gprs/gsm_04_08_gprs.c
+++ /dev/null
@@ -1,762 +0,0 @@
-/* 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>
- *
- * 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 <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>
-
-/* 10.5.5.14 GPRS MM Cause / Table 10.5.147 */
-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 */
-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 }
-};
-
-static const char *att_name(uint8_t type)
-{
-	switch (type) {
-	case GPRS_ATT_T_ATTACH:
-		return "GPRS attach";
-	case GPRS_ATT_T_ATT_WHILE_IMSI:
-		return "GPRS attach while IMSI attached";
-	case GPRS_ATT_T_COMBINED:
-		return "Combined GPRS/IMSI attach";
-	default:
-		return "unknown";
-	}
-}
-
-static const char *upd_name(uint8_t type)
-{
-	switch (type) {
-	case GPRS_UPD_T_RA:
-		return "RA updating";
-	case GPRS_UPD_T_RA_LA:
-		return "combined RA/LA updating";
-	case GPRS_UPD_T_RA_LA_IMSI_ATT:
-		return "combined RA/LA updating + IMSI attach";
-	case GPRS_UPD_T_PERIODIC:
-		return "periodic updating";
-	}
-	return "unknown";
-}
-
-/* Send a message through the underlying layer */
-static int gsm48_gmm_sendmsg(struct msgb *msg, int command)
-{
-	/* caller needs to provide TLLI, BVCI and NSEI */
-	return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command);
-}
-
-/* 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);
-}
-
-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 msgb *old_msg)
-{
-	struct msgb *msg = gsm48_msgb_alloc();
-	struct gsm48_hdr *gh;
-	struct gsm48_attach_ack *aa;
-	struct gprs_ra_id ra_id;
-
-	DEBUGP(DMM, "<- GPRS ATTACH ACCEPT\n");
-
-	gmm_copy_id(msg, old_msg);
-
-	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 */
-	bssgp_parse_cell_id(&ra_id, msgb_bcid(old_msg));
-	gsm48_construct_ra(aa->ra_id.digits, &ra_id);
-
-	/* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */
-	return gsm48_gmm_sendmsg(msg, 0);
-}
-
-/* Chapter 9.4.5: Attach reject */
-static int gsm48_tx_gmm_att_rej(struct msgb *old_msg, uint8_t gmm_cause)
-{
-	struct msgb *msg = gsm48_msgb_alloc();
-	struct gsm48_hdr *gh;
-
-	DEBUGP(DMM, "<- GPRS ATTACH REJECT\n");
-
-	gmm_copy_id(msg, old_msg);
-
-	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);
-}
-
-/* Transmit Chapter 9.4.12 Identity Request */
-static int gsm48_tx_gmm_id_req(struct msgb *old_msg, 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);
-
-	gmm_copy_id(msg, old_msg);
-
-	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, 0);
-}
-
-/* Check if we can already authorize a subscriber */
-static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx, struct msgb *msg)
-{
-	if (strlen(ctx->imei) && strlen(ctx->imsi)) {
-		ctx->mm_state = GMM_REGISTERED_NORMAL;
-		return gsm48_tx_gmm_att_ack(msg);
-	} 
-	if (!strlen(ctx->imei))
-		return gsm48_tx_gmm_id_req(msg, GSM_MI_TYPE_IMEI);
-
-	if (!strlen(ctx->imsi))
-		return gsm48_tx_gmm_id_req(msg, GSM_MI_TYPE_IMSI);
-
-	return 0;
-}
-
-/* Parse Chapter 9.4.13 Identity Response */
-static int gsm48_rx_gmm_id_resp(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];
-	struct gprs_ra_id ra_id;
-	struct sgsn_mm_ctx *ctx;
-
-	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);
-
-	bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
-	ctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id);
-	if (!ctx) {
-		DEBUGP(DMM, "from unknown TLLI 0x%08x?!?\n", msgb_tlli(msg));
-		return -EINVAL;
-	}
-
-	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, msg);
-}
-
-static void attach_rej_cb(void *data)
-{
-	struct sgsn_mm_ctx *ctx = data;
-
-	/* FIXME: determine through which BTS/TRX to send this */
-	//gsm48_tx_gmm_att_rej(ctx->tlli, GMM_CAUSE_MS_ID_NOT_DERIVED);
-	ctx->mm_state = GMM_DEREGISTERED;
-	/* FIXME: release the context */
-}
-
-static void schedule_reject(struct sgsn_mm_ctx *ctx)
-{
-	ctx->T = 3370;
-	ctx->timer.cb = attach_rej_cb;
-	ctx->timer.data = ctx;
-	bsc_schedule_timer(&ctx->timer, 6, 0);
-}
-
-/* Section 9.4.1 Attach request */
-static int gsm48_rx_gmm_att_req(struct msgb *msg)
-{
-	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
-	uint8_t *cur = gh->data, *msnc, *mi, *old_ra_info;
-	uint8_t msnc_len, att_type, mi_len, mi_type;
-	uint16_t drx_par;
-	uint32_t tmsi;
-	char mi_string[GSM48_MI_SIZE];
-	struct gprs_ra_id ra_id;
-	uint16_t cid;
-	struct sgsn_mm_ctx *ctx;
-
-	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++;
-	drx_par |= *cur++ << 8;
-
-	/* 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, att_name(att_type));
-
-	/* Old routing area identification 10.5.5.15 */
-	old_ra_info = cur;
-	cur += 6;
-
-	/* MS Radio Access Capability 10.5.5.12a */
-
-	/* 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 */
-		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(msg, GMM_CAUSE_NET_FAIL);
-			strncpy(ctx->imsi, mi_string, sizeof(ctx->imsi));
-#endif
-		}
-		/* FIXME: Start some timer */
-		ctx->mm_state = GMM_COMMON_PROC_INIT;
-		ctx->tlli = msgb_tlli(msg);
-		break;
-	case GSM_MI_TYPE_TMSI:
-		tmsi = strtoul(mi_string, NULL, 10);
-		/* Try to find MM context based on P-TMSI */
-		ctx = sgsn_mm_ctx_by_ptmsi(tmsi);
-		if (!ctx) {
-			ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id);
-			/* FIXME: Start some timer */
-			ctx->mm_state = GMM_COMMON_PROC_INIT;
-			ctx->tlli = msgb_tlli(msg);
-		}
-		break;
-	default:
-		return 0;
-	}
-	/* Update MM Context with currient RA and Cell ID */
-	ctx->ra = ra_id;
-	ctx->cell_id = cid;
-
-	/* FIXME: allocate a new P-TMSI (+ P-TMSI signature) */
-	/* FIXME: update the TLLI with the new local TLLI based on the P-TMSI */
-
-	DEBUGPC(DMM, "\n");
-
-	return ctx ? gsm48_gmm_authorize(ctx, msg) : 0;
-
-err_inval:
-	DEBUGPC(DMM, "\n");
-	return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_SEM_INCORR_MSG);
-}
-
-/* Chapter 9.4.15: Routing area update accept */
-static int gsm48_tx_gmm_ra_upd_ack(struct msgb *old_msg)
-{
-	struct msgb *msg = gsm48_msgb_alloc();
-	struct gsm48_hdr *gh;
-	struct gsm48_ra_upd_ack *rua;
-	struct gprs_ra_id ra_id;
-
-	DEBUGP(DMM, "<- ROUTING AREA UPDATE ACCEPT\n");
-
-	gmm_copy_id(msg, old_msg);
-
-	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;
-
-	bssgp_parse_cell_id(&ra_id, msgb_bcid(old_msg));
-	gsm48_construct_ra(rua->ra_id.digits, &ra_id);
-
-	/* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */
-	return gsm48_gmm_sendmsg(msg, 0);
-}
-
-/* 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);
-}
-
-/* Chapter 9.4.14: Routing area update request */
-static int gsm48_rx_gmm_ra_upd_req(struct msgb *msg)
-{
-	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
-	struct sgsn_mm_ctx *mmctx;
-	uint8_t *cur = gh->data;
-	struct gprs_ra_id old_ra_id;
-	uint8_t upd_type;
-
-	/* Update Type 10.5.5.18 */
-	upd_type = *cur++ & 0x0f;
-
-	DEBUGP(DMM, "GMM RA UPDATE REQUEST type=\"%s\" ", upd_name(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 */
-
-	/* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status,
-	 * DRX parameter, MS network capability */
-
-	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 */
-	mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &old_ra_id);
-	if (!mmctx || mmctx->mm_state == GMM_DEREGISTERED) {
-		/* The MS has to perform GPRS attach */
-		DEBUGPC(DMM, " REJECT\n");
-		return gsm48_tx_gmm_ra_upd_rej(msg, GMM_CAUSE_IMPL_DETACHED);
-	}
-
-	/* 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 */
-
-	DEBUGPC(DMM, " ACCEPT\n");
-	return gsm48_tx_gmm_ra_upd_ack(msg);
-}
-
-static int gsm48_rx_gmm_status(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 msgb *msg)
-{
-	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
-	int rc;
-
-	switch (gh->msg_type) {
-	case GSM48_MT_GMM_RA_UPD_REQ:
-		rc = gsm48_rx_gmm_ra_upd_req(msg);
-		break;
-	case GSM48_MT_GMM_ATTACH_REQ:
-		rc = gsm48_rx_gmm_att_req(msg);
-		break;
-	case GSM48_MT_GMM_ID_RESP:
-		rc = gsm48_rx_gmm_id_resp(msg);
-		break;
-	case GSM48_MT_GMM_STATUS:
-		rc = gsm48_rx_gmm_status(msg);
-		break;
-	case GSM48_MT_GMM_RA_UPD_COMPL:
-		/* only in case SGSN offered new P-TMSI */
-	case GSM48_MT_GMM_ATTACH_COMPL:
-		/* only in case SGSN offered new P-TMSI */
-	case GSM48_MT_GMM_DETACH_REQ:
-	case GSM48_MT_GMM_PTMSI_REALL_COMPL:
-	case GSM48_MT_GMM_AUTH_CIPH_RESP:
-		DEBUGP(DMM, "Unimplemented GSM 04.08 GMM msg type 0x%02x\n",
-			gh->msg_type);
-		break;
-	default:
-		DEBUGP(DMM, "Unknown GSM 04.08 GMM msg type 0x%02x\n",
-			gh->msg_type);
-		break;
-	}
-
-	return rc;
-}
-
-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 */
-static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_ctx_req *req)
-{
-	struct gsm48_hdr *old_gh = (struct gsm48_hdr *) msgb_gmmh(old_msg);
-	struct msgb *msg = gsm48_msgb_alloc();
-	struct gsm48_act_pdp_ctx_ack *act_ack;
-	struct gsm48_hdr *gh;
-	uint8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */
-
-	DEBUGP(DMM, "<- ACTIVATE PDP CONTEXT ACK\n");
-
-	gmm_copy_id(msg, old_msg);
-
-	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, req->req_llc_sapi);
-	/* copy QoS parameters from original request */
-	msgb_lv_put(msg, sizeof(default_qos), (uint8_t *)&default_qos);
-	/* Radio priority 10.5.7.2 */
-	msgb_v_put(msg, 4);
-	/* PDP address */
-	msgb_put_pdp_addr_ipv4(msg, 0x01020304);
-	/* Optional: Protocol configuration options */
-	/* Optional: Packet Flow Identifier */
-
-	return gsm48_gmm_sendmsg(msg, 0);
-}
-
-/* Section 9.5.9: Deactivate PDP Context Accept */
-static int gsm48_tx_gsm_deact_pdp_acc(struct msgb *old_msg)
-{
-	struct gsm48_hdr *old_gh = (struct gsm48_hdr *) msgb_gmmh(old_msg);
-	struct msgb *msg = gsm48_msgb_alloc();
-	struct gsm48_hdr *gh;
-	uint8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */
-
-	DEBUGP(DMM, "<- DEACTIVATE PDP CONTEXT ACK\n");
-
-	gmm_copy_id(msg, old_msg);
-
-	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);
-}
-
-/* Section 9.5.1: Activate PDP Context Request */
-static int gsm48_rx_gsm_act_pdp_req(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 *pdp_addr_lv = act_req->data;
-	uint8_t req_qos_len, req_pdpa_len;
-	uint8_t *req_qos, *req_pdpa;
-	struct tlv_parsed tp;
-
-	DEBUGP(DMM, "ACTIVATE PDP CONTEXT REQ: ");
-	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;
-	}
-
-	/* FIXME: parse TLV for AP name and protocol config options */
-	if (TLVP_PRESENT(&tp, GSM48_IE_GSM_APN)) {}
-	if (TLVP_PRESENT(&tp, GSM48_IE_GSM_PROTO_CONF_OPT)) {}
-
-	return gsm48_tx_gsm_act_pdp_acc(msg, act_req);
-}
-
-/* Section 9.5.8: Deactivate PDP Context Request */
-static int gsm48_rx_gsm_deact_pdp_req(struct msgb *msg)
-{
-	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
-
-	DEBUGP(DMM, "DEACTIVATE PDP CONTEXT REQ (cause: %s)\n",
-		get_value_string(gsm_cause_names, gh->data[0]));
-
-	return gsm48_tx_gsm_deact_pdp_acc(msg);
-}
-
-static int gsm48_rx_gsm_status(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 msgb *msg)
-{
-	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
-	int rc;
-
-	switch (gh->msg_type) {
-	case GSM48_MT_GSM_ACT_PDP_REQ:
-		rc = gsm48_rx_gsm_act_pdp_req(msg);
-		break;
-	case GSM48_MT_GSM_DEACT_PDP_REQ:
-		rc = gsm48_rx_gsm_deact_pdp_req(msg);
-	case GSM48_MT_GSM_STATUS:
-		rc = gsm48_rx_gsm_status(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);
-		break;
-	default:
-		DEBUGP(DMM, "Unknown GSM 04.08 GSM msg type 0x%02x\n",
-			gh->msg_type);
-		break;
-
-	}
-
-	return rc;
-}
-
-/* Main entry point for incoming 04.08 GPRS messages */
-int gsm0408_gprs_rcvmsg(struct msgb *msg)
-{
-	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
-	uint8_t pdisc = gh->proto_discr & 0x0f;
-	int rc = -EINVAL;
-
-	switch (pdisc) {
-	case GSM48_PDISC_MM_GPRS:
-		rc = gsm0408_rcv_gmm(msg);
-		break;
-	case GSM48_PDISC_SM_GPRS:
-		rc = gsm0408_rcv_gsm(msg);
-		break;
-	default:
-		DEBUGP(DMM, "Unknown GSM 04.08 discriminator 0x%02x\n",
-			pdisc);
-		break;
-	}
-
-	return rc;
-}
diff --git a/openbsc/src/gprs/osmo_gbproxy.cfg b/openbsc/src/gprs/osmo_gbproxy.cfg
index d51b04a..d6b5619 100644
--- a/openbsc/src/gprs/osmo_gbproxy.cfg
+++ b/openbsc/src/gprs/osmo_gbproxy.cfg
@@ -1,13 +1,24 @@
 !
-! OpenBSC configuration saved from vty
-!   !
+! Osmocom Gb Proxy (0.9.0.404-6463) configuration saved from vty
+!!
 !
 line vty
  no login
 !
 gbproxy
-  nsip bss local port 23000
-  nsip sgsn remote ip 127.0.0.1
-  nsip sgsn remote port 7777
-  nsip sgsn nsei 101
-  nsip sgsn nsvci 101
+ 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
index f39e853..c4c9ec1 100644
--- a/openbsc/src/gprs/osmo_sgsn.cfg
+++ b/openbsc/src/gprs/osmo_sgsn.cfg
@@ -1,9 +1,23 @@
 !
-! OpenBSC configuration saved from vty
-!   !
+! Osmocom SGSN (0.9.0.474-0ede2) configuration saved from vty
+!!
 !
 line vty
  no login
 !
 sgsn
-  nsip local port 23000
+ 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
index b355fb5..27d156a 100644
--- a/openbsc/src/gprs/sgsn_main.c
+++ b/openbsc/src/gprs/sgsn_main.c
@@ -38,13 +38,17 @@
 #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/telnet_interface.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"
 
@@ -57,18 +61,19 @@
 void *tall_bsc_ctx;
 
 struct gprs_ns_inst *sgsn_nsi;
-
-const char *openbsc_version = "Osmocom NSIP Proxy " PACKAGE_VERSION;
 const char *openbsc_copyright =
 	"Copyright (C) 2010 Harald Welte and On-Waves\n"
-	"Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\n"
-	"Dieter Spaar, Andreas Eversberg, Holger Freyther\n\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 char *config_file = "osmo_sgsn.cfg";
-static struct sgsn_config sgcfg;
+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,
@@ -120,6 +125,14 @@
 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;
@@ -141,25 +154,51 @@
 	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);
-	telnet_init(&dummy_network, 4245);
+	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 = sgcfg.nsi = sgsn_nsi;
+	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(config_file, &sgcfg);
+	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);
 	}
 
-	nsip_listen(sgsn_nsi, sgcfg.nsip_listen_port);
+	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);
@@ -169,15 +208,3 @@
 
 	exit(0);
 }
-
-struct gsm_network;
-int bsc_vty_init(struct gsm_network *dummy)
-{
-	cmd_init(1);
-	vty_init();
-
-	openbsc_vty_add_cmds();
-        sgsn_vty_init();
-	return 0;
-}
-
diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c
index ec18fcb..873fa20 100644
--- a/openbsc/src/gprs/sgsn_vty.c
+++ b/openbsc/src/gprs/sgsn_vty.c
@@ -25,13 +25,19 @@
 #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 <vty/command.h>
-#include <vty/vty.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/vty.h>
+
+#include <pdp.h>
 
 static struct sgsn_config *g_cfg = NULL;
 
@@ -43,90 +49,227 @@
 
 static int config_write_sgsn(struct vty *vty)
 {
-	struct in_addr ia;
+	struct sgsn_ggsn_ctx *gctx;
 
 	vty_out(vty, "sgsn%s", VTY_NEWLINE);
 
-	if (g_cfg->nsip_listen_ip) {
-		ia.s_addr = htonl(g_cfg->nsip_listen_ip);
-		vty_out(vty, "  nsip local ip %s%s", inet_ntoa(ia),
-			VTY_NEWLINE);
-	}
-	vty_out(vty, "  nsip local port %u%s", g_cfg->nsip_listen_port,
-		VTY_NEWLINE);
+	vty_out(vty, " gtp local-ip %s%s",
+		inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
 
-	return CMD_SUCCESS;
-}
-
-DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn",
-      SHOW_STR "Display information about the SGSN")
-{
-	/* FIXME: iterate over list of NS-VC's and display their state */
-	struct gprs_ns_inst *nsi = g_cfg->nsi;
-	struct gprs_nsvc *nsvc;
-
-	llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) {
-		vty_out(vty, "NSEI %5u, NS-VC %5u, %s-mode, %s %s%s",
-			nsvc->nsei, nsvc->nsvci,
-			nsvc->remote_end_is_sgsn ? "BSS" : "SGSN",
-			nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD",
-			nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED",
-			VTY_NEWLINE);
-		if (nsvc->nsi->ll == GPRS_NS_LL_UDP)
-			vty_out(vty, "  remote peer %s:%u%s",
-				inet_ntoa(nsvc->ip.bts_addr.sin_addr),
-				ntohs(nsvc->ip.bts_addr.sin_port), 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;
 }
 
-DEFUN(cfg_sgsn,
-      cfg_sgsn_cmd,
-      "sgsn",
-      "Configure the SGSN")
+#define SGSN_STR	"Configure the SGSN"
+
+DEFUN(cfg_sgsn, cfg_sgsn_cmd,
+	"sgsn",
+	SGSN_STR)
 {
 	vty->node = SGSN_NODE;
 	return CMD_SUCCESS;
 }
 
-
-DEFUN(cfg_nsip_local_ip,
-      cfg_nsip_local_ip_cmd,
-      "nsip local ip A.B.C.D",
-      "Set the IP address on which we listen for BSS connects")
+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")
 {
-	struct in_addr ia;
-
-	inet_aton(argv[0], &ia);
-	g_cfg->nsip_listen_ip = ntohl(ia.s_addr);
+	inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
 
 	return CMD_SUCCESS;
 }
 
-DEFUN(cfg_nsip_local_port,
-      cfg_nsip_local_port_cmd,
-      "nsip local port <0-65534>",
-      "Set the UDP port on which we listen for BSS connects")
+DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
+	"ggsn <0-255> remote-ip A.B.C.D",
+	"")
 {
-	unsigned int port = atoi(argv[0]);
+	uint32_t id = atoi(argv[0]);
+	struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
 
-	g_cfg->nsip_listen_port = port;
+	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(VIEW_NODE, &show_sgsn_cmd);
+	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, &cfg_nsip_local_ip_cmd);
-	install_element(SGSN_NODE, &cfg_nsip_local_port_cmd);
+	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;
 }
@@ -136,7 +279,7 @@
 	int 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;
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index b0e5541..297a2c9 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -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,11 +53,13 @@
 #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);
-static int gsm48_tx_simple(struct gsm_lchan *lchan,
+int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn, u_int32_t tmsi);
+static int gsm48_tx_simple(struct gsm_subscriber_connection *conn,
 			   u_int8_t pdisc, u_int8_t msg_type);
 static void schedule_reject(struct gsm_subscriber_connection *conn);
 
@@ -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);
+}
+
+static int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq,
+				gsm_cbfn *cb, void *cb_data)
+{
+	struct gsm_network *net = conn->bts->network;
+	struct gsm_subscriber *subscr = 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 (conn->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, conn, cb_data) :
+			0;
+
+	/* Start an operation (can't have more than one pending !!!) */
+	if (conn->sec_operation)
+		return -EBUSY;
+
+	allocate_security_operation(conn);
+	op = 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(conn, op->atuple.rand, op->atuple.key_seq);
+	} else if (rc == 2) {
+		/* Start ciphering directly */
+		conn->lchan->encr.alg_id = RSL_ENC_ALG_A5(net->a5_encryption);
+		conn->lchan->encr.key_len = 8;
+		memcpy(conn->lchan->encr.key, op->atuple.kc, 8);
+
+		return gsm48_send_rr_ciph_mode(conn->lchan, 0);
+	}
+
+	return -EINVAL; /* not reached */
+}
+
 static int authorize_subscriber(struct gsm_loc_updating_operation *loc,
 				struct gsm_subscriber *subscriber)
 {
@@ -116,99 +235,108 @@
 					   struct gsm_loc_updating_operation);
 }
 
+static int _gsm0408_authorize_sec_cb(unsigned int hooknum, unsigned int event,
+                                     struct msgb *msg, void *data, void *param)
+{
+	struct gsm_subscriber_connection *conn = data;
+	int rc = 0;
+
+	switch (event) {
+		case GSM_SECURITY_AUTH_FAILED:
+			release_loc_updating_req(conn);
+			break;
+
+		case GSM_SECURITY_NOAVAIL:
+		case GSM_SECURITY_SUCCEEDED:
+			/* We're all good */
+			db_subscriber_alloc_tmsi(conn->subscr);
+			rc = gsm0408_loc_upd_acc(conn, conn->subscr->tmsi);
+			if (conn->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, conn->bts,
+				      GSM_SUBSCRIBER_UPDATE_ATTACHED);
+
+			/* try to close channel ASAP */
+			release_loc_updating_req(conn);
+			lchan_auto_release(conn->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)) {
-		int rc;
-
-		db_subscriber_alloc_tmsi(conn->subscr);
-		release_loc_updating_req(conn);
-		rc = gsm0408_loc_upd_acc(msg->lchan, conn->subscr->tmsi);
-		if (msg->lchan->ts->trx->bts->network->send_mm_info) {
-			/* send MM INFO with network name */
-			rc = gsm48_tx_mm_info(msg->lchan);
-		}
-
-		/* 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, msg->trx->bts,
-			      GSM_SUBSCRIBER_UPDATE_ATTACHED);
-
-		/* try to close channel ASAP */
-		lchan_auto_release(conn->lchan);
-		return rc;
-	}
-
+	if (authorize_subscriber(conn->loc_operation, conn->subscr))
+		return gsm48_secure_channel(conn,
+			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->conn);
+	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->conn && trans->conn->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_subscriber_connection *conn;
-	struct gsm_bts *bts = lchan->ts->trx->bts;
-	struct msgb *msg = gsm48_msgb_alloc();
-	struct gsm48_hdr *gh;
-	
-	msg->lchan = lchan;
-	conn = &lchan->conn;
+	struct gsm_bts *bts = conn->bts;
+	struct msgb *msg;
 
-	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
-	gh->proto_discr = GSM48_PDISC_MM;
-	gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
-	gh->data[0] = cause;
+	counter_inc(bts->network->stats.loc_upd_resp.reject);
+
+	msg = gsm48_create_loc_upd_rej(cause);
+	if (!msg) {
+		LOGP(DMM, LOGL_ERROR, "Failed to create msg for LOCATION UPDATING REJECT.\n");
+		return -1;
+	}
+	
+	msg->lchan = conn->lchan;
 
 	LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT "
 	     "LAC=%u BTS=%u\n", conn->subscr ?
 	     			subscr_name(conn->subscr) : "unknown",
-	     lchan->ts->trx->bts->location_area_code, lchan->ts->trx->bts->nr);
+	     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;
@@ -225,23 +353,23 @@
 
 	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);
 }
 
 
@@ -298,8 +426,8 @@
 	struct gsm_lchan *lchan = conn->lchan;
 	struct gsm_bts *bts = lchan->ts->trx->bts;
 
+	gsm0408_loc_upd_rej(conn, bts->network->reject_cause);
 	release_loc_updating_req(conn);
-	gsm0408_loc_upd_rej(lchan, bts->network->reject_cause);
 	lchan_auto_release(lchan);
 }
 
@@ -368,17 +496,19 @@
 	if (conn->loc_operation) {
 		DEBUGPC(DMM, "ignoring request due an existing one: %p.\n",
 			conn->loc_operation);
-		gsm0408_loc_upd_rej(lchan, GSM48_REJECT_PROTOCOL_ERROR);
+		gsm0408_loc_upd_rej(conn, GSM48_REJECT_PROTOCOL_ERROR);
 		return 0;
 	}
 
 	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);
+		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 */
@@ -389,18 +519,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);
-		conn->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);
+			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:
@@ -437,11 +566,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
@@ -450,7 +579,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;
@@ -536,11 +665,11 @@
 
 	DEBUGP(DMM, "-> MM INFO\n");
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_conn_sendmsg(msg, conn, NULL);
 }
 
 /* Section 9.2.2 */
-int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand, int key_seq)
+int gsm48_tx_mm_auth_req(struct gsm_subscriber_connection *conn, u_int8_t *rand, int key_seq)
 {
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
@@ -548,7 +677,7 @@
 
 	DEBUGP(DMM, "-> AUTH REQ (rand = %s)\n", hexdump(rand, 16));
 
-	msg->lchan = lchan;
+	msg->lchan = conn->lchan;
 	gh->proto_discr = GSM48_PDISC_MM;
 	gh->msg_type = GSM48_MT_MM_AUTH_REQ;
 
@@ -558,40 +687,66 @@
 	if (rand)
 		memcpy(ar->rand, rand, 16);
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_conn_sendmsg(msg, conn, NULL);
 }
 
 /* Section 9.2.1 */
-int gsm48_tx_mm_auth_rej(struct gsm_lchan *lchan)
+int gsm48_tx_mm_auth_rej(struct gsm_subscriber_connection *conn)
 {
 	DEBUGP(DMM, "-> AUTH REJECT\n");
-	return gsm48_tx_simple(lchan, GSM48_PDISC_MM, GSM48_MT_MM_AUTH_REJ);
+	return gsm48_tx_simple(conn, GSM48_PDISC_MM, GSM48_MT_MM_AUTH_REJ);
 }
 
-static int gsm48_tx_mm_serv_ack(struct gsm_lchan *lchan)
+static int gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn)
 {
 	DEBUGP(DMM, "-> CM SERVICE ACK\n");
-	return gsm48_tx_simple(lchan, GSM48_PDISC_MM, GSM48_MT_MM_CM_SERV_ACC);
+	return gsm48_tx_simple(conn, GSM48_PDISC_MM, GSM48_MT_MM_CM_SERV_ACC);
 }
 
 /* 9.2.6 CM service reject */
 static int gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
 				enum gsm48_reject_value value)
 {
-	struct msgb *msg = gsm48_msgb_alloc();
-	struct gsm48_hdr *gh;
+	struct msgb *msg;
 
-	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
+	msg = gsm48_create_mm_serv_rej(value);
+	if (!msg) {
+		LOGP(DMM, LOGL_ERROR, "Failed to allocate CM Service Reject.\n");
+		return -1;
+	}
 
+	DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
 	msg->lchan = conn->lchan;
 	use_subscr_con(conn);
+	return gsm48_conn_sendmsg(msg, conn, NULL);
+}
 
-	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);
+static int _gsm48_rx_mm_serv_req_sec_cb(
+	unsigned int hooknum, unsigned int event,
+	struct msgb *msg, void *data, void *param)
+{
+	struct gsm_subscriber_connection *conn = data;
+	int rc = 0;
 
-	return gsm48_sendmsg(msg, NULL);
+	switch (event) {
+		case GSM_SECURITY_AUTH_FAILED:
+			/* Nothing to do */
+			break;
+
+		case GSM_SECURITY_NOAVAIL:
+			rc = gsm48_tx_mm_serv_ack(conn);
+			break;
+
+		case GSM_SECURITY_SUCCEEDED:
+			/* nothing to do. CIPHER MODE COMMAND is
+			 * implicit CM SERV ACK */
+			break;
+
+		default:
+			rc = -EINVAL;
+	};
+
+	return rc;
 }
 
 /*
@@ -613,7 +768,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);
@@ -669,7 +824,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->conn, req->cipher_key_seq,
+			_gsm48_rx_mm_serv_req_sec_cb, NULL);
 }
 
 static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
@@ -736,6 +892,48 @@
 	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_subscriber_connection *conn = &msg->lchan->conn;
+	struct gsm_network *net = conn->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, conn, conn->sec_operation->cb_data);
+
+		release_security_operation(conn);
+		return gsm48_tx_mm_auth_rej(conn);
+	}
+
+	DEBUGPC(DMM, "OK\n");
+
+	/* Start ciphering */
+	conn->lchan->encr.alg_id = RSL_ENC_ALG_A5(net->a5_encryption);
+	conn->lchan->encr.key_len = 8;
+	memcpy(conn->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)
 {
@@ -769,7 +967,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",
@@ -785,13 +983,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);
 
@@ -908,6 +1109,36 @@
 	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_subscriber_connection *conn = &msg->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, conn, conn->sec_operation->cb_data);
+	}
+
+	/* Complete the operation */
+	release_security_operation(conn);
+
+	return rc;
+}
+
 /* Chapter 9.1.16 Handover complete */
 static int gsm48_rx_rr_ho_compl(struct msgb *msg)
 {
@@ -965,8 +1196,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);
@@ -983,13 +1213,13 @@
 	return rc;
 }
 
-int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id,
+int gsm48_send_rr_app_info(struct gsm_subscriber_connection *conn, u_int8_t apdu_id,
 			   u_int8_t apdu_len, const u_int8_t *apdu)
 {
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
 
-	msg->lchan = lchan;
+	msg->lchan = conn->lchan;
 	
 	DEBUGP(DRR, "TX APPLICATION INFO id=0x%02x, len=%u\n",
 		apdu_id, apdu_len);
@@ -1001,7 +1231,7 @@
 	gh->data[1] = apdu_len;
 	memcpy(gh->data+2, apdu, apdu_len);
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_conn_sendmsg(msg, conn, NULL);
 }
 
 /* Call Control */
@@ -1039,21 +1269,21 @@
 	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,
+static int gsm48_tx_simple(struct gsm_subscriber_connection *conn,
 			   u_int8_t pdisc, u_int8_t msg_type)
 {
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
 
-	msg->lchan = lchan;
+	msg->lchan = conn->lchan;
 
 	gh->proto_discr = pdisc;
 	gh->msg_type = msg_type;
 
-	return gsm48_sendmsg(msg, NULL);
+	return gsm48_conn_sendmsg(msg, conn, NULL);
 }
 
 static void gsm48_stop_cc_timer(struct gsm_trans *trans)
@@ -1595,7 +1825,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)
@@ -1663,7 +1893,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)
@@ -1725,7 +1955,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)
@@ -1742,7 +1972,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)
@@ -1771,7 +2001,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)
@@ -1842,7 +2072,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)
@@ -1930,7 +2160,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)
@@ -1975,7 +2205,7 @@
 		/* release collision 5.4.5 */
 		rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel);
 	} else {
-		rc = gsm48_tx_simple(msg->lchan,
+		rc = gsm48_tx_simple(trans->conn,
 				     GSM48_PDISC_CC | (trans->transaction_id << 4),
 				     GSM48_MT_CC_RELEASE_COMPL);
 		rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_IND, &rel);
@@ -2018,7 +2248,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)
@@ -2108,7 +2338,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)
@@ -2148,7 +2378,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)
@@ -2167,7 +2397,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)
@@ -2184,7 +2414,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)
@@ -2204,7 +2434,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)
@@ -2221,7 +2451,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)
@@ -2256,7 +2486,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)
@@ -2273,7 +2503,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)
@@ -2283,7 +2513,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)
@@ -2333,7 +2563,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)
@@ -2373,7 +2603,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)
@@ -2421,7 +2651,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)
@@ -2435,7 +2665,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)
@@ -2469,7 +2699,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)
@@ -2568,7 +2798,7 @@
 {
 	int i, rc = 0;
 	struct gsm_trans *trans = NULL, *transt;
-	struct gsm_lchan *lchan = NULL;
+	struct gsm_subscriber_connection *conn = NULL;
 	struct gsm_bts *bts = NULL;
 	struct gsm_mncc *data = arg, rel;
 
@@ -2673,10 +2903,10 @@
 			return -ENOMEM;
 		}
 		/* Find lchan */
-		lchan = lchan_for_subscr(subscr);
+		conn = connection_for_subscr(subscr);
 
 		/* If subscriber has no lchan */
-		if (!lchan) {
+		if (!conn) {
 			/* find transaction with this subscriber already paging */
 			llist_for_each_entry(transt, &net->trans_list, entry) {
 				/* Transaction of our lchan? */
@@ -2702,16 +2932,16 @@
 			return 0;
 		}
 		/* Assign lchan */
-		trans->conn = &lchan->conn;
+		trans->conn = conn;
 		use_subscr_con(trans->conn);
 		subscr_put(subscr);
 	}
 
 	if (trans->conn)
-		lchan = trans->conn->lchan;
+		conn = trans->conn;
 
 	/* if paging did not respond yet */
-	if (!lchan) {
+	if (!conn) {
 		DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
 			"Received '%s' from MNCC in paging state\n",
 			(trans->subscr)?(trans->subscr->extension):"-",
@@ -2729,7 +2959,7 @@
 
 	DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
 		"Received '%s' from MNCC in state %d (%s)\n",
-		lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
+		conn->bts->nr, conn->lchan->ts->trx->nr, conn->lchan->ts->nr,
 		trans->transaction_id,
 		(trans->conn->subscr)?(trans->conn->subscr->extension):"-",
 		get_mncc_name(msg_type), trans->cc.state,
@@ -2841,7 +3071,7 @@
 				    transaction_id, new_callref++);
 		if (!trans) {
 			DEBUGP(DCC, "No memory for trans.\n");
-			rc = gsm48_tx_simple(msg->lchan,
+			rc = gsm48_tx_simple(trans->conn,
 					     GSM48_PDISC_CC | (transaction_id << 4),
 					     GSM48_MT_CC_RELEASE_COMPL);
 			return -ENOMEM;
@@ -2887,7 +3117,7 @@
 		rc = gsm0408_rcv_rr(msg);
 		break;
 	case GSM48_PDISC_SMS:
-		rc = gsm0411_rcv_sms(msg, link_id);
+		rc = gsm0411_rcv_sms(&msg->lchan->conn, msg, link_id);
 		break;
 	case GSM48_PDISC_MM_GPRS:
 	case GSM48_PDISC_SM_GPRS:
@@ -2906,31 +3136,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 1b3ed25..952d724 100644
--- a/openbsc/src/gsm_04_08_utils.c
+++ b/openbsc/src/gsm_04_08_utils.c
@@ -40,35 +40,12 @@
  * or should OpenBSC always act as RTP relay/proxy in between (0) ? */
 int ipacc_rtp_direct = 1;
 
-int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans)
+static int gsm48_sendmsg(struct msgb *msg)
 {
-	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) {
+	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);
 }
 
@@ -220,7 +197,7 @@
 		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 */
@@ -243,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;
@@ -354,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 */
@@ -397,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 */
@@ -438,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)
@@ -573,3 +564,36 @@
 
 	return 0;
 }
+
+struct msgb *gsm48_create_mm_serv_rej(enum gsm48_reject_value value)
+{
+	struct msgb *msg;
+	struct gsm48_hdr *gh;
+
+	msg = gsm48_msgb_alloc();
+	if (!msg)
+		return NULL;
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
+	gh->proto_discr = GSM48_PDISC_MM;
+	gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
+	gh->data[0] = value;
+
+	return msg;
+}
+
+struct msgb *gsm48_create_loc_upd_rej(uint8_t cause)
+{
+	struct gsm48_hdr *gh;
+	struct msgb *msg;
+
+	msg = gsm48_msgb_alloc();
+	if (!msg)
+		return NULL;
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
+	gh->proto_discr = GSM48_PDISC_MM;
+	gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
+	gh->data[0] = cause;
+	return msg;
+}
diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c
index 3492f1f..ee0aba5 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,7 +26,6 @@
  */
 
 
-#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -48,12 +49,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;
 
@@ -100,6 +100,8 @@
 	{ 0, NULL }
 };
 
+static int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms);
+
 struct gsm_sms *sms_alloc(void)
 {
 	return talloc_zero(tall_gsms_ctx, struct gsm_sms);
@@ -116,6 +118,19 @@
 	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)
+		return;
+
+	subscr_put_channel(conn);
+}
+
 struct msgb *gsm411_msgb_alloc(void)
 {
 	return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM,
@@ -368,9 +383,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:
@@ -405,8 +422,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;
 }
@@ -450,11 +465,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);
@@ -550,6 +560,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:
@@ -586,7 +600,7 @@
 		}
 	}
 
-	gsms->sender = subscr_get(msg->lchan->conn.subscr);
+	gsms->sender = subscr_get(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, "
@@ -745,20 +759,14 @@
 	trans->sms.sms = NULL;
 
 	/* check for more messages for this subscriber */
-	assert(msg->lchan->conn.subscr == trans->subscr);
-
 	sms = db_sms_get_unsent_for_subscr(trans->subscr);
 	if (sms)
-		gsm411_send_sms_lchan(trans->conn, sms);
+		gsm411_send_sms(trans->conn, sms);
+	else
+		gsm411_release_conn(trans->conn);
 
 	/* free the transaction here */
 	trans_free(trans);
-
-	/* release channel if done */
-#warning "BROKEN. The SAPI will be released automatically by the BSC"
-	if (!sms)
-		rsl_release_request(msg->lchan, trans->sms.link_id);
-
 	return 0;
 }
 
@@ -808,8 +816,6 @@
 	sms_free(sms);
 	trans->sms.sms = NULL;
 
-	//trans_free(trans);
-
 	return 0;
 }
 
@@ -828,13 +834,11 @@
 	dispatch_signal(SS_SMS, S_SMS_SMMA, trans->subscr);
 
 	/* check for more messages for this subscriber */
-	assert(msg->lchan->conn.subscr == trans->subscr);
 	sms = db_sms_get_unsent_for_subscr(trans->subscr);
 	if (sms)
-		gsm411_send_sms_lchan(trans->conn, sms);
+		gsm411_send_sms(trans->conn, sms);
 	else
-		rsl_release_request(msg->lchan, trans->sms.link_id);
-#warning "BROKEN: The SAPI=3 will be released automatically by the BSC"
+		gsm411_release_conn(trans->conn);
 
 	return rc;
 }
@@ -908,25 +912,25 @@
 }
 
 /* Entry point for incoming GSM48_PDISC_SMS from abis_rsl.c */
-int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id)
+int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
+		    struct msgb *msg, u_int8_t link_id)
 {
 	struct gsm48_hdr *gh = msgb_l3(msg);
 	u_int8_t msg_type = gh->msg_type;
 	u_int8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */
-	struct gsm_lchan *lchan = msg->lchan;
 	struct gsm_trans *trans;
 	int rc = 0;
 
-	if (!lchan->conn.subscr)
+	if (!conn->subscr)
 		return -EIO;
 		/* FIXME: send some error message */
 
 	DEBUGP(DSMS, "trans_id=%x ", transaction_id);
-	trans = trans_find_by_id(lchan->conn.subscr, GSM48_PDISC_SMS,
+	trans = trans_find_by_id(conn->subscr, GSM48_PDISC_SMS,
 				 transaction_id);
 	if (!trans) {
 		DEBUGPC(DSMS, "(new) ");
-		trans = trans_alloc(lchan->conn.subscr, GSM48_PDISC_SMS,
+		trans = trans_alloc(conn->subscr, GSM48_PDISC_SMS,
 				    transaction_id, new_callref++);
 		if (!trans) {
 			DEBUGPC(DSMS, "No memory for trans\n");
@@ -938,7 +942,7 @@
 		trans->sms.is_mt = 0;
 		trans->sms.link_id = link_id;
 
-		trans->conn = &lchan->conn;
+		trans->conn = conn;
 		use_subscr_con(trans->conn);
 	}
 
@@ -958,7 +962,7 @@
 				if (i == transaction_id)
 					continue;
 
-				ptrans = trans_find_by_id(lchan->conn.subscr,
+				ptrans = trans_find_by_id(conn->subscr,
 				                          GSM48_PDISC_SMS, i);
 				if (!ptrans)
 					continue;
@@ -1000,7 +1004,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;
@@ -1025,20 +1029,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_subscriber_connection *conn, struct gsm_sms *sms)
+static int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
 {
 	struct msgb *msg = gsm411_msgb_alloc();
 	struct gsm_trans *trans;
@@ -1050,6 +1044,7 @@
 	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;
 	}
 
@@ -1060,6 +1055,7 @@
 			    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;
 	}
@@ -1090,20 +1086,16 @@
 	/* 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");
 
@@ -1113,30 +1105,6 @@
 	/* 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:
-#warning "BROKEN: The BSC will establish this transparently"
-		gsm411_send_sms_lchan(&lchan->conn, sms);
-		break;
-	case BSC_RLLR_IND_REL_IND:
-	case BSC_RLLR_IND_ERR_IND:
-	case BSC_RLLR_IND_TIMEOUT:
-#warning "BROKEN: We will need to handle SAPI n Reject"
-		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,
@@ -1144,7 +1112,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);
@@ -1154,22 +1122,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->conn, sms);
 		break;
 	case GSM_PAGING_EXPIRED:
+	case GSM_PAGING_OOM:
 		sms_free(sms);
 		rc = -ETIMEDOUT;
 		break;
-	default:
-		rc = -EINVAL;
-		break;
 	}
 
 	return rc;
@@ -1181,22 +1141,18 @@
 int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
 			   struct gsm_sms *sms)
 {
-	struct gsm_lchan *lchan;
-	int rc;
+	struct gsm_subscriber_connection *conn;
 
 	/* 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);
+	conn = connection_for_subscr(subscr);
+	if (conn) {
+		use_subscr_con(conn);
+		return gsm411_send_sms(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;
 }
 
@@ -1204,7 +1160,7 @@
 			 void *handler_data, void *signal_data)
 {
 	struct gsm_subscriber *subscr;
-	struct gsm_lchan *lchan;
+	struct gsm_subscriber_connection *conn;
 	struct gsm_sms *sms;
 
 	switch (signal) {
@@ -1212,14 +1168,14 @@
 		/* A subscriber has attached. Check if there are
 		 * any pending SMS for him to be delivered */
 		subscr = signal_data;
-		lchan = lchan_for_subscr(subscr);
-		if (!lchan)
+		conn = connection_for_subscr(subscr);
+		if (!conn)
 			break;
 		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(conn);
+		gsm411_send_sms(conn, sms);
 		break;
 	default:
 		break;
@@ -1229,9 +1185,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 ef10b17..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);
@@ -294,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,
@@ -324,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 a4b3212..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 }
 };
 
@@ -534,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 40c3bbd..264f128 100644
--- a/openbsc/src/gsm_subscriber_base.c
+++ b/openbsc/src/gsm_subscriber_base.c
@@ -106,7 +106,7 @@
 	/* paging failed, quit now */
 	if (rc <= 0) {
 		subscr_paging_cb(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED,
-				 NULL, NULL, request->param);
+				 NULL, NULL, subscr);
 	}
 }
 
@@ -185,9 +185,8 @@
 	}
 }
 
-void subscr_put_channel(struct gsm_lchan *lchan)
+void subscr_put_channel(struct gsm_subscriber_connection *conn)
 {
-	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
@@ -208,7 +207,7 @@
 
 	put_subscr_con(conn);
 
-	if (lchan->conn.subscr && !llist_empty(&lchan->conn.subscr->requests))
-		subscr_send_paging_request(lchan->conn.subscr);
+	if (conn->subscr && !llist_empty(&conn->subscr->requests))
+		subscr_send_paging_request(conn->subscr);
 }
 
diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c
index 721cadd..4968e80 100644
--- a/openbsc/src/input/ipaccess.c
+++ b/openbsc/src/input/ipaccess.c
@@ -44,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
@@ -763,13 +764,13 @@
 	e1h->gsmnet = gsmnet;
 
 	/* Listen for OML connections */
-	ret = make_sock(&e1h->listen_fd, IPPROTO_TCP, IPA_TCP_PORT_OML,
+	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, IPPROTO_TCP,
+	ret = make_sock(&e1h->rsl_listen_fd, IPPROTO_TCP, 0,
 			IPA_TCP_PORT_RSL, rsl_listen_fd_cb);
 	if (ret < 0)
 		return ret;
diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c
index f27e51f..52b18e2 100644
--- a/openbsc/src/ipaccess/ipaccess-config.c
+++ b/openbsc/src/ipaccess/ipaccess-config.c
@@ -602,18 +602,20 @@
 
 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;
diff --git a/openbsc/src/ipaccess/ipaccess-proxy.c b/openbsc/src/ipaccess/ipaccess-proxy.c
index 3860813..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>
@@ -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 };
@@ -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;
@@ -617,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;
 }
@@ -805,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;
@@ -843,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) {
@@ -859,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' */
@@ -977,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))
 {
@@ -1000,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;
 	}
 
@@ -1019,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)
 {
@@ -1043,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;
@@ -1081,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;
 }
 
@@ -1100,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;
@@ -1115,6 +1359,8 @@
 	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)
 		exit(1);
diff --git a/openbsc/src/mgcp/mgcp_main.c b/openbsc/src/mgcp/mgcp_main.c
index f7f1f80..d5b6502 100644
--- a/openbsc/src/mgcp/mgcp_main.c
+++ b/openbsc/src/mgcp/mgcp_main.c
@@ -39,10 +39,10 @@
 #include <osmocore/select.h>
 #include <openbsc/mgcp.h>
 #include <openbsc/mgcp_internal.h>
-#include <openbsc/telnet_interface.h>
+#include <osmocom/vty//telnet_interface.h>
 #include <openbsc/vty.h>
 
-#include <vty/command.h>
+#include <osmocom/vty/command.h>
 
 #include "../../bscconfig.h"
 
@@ -58,7 +58,6 @@
 static struct mgcp_config *cfg;
 static int reset_endpoints = 0;
 
-const char *openbsc_version = "OpenBSC MGCP " PACKAGE_VERSION;
 const char *openbsc_copyright =
 	"Copyright (C) 2009-2010 Holger Freyther and On-Waves\n"
 	"Contributions by Daniel Willmann, Jan Lübbe,Stefan Schmidt\n"
@@ -79,12 +78,6 @@
 	printf(" -c --config-file filename The config file to use.\n");
 }
 
-static void print_mgcp_version()
-{
-	printf("%s\n\n", openbsc_version);
-	printf("%s", openbsc_copyright);
-}
-
 static void handle_options(int argc, char** argv)
 {
 	while (1) {
@@ -110,7 +103,7 @@
 			config_file = talloc_strdup(tall_bsc_ctx, optarg);
 			break;
 		case 'V':
-			print_mgcp_version();
+			print_version(1);
 			exit(0);
 			break;
 		default:
@@ -181,6 +174,13 @@
 	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)
 {
@@ -200,13 +200,21 @@
 	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;
@@ -259,15 +267,3 @@
 
 	return 0;
 }
-
-struct gsm_network;
-int bsc_vty_init(struct gsm_network *dummy)
-{
-	cmd_init(1);
-	vty_init();
-
-	openbsc_vty_add_cmds();
-        mgcp_vty_init();
-	return 0;
-}
-
diff --git a/openbsc/src/mgcp/mgcp_vty.c b/openbsc/src/mgcp/mgcp_vty.c
index 3286198..f923b22 100644
--- a/openbsc/src/mgcp/mgcp_vty.c
+++ b/openbsc/src/mgcp/mgcp_vty.c
@@ -29,9 +29,10 @@
 #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>
 
@@ -254,6 +255,8 @@
 	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);
@@ -276,7 +279,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;
diff --git a/openbsc/src/nat/Makefile.am b/openbsc/src/nat/Makefile.am
new file mode 100644
index 0000000..0ca3bdf
--- /dev/null
+++ b/openbsc/src/nat/Makefile.am
@@ -0,0 +1,13 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
+AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS)
+AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS)
+
+bin_PROGRAMS = bsc_nat
+
+
+bsc_nat_SOURCES = bsc_filter.c bsc_mgcp_utils.c bsc_nat.c bsc_nat_utils.c \
+		  bsc_nat_vty.c bsc_sccp.c \
+		$(top_srcdir)/src/debug.c $(top_srcdir)/src/bsc_msc.c
+bsc_nat_LDADD = $(top_builddir)/src/libvty.a $(top_builddir)/src/libsccp.a \
+		$(top_builddir)/src/libmgcp.a $(top_builddir)/src/libbsc.a \
+		-lrt
diff --git a/openbsc/src/nat/bsc_filter.c b/openbsc/src/nat/bsc_filter.c
new file mode 100644
index 0000000..8f79f00
--- /dev/null
+++ b/openbsc/src/nat/bsc_filter.c
@@ -0,0 +1,216 @@
+/* BSC Multiplexer/NAT */
+
+/*
+ * (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_nat.h>
+#include <openbsc/ipaccess.h>
+#include <openbsc/debug.h>
+
+#include <osmocore/talloc.h>
+#include <osmocore/protocol/gsm_08_08.h>
+
+#include <sccp/sccp.h>
+
+/*
+ * The idea is to have a simple struct describing a IPA packet with
+ * SCCP SSN and the GSM 08.08 payload and decide. We will both have
+ * a white and a blacklist of packets we want to handle.
+ *
+ * TODO: Implement a "NOT" in the filter language.
+ */
+
+#define ALLOW_ANY -1
+
+#define FILTER_TO_BSC	1
+#define FILTER_TO_MSC	2
+#define FILTER_TO_BOTH	3
+
+
+struct bsc_pkt_filter {
+	int ipa_proto;
+	int dest_ssn;
+	int bssap;
+	int gsm;
+	int filter_dir;
+};
+
+static struct bsc_pkt_filter black_list[] = {
+	/* filter reset messages to the MSC */
+	{ IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET, FILTER_TO_MSC },
+
+	/* filter reset ack messages to the BSC */
+	{ IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET_ACKNOWLEDGE, FILTER_TO_BSC },
+
+	/* filter ip access */
+	{ IPAC_PROTO_IPACCESS, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_MSC },
+};
+
+static struct bsc_pkt_filter white_list[] = {
+	/* allow IPAC_PROTO_SCCP messages to both sides */
+	{ IPAC_PROTO_SCCP, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH },
+
+	/* allow MGCP messages to both sides */
+	{ NAT_IPAC_PROTO_MGCP, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH },
+};
+
+struct bsc_nat_parsed* bsc_nat_parse(struct msgb *msg)
+{
+	struct sccp_parse_result result;
+	struct bsc_nat_parsed *parsed;
+	struct ipaccess_head *hh;
+
+	/* quick fail */
+	if (msg->len < 4)
+		return NULL;
+
+	parsed = talloc_zero(msg, struct bsc_nat_parsed);
+	if (!parsed)
+		return NULL;
+
+	/* more init */
+	parsed->ipa_proto = parsed->called_ssn = parsed->calling_ssn = -1;
+	parsed->sccp_type = parsed->bssap = parsed->gsm_type = -1;
+
+	/* start parsing */
+	hh = (struct ipaccess_head *) msg->data;
+	parsed->ipa_proto = hh->proto;
+
+	msg->l2h = &hh->data[0];
+
+	/* do a size check on the input */
+	if (ntohs(hh->len) != msgb_l2len(msg)) {
+		LOGP(DINP, LOGL_ERROR, "Wrong input length?\n");
+		talloc_free(parsed);
+		return NULL;
+	}
+
+	/* analyze sccp down here */
+	if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
+		memset(&result, 0, sizeof(result));
+		if (sccp_parse_header(msg, &result) != 0) {
+			talloc_free(parsed);
+			return 0;
+		}
+
+		if (msg->l3h && msgb_l3len(msg) < 3) {
+			LOGP(DNAT, LOGL_ERROR, "Not enough space or GSM payload\n");
+			talloc_free(parsed);
+			return 0;
+		}
+
+		parsed->sccp_type = sccp_determine_msg_type(msg);
+		parsed->src_local_ref = result.source_local_reference;
+		parsed->dest_local_ref = result.destination_local_reference;
+		parsed->called_ssn = result.called.ssn;
+		parsed->calling_ssn = result.calling.ssn;
+
+		/* in case of connection confirm we have no payload */
+		if (msg->l3h) {
+			parsed->bssap = msg->l3h[0];
+			parsed->gsm_type = msg->l3h[2];
+		}
+	}
+
+	return parsed;
+}
+
+int bsc_nat_filter_ipa(int dir, struct msgb *msg, struct bsc_nat_parsed *parsed)
+{
+	int i;
+
+	/* go through the blacklist now */
+	for (i = 0; i < ARRAY_SIZE(black_list); ++i) {
+		/* ignore the rule? */
+		if (black_list[i].filter_dir != FILTER_TO_BOTH
+		    && black_list[i].filter_dir != dir)
+			continue;
+
+		/* the proto is not blacklisted */
+		if (black_list[i].ipa_proto != ALLOW_ANY
+		    && black_list[i].ipa_proto != parsed->ipa_proto)
+			continue;
+
+		if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
+			/* the SSN is not blacklisted */
+			if (black_list[i].dest_ssn != ALLOW_ANY
+			    && black_list[i].dest_ssn != parsed->called_ssn)
+				continue;
+
+			/* bssap */
+			if (black_list[i].bssap != ALLOW_ANY
+			    && black_list[i].bssap != parsed->bssap)
+				continue;
+
+			/* gsm */
+			if (black_list[i].gsm != ALLOW_ANY
+			    && black_list[i].gsm != parsed->gsm_type)
+				continue;
+
+			/* blacklisted */
+			LOGP(DNAT, LOGL_INFO, "Blacklisted with rule %d\n", i);
+			return 1;
+		} else {
+			/* blacklisted, we have no content sniffing yet */
+			LOGP(DNAT, LOGL_INFO, "Blacklisted with rule %d\n", i);
+			return 1;
+		}
+	}
+
+	/* go through the whitelust now */
+	for (i = 0; i < ARRAY_SIZE(white_list); ++i) {
+		/* ignore the rule? */
+		if (white_list[i].filter_dir != FILTER_TO_BOTH
+		    && white_list[i].filter_dir != dir)
+			continue;
+
+		/* the proto is not whitelisted */
+		if (white_list[i].ipa_proto != ALLOW_ANY
+		    && white_list[i].ipa_proto != parsed->ipa_proto)
+			continue;
+
+		if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
+			/* the SSN is not whitelisted */
+			if (white_list[i].dest_ssn != ALLOW_ANY
+			    && white_list[i].dest_ssn != parsed->called_ssn)
+				continue;
+
+			/* bssap */
+			if (white_list[i].bssap != ALLOW_ANY
+			    && white_list[i].bssap != parsed->bssap)
+				continue;
+
+			/* gsm */
+			if (white_list[i].gsm != ALLOW_ANY
+			    && white_list[i].gsm != parsed->gsm_type)
+				continue;
+
+			/* whitelisted */
+			LOGP(DNAT, LOGL_INFO, "Whitelisted with rule %d\n", i);
+			return 0;
+		} else {
+			/* whitelisted */
+			return 0;
+		}
+	}
+
+	return 1;
+}
diff --git a/openbsc/src/nat/bsc_mgcp_utils.c b/openbsc/src/nat/bsc_mgcp_utils.c
new file mode 100644
index 0000000..5d24acf
--- /dev/null
+++ b/openbsc/src/nat/bsc_mgcp_utils.c
@@ -0,0 +1,559 @@
+/*
+ * (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_nat.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/debug.h>
+#include <openbsc/mgcp.h>
+#include <openbsc/mgcp_internal.h>
+
+#include <sccp/sccp.h>
+
+#include <osmocore/talloc.h>
+#include <osmocore/gsm0808.h>
+#include <osmocore/protocol/gsm_08_08.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+int bsc_mgcp_assign(struct sccp_connections *con, struct msgb *msg)
+{
+	struct sccp_connections *mcon;
+	struct tlv_parsed tp;
+	u_int16_t cic;
+	u_int8_t timeslot;
+	u_int8_t multiplex;
+	int combined;
+
+	if (!msg->l3h) {
+		LOGP(DNAT, LOGL_ERROR, "Assignment message should have l3h pointer.\n");
+		return -1;
+	}
+
+	if (msgb_l3len(msg) < 3) {
+		LOGP(DNAT, LOGL_ERROR, "Assignment message has not enough space for GSM0808.\n");
+		return -1;
+	}
+
+	tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0);
+	if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) {
+		LOGP(DNAT, LOGL_ERROR, "Circuit identity code not found in assignment message.\n");
+		return -1;
+	}
+
+	cic = ntohs(*(u_int16_t *)TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE));
+	timeslot = cic & 0x1f;
+	multiplex = (cic & ~0x1f) >> 5;
+
+
+	combined = (32 * multiplex) + timeslot;
+
+	/* find stale connections using that endpoint */
+	llist_for_each_entry(mcon, &con->bsc->nat->sccp_connections, list_entry) {
+		if (mcon->msc_timeslot == combined) {
+			LOGP(DNAT, LOGL_ERROR,
+			     "Timeslot %d was assigned to 0x%x and now 0x%x\n",
+			     combined,
+			     sccp_src_ref_to_int(&mcon->patched_ref),
+			     sccp_src_ref_to_int(&con->patched_ref));
+			bsc_mgcp_dlcx(mcon);
+		}
+	}
+
+	con->msc_timeslot = combined;
+	con->bsc_timeslot = con->msc_timeslot;
+	return 0;
+}
+
+static void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int i)
+{
+	if (nat->bsc_endpoints[i].transaction_id) {
+		talloc_free(nat->bsc_endpoints[i].transaction_id);
+		nat->bsc_endpoints[i].transaction_id = NULL;
+	}
+
+	nat->bsc_endpoints[i].bsc = NULL;
+}
+
+void bsc_mgcp_free_endpoints(struct bsc_nat *nat)
+{
+	int i;
+
+	for (i = 1; i < nat->mgcp_cfg->number_endpoints; ++i){
+		bsc_mgcp_free_endpoint(nat, i);
+		mgcp_free_endp(&nat->mgcp_cfg->endpoints[i]);
+	}
+}
+
+/* send a MDCX where we do not want a response */
+static void bsc_mgcp_send_mdcx(struct bsc_connection *bsc, struct mgcp_endpoint *endp)
+{
+	char buf[2096];
+	int len;
+
+	len = snprintf(buf, sizeof(buf),
+		       "MDCX 23 %x@mgw MGCP 1.0\r\n"
+		       "Z: noanswer\r\n"
+		       "\r\n"
+		       "c=IN IP4 %s\r\n"
+		       "m=audio %d RTP/AVP 255\r\n",
+		       ENDPOINT_NUMBER(endp),
+		       bsc->nat->mgcp_cfg->source_addr,
+		       endp->rtp_port);
+	if (len < 0) {
+		LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n");
+		return;
+	}
+}
+
+static void bsc_mgcp_send_dlcx(struct bsc_connection *bsc, int endpoint)
+{
+	char buf[2096];
+	int len;
+
+	len = snprintf(buf, sizeof(buf),
+		       "DLCX 23 %x@mgw MGCP 1.0\r\n"
+		       "Z: noanswer\r\n", endpoint);
+	if (len < 0) {
+		LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n");
+		return;
+	}
+
+	bsc_write_mgcp(bsc, (u_int8_t *) buf, len);
+}
+
+void bsc_mgcp_init(struct sccp_connections *con)
+{
+	con->msc_timeslot = -1;
+	con->bsc_timeslot = -1;
+	con->crcx = 0;
+}
+
+void bsc_mgcp_dlcx(struct sccp_connections *con)
+{
+	/* send a DLCX down the stream */
+	if (con->bsc_timeslot != -1 && con->crcx) {
+		int endp = mgcp_timeslot_to_endpoint(0, con->msc_timeslot);
+		bsc_mgcp_send_dlcx(con->bsc, endp);
+		bsc_mgcp_free_endpoint(con->bsc->nat, endp);
+	}
+
+	bsc_mgcp_init(con);
+}
+
+
+struct sccp_connections *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint)
+{
+	struct sccp_connections *con = NULL;
+	struct sccp_connections *sccp;
+
+	llist_for_each_entry(sccp, &nat->sccp_connections, list_entry) {
+		if (sccp->msc_timeslot == -1)
+			continue;
+		if (mgcp_timeslot_to_endpoint(0, sccp->msc_timeslot) != endpoint)
+			continue;
+
+		con = sccp;
+	}
+
+	if (con)
+		return con;
+
+	LOGP(DMGCP, LOGL_ERROR, "Failed to find the connection.\n");
+	return NULL;
+}
+
+int bsc_mgcp_policy_cb(struct mgcp_config *cfg, int endpoint, int state, const char *transaction_id)
+{
+	struct bsc_nat *nat;
+	struct bsc_endpoint *bsc_endp;
+	struct sccp_connections *sccp;
+	struct mgcp_endpoint *mgcp_endp;
+	struct msgb *bsc_msg;
+
+	nat = cfg->data;
+	bsc_endp = &nat->bsc_endpoints[endpoint];
+	mgcp_endp = &nat->mgcp_cfg->endpoints[endpoint];
+
+	if (bsc_endp->transaction_id) {
+		LOGP(DMGCP, LOGL_ERROR, "Endpoint 0x%x had pending transaction: '%s'\n",
+		     endpoint, bsc_endp->transaction_id);
+		talloc_free(bsc_endp->transaction_id);
+		bsc_endp->transaction_id = NULL;
+	}
+	bsc_endp->bsc = NULL;
+
+	sccp = bsc_mgcp_find_con(nat, endpoint);
+
+	if (!sccp) {
+		LOGP(DMGCP, LOGL_ERROR, "Did not find BSC for change on endpoint: 0x%x state: %d\n", endpoint, state);
+
+		switch (state) {
+		case MGCP_ENDP_CRCX:
+			return MGCP_POLICY_REJECT;
+			break;
+		case MGCP_ENDP_DLCX:
+			return MGCP_POLICY_CONT;
+			break;
+		case MGCP_ENDP_MDCX:
+			return MGCP_POLICY_CONT;
+			break;
+		default:
+			LOGP(DMGCP, LOGL_FATAL, "Unhandled state: %d\n", state);
+			return MGCP_POLICY_CONT;
+			break;
+		}
+	}
+
+	/* we need to generate a new and patched message */
+	bsc_msg = bsc_mgcp_rewrite((char *) nat->mgcp_msg, nat->mgcp_length,
+				   nat->mgcp_cfg->source_addr, mgcp_endp->rtp_port);
+	if (!bsc_msg) {
+		LOGP(DMGCP, LOGL_ERROR, "Failed to patch the msg.\n");
+		return MGCP_POLICY_CONT;
+	}
+
+
+	bsc_endp->transaction_id = talloc_strdup(nat, transaction_id);
+	bsc_endp->bsc = sccp->bsc;
+
+	/* we need to update some bits */
+	if (state == MGCP_ENDP_CRCX) {
+		struct sockaddr_in sock;
+		socklen_t len = sizeof(sock);
+		if (getpeername(sccp->bsc->write_queue.bfd.fd, (struct sockaddr *) &sock, &len) != 0) {
+			LOGP(DMGCP, LOGL_ERROR, "Can not get the peername...%d/%s\n",
+			      errno, strerror(errno));
+		} else {
+			mgcp_endp->bts = sock.sin_addr;
+		}
+
+		/* send the message and a fake MDCX for force sending of a dummy packet */
+		sccp->crcx = 1;
+		bsc_write(sccp->bsc, bsc_msg, NAT_IPAC_PROTO_MGCP);
+		bsc_mgcp_send_mdcx(sccp->bsc, mgcp_endp);
+		return MGCP_POLICY_DEFER;
+	} else if (state == MGCP_ENDP_DLCX) {
+		/* we will free the endpoint now and send a DLCX to the BSC */
+		msgb_free(bsc_msg);
+		bsc_mgcp_dlcx(sccp);
+		return MGCP_POLICY_CONT;
+	} else {
+		bsc_write(sccp->bsc, bsc_msg, NAT_IPAC_PROTO_MGCP);
+		return MGCP_POLICY_DEFER;
+	}
+}
+
+/*
+ * We have received a msg from the BSC. We will see if we know
+ * this transaction and if it belongs to the BSC. Then we will
+ * need to patch the content to point to the local network and we
+ * need to update the I: that was assigned by the BSS.
+ */
+void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg)
+{
+	struct msgb *output;
+	struct bsc_endpoint *bsc_endp = NULL;
+	struct mgcp_endpoint *endp = NULL;
+	int i, code;
+	char transaction_id[60];
+
+	/* Some assumption that our buffer is big enough.. and null terminate */
+	if (msgb_l2len(msg) > 2000) {
+		LOGP(DMGCP, LOGL_ERROR, "MGCP message too long.\n");
+		return;
+	}
+
+	msg->l2h[msgb_l2len(msg)] = '\0';
+
+	if (bsc_mgcp_parse_response((const char *) msg->l2h, &code, transaction_id) != 0) {
+		LOGP(DMGCP, LOGL_ERROR, "Failed to parse response code.\n");
+		return;
+	}
+
+	for (i = 1; i < bsc->nat->mgcp_cfg->number_endpoints; ++i) {
+		if (bsc->nat->bsc_endpoints[i].bsc != bsc)
+			continue;
+		/* no one listening? a bug? */
+		if (!bsc->nat->bsc_endpoints[i].transaction_id)
+			continue;
+		if (strcmp(transaction_id, bsc->nat->bsc_endpoints[i].transaction_id) != 0)
+			continue;
+
+		endp = &bsc->nat->mgcp_cfg->endpoints[i];
+		bsc_endp = &bsc->nat->bsc_endpoints[i];
+		break;
+	}
+
+	if (!bsc_endp) {
+		LOGP(DMGCP, LOGL_ERROR, "Could not find active endpoint: %s for msg: '%s'\n",
+		     transaction_id, (const char *) msg->l2h);
+		return;
+	}
+
+	endp->ci = bsc_mgcp_extract_ci((const char *) msg->l2h);
+
+	/* free some stuff */
+	talloc_free(bsc_endp->transaction_id);
+	bsc_endp->transaction_id = NULL;
+
+	/*
+	 * rewrite the information. In case the endpoint was deleted
+	 * there should be nothing for us to rewrite so putting endp->rtp_port
+	 * with the value of 0 should be no problem.
+	 */
+	output = bsc_mgcp_rewrite((char * ) msg->l2h, msgb_l2len(msg),
+				  bsc->nat->mgcp_cfg->source_addr, endp->rtp_port);
+
+	if (!output) {
+		LOGP(DMGCP, LOGL_ERROR, "Failed to rewrite MGCP msg.\n");
+		return;
+	}
+
+	if (write_queue_enqueue(&bsc->nat->mgcp_queue, output) != 0) {
+		LOGP(DMGCP, LOGL_ERROR, "Failed to queue MGCP msg.\n");
+		msgb_free(output);
+	}
+}
+
+int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60])
+{
+	/* we want to parse two strings */
+	return sscanf(str, "%3d %59s\n", code, transaction) != 2;
+}
+
+int bsc_mgcp_extract_ci(const char *str)
+{
+	int ci;
+	char *res = strstr(str, "I: ");
+	if (!res)
+		return CI_UNUSED;
+
+	if (sscanf(res, "I: %d", &ci) != 1)
+		return CI_UNUSED;
+	return ci;
+}
+
+/* we need to replace some strings... */
+struct msgb *bsc_mgcp_rewrite(char *input, int length, const char *ip, int port)
+{
+	static const char *ip_str = "c=IN IP4 ";
+	static const char *aud_str = "m=audio ";
+
+	char buf[128];
+	char *running, *token;
+	struct msgb *output;
+
+	if (length > 4096 - 128) {
+		LOGP(DMGCP, LOGL_ERROR, "Input is too long.\n");
+		return NULL;
+	}
+
+	output = msgb_alloc_headroom(4096, 128, "MGCP rewritten");
+	if (!output) {
+		LOGP(DMGCP, LOGL_ERROR, "Failed to allocate new MGCP msg.\n");
+		return NULL;
+	}
+
+	running = input;
+	output->l2h = output->data;
+	for (token = strsep(&running, "\n"); running; token = strsep(&running, "\n")) {
+		int len = strlen(token);
+		int cr = len > 0 && token[len - 1] == '\r';
+
+		if (strncmp(ip_str, token, (sizeof ip_str) - 1) == 0) {
+			output->l3h = msgb_put(output, strlen(ip_str));
+			memcpy(output->l3h, ip_str, strlen(ip_str));
+			output->l3h = msgb_put(output, strlen(ip));
+			memcpy(output->l3h, ip, strlen(ip));
+
+			if (cr) {
+				output->l3h = msgb_put(output, 2);
+				output->l3h[0] = '\r';
+				output->l3h[1] = '\n';
+			} else {
+				output->l3h = msgb_put(output, 1);
+				output->l3h[0] = '\n';
+			}
+		} else if (strncmp(aud_str, token, (sizeof aud_str) - 1) == 0) {
+			int payload;
+			if (sscanf(token, "m=audio %*d RTP/AVP %d", &payload) != 1) {
+				LOGP(DMGCP, LOGL_ERROR, "Could not parsed audio line.\n");
+				msgb_free(output);
+				return NULL;
+			}
+
+			snprintf(buf, sizeof(buf)-1, "m=audio %d RTP/AVP %d%s",
+				 port, payload, cr ? "\r\n" : "\n");
+			buf[sizeof(buf)-1] = '\0';
+
+			output->l3h = msgb_put(output, strlen(buf));
+			memcpy(output->l3h, buf, strlen(buf));
+		} else {
+			output->l3h = msgb_put(output, len + 1);
+			memcpy(output->l3h, token, len);
+			output->l3h[len] = '\n';
+		}
+	}
+
+	return output;
+}
+
+static int mgcp_do_read(struct bsc_fd *fd)
+{
+	struct bsc_nat *nat;
+	struct msgb *msg, *resp;
+	int rc;
+
+	nat = fd->data;
+
+	rc = read(fd->fd, nat->mgcp_msg, sizeof(nat->mgcp_msg) - 1);
+	if (rc <= 0) {
+		LOGP(DMGCP, LOGL_ERROR, "Failed to read errno: %d\n", errno);
+		return -1;
+	}
+
+	nat->mgcp_msg[rc] = '\0';
+	nat->mgcp_length = rc;
+
+	msg = msgb_alloc(sizeof(nat->mgcp_msg), "MGCP GW Read");
+	if (!msg) {
+		LOGP(DMGCP, LOGL_ERROR, "Failed to create buffer.\n");
+		return -1;
+	}
+
+	msg->l2h = msgb_put(msg, rc);
+	memcpy(msg->l2h, nat->mgcp_msg, msgb_l2len(msg));
+	resp = mgcp_handle_message(nat->mgcp_cfg, msg);
+	msgb_free(msg);
+
+	/* we do have a direct answer... e.g. AUEP */
+	if (resp) {
+		if (write_queue_enqueue(&nat->mgcp_queue, resp) != 0) {
+			LOGP(DMGCP, LOGL_ERROR, "Failed to enqueue msg.\n");
+			msgb_free(resp);
+		}
+	}
+
+	return 0;
+}
+
+static int mgcp_do_write(struct bsc_fd *bfd, struct msgb *msg)
+{
+	int rc;
+
+	rc = write(bfd->fd, msg->data, msg->len);
+
+	if (rc != msg->len) {
+		LOGP(DMGCP, LOGL_ERROR, "Failed to write msg to MGCP CallAgent.\n");
+		return -1;
+	}
+
+	return rc;
+}
+
+int bsc_mgcp_nat_init(struct bsc_nat *nat)
+{
+	int on;
+	struct sockaddr_in addr;
+
+	if (!nat->mgcp_cfg->call_agent_addr) {
+		LOGP(DMGCP, LOGL_ERROR, "The BSC nat requires the call agent ip to be set.\n");
+		return -1;
+	}
+
+	if (nat->mgcp_cfg->bts_ip) {
+		LOGP(DMGCP, LOGL_ERROR, "Do not set the BTS ip for the nat.\n");
+		return -1;
+	}
+
+	nat->mgcp_queue.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (nat->mgcp_queue.bfd.fd < 0) {
+		LOGP(DMGCP, LOGL_ERROR, "Failed to create MGCP socket. errno: %d\n", errno);
+		return -1;
+	}
+
+	on = 1;
+	setsockopt(nat->mgcp_queue.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(nat->mgcp_cfg->source_port);
+	inet_aton(nat->mgcp_cfg->source_addr, &addr.sin_addr);
+
+	if (bind(nat->mgcp_queue.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		LOGP(DMGCP, LOGL_ERROR, "Failed to bind. errno: %d\n", errno);
+		close(nat->mgcp_queue.bfd.fd);
+		nat->mgcp_queue.bfd.fd = -1;
+		return -1;
+	}
+
+	addr.sin_port = htons(2727);
+	inet_aton(nat->mgcp_cfg->call_agent_addr, &addr.sin_addr);
+	if (connect(nat->mgcp_queue.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		LOGP(DMGCP, LOGL_ERROR, "Failed to connect to: '%s'. errno: %d\n",
+		     nat->mgcp_cfg->call_agent_addr, errno);
+		close(nat->mgcp_queue.bfd.fd);
+		nat->mgcp_queue.bfd.fd = -1;
+		return -1;
+	}
+
+	write_queue_init(&nat->mgcp_queue, 10);
+	nat->mgcp_queue.bfd.when = BSC_FD_READ;
+	nat->mgcp_queue.bfd.data = nat;
+	nat->mgcp_queue.read_cb = mgcp_do_read;
+	nat->mgcp_queue.write_cb = mgcp_do_write;
+
+	if (bsc_register_fd(&nat->mgcp_queue.bfd) != 0) {
+		LOGP(DMGCP, LOGL_ERROR, "Failed to register MGCP fd.\n");
+		close(nat->mgcp_queue.bfd.fd);
+		nat->mgcp_queue.bfd.fd = -1;
+		return -1;
+	}
+
+	/* some more MGCP config handling */
+	nat->mgcp_cfg->audio_payload = -1;
+	nat->mgcp_cfg->data = nat;
+	nat->mgcp_cfg->policy_cb = bsc_mgcp_policy_cb;
+	nat->mgcp_cfg->force_realloc = 1;
+	nat->mgcp_cfg->bts_ip = "";
+	nat->bsc_endpoints = talloc_zero_array(nat,
+					       struct bsc_endpoint,
+					       nat->mgcp_cfg->number_endpoints + 1);
+
+	return 0;
+}
+
+void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc)
+{
+	int i;
+	for (i = 1; i < bsc->nat->mgcp_cfg->number_endpoints; ++i) {
+		struct bsc_endpoint *bsc_endp = &bsc->nat->bsc_endpoints[i];
+
+		if (bsc_endp->bsc != bsc)
+			continue;
+
+		bsc_mgcp_free_endpoint(bsc->nat, i);
+		mgcp_free_endp(&bsc->nat->mgcp_cfg->endpoints[i]);
+	}
+}
diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c
new file mode 100644
index 0000000..2e8a00d
--- /dev/null
+++ b/openbsc/src/nat/bsc_nat.c
@@ -0,0 +1,1171 @@
+/* BSC Multiplexer/NAT */
+
+/*
+ * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (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 <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/bsc_msc.h>
+#include <openbsc/bsc_nat.h>
+#include <openbsc/ipaccess.h>
+#include <openbsc/abis_nm.h>
+#include <openbsc/vty.h>
+
+#include <osmocore/gsm0808.h>
+#include <osmocore/talloc.h>
+
+#include <osmocore/protocol/gsm_08_08.h>
+
+#include <osmocom/vty/telnet_interface.h>
+#include <osmocom/vty/vty.h>
+
+#include <sccp/sccp.h>
+
+#include "../../bscconfig.h"
+
+#define SCCP_CLOSE_TIME 20
+#define SCCP_CLOSE_TIME_TIMEOUT 19
+
+struct log_target *stderr_target;
+static const char *config_file = "bsc-nat.cfg";
+static struct in_addr local_addr;
+static struct bsc_fd bsc_listen;
+static const char *msc_ip = NULL;
+static struct timer_list sccp_close;
+
+const char *openbsc_copyright =
+	"Copyright (C) 2010 Holger Hans Peter Freyther 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 bsc_nat *nat;
+static void bsc_send_data(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length, int);
+static void msc_send_reset(struct bsc_msc_connection *con);
+
+struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num)
+{
+	struct bsc_config *conf;
+
+	llist_for_each_entry(conf, &nat->bsc_configs, entry)
+		if (conf->nr == num)
+			return conf;
+
+	return NULL;
+}
+
+/*
+ * below are stubs we need to link
+ */
+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 abis_om_obj_inst *obj_ins)
+{
+	return -1;
+}
+
+void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
+{}
+
+int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
+{
+	return -1;
+}
+
+static void queue_for_msc(struct bsc_msc_connection *con, struct msgb *msg)
+{
+	if (write_queue_enqueue(&nat->msc_con->write_queue, msg) != 0) {
+		LOGP(DINP, LOGL_ERROR, "Failed to enqueue the write.\n");
+		msgb_free(msg);
+	}
+}
+
+static void send_reset_ack(struct bsc_connection *bsc)
+{
+	static const u_int8_t gsm_reset_ack[] = {
+		0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
+		0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03,
+		0x00, 0x01, 0x31,
+	};
+
+	bsc_send_data(bsc, gsm_reset_ack, sizeof(gsm_reset_ack), IPAC_PROTO_SCCP);
+}
+
+static void send_ping(struct bsc_connection *bsc)
+{
+	static const u_int8_t id_ping[] = {
+		IPAC_MSGT_PING,
+	};
+
+	bsc_send_data(bsc, id_ping, sizeof(id_ping), IPAC_PROTO_IPACCESS);
+}
+
+static void send_pong(struct bsc_connection *bsc)
+{
+	static const u_int8_t id_pong[] = {
+		IPAC_MSGT_PONG,
+	};
+
+	bsc_send_data(bsc, id_pong, sizeof(id_pong), IPAC_PROTO_IPACCESS);
+}
+
+static void bsc_pong_timeout(void *_bsc)
+{
+	struct bsc_connection *bsc = _bsc;
+
+	LOGP(DNAT, LOGL_ERROR, "BSC Nr: %d PONG timeout.\n", bsc->cfg->nr);
+	bsc_close_connection(bsc);
+}
+
+static void bsc_ping_timeout(void *_bsc)
+{
+	struct bsc_connection *bsc = _bsc;
+
+	if (bsc->nat->ping_timeout < 0)
+		return;
+
+	send_ping(bsc);
+
+	/* send another ping in 20 seconds */
+	bsc_schedule_timer(&bsc->ping_timeout, bsc->nat->ping_timeout, 0);
+
+	/* also start a pong timer */
+	bsc_schedule_timer(&bsc->pong_timeout, bsc->nat->pong_timeout, 0);
+}
+
+static void start_ping_pong(struct bsc_connection *bsc)
+{
+	bsc->pong_timeout.data = bsc;
+	bsc->pong_timeout.cb = bsc_pong_timeout;
+	bsc->ping_timeout.data = bsc;
+	bsc->ping_timeout.cb = bsc_ping_timeout;
+
+	bsc_ping_timeout(bsc);
+}
+
+static void send_id_ack(struct bsc_connection *bsc)
+{
+	static const u_int8_t id_ack[] = {
+		IPAC_MSGT_ID_ACK
+	};
+
+	bsc_send_data(bsc, id_ack, sizeof(id_ack), IPAC_PROTO_IPACCESS);
+}
+
+static void send_id_req(struct bsc_connection *bsc)
+{
+	static const u_int8_t id_req[] = {
+		IPAC_MSGT_ID_GET,
+		0x01, IPAC_IDTAG_UNIT,
+		0x01, IPAC_IDTAG_MACADDR,
+		0x01, IPAC_IDTAG_LOCATION1,
+		0x01, IPAC_IDTAG_LOCATION2,
+		0x01, IPAC_IDTAG_EQUIPVERS,
+		0x01, IPAC_IDTAG_SWVERSION,
+		0x01, IPAC_IDTAG_UNITNAME,
+		0x01, IPAC_IDTAG_SERNR,
+	};
+
+	bsc_send_data(bsc, id_req, sizeof(id_req), IPAC_PROTO_IPACCESS);
+}
+
+static void nat_send_rlsd(struct sccp_connections *conn)
+{
+	struct sccp_connection_released *rel;
+	struct msgb *msg;
+
+	msg = msgb_alloc_headroom(4096, 128, "rlsd");
+	if (!msg) {
+		LOGP(DNAT, LOGL_ERROR, "Failed to allocate clear command.\n");
+		return;
+	}
+
+	msg->l2h = msgb_put(msg, sizeof(*rel));
+	rel = (struct sccp_connection_released *) msg->l2h;
+	rel->type = SCCP_MSG_TYPE_RLSD;
+	rel->release_cause = SCCP_RELEASE_CAUSE_SCCP_FAILURE;
+	rel->destination_local_reference = conn->remote_ref;
+	rel->source_local_reference = conn->patched_ref;
+
+	ipaccess_prepend_header(msg, IPAC_PROTO_SCCP);
+
+	queue_for_msc(nat->msc_con, msg);
+}
+
+static void nat_send_rlc(struct sccp_source_reference *src,
+			 struct sccp_source_reference *dst)
+{
+	struct sccp_connection_release_complete *rlc;
+	struct msgb *msg;
+
+	msg = msgb_alloc_headroom(4096, 128, "rlc");
+	if (!msg) {
+		LOGP(DNAT, LOGL_ERROR, "Failed to allocate clear command.\n");
+		return;
+	}
+
+	msg->l2h = msgb_put(msg, sizeof(*rlc));
+	rlc = (struct sccp_connection_release_complete *) msg->l2h;
+	rlc->type = SCCP_MSG_TYPE_RLC;
+	rlc->destination_local_reference = *dst;
+	rlc->source_local_reference = *src;
+
+	ipaccess_prepend_header(msg, IPAC_PROTO_SCCP);
+
+	queue_for_msc(nat->msc_con, msg);
+}
+
+static void send_mgcp_reset(struct bsc_connection *bsc)
+{
+	static const u_int8_t mgcp_reset[] = {
+	    "RSIP 1 13@mgw MGCP 1.0\r\n"
+	};
+
+	bsc_write_mgcp(bsc, mgcp_reset, sizeof mgcp_reset - 1);
+}
+
+/*
+ * Below is the handling of messages coming
+ * from the MSC and need to be forwarded to
+ * a real BSC.
+ */
+static void initialize_msc_if_needed()
+{
+	if (nat->first_contact)
+		return;
+
+	nat->first_contact = 1;
+	msc_send_reset(nat->msc_con);
+}
+
+static void send_id_get_response()
+{
+	struct msgb *msg = bsc_msc_id_get_resp(nat->token);
+	if (!msg)
+		return;
+
+	ipaccess_prepend_header(msg, IPAC_PROTO_IPACCESS);
+	queue_for_msc(nat->msc_con, msg);
+}
+
+/*
+ * Currently we are lacking refcounting so we need to copy each message.
+ */
+static void bsc_send_data(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length, int proto)
+{
+	struct msgb *msg;
+
+	if (length > 4096 - 128) {
+		LOGP(DINP, LOGL_ERROR, "Can not send message of that size.\n");
+		return;
+	}
+
+	msg = msgb_alloc_headroom(4096, 128, "to-bsc");
+	if (!msg) {
+		LOGP(DINP, LOGL_ERROR, "Failed to allocate memory for BSC msg.\n");
+		return;
+	}
+
+	msg->l2h = msgb_put(msg, length);
+	memcpy(msg->data, data, length);
+
+	bsc_write(bsc, msg, proto);
+}
+
+static void bsc_send_con_refuse(struct bsc_connection *bsc,
+				struct bsc_nat_parsed *parsed, int con_type)
+{
+	struct msgb *payload;
+	struct msgb *refuse;
+
+	if (con_type == NAT_CON_TYPE_LU)
+		payload = gsm48_create_loc_upd_rej(GSM48_REJECT_PLMN_NOT_ALLOWED);
+	else if (con_type == NAT_CON_TYPE_CM_SERV_REQ)
+		payload = gsm48_create_mm_serv_rej(GSM48_REJECT_PLMN_NOT_ALLOWED);
+
+	/*
+	 * Some BSCs do not handle the payload inside a SCCP CREF msg
+	 * so we will need to:
+	 * 1.) Allocate a local connection and mark it as local..
+	 * 2.) queue data for downstream.. and the RLC should delete everything
+	 */
+	if (payload) {
+		struct msgb *cc, *udt, *rlsd;
+		struct sccp_connections *con;
+		con = create_sccp_src_ref(bsc, parsed);
+		if (!con)
+			goto send_refuse;
+
+		/* declare it local and assign a unique remote_ref */
+		con->con_type = NAT_CON_TYPE_LOCAL_REJECT;
+		con->con_local = 1;
+		con->has_remote_ref = 1;
+		con->remote_ref = con->patched_ref;
+
+		/* 1. create a confirmation */
+		cc = sccp_create_cc(&con->remote_ref, &con->real_ref);
+		if (!cc)
+			goto send_refuse;
+
+		/* 2. create the DT1 */
+		gsm0808_prepend_dtap_header(payload, 0);
+		udt = sccp_create_dt1(&con->real_ref, payload->data, payload->len);
+		if (!udt) {
+			msgb_free(cc);
+			goto send_refuse;
+		}
+
+		/* 3. send a RLSD */
+		rlsd = sccp_create_rlsd(&con->remote_ref, &con->real_ref,
+					SCCP_RELEASE_CAUSE_END_USER_ORIGINATED);
+		if (!rlsd) {
+			msgb_free(cc);
+			msgb_free(udt);
+			goto send_refuse;
+		}
+
+		bsc_write(bsc, cc, IPAC_PROTO_SCCP);
+		bsc_write(bsc, udt, IPAC_PROTO_SCCP);
+		bsc_write(bsc, rlsd, IPAC_PROTO_SCCP);
+		msgb_free(payload);
+		return;
+	}
+
+
+send_refuse:
+	if (payload)
+		msgb_free(payload);
+
+	refuse = sccp_create_refuse(parsed->src_local_ref,
+				    SCCP_REFUSAL_SCCP_FAILURE, NULL, 0);
+	if (!refuse) {
+		LOGP(DNAT, LOGL_ERROR,
+		     "Creating refuse msg failed for SCCP 0x%x on BSC Nr: %d.\n",
+		      sccp_src_ref_to_int(parsed->src_local_ref), bsc->cfg->nr);
+		return;
+	}
+
+	bsc_write(bsc, refuse, IPAC_PROTO_SCCP);
+}
+
+
+static int forward_sccp_to_bts(struct msgb *msg)
+{
+	struct sccp_connections *con;
+	struct bsc_connection *bsc;
+	struct bsc_nat_parsed *parsed;
+	int proto;
+
+	/* filter, drop, patch the message? */
+	parsed = bsc_nat_parse(msg);
+	if (!parsed) {
+		LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n");
+		return -1;
+	}
+
+	if (bsc_nat_filter_ipa(DIR_BSC, msg, parsed))
+		goto exit;
+
+	proto = parsed->ipa_proto;
+
+	/* Route and modify the SCCP packet */
+	if (proto == IPAC_PROTO_SCCP) {
+		switch (parsed->sccp_type) {
+		case SCCP_MSG_TYPE_UDT:
+			/* forward UDT messages to every BSC */
+			goto send_to_all;
+			break;
+		case SCCP_MSG_TYPE_RLSD:
+		case SCCP_MSG_TYPE_CREF:
+		case SCCP_MSG_TYPE_DT1:
+		case SCCP_MSG_TYPE_IT:
+			con = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
+			if (parsed->gsm_type == BSS_MAP_MSG_ASSIGMENT_RQST) {
+				counter_inc(nat->stats.sccp.calls);
+
+				if (con) {
+					counter_inc(con->bsc->cfg->stats.sccp.calls);
+					if (bsc_mgcp_assign(con, msg) != 0)
+						LOGP(DNAT, LOGL_ERROR, "Failed to assign...\n");
+				} else
+					LOGP(DNAT, LOGL_ERROR, "Assignment command but no BSC.\n");
+			}
+			break;
+		case SCCP_MSG_TYPE_CC:
+			con = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
+			if (!con || update_sccp_src_ref(con, parsed) != 0)
+				goto exit;
+			break;
+		case SCCP_MSG_TYPE_RLC:
+			LOGP(DNAT, LOGL_ERROR, "Unexpected release complete from MSC.\n");
+			goto exit;
+			break;
+		case SCCP_MSG_TYPE_CR:
+			/* MSC never opens a SCCP connection, fall through */
+		default:
+			goto exit;
+		}
+
+		if (!con && parsed->sccp_type == SCCP_MSG_TYPE_RLSD) {
+			LOGP(DNAT, LOGL_NOTICE, "Sending fake RLC on RLSD message to network.\n");
+			/* Exchange src/dest for the reply */
+			nat_send_rlc(parsed->dest_local_ref, parsed->src_local_ref);
+		} else if (!con)
+			LOGP(DNAT, LOGL_ERROR, "Unknown connection for msg type: 0x%x from the MSC.\n", parsed->sccp_type);
+	}
+
+	talloc_free(parsed);
+	if (!con)
+		return -1;
+	if (!con->bsc->authenticated) {
+		LOGP(DNAT, LOGL_ERROR, "Selected BSC not authenticated.\n");
+		return -1;
+	}
+
+	bsc_send_data(con->bsc, msg->l2h, msgb_l2len(msg), proto);
+	return 0;
+
+send_to_all:
+	/*
+	 * Filter Paging from the network. We do not want to send a PAGING
+	 * Command to every BSC in our network. We will analys the PAGING
+	 * message and then send it to the authenticated messages...
+	 */
+	if (parsed->ipa_proto == IPAC_PROTO_SCCP && parsed->gsm_type == BSS_MAP_MSG_PAGING) {
+		int lac;
+		bsc = bsc_nat_find_bsc(nat, msg, &lac);
+		if (bsc && bsc->cfg->forbid_paging)
+			LOGP(DNAT, LOGL_DEBUG, "Paging forbidden for BTS: %d\n", bsc->cfg->nr);
+		else if (bsc)
+			bsc_send_data(bsc, msg->l2h, msgb_l2len(msg), parsed->ipa_proto);
+		else
+			LOGP(DNAT, LOGL_ERROR, "Could not determine BSC for paging on lac: %d/0x%x\n",
+			     lac, lac);
+
+		goto exit;
+	}
+	/* currently send this to every BSC connected */
+	llist_for_each_entry(bsc, &nat->bsc_connections, list_entry) {
+		if (!bsc->authenticated)
+			continue;
+
+		bsc_send_data(bsc, msg->l2h, msgb_l2len(msg), parsed->ipa_proto);
+	}
+
+exit:
+	talloc_free(parsed);
+	return 0;
+}
+
+static void msc_connection_was_lost(struct bsc_msc_connection *con)
+{
+	struct bsc_connection *bsc, *tmp;
+
+	counter_inc(nat->stats.msc.reconn);
+
+	LOGP(DMSC, LOGL_ERROR, "Closing all connections downstream.\n");
+	llist_for_each_entry_safe(bsc, tmp, &nat->bsc_connections, list_entry)
+		bsc_close_connection(bsc);
+
+	nat->first_contact = 0;
+	bsc_mgcp_free_endpoints(nat);
+	bsc_msc_schedule_connect(con);
+}
+
+static void msc_send_reset(struct bsc_msc_connection *msc_con)
+{
+	static const u_int8_t reset[] = {
+		0x00, 0x12, 0xfd,
+		0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe,
+		0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04,
+		0x01, 0x20
+	};
+
+	struct msgb *msg;
+
+	msg = msgb_alloc_headroom(4096, 128, "08.08 reset");
+	if (!msg) {
+		LOGP(DMSC, LOGL_ERROR, "Failed to allocate reset msg.\n");
+		return;
+	}
+
+	msg->l2h = msgb_put(msg, sizeof(reset));
+	memcpy(msg->l2h, reset, msgb_l2len(msg));
+
+	queue_for_msc(nat->msc_con, msg);
+
+	LOGP(DMSC, LOGL_NOTICE, "Scheduled GSM0808 reset msg for the MSC.\n");
+}
+
+static int ipaccess_msc_read_cb(struct bsc_fd *bfd)
+{
+	int error;
+	struct msgb *msg = ipaccess_read_msg(bfd, &error);
+	struct ipaccess_head *hh;
+
+	if (!msg) {
+		if (error == 0)
+			LOGP(DNAT, LOGL_FATAL, "The connection the MSC was lost, exiting\n");
+		else
+			LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
+
+		bsc_msc_lost(nat->msc_con);
+		return -1;
+	}
+
+	LOGP(DNAT, LOGL_DEBUG, "MSG from MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
+
+	/* handle base message handling */
+	hh = (struct ipaccess_head *) msg->data;
+	ipaccess_rcvmsg_base(msg, bfd);
+
+	/* initialize the networking. This includes sending a GSM08.08 message */
+	if (hh->proto == IPAC_PROTO_IPACCESS) {
+		if (msg->l2h[0] == IPAC_MSGT_ID_ACK)
+			initialize_msc_if_needed();
+		else if (msg->l2h[0] == IPAC_MSGT_ID_GET)
+			send_id_get_response();
+	} else if (hh->proto == IPAC_PROTO_SCCP)
+		forward_sccp_to_bts(msg);
+
+	msgb_free(msg);
+	return 0;
+}
+
+static int ipaccess_msc_write_cb(struct bsc_fd *bfd, struct msgb *msg)
+{
+	int rc;
+	rc = write(bfd->fd, msg->data, msg->len);
+
+	if (rc != msg->len) {
+		LOGP(DNAT, LOGL_ERROR, "Failed to write MSG to MSC.\n");
+		return -1;
+	}
+
+	return rc;
+}
+
+/*
+ * Below is the handling of messages coming
+ * from the BSC and need to be forwarded to
+ * a real BSC.
+ */
+
+/*
+ * Remove the connection from the connections list,
+ * remove it from the patching of SCCP header lists
+ * as well. Maybe in the future even close connection..
+ */
+void bsc_close_connection(struct bsc_connection *connection)
+{
+	struct sccp_connections *sccp_patch, *tmp;
+
+	/* stop the timeout timer */
+	bsc_del_timer(&connection->id_timeout);
+	bsc_del_timer(&connection->ping_timeout);
+	bsc_del_timer(&connection->pong_timeout);
+
+	/* remove all SCCP connections */
+	llist_for_each_entry_safe(sccp_patch, tmp, &nat->sccp_connections, list_entry) {
+		if (sccp_patch->bsc != connection)
+			continue;
+
+		if (sccp_patch->has_remote_ref)
+			nat_send_rlsd(sccp_patch);
+		sccp_connection_destroy(sccp_patch);
+	}
+
+	/* close endpoints allocated by this BSC */
+	bsc_mgcp_clear_endpoints_for(connection);
+
+	bsc_unregister_fd(&connection->write_queue.bfd);
+	close(connection->write_queue.bfd.fd);
+	write_queue_clear(&connection->write_queue);
+	llist_del(&connection->list_entry);
+
+	talloc_free(connection);
+}
+
+static void ipaccess_close_bsc(void *data)
+{
+	struct sockaddr_in sock;
+	socklen_t len = sizeof(sock);
+	struct bsc_connection *conn = data;
+
+
+	getpeername(conn->write_queue.bfd.fd, (struct sockaddr *) &sock, &len);
+	LOGP(DNAT, LOGL_ERROR, "BSC on %s didn't respond to identity request. Closing.\n",
+	     inet_ntoa(sock.sin_addr));
+	bsc_close_connection(conn);
+}
+
+static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc)
+{
+	struct bsc_config *conf;
+	const char* token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME);
+
+	if (bsc->cfg) {
+		LOGP(DNAT, LOGL_ERROR, "Reauth on fd %d bsc nr %d\n",
+		     bsc->write_queue.bfd.fd, bsc->cfg->nr);
+		return;
+	}
+
+	llist_for_each_entry(conf, &bsc->nat->bsc_configs, entry) {
+		if (strcmp(conf->token, token) == 0) {
+			counter_inc(conf->stats.net.reconn);
+			bsc->authenticated = 1;
+			bsc->cfg = conf;
+			bsc_del_timer(&bsc->id_timeout);
+			LOGP(DNAT, LOGL_NOTICE, "Authenticated bsc nr: %d lac: %d on fd %d\n",
+			     conf->nr, conf->lac, bsc->write_queue.bfd.fd);
+			start_ping_pong(bsc);
+			return;
+		}
+	}
+
+	LOGP(DNAT, LOGL_ERROR, "No bsc found for token %s on fd: %d.\n", token,
+	     bsc->write_queue.bfd.fd);
+}
+
+static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
+{
+	int con_found = 0;
+	int con_filter = 0;
+	struct bsc_connection *con_bsc = NULL;
+	int con_type;
+	struct bsc_nat_parsed *parsed;
+
+	/* Parse and filter messages */
+	parsed = bsc_nat_parse(msg);
+	if (!parsed) {
+		LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n");
+		msgb_free(msg);
+		return -1;
+	}
+
+	if (bsc_nat_filter_ipa(DIR_MSC, msg, parsed))
+		goto exit;
+
+	/*
+	 * check authentication after filtering to not reject auth
+	 * responses coming from the BSC. We have to make sure that
+	 * nothing from the exit path will forward things to the MSC
+	 */
+	if (!bsc->authenticated) {
+		LOGP(DNAT, LOGL_ERROR, "BSC is not authenticated.\n");
+		msgb_free(msg);
+		return -1;
+	}
+
+
+	/* modify the SCCP entries */
+	if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
+		struct sccp_connections *con;
+		switch (parsed->sccp_type) {
+		case SCCP_MSG_TYPE_CR:
+			if (bsc_nat_filter_sccp_cr(bsc, msg, parsed, &con_type) != 0)
+				goto exit3;
+			if (!create_sccp_src_ref(bsc, parsed))
+				goto exit2;
+			con = patch_sccp_src_ref_to_msc(msg, parsed, bsc);
+			con->con_type = con_type;
+			con_found = 1;
+			con_bsc = con->bsc;
+			break;
+		case SCCP_MSG_TYPE_RLSD:
+		case SCCP_MSG_TYPE_CREF:
+		case SCCP_MSG_TYPE_DT1:
+		case SCCP_MSG_TYPE_CC:
+		case SCCP_MSG_TYPE_IT:
+			con = patch_sccp_src_ref_to_msc(msg, parsed, bsc);
+			if (con) {
+				con_found = 1;
+				con_bsc = con->bsc;
+				con_filter = con->con_local;
+			}
+			break;
+		case SCCP_MSG_TYPE_RLC:
+			con = patch_sccp_src_ref_to_msc(msg, parsed, bsc);
+			if (con) {
+				con_found = 1;
+				con_bsc = con->bsc;
+				con_filter = con->con_local;
+			}
+			remove_sccp_src_ref(bsc, msg, parsed);
+			break;
+		case SCCP_MSG_TYPE_UDT:
+			/* simply forward everything */
+			con = NULL;
+			break;
+		default:
+			LOGP(DNAT, LOGL_ERROR, "Not forwarding to msc sccp type: 0x%x\n", parsed->sccp_type);
+			con = NULL;
+			goto exit2;
+			break;
+		}
+        } else if (parsed->ipa_proto == NAT_IPAC_PROTO_MGCP) {
+                bsc_mgcp_forward(bsc, msg);
+                goto exit2;
+	} else {
+		LOGP(DNAT, LOGL_ERROR, "Not forwarding unknown stream id: 0x%x\n", parsed->ipa_proto);
+		goto exit2;
+	}
+
+	if (con_found && con_bsc != bsc) {
+		LOGP(DNAT, LOGL_ERROR, "The connection belongs to a different BTS: input: %d con: %d\n",
+		     bsc->cfg->nr, con_bsc->cfg->nr);
+		goto exit2;
+	}
+
+	/* do not forward messages to the MSC */
+	if (con_filter)
+		goto exit2;
+
+	/* send the non-filtered but maybe modified msg */
+	queue_for_msc(nat->msc_con, msg);
+	talloc_free(parsed);
+	return 0;
+
+exit:
+	/* if we filter out the reset send an ack to the BSC */
+	if (parsed->bssap == 0 && parsed->gsm_type == BSS_MAP_MSG_RESET) {
+		send_reset_ack(bsc);
+		send_reset_ack(bsc);
+	} else if (parsed->ipa_proto == IPAC_PROTO_IPACCESS) {
+		/* do we know who is handling this? */
+		if (msg->l2h[0] == IPAC_MSGT_ID_RESP) {
+			struct tlv_parsed tvp;
+			ipaccess_idtag_parse(&tvp,
+					     (unsigned char *) msg->l2h + 2,
+					     msgb_l2len(msg) - 2);
+			if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME))
+				ipaccess_auth_bsc(&tvp, bsc);
+		}
+
+		goto exit2;
+	}
+
+exit2:
+	talloc_free(parsed);
+	msgb_free(msg);
+	return -1;
+
+exit3:
+	/* send a SCCP Connection Refused */
+	bsc_send_con_refuse(bsc, parsed, con_type);
+	talloc_free(parsed);
+	msgb_free(msg);
+	return -1;
+}
+
+static int ipaccess_bsc_read_cb(struct bsc_fd *bfd)
+{
+	int error;
+	struct bsc_connection *bsc = bfd->data;
+	struct msgb *msg = ipaccess_read_msg(bfd, &error);
+	struct ipaccess_head *hh;
+
+	if (!msg) {
+		if (error == 0)
+			LOGP(DNAT, LOGL_ERROR,
+			     "The connection to the BSC Nr: %d was lost. Cleaning it\n",
+			     bsc->cfg ? bsc->cfg->nr : -1);
+		else
+			LOGP(DNAT, LOGL_ERROR,
+			     "Stream error on BSC Nr: %d. Failed to parse ip access message: %d\n",
+			     bsc->cfg ? bsc->cfg->nr : -1, error);
+
+		bsc_close_connection(bsc);
+		return -1;
+	}
+
+
+	LOGP(DNAT, LOGL_DEBUG, "MSG from BSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
+
+	/* Handle messages from the BSC */
+	hh = (struct ipaccess_head *) msg->data;
+
+	/* stop the pong timeout */
+	if (hh->proto == IPAC_PROTO_IPACCESS) {
+		if (msg->l2h[0] == IPAC_MSGT_PONG) {
+			bsc_del_timer(&bsc->pong_timeout);
+			msgb_free(msg);
+			return 0;
+		} else if (msg->l2h[0] == IPAC_MSGT_PING) {
+			send_pong(bsc);
+			msgb_free(msg);
+			return 0;
+		}
+	}
+
+	/* FIXME: Currently no PONG is sent to the BSC */
+	/* FIXME: Currently no ID ACK is sent to the BSC */
+	forward_sccp_to_msc(bsc, msg);
+
+	return 0;
+}
+
+static int ipaccess_bsc_write_cb(struct bsc_fd *bfd, struct msgb *msg)
+{
+	int rc;
+
+	rc = write(bfd->fd, msg->data, msg->len);
+	if (rc != msg->len)
+		LOGP(DNAT, LOGL_ERROR, "Failed to write message to the BSC.\n");
+
+	return rc;
+}
+
+static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
+{
+	struct bsc_connection *bsc;
+	int fd, rc, on;
+	struct sockaddr_in sa;
+	socklen_t sa_len = sizeof(sa);
+
+	if (!(what & BSC_FD_READ))
+		return 0;
+
+	fd = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
+	if (fd < 0) {
+		perror("accept");
+		return fd;
+	}
+
+	/* count the reconnect */
+	counter_inc(nat->stats.bsc.reconn);
+
+	/*
+	 * if we are not connected to a msc... just close the socket
+	 */
+	if (!nat->msc_con->is_connected) {
+		LOGP(DNAT, LOGL_NOTICE, "Disconnecting BSC due lack of MSC connection.\n");
+		close(fd);
+		return 0;
+	}
+
+	on = 1;
+	rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
+	if (rc != 0)
+                LOGP(DNAT, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
+
+	rc = setsockopt(fd, IPPROTO_IP, IP_TOS,
+			&nat->bsc_ip_tos, sizeof(nat->bsc_ip_tos));
+	if (rc != 0)
+		LOGP(DNAT, LOGL_ERROR, "Failed to set IP_TOS: %s\n", strerror(errno));
+
+	/* todo... do something with the connection */
+	/* todo... use GNUtls to see if we want to trust this as a BTS */
+
+	/*
+	 *
+	 */
+	bsc = bsc_connection_alloc(nat);
+	if (!bsc) {
+		LOGP(DNAT, LOGL_ERROR, "Failed to allocate BSC struct.\n");
+		close(fd);
+		return -1;
+	}
+
+	bsc->write_queue.bfd.data = bsc;
+	bsc->write_queue.bfd.fd = fd;
+	bsc->write_queue.read_cb = ipaccess_bsc_read_cb;
+	bsc->write_queue.write_cb = ipaccess_bsc_write_cb;
+	bsc->write_queue.bfd.when = BSC_FD_READ;
+	if (bsc_register_fd(&bsc->write_queue.bfd) < 0) {
+		LOGP(DNAT, LOGL_ERROR, "Failed to register BSC fd.\n");
+		close(fd);
+		talloc_free(bsc);
+		return -2;
+	}
+
+	LOGP(DNAT, LOGL_NOTICE, "BSC connection on %d with IP: %s\n",
+		fd, inet_ntoa(sa.sin_addr));
+	llist_add(&bsc->list_entry, &nat->bsc_connections);
+	send_id_ack(bsc);
+	send_id_req(bsc);
+	send_mgcp_reset(bsc);
+
+	/*
+	 * start the hangup timer
+	 */
+	bsc->id_timeout.data = bsc;
+	bsc->id_timeout.cb = ipaccess_close_bsc;
+	bsc_schedule_timer(&bsc->id_timeout, nat->auth_timeout, 0);
+	return 0;
+}
+
+static int listen_for_bsc(struct bsc_fd *bfd, struct in_addr *in_addr, int port)
+{
+	struct sockaddr_in addr;
+	int ret, on = 1;
+
+	bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	bfd->cb = ipaccess_listen_bsc_cb;
+	bfd->when = BSC_FD_READ;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	addr.sin_addr.s_addr = in_addr->s_addr;
+
+	setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+	ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
+	if (ret < 0) {
+		fprintf(stderr, "Could not bind the BSC socket %s\n",
+			strerror(errno));
+		return -EIO;
+	}
+
+	ret = listen(bfd->fd, 1);
+	if (ret < 0) {
+		perror("listen");
+		return ret;
+	}
+
+	ret = bsc_register_fd(bfd);
+	if (ret < 0) {
+		perror("register_listen_fd");
+		return ret;
+	}
+	return 0;
+}
+
+static void print_usage()
+{
+	printf("Usage: bsc_nat\n");
+}
+
+static void print_help()
+{
+	printf("  Some useful help...\n");
+	printf("  -h --help this text\n");
+	printf("  -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
+	printf("  -s --disable-color\n");
+	printf("  -c --config-file filename The config file to use.\n");
+	printf("  -m --msc=IP. The address of the MSC.\n");
+	printf("  -l --local=IP. The local address of this BSC.\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'},
+			{"msc", 1, 0, 'm'},
+			{"local", 1, 0, 'l'},
+			{0, 0, 0, 0}
+		};
+
+		c = getopt_long(argc, argv, "hd:sTPc:m:l:",
+				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 'm':
+			msc_ip = optarg;
+			break;
+		case 'l':
+			inet_aton(optarg, &local_addr);
+			break;
+		default:
+			/* ignore */
+			break;
+		}
+	}
+}
+
+static void signal_handler(int signal)
+{
+	switch (signal) {
+	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_full(tall_bsc_ctx, stderr);
+		break;
+	default:
+		break;
+	}
+}
+
+static void sccp_close_unconfirmed(void *_data)
+{
+	struct sccp_connections *conn, *tmp1;
+	struct timespec now;
+	clock_gettime(CLOCK_MONOTONIC, &now);
+
+	llist_for_each_entry_safe(conn, tmp1, &nat->sccp_connections, list_entry) {
+		if (conn->has_remote_ref)
+			continue;
+
+		int diff = (now.tv_sec - conn->creation_time.tv_sec) / 60;
+		if (diff < SCCP_CLOSE_TIME_TIMEOUT)
+			continue;
+
+		LOGP(DNAT, LOGL_ERROR, "SCCP connection 0x%x/0x%x was never confirmed.\n",
+		     sccp_src_ref_to_int(&conn->real_ref),
+		     sccp_src_ref_to_int(&conn->patched_ref));
+		sccp_connection_destroy(conn);
+	}
+
+	bsc_schedule_timer(&sccp_close, SCCP_CLOSE_TIME, 0);
+}
+
+extern void *tall_msgb_ctx;
+extern void *tall_ctr_ctx;
+static void talloc_init_ctx()
+{
+	tall_bsc_ctx = talloc_named_const(NULL, 0, "nat");
+	tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb");
+	tall_ctr_ctx = talloc_named_const(tall_bsc_ctx, 0, "counter");
+}
+
+extern enum node_type bsc_vty_go_parent(struct vty *vty);
+
+static struct vty_app_info vty_info = {
+	.name 		= "BSC NAT",
+	.version	= PACKAGE_VERSION,
+	.go_parent_cb	= bsc_vty_go_parent,
+};
+
+int main(int argc, char** argv)
+{
+	talloc_init_ctx();
+
+
+	log_init(&log_info);
+	stderr_target = log_target_create_stderr();
+	log_add_target(stderr_target);
+	log_set_all_filter(stderr_target, 1);
+
+	nat = bsc_nat_alloc();
+	if (!nat) {
+		fprintf(stderr, "Failed to allocate the BSC nat.\n");
+		return -4;
+	}
+
+	nat->mgcp_cfg = talloc_zero(nat, struct mgcp_config);
+	if (!nat->mgcp_cfg) {
+		fprintf(stderr, "Failed to allocate MGCP cfg.\n");
+		return -5;
+	}
+
+	vty_info.copyright = openbsc_copyright;
+	vty_init(&vty_info);
+	logging_vty_add_cmds();
+	bsc_nat_vty_init(nat);
+
+
+	/* parse options */
+	local_addr.s_addr = INADDR_ANY;
+	handle_options(argc, argv);
+
+	/* init vty and parse */
+	telnet_init(tall_bsc_ctx, NULL, 4244);
+	if (mgcp_parse_config(config_file, nat->mgcp_cfg) < 0) {
+		fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
+		return -3;
+	}
+
+	/* over rule the VTY config */
+	if (msc_ip)
+		bsc_nat_set_msc_ip(nat, msc_ip);
+
+	/* seed the PRNG */
+	srand(time(NULL));
+
+	/*
+	 * Setup the MGCP code..
+	 */
+	if (bsc_mgcp_nat_init(nat) != 0)
+		return -4;
+
+	/* connect to the MSC */
+	nat->msc_con = bsc_msc_create(nat->msc_ip, nat->msc_port, 0);
+	if (!nat->msc_con) {
+		fprintf(stderr, "Creating a bsc_msc_connection failed.\n");
+		exit(1);
+	}
+
+	nat->msc_con->connection_loss = msc_connection_was_lost;
+	nat->msc_con->write_queue.read_cb = ipaccess_msc_read_cb;
+	nat->msc_con->write_queue.write_cb = ipaccess_msc_write_cb;;
+	bsc_msc_connect(nat->msc_con);
+
+	/* wait for the BSC */
+	if (listen_for_bsc(&bsc_listen, &local_addr, 5000) < 0) {
+		fprintf(stderr, "Failed to listen for BSC.\n");
+		exit(1);
+	}
+
+	signal(SIGABRT, &signal_handler);
+	signal(SIGUSR1, &signal_handler);
+	signal(SIGPIPE, SIG_IGN);
+
+	/* recycle timer */
+	sccp_close.cb = sccp_close_unconfirmed;
+	sccp_close.data = NULL;
+	bsc_schedule_timer(&sccp_close, SCCP_CLOSE_TIME, 0);
+
+	while (1) {
+		bsc_select_main(0);
+	}
+
+	return 0;
+}
diff --git a/openbsc/src/nat/bsc_nat_utils.c b/openbsc/src/nat/bsc_nat_utils.c
new file mode 100644
index 0000000..eed7f3a
--- /dev/null
+++ b/openbsc/src/nat/bsc_nat_utils.c
@@ -0,0 +1,492 @@
+
+/* BSC Multiplexer/NAT Utilities */
+
+/*
+ * (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_nat.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/debug.h>
+#include <openbsc/ipaccess.h>
+
+#include <osmocore/linuxlist.h>
+#include <osmocore/talloc.h>
+#include <osmocore/gsm0808.h>
+
+#include <osmocore/protocol/gsm_08_08.h>
+
+#include <sccp/sccp.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+struct bsc_nat *bsc_nat_alloc(void)
+{
+	struct bsc_nat *nat = talloc_zero(tall_bsc_ctx, struct bsc_nat);
+	if (!nat)
+		return NULL;
+
+	INIT_LLIST_HEAD(&nat->sccp_connections);
+	INIT_LLIST_HEAD(&nat->bsc_connections);
+	INIT_LLIST_HEAD(&nat->bsc_configs);
+	INIT_LLIST_HEAD(&nat->access_lists);
+
+	nat->stats.sccp.conn = counter_alloc("nat.sccp.conn");
+	nat->stats.sccp.calls = counter_alloc("nat.sccp.calls");
+	nat->stats.bsc.reconn = counter_alloc("nat.bsc.conn");
+	nat->stats.bsc.auth_fail = counter_alloc("nat.bsc.auth_fail");
+	nat->stats.msc.reconn = counter_alloc("nat.msc.conn");
+	nat->msc_ip = talloc_strdup(nat, "127.0.0.1");
+	nat->msc_port = 5000;
+	nat->auth_timeout = 2;
+	nat->ping_timeout = 20;
+	nat->pong_timeout = 5;
+	return nat;
+}
+
+void bsc_nat_set_msc_ip(struct bsc_nat *nat, const char *ip)
+{
+	if (nat->msc_ip)
+		talloc_free(nat->msc_ip);
+	nat->msc_ip = talloc_strdup(nat, ip);
+}
+
+struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat)
+{
+	struct bsc_connection *con = talloc_zero(nat, struct bsc_connection);
+	if (!con)
+		return NULL;
+
+	con->nat = nat;
+	write_queue_init(&con->write_queue, 100);
+	return con;
+}
+
+struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token, unsigned int lac)
+{
+	struct bsc_config *conf = talloc_zero(nat, struct bsc_config);
+	if (!conf)
+		return NULL;
+
+	conf->token = talloc_strdup(conf, token);
+	conf->lac = lac;
+	conf->nr = nat->num_bsc;
+	conf->nat = nat;
+
+	llist_add_tail(&conf->entry, &nat->bsc_configs);
+	++nat->num_bsc;
+
+	conf->stats.sccp.conn = counter_alloc("nat.bsc.sccp.conn");
+	conf->stats.sccp.calls = counter_alloc("nat.bsc.sccp.calls");
+	conf->stats.net.reconn = counter_alloc("nat.bsc.net.reconnects");
+
+	return conf;
+}
+
+void sccp_connection_destroy(struct sccp_connections *conn)
+{
+	LOGP(DNAT, LOGL_DEBUG, "Destroy 0x%x <-> 0x%x mapping for con %p\n",
+	     sccp_src_ref_to_int(&conn->real_ref),
+	     sccp_src_ref_to_int(&conn->patched_ref), conn->bsc);
+	bsc_mgcp_dlcx(conn);
+	llist_del(&conn->list_entry);
+	talloc_free(conn);
+}
+
+struct bsc_connection *bsc_nat_find_bsc(struct bsc_nat *nat, struct msgb *msg, int *lac_out)
+{
+	struct bsc_connection *bsc;
+	int data_length;
+	const u_int8_t *data;
+	struct tlv_parsed tp;
+	int i = 0;
+
+	*lac_out = -1;
+
+	if (!msg->l3h || msgb_l3len(msg) < 3) {
+		LOGP(DNAT, LOGL_ERROR, "Paging message is too short.\n");
+		return NULL;
+	}
+
+	tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0);
+	if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST)) {
+		LOGP(DNAT, LOGL_ERROR, "No CellIdentifier List inside paging msg.\n");
+		return NULL;
+	}
+
+	data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
+	data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
+
+	/* No need to try a different BSS */
+	if (data[0] == CELL_IDENT_BSS) {
+		return NULL;
+	} else if (data[0] != CELL_IDENT_LAC) {
+		LOGP(DNAT, LOGL_ERROR, "Unhandled cell ident discrminator: %d\n", data[0]);
+		return NULL;
+	}
+
+	/* Currently we only handle one BSC */
+	for (i = 1; i < data_length - 1; i += 2) {
+		unsigned int _lac = ntohs(*(unsigned int *) &data[i]);
+		*lac_out = _lac;
+		llist_for_each_entry(bsc, &nat->bsc_connections, list_entry) {
+			if (!bsc->cfg)
+				continue;
+			if (!bsc->authenticated || _lac != bsc->cfg->lac)
+				continue;
+
+			return bsc;
+		}
+	}
+
+	return NULL;
+}
+
+int bsc_write_mgcp(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length)
+{
+	struct msgb *msg;
+
+	if (length > 4096 - 128) {
+		LOGP(DINP, LOGL_ERROR, "Can not send message of that size.\n");
+		return -1;
+	}
+
+	msg = msgb_alloc_headroom(4096, 128, "to-bsc");
+	if (!msg) {
+		LOGP(DINP, LOGL_ERROR, "Failed to allocate memory for BSC msg.\n");
+		return -1;
+	}
+
+	/* copy the data */
+	msg->l3h = msgb_put(msg, length);
+	memcpy(msg->l3h, data, length);
+
+        return bsc_write(bsc, msg, NAT_IPAC_PROTO_MGCP);
+}
+
+int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int proto)
+{
+	/* prepend the header */
+	ipaccess_prepend_header(msg, proto);
+
+	if (write_queue_enqueue(&bsc->write_queue, msg) != 0) {
+		LOGP(DINP, LOGL_ERROR, "Failed to enqueue the write.\n");
+		msgb_free(msg);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int lst_check_allow(struct bsc_nat_acc_lst *lst, const char *mi_string)
+{
+	struct bsc_nat_acc_lst_entry *entry;
+
+	llist_for_each_entry(entry, &lst->fltr_list, list) {
+		if (!entry->imsi_allow)
+			continue;
+		if (regexec(&entry->imsi_allow_re, mi_string, 0, NULL, 0) == 0)
+			return 0;
+	}
+
+	return 1;
+}
+
+static int lst_check_deny(struct bsc_nat_acc_lst *lst, const char *mi_string)
+{
+	struct bsc_nat_acc_lst_entry *entry;
+
+	llist_for_each_entry(entry, &lst->fltr_list, list) {
+		if (!entry->imsi_deny)
+			continue;
+		if (regexec(&entry->imsi_deny_re, mi_string, 0, NULL, 0) == 0)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* apply white/black list */
+static int auth_imsi(struct bsc_connection *bsc, const char *mi_string)
+{
+	/*
+	 * Now apply blacklist/whitelist of the BSC and the NAT.
+	 * 1.) Reject if the IMSI is not allowed at the BSC
+	 * 2.) Allow directly if the IMSI is allowed at the BSC
+	 * 3.) Reject if the IMSI not allowed at the global level.
+	 * 4.) Allow directly if the IMSI is allowed at the global level
+	 */
+	struct bsc_nat_acc_lst *nat_lst = NULL;
+	struct bsc_nat_acc_lst *bsc_lst = NULL;
+
+	bsc_lst = bsc_nat_acc_lst_find(bsc->nat, bsc->cfg->acc_lst_name);
+	nat_lst = bsc_nat_acc_lst_find(bsc->nat, bsc->nat->acc_lst_name);
+
+
+	if (bsc_lst) {
+		/* 1. BSC deny */
+		if (lst_check_deny(bsc_lst, mi_string) == 0) {
+			LOGP(DNAT, LOGL_ERROR,
+			     "Filtering %s by imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
+			return -2;
+		}
+
+		/* 2. BSC allow */
+		if (lst_check_allow(bsc_lst, mi_string) == 0)
+			return 0;
+	}
+
+	/* 3. NAT deny */
+	if (nat_lst) {
+		if (lst_check_deny(nat_lst, mi_string) == 0) {
+			LOGP(DNAT, LOGL_ERROR,
+			     "Filtering %s by nat imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
+			return -3;
+		}
+	}
+
+	return 0;
+}
+
+static int _cr_check_loc_upd(struct bsc_connection *bsc, uint8_t *data, unsigned int length)
+{
+	u_int8_t mi_type;
+	struct gsm48_loc_upd_req *lu;
+	char mi_string[GSM48_MI_SIZE];
+
+	if (length < sizeof(*lu)) {
+		LOGP(DNAT, LOGL_ERROR,
+		     "LU does not fit. Length is %d \n", length);
+		return -1;
+	}
+
+	lu = (struct gsm48_loc_upd_req *) data;
+	mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
+
+	/*
+	 * We can only deal with the IMSI. This will fail for a phone that
+	 * will send the TMSI of a previous network to us.
+	 */
+	if (mi_type != GSM_MI_TYPE_IMSI)
+		return 0;
+
+	gsm48_mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
+	return auth_imsi(bsc, mi_string);
+}
+
+static int _cr_check_cm_serv_req(struct bsc_connection *bsc, uint8_t *data, unsigned int length)
+{
+	static const uint32_t classmark_offset =
+				offsetof(struct gsm48_service_request, classmark);
+
+	char mi_string[GSM48_MI_SIZE];
+	uint8_t mi_type;
+	int rc;
+	struct gsm48_service_request *req;
+
+	/* unfortunately in Phase1 the classmark2 length is variable */
+
+	if (length < sizeof(*req)) {
+		LOGP(DNAT, LOGL_ERROR,
+		     "CM Serv Req does not fit. Length is %d\n", length);
+		return -1;
+	}
+
+	req = (struct gsm48_service_request *) data;
+	rc = gsm48_extract_mi((uint8_t *) &req->classmark,
+			      length - classmark_offset, mi_string, &mi_type);
+	if (rc < 0) {
+		LOGP(DNAT, LOGL_ERROR, "Failed to parse the classmark2/mi. error: %d\n", rc);
+		return -1;
+	}
+
+	/* we have to let the TMSI or such pass */
+	if (mi_type != GSM_MI_TYPE_IMSI)
+		return 0;
+
+	return auth_imsi(bsc, mi_string);
+}
+
+static int _cr_check_pag_resp(struct bsc_connection *bsc, uint8_t *data, unsigned int length)
+{
+	struct gsm48_pag_resp *resp;
+	char mi_string[GSM48_MI_SIZE];
+	u_int8_t mi_type;
+
+	if (length < sizeof(*resp)) {
+		LOGP(DNAT, LOGL_ERROR, "PAG RESP does not fit. Length was %d.\n", length);
+		return -1;
+	}
+
+	resp = (struct gsm48_pag_resp *) data;
+	if (gsm48_paging_extract_mi(resp, length, mi_string, &mi_type) < 0) {
+		LOGP(DNAT, LOGL_ERROR, "Failed to extract the MI.\n");
+		return -1;
+	}
+
+	/* we need to let it pass for now */
+	if (mi_type != GSM_MI_TYPE_IMSI)
+		return 0;
+
+	return auth_imsi(bsc, mi_string);
+}
+
+/* Filter out CR data... */
+int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed, int *con_type)
+{
+	struct tlv_parsed tp;
+	struct gsm48_hdr *hdr48;
+	int hdr48_len;
+	int len;
+
+	*con_type = NAT_CON_TYPE_NONE;
+
+	if (parsed->gsm_type != BSS_MAP_MSG_COMPLETE_LAYER_3) {
+		LOGP(DNAT, LOGL_ERROR,
+		     "Rejecting CR message due wrong GSM Type %d\n", parsed->gsm_type);
+		return -1;
+	}
+
+	/* the parsed has had some basic l3 length check */
+	len = msg->l3h[1];
+	if (msgb_l3len(msg) - 3 < len) {
+		LOGP(DNAT, LOGL_ERROR,
+		     "The CR Data has not enough space...\n");
+		return -1;
+	}
+
+	msg->l4h = &msg->l3h[3];
+	len -= 1;
+
+	tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h, len, 0, 0);
+
+	if (!TLVP_PRESENT(&tp, GSM0808_IE_LAYER_3_INFORMATION)) {
+		LOGP(DNAT, LOGL_ERROR, "CR Data does not contain layer3 information.\n");
+		return -1;
+	}
+
+	hdr48_len = TLVP_LEN(&tp, GSM0808_IE_LAYER_3_INFORMATION);
+
+	if (hdr48_len < sizeof(*hdr48)) {
+		LOGP(DNAT, LOGL_ERROR, "GSM48 header does not fit.\n");
+		return -1;
+	}
+
+	hdr48 = (struct gsm48_hdr *) TLVP_VAL(&tp, GSM0808_IE_LAYER_3_INFORMATION);
+
+	if (hdr48->proto_discr == GSM48_PDISC_MM &&
+	    hdr48->msg_type == GSM48_MT_MM_LOC_UPD_REQUEST) {
+		*con_type = NAT_CON_TYPE_LU;
+		return _cr_check_loc_upd(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48));
+	} else if (hdr48->proto_discr == GSM48_PDISC_MM &&
+		  hdr48->msg_type == GSM48_MT_MM_CM_SERV_REQ) {
+		*con_type = NAT_CON_TYPE_CM_SERV_REQ;
+		return _cr_check_cm_serv_req(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48));
+	} else if (hdr48->proto_discr == GSM48_PDISC_RR &&
+		   hdr48->msg_type == GSM48_MT_RR_PAG_RESP) {
+		*con_type = NAT_CON_TYPE_PAG_RESP;
+		return _cr_check_pag_resp(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48));
+	} else {
+		/* We only want to filter the above, let other things pass */
+		*con_type = NAT_CON_TYPE_OTHER;
+		return 0;
+	}
+}
+
+void bsc_parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv)
+{
+	if (*imsi) {
+		talloc_free(*imsi);
+		*imsi = NULL;
+	}
+	regfree(reg);
+
+	if (argc > 0) {
+		*imsi = talloc_strdup(ctx, argv[0]);
+		regcomp(reg, argv[0], 0);
+	}
+}
+
+static const char *con_types [] = {
+	[NAT_CON_TYPE_NONE] = "n/a",
+	[NAT_CON_TYPE_LU] = "Location Update",
+	[NAT_CON_TYPE_CM_SERV_REQ] = "CM Serv Req",
+	[NAT_CON_TYPE_PAG_RESP] = "Paging Response",
+	[NAT_CON_TYPE_LOCAL_REJECT] = "Local Reject",
+	[NAT_CON_TYPE_OTHER] = "Other",
+};
+
+const char *bsc_con_type_to_string(int type)
+{
+	return con_types[type];
+}
+
+struct bsc_nat_acc_lst *bsc_nat_acc_lst_find(struct bsc_nat *nat, const char *name)
+{
+	struct bsc_nat_acc_lst *lst;
+
+	if (!name)
+		return NULL;
+
+	llist_for_each_entry(lst, &nat->access_lists, list)
+		if (strcmp(lst->name, name) == 0)
+			return lst;
+
+	return NULL;
+}
+
+struct bsc_nat_acc_lst *bsc_nat_acc_lst_get(struct bsc_nat *nat, const char *name)
+{
+	struct bsc_nat_acc_lst *lst;
+
+	lst = bsc_nat_acc_lst_find(nat, name);
+	if (lst)
+		return lst;
+
+	lst = talloc_zero(nat, struct bsc_nat_acc_lst);
+	if (!lst) {
+		LOGP(DNAT, LOGL_ERROR, "Failed to allocate access list");
+		return NULL;
+	}
+
+	INIT_LLIST_HEAD(&lst->fltr_list);
+	lst->name = talloc_strdup(lst, name);
+	llist_add_tail(&lst->list, &nat->access_lists);
+	return lst;
+}
+
+void bsc_nat_acc_lst_delete(struct bsc_nat_acc_lst *lst)
+{
+	llist_del(&lst->list);
+	talloc_free(lst);
+}
+
+struct bsc_nat_acc_lst_entry *bsc_nat_acc_lst_entry_create(struct bsc_nat_acc_lst *lst)
+{
+	struct bsc_nat_acc_lst_entry *entry;
+
+	entry = talloc_zero(lst, struct bsc_nat_acc_lst_entry);
+	if (!entry)
+		return NULL;
+
+	llist_add_tail(&entry->list, &lst->fltr_list);
+	return entry;
+}
\ No newline at end of file
diff --git a/openbsc/src/nat/bsc_nat_vty.c b/openbsc/src/nat/bsc_nat_vty.c
new file mode 100644
index 0000000..ea168a4
--- /dev/null
+++ b/openbsc/src/nat/bsc_nat_vty.c
@@ -0,0 +1,557 @@
+/* OpenBSC NAT interface to quagga VTY */
+/* (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 <openbsc/vty.h>
+#include <openbsc/bsc_nat.h>
+#include <openbsc/bsc_msc.h>
+#include <openbsc/gsm_04_08.h>
+#include <openbsc/mgcp.h>
+#include <openbsc/vty.h>
+
+#include <osmocore/talloc.h>
+
+#include <sccp/sccp.h>
+
+#include <stdlib.h>
+
+static struct bsc_nat *_nat;
+
+static struct cmd_node nat_node = {
+	NAT_NODE,
+	"%s(nat)#",
+	1,
+};
+
+static struct cmd_node bsc_node = {
+	BSC_NODE,
+	"%s(bsc)#",
+	1,
+};
+
+static void write_acc_lst(struct vty *vty, struct bsc_nat_acc_lst *lst)
+{
+	struct bsc_nat_acc_lst_entry *entry;
+
+	llist_for_each_entry(entry, &lst->fltr_list, list) {
+		if (entry->imsi_allow)
+			vty_out(vty, " access-list %s imsi-allow %s%s",
+				lst->name, entry->imsi_allow, VTY_NEWLINE);
+		if (entry->imsi_deny)
+			vty_out(vty, " access-list %s imsi-deny %s%s",
+				lst->name, entry->imsi_deny, VTY_NEWLINE);
+	}
+}
+
+static int config_write_nat(struct vty *vty)
+{
+	struct bsc_nat_acc_lst *lst;
+
+	vty_out(vty, "nat%s", VTY_NEWLINE);
+	vty_out(vty, " msc ip %s%s", _nat->msc_ip, VTY_NEWLINE);
+	vty_out(vty, " msc port %d%s", _nat->msc_port, VTY_NEWLINE);
+	vty_out(vty, " timeout auth %d%s", _nat->auth_timeout, VTY_NEWLINE);
+	vty_out(vty, " timeout ping %d%s", _nat->ping_timeout, VTY_NEWLINE);
+	vty_out(vty, " timeout pong %d%s", _nat->pong_timeout, VTY_NEWLINE);
+	if (_nat->token)
+		vty_out(vty, " token %s%s", _nat->token, VTY_NEWLINE);
+	vty_out(vty, " ip-tos %d%s", _nat->bsc_ip_tos, VTY_NEWLINE);
+	if (_nat->acc_lst_name)
+		vty_out(vty, " access-list-name %s%s", _nat->acc_lst_name, VTY_NEWLINE);
+
+	llist_for_each_entry(lst, &_nat->access_lists, list) {
+		write_acc_lst(vty, lst);
+	}
+
+	return CMD_SUCCESS;
+}
+
+static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc)
+{
+	vty_out(vty, " bsc %u%s", bsc->nr, VTY_NEWLINE);
+	vty_out(vty, "  token %s%s", bsc->token, VTY_NEWLINE);
+	vty_out(vty, "  location_area_code %u%s", bsc->lac, VTY_NEWLINE);
+	vty_out(vty, "  paging forbidden %d%s", bsc->forbid_paging, VTY_NEWLINE);
+	if (bsc->description)
+		vty_out(vty, "  description %s%s", bsc->description, VTY_NEWLINE);
+	if (bsc->acc_lst_name)
+		vty_out(vty, "  access-list-name %s%s", bsc->acc_lst_name, VTY_NEWLINE);
+}
+
+static int config_write_bsc(struct vty *vty)
+{
+	struct bsc_config *bsc;
+
+	llist_for_each_entry(bsc, &_nat->bsc_configs, entry)
+		config_write_bsc_single(vty, bsc);
+	return CMD_SUCCESS;
+}
+
+
+DEFUN(show_sccp, show_sccp_cmd, "show sccp connections",
+      SHOW_STR "Display information about current SCCP connections")
+{
+	struct sccp_connections *con;
+	vty_out(vty, "Listing all opening SCCP connections%s", VTY_NEWLINE);
+
+	llist_for_each_entry(con, &_nat->sccp_connections, list_entry) {
+		vty_out(vty, "For BSC Nr: %d lac: %d; BSC ref: 0x%x; MUX ref: 0x%x; Network has ref: %d ref: 0x%x MSC/BSC mux: 0x%x/0x%x type: %s%s",
+			con->bsc->cfg ? con->bsc->cfg->nr : -1,
+			con->bsc->cfg ? con->bsc->cfg->lac : -1,
+			sccp_src_ref_to_int(&con->real_ref),
+			sccp_src_ref_to_int(&con->patched_ref),
+			con->has_remote_ref,
+			sccp_src_ref_to_int(&con->remote_ref),
+			con->msc_timeslot, con->bsc_timeslot,
+			bsc_con_type_to_string(con->con_type),
+			VTY_NEWLINE);
+	}
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(show_bsc, show_bsc_cmd, "show bsc connections",
+      SHOW_STR "Display information about current BSCs")
+{
+	struct bsc_connection *con;
+	struct sockaddr_in sock;
+	socklen_t len = sizeof(sock);
+
+	llist_for_each_entry(con, &_nat->bsc_connections, list_entry) {
+		getpeername(con->write_queue.bfd.fd, (struct sockaddr *) &sock, &len);
+		vty_out(vty, "BSC nr: %d lac: %d auth: %d fd: %d peername: %s%s",
+			con->cfg ? con->cfg->nr : -1,
+			con->cfg ? con->cfg->lac : -1,
+			con->authenticated, con->write_queue.bfd.fd,
+			inet_ntoa(sock.sin_addr), VTY_NEWLINE);
+	}
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(show_bsc_cfg, show_bsc_cfg_cmd, "show bsc config",
+      SHOW_STR "Display information about known BSC configs")
+{
+	struct bsc_config *conf;
+	llist_for_each_entry(conf, &_nat->bsc_configs, entry) {
+		vty_out(vty, "BSC token: '%s' lac: %u nr: %u%s",
+			conf->token, conf->lac, conf->nr, VTY_NEWLINE);
+		if (conf->acc_lst_name)
+			vty_out(vty, " access-list: %s%s",
+				conf->acc_lst_name, VTY_NEWLINE);
+		vty_out(vty, " paging forbidden: %d%s",
+			conf->forbid_paging, VTY_NEWLINE);
+		if (conf->description)
+			vty_out(vty, " description: %s%s", conf->description, VTY_NEWLINE);
+		else
+			vty_out(vty, " No description.%s", VTY_NEWLINE);
+
+	}
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(show_stats,
+      show_stats_cmd,
+      "show statistics [NR]",
+	SHOW_STR "Display network statistics")
+{
+	struct bsc_config *conf;
+
+	int nr = -1;
+
+	if (argc == 1)
+		nr = atoi(argv[0]);
+
+	vty_out(vty, "NAT statistics%s", VTY_NEWLINE);
+	vty_out(vty, " SCCP Connections %lu total, %lu calls%s",
+		counter_get(_nat->stats.sccp.conn),
+		counter_get(_nat->stats.sccp.calls), VTY_NEWLINE);
+	vty_out(vty, " MSC Connections %lu%s",
+		counter_get(_nat->stats.msc.reconn), VTY_NEWLINE);
+	vty_out(vty, " BSC Connections %lu total, %lu auth failed.%s",
+		counter_get(_nat->stats.bsc.reconn),
+		counter_get(_nat->stats.bsc.auth_fail), VTY_NEWLINE);
+
+	llist_for_each_entry(conf, &_nat->bsc_configs, entry) {
+		if (argc == 1 && nr != conf->nr)
+			continue;
+
+		vty_out(vty, " BSC lac: %d nr: %d%s",
+			conf->lac, conf->nr, VTY_NEWLINE);
+		vty_out(vty, "   SCCP Connnections %lu total, %lu calls%s",
+			counter_get(conf->stats.sccp.conn),
+			counter_get(conf->stats.sccp.calls), VTY_NEWLINE);
+		vty_out(vty, "   BSC Connections %lu total%s",
+			counter_get(conf->stats.net.reconn), VTY_NEWLINE);
+	}
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(show_msc,
+      show_msc_cmd,
+      "show msc connection",
+      SHOW_STR "Show the status of the MSC connection.")
+{
+	if (!_nat->msc_con) {
+		vty_out(vty, "The MSC is not yet configured.\n");
+		return CMD_WARNING;
+	}
+
+	vty_out(vty, "MSC on %s:%d is connected: %d%s\n",
+		_nat->msc_con->ip, _nat->msc_con->port,
+		_nat->msc_con->is_connected, VTY_NEWLINE);
+	return CMD_SUCCESS;
+}
+
+DEFUN(close_bsc,
+      close_bsc_cmd,
+      "close bsc connection BSC_NR",
+      "Close the connection with the BSC identified by the config number.")
+{
+	struct bsc_connection *bsc;
+	int bsc_nr = atoi(argv[0]);
+
+	llist_for_each_entry(bsc, &_nat->bsc_connections, list_entry) {
+		if (!bsc->cfg || bsc->cfg->nr != bsc_nr)
+			continue;
+		bsc_close_connection(bsc);
+		break;
+	}
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nat, cfg_nat_cmd, "nat", "Configute the NAT")
+{
+	vty->index = _nat;
+	vty->node = NAT_NODE;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nat_msc_ip,
+      cfg_nat_msc_ip_cmd,
+      "msc ip A.B.C.D",
+      "Set the IP address of the MSC.")
+{
+	bsc_nat_set_msc_ip(_nat, argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nat_msc_port,
+      cfg_nat_msc_port_cmd,
+      "msc port <1-65500>",
+      "Set the port of the MSC.")
+{
+	_nat->msc_port = atoi(argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nat_auth_time,
+      cfg_nat_auth_time_cmd,
+      "timeout auth <1-256>",
+      "The time to wait for an auth response.")
+{
+	_nat->auth_timeout = atoi(argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nat_ping_time,
+      cfg_nat_ping_time_cmd,
+      "timeout ping NR",
+      "Send a ping every NR seconds. Negative to disable.")
+{
+	_nat->ping_timeout = atoi(argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nat_pong_time,
+      cfg_nat_pong_time_cmd,
+      "timeout pong NR",
+      "Wait NR seconds for the PONG response. Should be smaller than ping.")
+{
+	_nat->pong_timeout = atoi(argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nat_token, cfg_nat_token_cmd,
+      "token TOKEN",
+      "Set a token for the NAT")
+{
+	if (_nat->token)
+		talloc_free(_nat->token);
+	_nat->token = talloc_strdup(_nat, argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nat_bsc_ip_tos, cfg_nat_bsc_ip_tos_cmd,
+      "ip-tos <0-255>",
+      "Set the IP_TOS for the BSCs to use\n" "Set the IP_TOS attribute")
+{
+	_nat->bsc_ip_tos = atoi(argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nat_acc_lst_name,
+      cfg_nat_acc_lst_name_cmd,
+      "access-list-name NAME",
+      "Set the name of the access list to use.\n"
+      "The name of the to be used access list.")
+{
+	if (_nat->acc_lst_name)
+		talloc_free(_nat->acc_lst_name);
+	_nat->acc_lst_name = talloc_strdup(_nat, argv[0]);
+	return CMD_SUCCESS;
+}
+
+/* per BSC configuration */
+DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", "Select a BSC to configure")
+{
+	int bsc_nr = atoi(argv[0]);
+	struct bsc_config *bsc;
+
+	if (bsc_nr > _nat->num_bsc) {
+		vty_out(vty, "%% The next unused BSC number is %u%s",
+			_nat->num_bsc, VTY_NEWLINE);
+		return CMD_WARNING;
+	} else if (bsc_nr == _nat->num_bsc) {
+		/* allocate a new one */
+		bsc = bsc_config_alloc(_nat, "unknown", 0);
+	} else
+		bsc = bsc_config_num(_nat, bsc_nr);
+
+	if (!bsc)
+		return CMD_WARNING;
+
+	vty->index = bsc;
+	vty->node = BSC_NODE;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bsc_token, cfg_bsc_token_cmd, "token TOKEN", "Set the token")
+{
+	struct bsc_config *conf = vty->index;
+
+	if (conf->token)
+	    talloc_free(conf->token);
+	conf->token = talloc_strdup(conf, argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bsc_lac, cfg_bsc_lac_cmd, "location_area_code <0-65535>",
+      "Set the Location Area Code (LAC) of this BSC")
+{
+	struct bsc_config *tmp;
+	struct bsc_config *conf = vty->index;
+
+	int lac = atoi(argv[0]);
+
+	if (lac == GSM_LAC_RESERVED_DETACHED || lac == GSM_LAC_RESERVED_ALL_BTS) {
+		vty_out(vty, "%% LAC %d is reserved by GSM 04.08%s",
+			lac, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	/* verify that the LACs are unique */
+	llist_for_each_entry(tmp, &_nat->bsc_configs, entry) {
+		if (tmp->lac == lac) {
+			vty_out(vty, "%% LAC %d is already used.%s", lac, VTY_NEWLINE);
+			return CMD_ERR_INCOMPLETE;
+		}
+	}
+
+	conf->lac = lac;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_lst_imsi_allow,
+      cfg_lst_imsi_allow_cmd,
+      "access-list NAME imsi-allow [REGEXP]",
+      "Allow IMSIs matching the REGEXP\n"
+      "The name of the access-list\n"
+      "The regexp of allowed IMSIs\n")
+{
+	struct bsc_nat_acc_lst *acc;
+	struct bsc_nat_acc_lst_entry *entry;
+
+	acc = bsc_nat_acc_lst_get(_nat, argv[0]);
+	if (!acc)
+		return CMD_WARNING;
+
+	entry = bsc_nat_acc_lst_entry_create(acc);
+	if (!entry)
+		return CMD_WARNING;
+
+	bsc_parse_reg(acc, &entry->imsi_allow_re, &entry->imsi_allow, argc - 1, &argv[1]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_lst_imsi_deny,
+      cfg_lst_imsi_deny_cmd,
+      "access-list NAME imsi-deny [REGEXP]",
+      "Allow IMSIs matching the REGEXP\n"
+      "The name of the access-list\n"
+      "The regexp of to be denied IMSIs\n")
+{
+	struct bsc_nat_acc_lst *acc;
+	struct bsc_nat_acc_lst_entry *entry;
+
+	acc = bsc_nat_acc_lst_get(_nat, argv[0]);
+	if (!acc)
+		return CMD_WARNING;
+
+	entry = bsc_nat_acc_lst_entry_create(acc);
+	if (!entry)
+		return CMD_WARNING;
+
+	bsc_parse_reg(acc, &entry->imsi_deny_re, &entry->imsi_deny, argc - 1, &argv[1]);
+	return CMD_SUCCESS;
+}
+
+/* naming to follow Zebra... */
+DEFUN(cfg_lst_no,
+      cfg_lst_no_cmd,
+      "no access-list NAME",
+      NO_STR "Remove an access-list by name\n"
+      "The access-list to remove\n")
+{
+	struct bsc_nat_acc_lst *acc;
+	acc = bsc_nat_acc_lst_find(_nat, argv[0]);
+	if (!acc)
+		return CMD_WARNING;
+
+	bsc_nat_acc_lst_delete(acc);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bsc_acc_lst_name,
+      cfg_bsc_acc_lst_name_cmd,
+      "access-list-name NAME",
+      "Set the name of the access list to use.\n"
+      "The name of the to be used access list.")
+{
+	struct bsc_config *conf = vty->index;
+
+	if (conf->acc_lst_name)
+		talloc_free(conf->acc_lst_name);
+	conf->acc_lst_name = talloc_strdup(conf, argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bsc_paging,
+      cfg_bsc_paging_cmd,
+      "paging forbidden (0|1)",
+      "Forbid sending PAGING REQUESTS to the BSC.")
+{
+	struct bsc_config *conf = vty->index;
+
+	if (strcmp("1", argv[0]) == 0)
+		conf->forbid_paging = 1;
+	else
+		conf->forbid_paging = 0;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bsc_desc,
+      cfg_bsc_desc_cmd,
+      "description DESC",
+      "Provide a description for the given BSC.")
+{
+	struct bsc_config *conf = vty->index;
+
+	if (conf->description)
+		talloc_free(conf->description);
+	conf->description = talloc_strdup(conf, argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(test_regex, test_regex_cmd,
+      "test regex PATTERN STRING",
+      "Check if the string is matching the current pattern.")
+{
+	regex_t reg;
+	char *str = NULL;
+
+	memset(&reg, 0, sizeof(reg));
+	bsc_parse_reg(_nat, &reg, &str, 1, argv);
+
+	vty_out(vty, "String matches allow pattern: %d%s",
+		regexec(&reg, argv[1], 0, NULL, 0) == 0, VTY_NEWLINE);
+
+	talloc_free(str);
+	regfree(&reg);
+	return CMD_SUCCESS;
+}
+
+int bsc_nat_vty_init(struct bsc_nat *nat)
+{
+	_nat = nat;
+
+	/* show commands */
+	install_element_ve(&show_sccp_cmd);
+	install_element_ve(&show_bsc_cmd);
+	install_element_ve(&show_bsc_cfg_cmd);
+	install_element_ve(&show_stats_cmd);
+	install_element_ve(&close_bsc_cmd);
+	install_element_ve(&show_msc_cmd);
+	install_element_ve(&test_regex_cmd);
+
+	/* nat group */
+	install_element(CONFIG_NODE, &cfg_nat_cmd);
+	install_node(&nat_node, config_write_nat);
+	install_default(NAT_NODE);
+	install_element(NAT_NODE, &cfg_nat_msc_ip_cmd);
+	install_element(NAT_NODE, &cfg_nat_msc_port_cmd);
+	install_element(NAT_NODE, &cfg_nat_auth_time_cmd);
+	install_element(NAT_NODE, &cfg_nat_ping_time_cmd);
+	install_element(NAT_NODE, &cfg_nat_pong_time_cmd);
+	install_element(NAT_NODE, &cfg_nat_token_cmd);
+	install_element(NAT_NODE, &cfg_nat_bsc_ip_tos_cmd);
+	install_element(NAT_NODE, &cfg_nat_acc_lst_name_cmd);
+
+	/* access-list */
+	install_element(NAT_NODE, &cfg_lst_imsi_allow_cmd);
+	install_element(NAT_NODE, &cfg_lst_imsi_deny_cmd);
+	install_element(NAT_NODE, &cfg_lst_no_cmd);
+
+	/* BSC subgroups */
+	install_element(NAT_NODE, &cfg_bsc_cmd);
+	install_node(&bsc_node, config_write_bsc);
+	install_default(BSC_NODE);
+	install_element(BSC_NODE, &cfg_bsc_token_cmd);
+	install_element(BSC_NODE, &cfg_bsc_lac_cmd);
+	install_element(BSC_NODE, &cfg_bsc_paging_cmd);
+	install_element(BSC_NODE, &cfg_bsc_desc_cmd);
+	install_element(BSC_NODE, &cfg_bsc_acc_lst_name_cmd);
+
+	mgcp_vty_init();
+
+	return 0;
+}
+
+
+/* called by the telnet interface... we have our own init above */
+void bsc_vty_init()
+{}
diff --git a/openbsc/src/nat/bsc_sccp.c b/openbsc/src/nat/bsc_sccp.c
new file mode 100644
index 0000000..94b332a
--- /dev/null
+++ b/openbsc/src/nat/bsc_sccp.c
@@ -0,0 +1,236 @@
+/* SCCP patching and handling routines */
+/*
+ * (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/debug.h>
+#include <openbsc/bsc_nat.h>
+
+#include <sccp/sccp.h>
+
+#include <osmocore/talloc.h>
+
+#include <string.h>
+#include <time.h>
+
+static int equal(struct sccp_source_reference *ref1, struct sccp_source_reference *ref2)
+{
+	return memcmp(ref1, ref2, sizeof(*ref1)) == 0;
+}
+
+/*
+ * SCCP patching below
+ */
+
+/* check if we are using this ref for patched already */
+static int sccp_ref_is_free(struct sccp_source_reference *ref, struct bsc_nat *nat)
+{
+	struct sccp_connections *conn;
+
+	llist_for_each_entry(conn, &nat->sccp_connections, list_entry) {
+		if (memcmp(ref, &conn->patched_ref, sizeof(*ref)) == 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* copied from sccp.c */
+static int assign_src_local_reference(struct sccp_source_reference *ref, struct bsc_nat *nat)
+{
+	static u_int32_t last_ref = 0x50000;
+	int wrapped = 0;
+
+	do {
+		struct sccp_source_reference reference;
+		reference.octet1 = (last_ref >>  0) & 0xff;
+		reference.octet2 = (last_ref >>  8) & 0xff;
+		reference.octet3 = (last_ref >> 16) & 0xff;
+
+		++last_ref;
+		/* do not use the reversed word and wrap around */
+		if ((last_ref & 0x00FFFFFF) == 0x00FFFFFF) {
+			LOGP(DNAT, LOGL_NOTICE, "Wrapped searching for a free code\n");
+			last_ref = 0;
+			++wrapped;
+		}
+
+		if (sccp_ref_is_free(&reference, nat) == 0) {
+			*ref = reference;
+			return 0;
+		}
+	} while (wrapped != 2);
+
+	LOGP(DNAT, LOGL_ERROR, "Finding a free reference failed\n");
+	return -1;
+}
+
+struct sccp_connections *create_sccp_src_ref(struct bsc_connection *bsc,
+					     struct bsc_nat_parsed *parsed)
+{
+	struct sccp_connections *conn;
+
+	/* Some commercial BSCs like to reassign there SRC ref */
+	llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) {
+		if (conn->bsc != bsc)
+			continue;
+		if (memcmp(&conn->real_ref, parsed->src_local_ref, sizeof(conn->real_ref)) != 0)
+			continue;
+
+		/* the BSC has reassigned the SRC ref and we failed to keep track */
+		memset(&conn->remote_ref, 0, sizeof(conn->remote_ref));
+		if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) {
+			LOGP(DNAT, LOGL_ERROR, "BSC %d reused src ref: %d and we failed to generate a new id.\n",
+			     bsc->cfg->nr, sccp_src_ref_to_int(parsed->src_local_ref));
+			bsc_mgcp_dlcx(conn);
+			llist_del(&conn->list_entry);
+			talloc_free(conn);
+			return NULL;
+		} else {
+			clock_gettime(CLOCK_MONOTONIC, &conn->creation_time);
+			bsc_mgcp_dlcx(conn);
+			return conn;
+		}
+	}
+
+
+	conn = talloc_zero(bsc->nat, struct sccp_connections);
+	if (!conn) {
+		LOGP(DNAT, LOGL_ERROR, "Memory allocation failure.\n");
+		return NULL;
+	}
+
+	conn->bsc = bsc;
+	clock_gettime(CLOCK_MONOTONIC, &conn->creation_time);
+	conn->real_ref = *parsed->src_local_ref;
+	if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) {
+		LOGP(DNAT, LOGL_ERROR, "Failed to assign a ref.\n");
+		talloc_free(conn);
+		return NULL;
+	}
+
+	bsc_mgcp_init(conn);
+	llist_add_tail(&conn->list_entry, &bsc->nat->sccp_connections);
+	counter_inc(bsc->cfg->stats.sccp.conn);
+	counter_inc(bsc->cfg->nat->stats.sccp.conn);
+
+	LOGP(DNAT, LOGL_DEBUG, "Created 0x%x <-> 0x%x mapping for con %p\n",
+	     sccp_src_ref_to_int(&conn->real_ref),
+	     sccp_src_ref_to_int(&conn->patched_ref), bsc);
+
+	return conn;
+}
+
+int update_sccp_src_ref(struct sccp_connections *sccp, struct bsc_nat_parsed *parsed)
+{
+	if (!parsed->dest_local_ref || !parsed->src_local_ref) {
+		LOGP(DNAT, LOGL_ERROR, "CC MSG should contain both local and dest address.\n");
+		return -1;
+	}
+
+	sccp->remote_ref = *parsed->src_local_ref;
+	sccp->has_remote_ref = 1;
+	LOGP(DNAT, LOGL_DEBUG, "Updating 0x%x to remote 0x%x on %p\n",
+	     sccp_src_ref_to_int(&sccp->patched_ref),
+	     sccp_src_ref_to_int(&sccp->remote_ref), sccp->bsc);
+
+	return 0;
+}
+
+void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
+{
+	struct sccp_connections *conn;
+
+	llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) {
+		if (memcmp(parsed->src_local_ref,
+			   &conn->patched_ref, sizeof(conn->patched_ref)) == 0) {
+
+			sccp_connection_destroy(conn);
+			return;
+		}
+	}
+
+	LOGP(DNAT, LOGL_ERROR, "Can not remove connection: 0x%x\n",
+	     sccp_src_ref_to_int(parsed->src_local_ref));
+}
+
+/*
+ * We have a message from the MSC to the BSC. The MSC is using
+ * an address that was assigned by the MUX, we need to update the
+ * dest reference to the real network.
+ */
+struct sccp_connections *patch_sccp_src_ref_to_bsc(struct msgb *msg,
+						   struct bsc_nat_parsed *parsed,
+						   struct bsc_nat *nat)
+{
+	struct sccp_connections *conn;
+
+	if (!parsed->dest_local_ref) {
+		LOGP(DNAT, LOGL_ERROR, "MSG should contain dest_local_ref.\n");
+		return NULL;
+	}
+
+
+	llist_for_each_entry(conn, &nat->sccp_connections, list_entry) {
+		if (!equal(parsed->dest_local_ref, &conn->patched_ref))
+			continue;
+
+		/* Change the dest address to the real one */
+		*parsed->dest_local_ref = conn->real_ref;
+		return conn;
+	}
+
+	return NULL;
+}
+
+/*
+ * These are message to the MSC. We will need to find the BSC
+ * Connection by either the SRC or the DST local reference.
+ *
+ * In case of a CR we need to work by the SRC local reference
+ * in all other cases we need to work by the destination local
+ * reference..
+ */
+struct sccp_connections *patch_sccp_src_ref_to_msc(struct msgb *msg,
+						   struct bsc_nat_parsed *parsed,
+						   struct bsc_connection *bsc)
+{
+	struct sccp_connections *conn;
+
+	llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) {
+		if (conn->bsc != bsc)
+			continue;
+
+		if (parsed->src_local_ref) {
+			if (equal(parsed->src_local_ref, &conn->real_ref)) {
+				*parsed->src_local_ref = conn->patched_ref;
+				return conn;
+			}
+		} else if (parsed->dest_local_ref) {
+			if (equal(parsed->dest_local_ref, &conn->remote_ref))
+				return conn;
+		} else {
+			LOGP(DNAT, LOGL_ERROR, "Header has neither loc/dst ref.\n");
+			return NULL;
+		}
+	}
+
+	return NULL;
+}
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 12ed903..ca37678 100644
--- a/openbsc/src/paging.c
+++ b/openbsc/src/paging.c
@@ -92,8 +92,7 @@
 		mi_len = gsm48_generate_mid_from_tmsi(mi, request->subscr->tmsi);
 
 	page_group = calculate_group(request->bts, request->subscr);
-	rsl_paging_cmd(request->bts, page_group, mi_len, mi,
-			request->chan_type);
+	gsm0808_page(request->bts, page_group, mi_len, mi, request->chan_type);
 }
 
 /*
diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c
index 039d2c8..d9f5da5 100644
--- a/openbsc/src/rest_octets.c
+++ b/openbsc/src/rest_octets.c
@@ -316,8 +316,16 @@
 	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 */
+	}
 
 	if (!gco->ext_info_present) {
 		/* no extension information */
diff --git a/openbsc/src/rrlp.c b/openbsc/src/rrlp.c
index 3504451..b5c7daf 100644
--- a/openbsc/src/rrlp.c
+++ b/openbsc/src/rrlp.c
@@ -40,9 +40,9 @@
 	Accuracy=60, Method=gpsOrEOTD, ResponseTime=5, multipleSets */
 static const u_int8_t ass_pref_pos_req[] = { 0x40, 0x03, 0x79, 0x50 };
 
-static int send_rrlp_req(struct gsm_lchan *lchan)
+static int send_rrlp_req(struct gsm_subscriber_connection *conn)
 {
-	struct gsm_network *net = lchan->ts->trx->bts->network;
+	struct gsm_network *net = conn->bts->network;
 	const u_int8_t *req;
 
 	switch (net->rrlp.mode) {
@@ -60,7 +60,7 @@
 		return 0;
 	}
 
-	return gsm48_send_rr_app_info(lchan, 0x00,
+	return gsm48_send_rr_app_info(conn, 0x00,
 				      sizeof(ms_based_pos_req), req);
 }
 
@@ -68,16 +68,16 @@
 			 void *handler_data, void *signal_data)
 {
 	struct gsm_subscriber *subscr;
-	struct gsm_lchan *lchan;
+	struct gsm_subscriber_connection *conn;
 
 	switch (signal) {
 	case S_SUBSCR_ATTACHED:
 		/* A subscriber has attached. */
 		subscr = signal_data;
-		lchan = lchan_for_subscr(subscr);
-		if (!lchan)
+		conn = connection_for_subscr(subscr);
+		if (!conn)
 			break;
-		send_rrlp_req(lchan);
+		send_rrlp_req(conn);
 		break;
 	}
 	return 0;
@@ -91,7 +91,7 @@
 	switch (signal) {
 	case S_PAGING_SUCCEEDED:
 		/* A subscriber has attached. */
-		send_rrlp_req(psig_data->lchan);
+		send_rrlp_req(&psig_data->lchan->conn);
 		break;
 	case S_PAGING_EXPIRED:
 		break;
diff --git a/openbsc/src/sccp/sccp.c b/openbsc/src/sccp/sccp.c
index de18614..f4335c0 100644
--- a/openbsc/src/sccp/sccp.c
+++ b/openbsc/src/sccp/sccp.c
@@ -638,7 +638,7 @@
 		connection->state_cb(connection, old_state);
 }
 
-static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause)
+struct msgb *sccp_create_refuse(struct sccp_source_reference *src_ref, int cause, uint8_t *inp, int length)
 {
 	struct msgb *msgb;
 	struct sccp_connection_refused *ref;
@@ -646,6 +646,11 @@
 
 	msgb = msgb_alloc_headroom(SCCP_MSG_SIZE,
 				   SCCP_MSG_HEADROOM, "sccp ref");
+	if (!msgb) {
+		LOGP(DSCCP, LOGL_ERROR, "Failed to allocate refusal msg.\n");
+		return NULL;
+	}
+
 	msgb->l2h = &msgb->data[0];
 
 	ref = (struct sccp_connection_refused *) msgb_put(msgb, sizeof(*ref));
@@ -655,40 +660,70 @@
 	ref->cause = cause;
 	ref->optional_start = 1;
 
+	if (inp) {
+		data = msgb_put(msgb, 1 + 1 + length);
+		data[0] = SCCP_PNC_DATA;
+		data[1] = length;
+		memcpy(&data[2], inp, length);
+	}
+
 	data = msgb_put(msgb, 1);
 	data[0] = SCCP_PNC_END_OF_OPTIONAL;
+	return msgb;
+}
+
+static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause)
+{
+	struct msgb *msgb = sccp_create_refuse(src_ref, cause, NULL, 0);
+	if (!msgb)
+		return -1;
 
 	_send_msg(msgb);
 	return 0;
 }
 
-static int _sccp_send_connection_confirm(struct sccp_connection *connection)
+struct msgb *sccp_create_cc(struct sccp_source_reference *src_ref,
+			    struct sccp_source_reference *dst_ref)
 {
 	struct msgb *response;
 	struct sccp_connection_confirm *confirm;
 	u_int8_t *optional_data;
 
-	if (assign_source_local_reference(connection) != 0)
-		return -1;
-
 	response = msgb_alloc_headroom(SCCP_MSG_SIZE,
 				       SCCP_MSG_HEADROOM, "sccp confirm");
+	if (!response) {
+		LOGP(DSCCP, LOGL_ERROR, "Failed to create SCCP Confirm.\n");
+		return NULL;
+	}
+
 	response->l2h = &response->data[0];
 
 	confirm = (struct sccp_connection_confirm *) msgb_put(response, sizeof(*confirm));
 
 	confirm->type = SCCP_MSG_TYPE_CC;
 	memcpy(&confirm->destination_local_reference,
-	       &connection->destination_local_reference,
-	       sizeof(connection->destination_local_reference));
+	       dst_ref, sizeof(*dst_ref));
 	memcpy(&confirm->source_local_reference,
-	       &connection->source_local_reference,
-	       sizeof(connection->source_local_reference));
+	       src_ref, sizeof(*src_ref));
 	confirm->proto_class = 2;
 	confirm->optional_start = 1;
 
 	optional_data = (u_int8_t *) msgb_put(response, 1);
 	optional_data[0] = SCCP_PNC_END_OF_OPTIONAL;
+	return response;
+}
+
+static int _sccp_send_connection_confirm(struct sccp_connection *connection)
+{
+	struct msgb *response;
+
+	if (assign_source_local_reference(connection) != 0)
+		return -1;
+
+	response = sccp_create_cc(&connection->source_local_reference,
+				  &connection->destination_local_reference);
+	if (!response)
+		return -1;
 
 	_send_msg(response);
 	_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_ESTABLISHED);
@@ -755,34 +790,49 @@
 	return 0;
 }
 
-static int _sccp_send_connection_data(struct sccp_connection *conn, struct msgb *_data)
+struct msgb *sccp_create_dt1(struct sccp_source_reference *dst_ref, uint8_t *inp_data, uint8_t len)
 {
 	struct msgb *msgb;
 	struct sccp_data_form1 *dt1;
 	u_int8_t *data;
-	int extra_size;
+
+	msgb = msgb_alloc_headroom(SCCP_MSG_SIZE,
+				   SCCP_MSG_HEADROOM, "sccp dt1");
+	if (!msgb) {
+		LOGP(DSCCP, LOGL_ERROR, "Failed to create DT1 msg.\n");
+		return NULL;
+	}
+
+	msgb->l2h = &msgb->data[0];
+
+	dt1 = (struct sccp_data_form1 *) msgb_put(msgb, sizeof(*dt1));
+	dt1->type = SCCP_MSG_TYPE_DT1;
+	memcpy(&dt1->destination_local_reference, dst_ref,
+	       sizeof(struct sccp_source_reference));
+	dt1->segmenting = 0;
+
+	/* copy the data */
+	dt1->variable_start = 1;
+	data = msgb_put(msgb, 1 + len);
+	data[0] = len;
+	memcpy(&data[1], inp_data, len);
+
+	return msgb;
+}
+
+static int _sccp_send_connection_data(struct sccp_connection *conn, struct msgb *_data)
+{
+	struct msgb *msgb;
 
 	if (msgb_l3len(_data) < 2 || msgb_l3len(_data) > 256) {
 		LOGP(DSCCP, LOGL_ERROR, "data size too big, segmenting unimplemented.\n");
 		return -1;
 	}
 
-	extra_size = 1 + msgb_l3len(_data);
-	msgb = msgb_alloc_headroom(SCCP_MSG_SIZE,
-				   SCCP_MSG_HEADROOM, "sccp dt1");
-	msgb->l2h = &msgb->data[0];
-
-	dt1 = (struct sccp_data_form1 *) msgb_put(msgb, sizeof(*dt1));
-	dt1->type = SCCP_MSG_TYPE_DT1;
-	memcpy(&dt1->destination_local_reference, &conn->destination_local_reference,
-	       sizeof(struct sccp_source_reference));
-	dt1->segmenting = 0;
-
-	/* copy the data */
-	dt1->variable_start = 1;
-	data = msgb_put(msgb, extra_size);
-	data[0] = extra_size - 1;
-	memcpy(&data[1], _data->l3h, extra_size - 1);
+	msgb = sccp_create_dt1(&conn->destination_local_reference,
+			       _data->l3h, msgb_l3len(_data));
+	if (!msgb)
+		return -1;
 
 	_send_msg(msgb);
 	return 0;
@@ -811,7 +861,8 @@
 	return 0;
 }
 
-static int _sccp_send_connection_released(struct sccp_connection *conn, int cause)
+struct msgb *sccp_create_rlsd(struct sccp_source_reference *src_ref,
+			      struct sccp_source_reference *dst_ref, int cause)
 {
 	struct msgb *msg;
 	struct sccp_connection_released *rel;
@@ -819,19 +870,36 @@
 
 	msg = msgb_alloc_headroom(SCCP_MSG_SIZE, SCCP_MSG_HEADROOM,
 				  "sccp: connection released");
+	if (!msg) {
+		LOGP(DSCCP, LOGL_ERROR, "Failed to allocate RLSD.\n");
+		return NULL;
+	}
+
 	msg->l2h = &msg->data[0];
 	rel = (struct sccp_connection_released *) msgb_put(msg, sizeof(*rel));
 	rel->type = SCCP_MSG_TYPE_RLSD;
 	rel->release_cause = cause;
 
 	/* copy the source references */
-	memcpy(&rel->destination_local_reference, &conn->destination_local_reference,
+	memcpy(&rel->destination_local_reference, dst_ref,
 	       sizeof(struct sccp_source_reference));
-	memcpy(&rel->source_local_reference, &conn->source_local_reference,
+	memcpy(&rel->source_local_reference, src_ref,
 	       sizeof(struct sccp_source_reference));
 
 	data = msgb_put(msg, 1);
 	data[0] = SCCP_PNC_END_OF_OPTIONAL;
+	return msg;
+}
+
+static int _sccp_send_connection_released(struct sccp_connection *conn, int cause)
+{
+	struct msgb *msg;
+
+	msg = sccp_create_rlsd(&conn->source_local_reference,
+			       &conn->destination_local_reference,
+			       cause);
+	if (!msg)
+		return -1;
 
 	_sccp_set_connection_state(conn, SCCP_CONNECTION_STATE_RELEASE);
 	_send_msg(msg);
diff --git a/openbsc/src/silent_call.c b/openbsc/src/silent_call.c
index 8bd5341..00acc1d 100644
--- a/openbsc/src/silent_call.c
+++ b/openbsc/src/silent_call.c
@@ -128,15 +128,13 @@
 /* end a silent call with a given subscriber */
 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)
+	conn = connection_for_subscr(subscr);
+	if (!conn)
 		return -EINVAL;
 
 	/* did we actually establish a silent call for this guy? */
-	conn = &lchan->conn;
 	if (!conn->silent_call)
 		return -EINVAL;
 
diff --git a/openbsc/src/socket.c b/openbsc/src/socket.c
index 3ed4d42..d60c43e 100644
--- a/openbsc/src/socket.c
+++ b/openbsc/src/socket.c
@@ -41,15 +41,26 @@
 #include <openbsc/gsm_data.h>
 #include <osmocore/talloc.h>
 
-int make_sock(struct bsc_fd *bfd, int proto, u_int16_t port,
+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;
 
-	if (proto == IPPROTO_UDP)
+	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;
@@ -57,26 +68,29 @@
 	//bfd->data = line;
 
 	if (bfd->fd < 0) {
-		LOGP(DINP, LOGL_ERROR, "could not create TCP socket.\n");
+		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);
-	addr.sin_addr.s_addr = INADDR_ANY;
+	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 l2 socket %s\n",
+		LOGP(DINP, LOGL_ERROR, "could not bind socket %s\n",
 			strerror(errno));
 		close(bfd->fd);
 		return -EIO;
 	}
 
-	if (proto != IPPROTO_UDP) {
+	if (proto == IPPROTO_TCP) {
 		ret = listen(bfd->fd, 1);
 		if (ret < 0) {
 			perror("listen");
diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c
index 3bd833a..337f756 100644
--- a/openbsc/src/system_information.c
+++ b/openbsc/src/system_information.c
@@ -397,17 +397,17 @@
 
 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 = 0,
+		.ext_info_present = 1,
 		.ext_info = {
 			/* The values below are just guesses ! */
 			.egprs_supported = 0,
 			.use_egprs_p_ch_req = 1,
-			.bep_period = 4,
+			.bep_period = 5,
 			.pfc_supported = 0,
 			.dtm_supported = 0,
 			.bss_paging_coordination = 0,
@@ -415,10 +415,10 @@
 	},
 	.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,
@@ -451,7 +451,8 @@
 	if (ret < 0)
 		return ret;
 
-	si13->header.l2_plen = ret & 0xff;
+	/* length is coded in bit 2 an up */
+	si13->header.l2_plen = 0x01;
 
 	return sizeof (*si13) + ret;
 }
diff --git a/openbsc/src/talloc_ctx.c b/openbsc/src/talloc_ctx.c
index 4b373b4..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;
@@ -22,6 +23,7 @@
 	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 c7de026..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) {
-		log_del_target(conn->dbg);
-		talloc_free(conn->dbg);
-	}
-
-	llist_del(&conn->entry);
-	talloc_free(conn);
-	return 0;
-}
-
-static int client_data(struct bsc_fd *fd, unsigned int what)
-{
-	struct telnet_connection *conn = fd->data;
-	int rc = 0;
-
-	if (what & BSC_FD_READ) {
-		conn->fd.when &= ~BSC_FD_READ;
-		rc = vty_read(conn->vty);
-	}
-
-	/* vty might have been closed from vithin vty_read() */
-	if (!conn->vty)
-		return rc;
-
-	if (what & BSC_FD_WRITE) {
-		rc = buffer_flush_all(conn->vty->obuf, fd->fd);
-		if (rc == BUFFER_EMPTY)
-			conn->fd.when &= ~BSC_FD_WRITE;
-	}
-
-	return rc;
-}
-
-static int telnet_new_connection(struct bsc_fd *fd, unsigned int what) {
-	struct telnet_connection *connection;
-	struct sockaddr_in sockaddr;
-	socklen_t len = sizeof(sockaddr);
-	int new_connection = accept(fd->fd, (struct sockaddr*)&sockaddr, &len);
-
-	if (new_connection < 0) {
-		LOGP(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/token_auth.c b/openbsc/src/token_auth.c
index 7fefea5..dc8cce2 100644
--- a/openbsc/src/token_auth.c
+++ b/openbsc/src/token_auth.c
@@ -99,12 +99,12 @@
 		subscr->authorized = 0;
 		db_sync_subscriber(subscr);
 		if (rc) {
-			struct gsm_lchan *lchan = lchan_for_subscr(subscr);
-			if (lchan) {
+			struct gsm_subscriber_connection *conn = connection_for_subscr(subscr);
+			if (conn) {
 				u_int8_t auth_rand[16];
 				/* kick the subscriber off the network */
-				gsm48_tx_mm_auth_req(lchan, auth_rand, 0);
-				gsm48_tx_mm_auth_rej(lchan);
+				gsm48_tx_mm_auth_req(conn, auth_rand, 0);
+				gsm48_tx_mm_auth_rej(conn);
 				/* FIXME: close the channel early ?*/
 				//gsm48_send_rr_Release(lchan);
 			}
@@ -118,7 +118,7 @@
 			void *handler_data, void *signal_data)
 {
 	struct gsm_sms *sms = signal_data;
-	struct gsm_lchan *lchan;
+	struct gsm_subscriber_connection *conn;
 	u_int8_t auth_rand[16];
 
 
@@ -136,11 +136,11 @@
 		return 0;
 
 
-	lchan = lchan_for_subscr(sms->receiver);
-	if (lchan) {
+	conn = connection_for_subscr(sms->receiver);
+	if (conn) {
 		/* kick the subscriber off the network */
-		gsm48_tx_mm_auth_req(lchan, auth_rand, 0);
-		gsm48_tx_mm_auth_rej(lchan);
+		gsm48_tx_mm_auth_req(conn, auth_rand, 0);
+		gsm48_tx_mm_auth_rej(conn);
 		/* FIXME: close the channel early ?*/
 		//gsm48_send_rr_Release(lchan);
 	}
diff --git a/openbsc/src/vty/buffer.c b/openbsc/src/vty/buffer.c
deleted file mode 100644
index 0bc1760..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(void *ctx, size_t size)
-{
-	struct buffer *b;
-
-	b = talloc_zero(ctx, struct buffer);
-
-	if (size)
-		b->size = size;
-	else {
-		static size_t default_size;
-		if (!default_size) {
-			long pgsz = sysconf(_SC_PAGESIZE);
-			default_size =
-			    ((((BUFFER_SIZE_DEFAULT - 1) / pgsz) + 1) * pgsz);
-		}
-		b->size = default_size;
-	}
-
-	return b;
-}
-
-/* Free buffer. */
-void buffer_free(struct buffer *b)
-{
-	buffer_reset(b);
-	talloc_free(b);
-}
-
-/* Make string clone. */
-char *buffer_getstr(struct buffer *b)
-{
-	size_t totlen = 0;
-	struct buffer_data *data;
-	char *s;
-	char *p;
-
-	for (data = b->head; data; data = data->next)
-		totlen += data->cp - data->sp;
-	if (!(s = _talloc_zero(tall_vty_ctx, (totlen + 1), "buffer_getstr")))
-		return NULL;
-	p = s;
-	for (data = b->head; data; data = data->next) {
-		memcpy(p, data->data + data->sp, data->cp - data->sp);
-		p += data->cp - data->sp;
-	}
-	*p = '\0';
-	return s;
-}
-
-/* Return 1 if buffer is empty. */
-int buffer_empty(struct buffer *b)
-{
-	return (b->head == NULL);
-}
-
-/* Clear and free all allocated data. */
-void buffer_reset(struct buffer *b)
-{
-	struct buffer_data *data;
-	struct buffer_data *next;
-
-	for (data = b->head; data; data = next) {
-		next = data->next;
-		BUFFER_DATA_FREE(data);
-	}
-	b->head = b->tail = NULL;
-}
-
-/* Add buffer_data to the end of buffer. */
-static struct buffer_data *buffer_add(struct buffer *b)
-{
-	struct buffer_data *d;
-
-	d = _talloc_zero(b,
-			 offsetof(struct buffer_data, data[b->size]),
-			 "buffer_add");
-	if (!d)
-		return NULL;
-	d->cp = d->sp = 0;
-	d->next = NULL;
-
-	if (b->tail)
-		b->tail->next = d;
-	else
-		b->head = d;
-	b->tail = d;
-
-	return d;
-}
-
-/* Write data to buffer. */
-void buffer_put(struct buffer *b, const void *p, size_t size)
-{
-	struct buffer_data *data = b->tail;
-	const char *ptr = p;
-
-	/* We use even last one byte of data buffer. */
-	while (size) {
-		size_t chunk;
-
-		/* If there is no data buffer add it. */
-		if (data == NULL || data->cp == b->size)
-			data = buffer_add(b);
-
-		chunk =
-		    ((size <=
-		      (b->size - data->cp)) ? size : (b->size - data->cp));
-		memcpy((data->data + data->cp), ptr, chunk);
-		size -= chunk;
-		ptr += chunk;
-		data->cp += chunk;
-	}
-}
-
-/* Insert character into the buffer. */
-void buffer_putc(struct buffer *b, u_char c)
-{
-	buffer_put(b, &c, 1);
-}
-
-/* Put string to the buffer. */
-void buffer_putstr(struct buffer *b, const char *c)
-{
-	buffer_put(b, c, strlen(c));
-}
-
-/* Keep flushing data to the fd until the buffer is empty or an error is
-   encountered or the operation would block. */
-buffer_status_t buffer_flush_all(struct buffer *b, int fd)
-{
-	buffer_status_t ret;
-	struct buffer_data *head;
-	size_t head_sp;
-
-	if (!b->head)
-		return BUFFER_EMPTY;
-	head_sp = (head = b->head)->sp;
-	/* Flush all data. */
-	while ((ret = buffer_flush_available(b, fd)) == BUFFER_PENDING) {
-		if ((b->head == head) && (head_sp == head->sp)
-		    && (errno != EINTR))
-			/* No data was flushed, so kernel buffer must be full. */
-			return ret;
-		head_sp = (head = b->head)->sp;
-	}
-
-	return ret;
-}
-
-#if 0
-/* Flush enough data to fill a terminal window of the given scene (used only
-   by vty telnet interface). */
-buffer_status_t
-buffer_flush_window(struct buffer * b, int fd, int width, int height,
-		    int erase_flag, int no_more_flag)
-{
-	int nbytes;
-	int iov_alloc;
-	int iov_index;
-	struct iovec *iov;
-	struct iovec small_iov[3];
-	char more[] = " --More-- ";
-	char erase[] =
-	    { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
-		' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
-		0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
-	};
-	struct buffer_data *data;
-	int column;
-
-	if (!b->head)
-		return BUFFER_EMPTY;
-
-	if (height < 1) {
-		zlog_warn
-		    ("%s called with non-positive window height %d, forcing to 1",
-		     __func__, height);
-		height = 1;
-	} else if (height >= 2)
-		height--;
-	if (width < 1) {
-		zlog_warn
-		    ("%s called with non-positive window width %d, forcing to 1",
-		     __func__, width);
-		width = 1;
-	}
-
-	/* For erase and more data add two to b's buffer_data count. */
-	if (b->head->next == NULL) {
-		iov_alloc = sizeof(small_iov) / sizeof(small_iov[0]);
-		iov = small_iov;
-	} else {
-		iov_alloc = ((height * (width + 2)) / b->size) + 10;
-		iov = XMALLOC(MTYPE_TMP, iov_alloc * sizeof(*iov));
-	}
-	iov_index = 0;
-
-	/* Previously print out is performed. */
-	if (erase_flag) {
-		iov[iov_index].iov_base = erase;
-		iov[iov_index].iov_len = sizeof erase;
-		iov_index++;
-	}
-
-	/* Output data. */
-	column = 1;		/* Column position of next character displayed. */
-	for (data = b->head; data && (height > 0); data = data->next) {
-		size_t cp;
-
-		cp = data->sp;
-		while ((cp < data->cp) && (height > 0)) {
-			/* Calculate lines remaining and column position after displaying
-			   this character. */
-			if (data->data[cp] == '\r')
-				column = 1;
-			else if ((data->data[cp] == '\n') || (column == width)) {
-				column = 1;
-				height--;
-			} else
-				column++;
-			cp++;
-		}
-		iov[iov_index].iov_base = (char *)(data->data + data->sp);
-		iov[iov_index++].iov_len = cp - data->sp;
-		data->sp = cp;
-
-		if (iov_index == iov_alloc)
-			/* This should not ordinarily happen. */
-		{
-			iov_alloc *= 2;
-			if (iov != small_iov) {
-				zlog_warn("%s: growing iov array to %d; "
-					  "width %d, height %d, size %lu",
-					  __func__, iov_alloc, width, height,
-					  (u_long) b->size);
-				iov =
-				    XREALLOC(MTYPE_TMP, iov,
-					     iov_alloc * sizeof(*iov));
-			} else {
-				/* This should absolutely never occur. */
-				zlog_err
-				    ("%s: corruption detected: iov_small overflowed; "
-				     "head %p, tail %p, head->next %p",
-				     __func__, b->head, b->tail, b->head->next);
-				iov =
-				    XMALLOC(MTYPE_TMP,
-					    iov_alloc * sizeof(*iov));
-				memcpy(iov, small_iov, sizeof(small_iov));
-			}
-		}
-	}
-
-	/* In case of `more' display need. */
-	if (b->tail && (b->tail->sp < b->tail->cp) && !no_more_flag) {
-		iov[iov_index].iov_base = more;
-		iov[iov_index].iov_len = sizeof more;
-		iov_index++;
-	}
-#ifdef IOV_MAX
-	/* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
-	   example: Solaris2.6 are defined IOV_MAX size at 16.     */
-	{
-		struct iovec *c_iov = iov;
-		nbytes = 0;	/* Make sure it's initialized. */
-
-		while (iov_index > 0) {
-			int iov_size;
-
-			iov_size =
-			    ((iov_index > IOV_MAX) ? IOV_MAX : iov_index);
-			if ((nbytes = writev(fd, c_iov, iov_size)) < 0) {
-				zlog_warn("%s: writev to fd %d failed: %s",
-					  __func__, fd, safe_strerror(errno));
-				break;
-			}
-
-			/* move pointer io-vector */
-			c_iov += iov_size;
-			iov_index -= iov_size;
-		}
-	}
-#else				/* IOV_MAX */
-	if ((nbytes = writev(fd, iov, iov_index)) < 0)
-		zlog_warn("%s: writev to fd %d failed: %s",
-			  __func__, fd, safe_strerror(errno));
-#endif				/* IOV_MAX */
-
-	/* Free printed buffer data. */
-	while (b->head && (b->head->sp == b->head->cp)) {
-		struct buffer_data *del;
-		if (!(b->head = (del = b->head)->next))
-			b->tail = NULL;
-		BUFFER_DATA_FREE(del);
-	}
-
-	if (iov != small_iov)
-		XFREE(MTYPE_TMP, iov);
-
-	return (nbytes < 0) ? BUFFER_ERROR :
-	    (b->head ? BUFFER_PENDING : BUFFER_EMPTY);
-}
-#endif
-
-/* This function (unlike other buffer_flush* functions above) is designed
-to work with non-blocking sockets.  It does not attempt to write out
-all of the queued data, just a "big" chunk.  It returns 0 if it was
-able to empty out the buffers completely, 1 if more flushing is
-required later, or -1 on a fatal write error. */
-buffer_status_t buffer_flush_available(struct buffer * b, int fd)
-{
-
-/* These are just reasonable values to make sure a significant amount of
-data is written.  There's no need to go crazy and try to write it all
-in one shot. */
-#ifdef IOV_MAX
-#define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX)
-#else
-#define MAX_CHUNKS 16
-#endif
-#define MAX_FLUSH 131072
-
-	struct buffer_data *d;
-	size_t written;
-	struct iovec iov[MAX_CHUNKS];
-	size_t iovcnt = 0;
-	size_t nbyte = 0;
-
-	for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH);
-	     d = d->next, iovcnt++) {
-		iov[iovcnt].iov_base = d->data + d->sp;
-		nbyte += (iov[iovcnt].iov_len = d->cp - d->sp);
-	}
-
-	if (!nbyte)
-		/* No data to flush: should we issue a warning message? */
-		return BUFFER_EMPTY;
-
-	/* only place where written should be sign compared */
-	if ((ssize_t) (written = writev(fd, iov, iovcnt)) < 0) {
-		if (ERRNO_IO_RETRY(errno))
-			/* Calling code should try again later. */
-			return BUFFER_PENDING;
-		return BUFFER_ERROR;
-	}
-
-	/* Free printed buffer data. */
-	while (written > 0) {
-		struct buffer_data *d;
-		if (!(d = b->head))
-			break;
-		if (written < d->cp - d->sp) {
-			d->sp += written;
-			return BUFFER_PENDING;
-		}
-
-		written -= (d->cp - d->sp);
-		if (!(b->head = d->next))
-			b->tail = NULL;
-		BUFFER_DATA_FREE(d);
-	}
-
-	return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
-
-#undef MAX_CHUNKS
-#undef MAX_FLUSH
-}
-
-buffer_status_t
-buffer_write(struct buffer * b, int fd, const void *p, size_t size)
-{
-	ssize_t nbytes;
-
-#if 0
-	/* Should we attempt to drain any previously buffered data?  This could help reduce latency in pushing out the data if we are stuck in a long-running thread that is preventing the main select loop from calling the flush thread... */
-
-	if (b->head && (buffer_flush_available(b, fd) == BUFFER_ERROR))
-		return BUFFER_ERROR;
-#endif
-	if (b->head)
-		/* Buffer is not empty, so do not attempt to write the new data. */
-		nbytes = 0;
-	else if ((nbytes = write(fd, p, size)) < 0) {
-		if (ERRNO_IO_RETRY(errno))
-			nbytes = 0;
-		else
-			return BUFFER_ERROR;
-	}
-	/* Add any remaining data to the buffer. */
-	{
-		size_t written = nbytes;
-		if (written < size)
-			buffer_put(b, ((const char *)p) + written,
-				   size - written);
-	}
-	return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
-}
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 a1130b6..0000000
--- a/openbsc/src/vty/command.c
+++ /dev/null
@@ -1,3424 +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);
-}
-
-/* Install a command into VIEW and ENABLE node */
-void install_element_ve(struct cmd_element *cmd)
-{
-	install_element(VIEW_NODE, cmd);
-	install_element(ENABLE_NODE, cmd);
-}
-
-#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. */
-gDEFUN(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;
-	case MGCP_NODE:
-	case GBPROXY_NODE:
-	case SGSN_NODE:
-	case NS_NODE:
-		vty->node = CONFIG_NODE;
-		vty->index = NULL;
-	default:
-		break;
-	}
-	return CMD_SUCCESS;
-}
-
-/* quit is alias of exit. */
-gALIAS(config_exit,
-      config_quit_cmd, "quit", "Exit current mode and down to previous mode\n")
-
-/* End of configuration. */
-    gDEFUN(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. */
-gDEFUN(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. */
-gDEFUN(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/utils.c b/openbsc/src/vty/utils.c
deleted file mode 100644
index d8dfb8e..0000000
--- a/openbsc/src/vty/utils.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/* utility routines for printing common objects in the Osmocom world */
-
-/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <stdint.h>
-#include <inttypes.h>
-
-#include <osmocore/linuxlist.h>
-#include <osmocore/talloc.h>
-#include <osmocore/timer.h>
-#include <osmocore/rate_ctr.h>
-
-#include <vty/vty.h>
-
-void vty_out_rate_ctr_group(struct vty *vty, const char *prefix,
-			    struct rate_ctr_group *ctrg)
-{
-	unsigned int i;
-
-	vty_out(vty, "%s%s:%s", prefix, ctrg->desc->group_description, VTY_NEWLINE);
-	for (i = 0; i < ctrg->desc->num_ctr; i++) {
-		struct rate_ctr *ctr = &ctrg->ctr[i];
-		vty_out(vty, " %s%s: %8" PRIu64 " "
-			"(%" PRIu64 "/s %" PRIu64 "/m %" PRIu64 "/h %" PRIu64 "/d)%s",
-			prefix, ctrg->desc->ctr_desc[i].description, ctr->current,
-			ctr->intv[RATE_CTR_INTV_SEC].rate,
-			ctr->intv[RATE_CTR_INTV_MIN].rate,
-			ctr->intv[RATE_CTR_INTV_HOUR].rate,
-			ctr->intv[RATE_CTR_INTV_DAY].rate,
-			VTY_NEWLINE);
-	};
-}
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 0806856..0000000
--- a/openbsc/src/vty/vty.c
+++ /dev/null
@@ -1,1675 +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(new, 0);	/* Use default buffer size. */
-	if (!new->obuf)
-		goto out_new;
-	new->buf = _talloc_zero(new, 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);
-
-	/* VTY_CLOSED is handled by the telnet_interface */
-	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(vty, 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(vty, 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(vty, 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]);
-		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(vty, 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_cmds.c b/openbsc/src/vty_interface_cmds.c
deleted file mode 100644
index dd5e108..0000000
--- a/openbsc/src/vty_interface_cmds.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/* OpenBSC logging helper for the VTY */
-/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
- * (C) 2009-2010 by Holger Hans Peter Freyther
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <openbsc/vty.h>
-#include <openbsc/telnet_interface.h>
-
-#include <osmocore/talloc.h>
-
-#include <vty/command.h>
-#include <vty/buffer.h>
-#include <vty/vty.h>
-
-#include <stdlib.h>
-
-#define LOGGING_STR	"Configure log message to this terminal\n"
-
-static void _vty_output(struct log_target *tgt, const char *line)
-{
-	struct vty *vty = tgt->tgt_vty.vty;
-	vty_out(vty, "%s", line);
-	/* This is an ugly hack, but there is no easy way... */
-	if (strchr(line, '\n'))
-		vty_out(vty, "\r");
-}
-
-struct log_target *log_target_create_vty(struct vty *vty)
-{
-	struct log_target *target;
-
-	target = log_target_create();
-	if (!target)
-		return NULL;
-
-	target->tgt_vty.vty = vty;
-	target->output = _vty_output;
-	return target;
-}
-
-DEFUN(enable_logging,
-      enable_logging_cmd,
-      "logging enable",
-	LOGGING_STR
-      "Enables logging to this vty\n")
-{
-	struct telnet_connection *conn;
-
-	conn = (struct telnet_connection *) vty->priv;
-	if (conn->dbg) {
-		vty_out(vty, "Logging already enabled.%s", VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	conn->dbg = log_target_create_vty(vty);
-	if (!conn->dbg)
-		return CMD_WARNING;
-
-	log_add_target(conn->dbg);
-	return CMD_SUCCESS;
-}
-
-DEFUN(logging_fltr_imsi,
-      logging_fltr_imsi_cmd,
-      "logging filter imsi IMSI",
-	LOGGING_STR
-      "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;
-	}
-
-	log_set_imsi_filter(conn->dbg, argv[0]);
-	return CMD_SUCCESS;
-}
-
-DEFUN(logging_fltr_all,
-      logging_fltr_all_cmd,
-      "logging filter all <0-1>",
-	LOGGING_STR
-      "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;
-	}
-
-	log_set_all_filter(conn->dbg, atoi(argv[0]));
-	return CMD_SUCCESS;
-}
-
-DEFUN(logging_use_clr,
-      logging_use_clr_cmd,
-      "logging color <0-1>",
-	LOGGING_STR
-      "Use color for printing messages\n")
-{
-	struct telnet_connection *conn;
-
-	conn = (struct telnet_connection *) vty->priv;
-	if (!conn->dbg) {
-		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	log_set_use_color(conn->dbg, atoi(argv[0]));
-	return CMD_SUCCESS;
-}
-
-DEFUN(logging_prnt_timestamp,
-      logging_prnt_timestamp_cmd,
-      "logging timestamp <0-1>",
-	LOGGING_STR
-      "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;
-	}
-
-	log_set_print_timestamp(conn->dbg, atoi(argv[0]));
-	return CMD_SUCCESS;
-}
-
-/* FIXME: those have to be kept in sync with the log levels and categories */
-#define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref|gprs|ns|bssgp|all)"
-#define CATEGORIES_HELP	\
-	"A-bis Radio Link Layer (RLL)\n"			\
-	"Layer3 Call Control (CC)\n"				\
-	"Layer3 Mobility Management (MM)\n"			\
-	"Layer3 Radio Resource (RR)\n"				\
-	"A-bis Radio Signalling Link (RSL)\n"			\
-	"A-bis Network Management / O&M (NM/OML)\n"		\
-	"Layer3 Short Messagaging Service (SMS)\n"		\
-	"Paging Subsystem\n"					\
-	"MNCC API for Call Control application\n"		\
-	"A-bis Input Subsystem\n"				\
-	"A-bis Input Driver for Signalling\n"			\
-	"A-bis Input Driver for B-Channel (voice data)\n"	\
-	"A-bis B-Channel / Sub-channel Multiplexer\n"		\
-	"Radio Measurements\n"					\
-	"SCCP\n"						\
-	"Mobile Switching Center\n"				\
-	"Media Gateway Control Protocol\n"			\
-	"Hand-over\n"						\
-	"Database Layer\n"					\
-	"Reference Counting\n"					\
-	"GPRS Core\n"						\
-	"GPRS Network Service (NS)\n"				\
-	"GPRS BSS Gateway Protocol (BSSGP)\n"			\
-	"Global setting for all subsytems\n"
-
-#define VTY_DEBUG_LEVELS "(everything|debug|info|notice|error|fatal)"
-#define LEVELS_HELP	\
-	"Log simply everything\n"				\
-	"Log debug messages and higher levels\n"		\
-	"Log informational messages and higher levels\n"	\
-	"Log noticable messages and higher levels\n"		\
-	"Log error messages and higher levels\n"		\
-	"Log only fatal messages\n"
-DEFUN(logging_level,
-      logging_level_cmd,
-      "logging level " VTY_DEBUG_CATEGORIES " " VTY_DEBUG_LEVELS,
-      LOGGING_STR
-      "Set the log level for a specified category\n"
-      CATEGORIES_HELP
-      LEVELS_HELP)
-{
-	struct telnet_connection *conn;
-	int category = log_parse_category(argv[0]);
-	int level = log_parse_level(argv[1]);
-
-	conn = (struct telnet_connection *) vty->priv;
-	if (!conn->dbg) {
-		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	if (level < 0) {
-		vty_out(vty, "Invalid level `%s'%s", argv[1], VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	/* Check for special case where we want to set global log level */
-	if (!strcmp(argv[0], "all")) {
-		log_set_log_level(conn->dbg, level);
-		return CMD_SUCCESS;
-	}
-
-	if (category < 0) {
-		vty_out(vty, "Invalid category `%s'%s", argv[0], VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	conn->dbg->categories[category].enabled = 1;
-	conn->dbg->categories[category].loglevel = level;
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(logging_set_category_mask,
-      logging_set_category_mask_cmd,
-      "logging set log mask MASK",
-	LOGGING_STR
-      "Decide which categories to output.\n")
-{
-	struct telnet_connection *conn;
-
-	conn = (struct telnet_connection *) vty->priv;
-	if (!conn->dbg) {
-		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	log_parse_category_mask(conn->dbg, argv[0]);
-	return CMD_SUCCESS;
-}
-
-DEFUN(diable_logging,
-      disable_logging_cmd,
-      "logging disable",
-	LOGGING_STR
-      "Disables logging to this vty\n")
-{
-	struct telnet_connection *conn;
-
-	conn = (struct telnet_connection *) vty->priv;
-	if (!conn->dbg) {
-		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	log_del_target(conn->dbg);
-	talloc_free(conn->dbg);
-	conn->dbg = NULL;
-	return CMD_SUCCESS;
-}
-
-static void vty_print_logtarget(struct vty *vty, const struct log_info *info,
-				const struct log_target *tgt)
-{
-	unsigned int i;
-
-	vty_out(vty, " Global Loglevel: %s%s",
-		log_level_str(tgt->loglevel), VTY_NEWLINE);
-	vty_out(vty, " Use color: %s, Print Timestamp: %s%s",
-		tgt->use_color ? "On" : "Off",
-		tgt->print_timestamp ? "On" : "Off", VTY_NEWLINE);
-
-	vty_out(vty, " Log Level specific information:%s", VTY_NEWLINE);
-
-	for (i = 0; i < info->num_cat; i++) {
-		const struct log_category *cat = &tgt->categories[i];
-		vty_out(vty, "  %-10s %-10s %-8s %s%s",
-			info->cat[i].name+1, log_level_str(cat->loglevel),
-			cat->enabled ? "Enabled" : "Disabled",
- 			info->cat[i].description,
-			VTY_NEWLINE);
-	}
-}
-
-#define SHOW_LOG_STR "Show current logging configuration\n"
-
-DEFUN(show_logging_vty,
-      show_logging_vty_cmd,
-      "show logging vty",
-	SHOW_STR SHOW_LOG_STR
-	"Show current logging configuration for this vty\n")
-{
-	struct telnet_connection *conn;
-
-	conn = (struct telnet_connection *) vty->priv;
-	if (!conn->dbg) {
-		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-	vty_print_logtarget(vty, &log_info, conn->dbg);
-
-	return CMD_SUCCESS;
-}
-
-void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *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);
-}
-
-void openbsc_vty_add_cmds()
-{
-	install_element_ve(&enable_logging_cmd);
-	install_element_ve(&disable_logging_cmd);
-	install_element_ve(&logging_fltr_imsi_cmd);
-	install_element_ve(&logging_fltr_all_cmd);
-	install_element_ve(&logging_use_clr_cmd);
-	install_element_ve(&logging_prnt_timestamp_cmd);
-	install_element_ve(&logging_set_category_mask_cmd);
-	install_element_ve(&logging_level_cmd);
-	install_element_ve(&show_logging_vty_cmd);
-}
diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c
index 1b2adbb..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>
 
@@ -43,35 +43,7 @@
 #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(NULL, 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)
 
@@ -100,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;
@@ -142,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);
@@ -151,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);
@@ -173,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",
@@ -221,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;
 
@@ -253,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;
@@ -266,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"))
@@ -293,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) {
@@ -308,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);
 
@@ -319,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) {
@@ -332,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) {
@@ -379,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) {
@@ -402,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;
 }
 
@@ -508,7 +528,7 @@
       "show statistics",
 	SHOW_STR "Display network statistics\n")
 {
-	struct gsm_network *net = gsmnet;
+	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",
@@ -538,10 +558,8 @@
 }
 
 
-int bsc_vty_init_extra(struct gsm_network *net)
+int bsc_vty_init_extra(void)
 {
-	gsmnet = net;
-
 	register_signal_handler(SS_SCALL, scall_cbfn, NULL);
 
 	install_element_ve(&show_subscr_cmd);
@@ -555,14 +573,10 @@
 	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/Makefile.am b/openbsc/tests/Makefile.am
index 3b1b931..b469832 100644
--- a/openbsc/tests/Makefile.am
+++ b/openbsc/tests/Makefile.am
@@ -1 +1 @@
-SUBDIRS = debug gsm0408 db channel sccp
+SUBDIRS = debug gsm0408 db channel sccp bsc-nat
diff --git a/openbsc/tests/bsc-nat/Makefile.am b/openbsc/tests/bsc-nat/Makefile.am
new file mode 100644
index 0000000..013a465
--- /dev/null
+++ b/openbsc/tests/bsc-nat/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include
+AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS)
+
+EXTRA_DIST = bsc_data.c
+
+noinst_PROGRAMS = bsc_nat_test
+
+bsc_nat_test_SOURCES = bsc_nat_test.c \
+			$(top_srcdir)/src/nat/bsc_filter.c \
+			$(top_srcdir)/src/nat/bsc_sccp.c \
+			$(top_srcdir)/src/nat/bsc_nat_utils.c \
+			$(top_srcdir)/src/nat/bsc_mgcp_utils.c \
+			$(top_srcdir)/src/mgcp/mgcp_protocol.c \
+			$(top_srcdir)/src/mgcp/mgcp_network.c
+bsc_nat_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libsccp.a $(LIBOSMOCORE_LIBS) -lrt
diff --git a/openbsc/tests/bsc-nat/bsc_data.c b/openbsc/tests/bsc-nat/bsc_data.c
new file mode 100644
index 0000000..34242db
--- /dev/null
+++ b/openbsc/tests/bsc-nat/bsc_data.c
@@ -0,0 +1,154 @@
+/* test data */
+
+/* BSC -> MSC, CR */
+static const u_int8_t bsc_cr[] = {
+0x00, 0x2e, 0xfd,
+0x01, 0x00, 0x00, 0x15, 0x02, 0x02, 0x04, 0x02,
+0x42, 0xfe, 0x0f, 0x21, 0x00, 0x1f, 0x57, 0x05,
+0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x1c, 0xc3,
+0x51, 0x17, 0x12, 0x05, 0x08, 0x20, 0x72, 0xf4,
+0x90, 0x20, 0x1d, 0x50, 0x08, 0x29, 0x47, 0x80,
+0x00, 0x00, 0x00, 0x00, 0x80, 0x00 };
+
+static const u_int8_t bsc_cr_patched[] = {
+0x00, 0x2e, 0xfd,
+0x01, 0x00, 0x00, 0x05, 0x02, 0x02, 0x04, 0x02,
+0x42, 0xfe, 0x0f, 0x21, 0x00, 0x1f, 0x57, 0x05,
+0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x1c, 0xc3,
+0x51, 0x17, 0x12, 0x05, 0x08, 0x20, 0x72, 0xf4,
+0x90, 0x20, 0x1d, 0x50, 0x08, 0x29, 0x47, 0x80,
+0x00, 0x00, 0x00, 0x00, 0x80, 0x00 };
+
+/* CC, MSC -> BSC */
+static const u_int8_t msc_cc[] = {
+0x00, 0x0a, 0xfd,
+0x02, 0x00, 0x00, 0x05, 0x01, 0x1f, 0xe4, 0x02,
+0x01, 0x00 };
+static const u_int8_t msc_cc_patched[] = {
+0x00, 0x0a, 0xfd,
+0x02, 0x00, 0x00, 0x15, 0x01, 0x1f, 0xe4, 0x02,
+0x01, 0x00 };
+
+/* Classmark, BSC -> MSC */
+static const u_int8_t bsc_dtap[] = {
+0x00, 0x17, 0xfd,
+0x06, 0x01, 0x1f, 0xe4, 0x00, 0x01, 0x10, 0x00,
+0x0e, 0x54, 0x12, 0x03, 0x50, 0x18, 0x93, 0x13,
+0x06, 0x60, 0x14, 0x45, 0x00, 0x81, 0x00 };
+
+static const u_int8_t bsc_dtap_patched[] = {
+0x00, 0x17, 0xfd,
+0x06, 0x01, 0x1f, 0xe4, 0x00, 0x01, 0x10, 0x00,
+0x0e, 0x54, 0x12, 0x03, 0x50, 0x18, 0x93, 0x13,
+0x06, 0x60, 0x14, 0x45, 0x00, 0x81, 0x00 };
+
+/* Clear command, MSC -> BSC */
+static const u_int8_t msc_dtap[] = {
+0x00, 0x0d, 0xfd,
+0x06, 0x00, 0x00, 0x05, 0x00, 0x01, 0x06, 0x00,
+0x04, 0x20, 0x04, 0x01, 0x09 };
+static const u_int8_t msc_dtap_patched[] = {
+0x00, 0x0d, 0xfd,
+0x06, 0x00, 0x00, 0x15, 0x00, 0x01, 0x06, 0x00,
+0x04, 0x20, 0x04, 0x01, 0x09 };
+
+/*RLSD, MSC -> BSC */
+static const u_int8_t msc_rlsd[] = {
+0x00, 0x0a, 0xfd,
+0x04, 0x00, 0x00, 0x05, 0x01, 0x1f, 0xe4, 0x00,
+0x01, 0x00 };
+static const u_int8_t msc_rlsd_patched[] = {
+0x00, 0x0a, 0xfd,
+0x04, 0x00, 0x00, 0x15, 0x01, 0x1f, 0xe4, 0x00,
+0x01, 0x00 };
+
+/* RLC, BSC -> MSC */
+static const u_int8_t bsc_rlc[] = {
+0x00, 0x07, 0xfd,
+0x05, 0x01, 0x1f, 0xe4, 0x00, 0x00, 0x15 };
+
+static const u_int8_t bsc_rlc_patched[] = {
+0x00, 0x07, 0xfd,
+0x05, 0x01, 0x1f, 0xe4, 0x00, 0x00, 0x05 };
+
+
+/* a paging command */
+static const u_int8_t paging_by_lac_cmd[] = {
+0x00, 0x22, 0xfd, 0x09,
+0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x02, 0x00,
+0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x12, 0x00,
+0x10, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10, 0x02,
+0x01, 0x50, 0x02, 0x30, 0x1a, 0x03, 0x05, 0x20,
+0x15 };
+
+/* an assignment command */
+static const u_int8_t ass_cmd[] = {
+0x00, 0x12, 0xfd, 0x06,
+0x00, 0x00, 0x49, 0x00, 0x01, 0x0b, 0x00, 0x09,
+0x01, 0x0b, 0x03, 0x01, 0x0a, 0x11, 0x01, 0x00,
+0x15 };
+
+/*
+ * MGCP messages
+ */
+
+/* nothing to patch */
+static const char crcx[] = "CRCX 23265295 8@mgw MGCP 1.0\r\nC: 394b0439fb\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n";
+static const char crcx_patched[] = "CRCX 23265295 8@mgw MGCP 1.0\r\nC: 394b0439fb\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n";
+
+
+/* patch the ip and port */
+static const char crcx_resp[] = "200 23265295\r\nI: 1\r\n\r\nv=0\r\nc=IN IP4 172.16.18.2\r\nm=audio 4002 RTP/AVP 98\r\na=rtpmap:98 AMR/8000\r\n";
+static const char crcx_resp_patched[] = "200 23265295\r\nI: 1\r\n\r\nv=0\r\nc=IN IP4 10.0.0.1\r\nm=audio 999 RTP/AVP 98\r\na=rtpmap:98 AMR/8000\r\n";
+
+/* patch the ip and port */
+static const char mdcx[] = " MDCX 23330829 8@mgw MGCP 1.0\r\nC: 394b0439fb\r\nI: 1\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 1049380491 0 IN IP4 172.16.18.2\r\ns=-\r\nc=IN IP4 172.16.18.2\r\nt=0 0\r\nm=audio 4410 RTP/AVP 126\r\na=rtpmap:126 AMR/8000/1\r\na=fmtp:126 mode-set=2;start-mode=0\r\na=ptime:20\r\na=recvonly\r\nm=image 4412 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n";
+static const char mdcx_patched[] = " MDCX 23330829 8@mgw MGCP 1.0\r\nC: 394b0439fb\r\nI: 1\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 1049380491 0 IN IP4 172.16.18.2\r\ns=-\r\nc=IN IP4 10.0.0.23\r\nt=0 0\r\nm=audio 6666 RTP/AVP 126\r\na=rtpmap:126 AMR/8000/1\r\na=fmtp:126 mode-set=2;start-mode=0\r\na=ptime:20\r\na=recvonly\r\nm=image 4412 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n";
+
+
+static const char mdcx_resp[] = "200 23330829\r\n\r\nv=0\r\nc=IN IP4 172.16.18.2\r\nm=audio 4002 RTP/AVP 98\r\na=rtpmap:98 AMR/8000\r\n";
+static const char mdcx_resp_patched[] = "200 23330829\r\n\r\nv=0\r\nc=IN IP4 10.0.0.23\r\nm=audio 5555 RTP/AVP 98\r\na=rtpmap:98 AMR/8000\r\n";
+
+/* different line ending */
+static const char mdcx_resp2[] = "200 33330829\n\nv=0\nc=IN IP4 172.16.18.2\nm=audio 4002 RTP/AVP 98\na=rtpmap:98 AMR/8000\n";
+static const char mdcx_resp_patched2[] = "200 33330829\n\nv=0\nc=IN IP4 10.0.0.23\nm=audio 5555 RTP/AVP 98\na=rtpmap:98 AMR/8000\n";
+
+struct mgcp_patch_test {
+	const char *orig;
+	const char *patch;
+	const char *ip;
+	const int port;
+};
+
+static const struct mgcp_patch_test mgcp_messages[] = {
+	{
+		.orig = crcx,
+		.patch = crcx_patched,
+		.ip = "0.0.0.0",
+		.port = 2323,
+	},
+	{
+		.orig = crcx_resp,
+		.patch = crcx_resp_patched,
+		.ip = "10.0.0.1",
+		.port = 999,
+	},
+	{
+		.orig = mdcx,
+		.patch = mdcx_patched,
+		.ip = "10.0.0.23",
+		.port = 6666,
+	},
+	{
+		.orig = mdcx_resp,
+		.patch = mdcx_resp_patched,
+		.ip = "10.0.0.23",
+		.port = 5555,
+	},
+	{
+		.orig = mdcx_resp2,
+		.patch = mdcx_resp_patched2,
+		.ip = "10.0.0.23",
+		.port = 5555,
+	},
+};
diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c
new file mode 100644
index 0000000..d1db2e4
--- /dev/null
+++ b/openbsc/tests/bsc-nat/bsc_nat_test.c
@@ -0,0 +1,727 @@
+/*
+ * BSC NAT Message filtering
+ *
+ * (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/debug.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/bsc_nat.h>
+
+#include <osmocore/talloc.h>
+
+#include <stdio.h>
+
+/* test messages for ipa */
+static u_int8_t ipa_id[] = {
+	0x00, 0x01, 0xfe, 0x06,
+};
+
+/* SCCP messages are below */
+static u_int8_t gsm_reset[] = {
+	0x00, 0x12, 0xfd,
+	0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe,
+	0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04,
+	0x01, 0x20,
+};
+
+static const u_int8_t gsm_reset_ack[] = {
+	0x00, 0x13, 0xfd,
+	0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
+	0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03,
+	0x00, 0x01, 0x31,
+};
+
+static const u_int8_t gsm_paging[] = {
+	0x00, 0x20, 0xfd,
+	0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
+	0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x10,
+	0x00, 0x0e, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10,
+	0x02, 0x01, 0x31, 0x97, 0x61, 0x1a, 0x01, 0x06,
+};
+
+/* BSC -> MSC connection open */
+static const u_int8_t bssmap_cr[] = {
+	0x00, 0x2c, 0xfd,
+	0x01, 0x01, 0x02, 0x03, 0x02, 0x02, 0x04, 0x02,
+	0x42, 0xfe, 0x0f, 0x1f, 0x00, 0x1d, 0x57, 0x05,
+	0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x12, 0xc3,
+	0x50, 0x17, 0x10, 0x05, 0x24, 0x11, 0x03, 0x33,
+	0x19, 0xa2, 0x08, 0x29, 0x47, 0x10, 0x02, 0x01,
+	0x31, 0x97, 0x61, 0x00
+};
+
+/* MSC -> BSC connection confirm */
+static const u_int8_t bssmap_cc[] = {
+	0x00, 0x0a, 0xfd,
+	0x02, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
+};
+
+/* MSC -> BSC released */
+static const u_int8_t bssmap_released[] = {
+	0x00, 0x0e, 0xfd,
+	0x04, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00, 0x01, 0x0f,
+	0x02, 0x23, 0x42, 0x00,
+};
+
+/* BSC -> MSC released */
+static const u_int8_t bssmap_release_complete[] = {
+	0x00, 0x07, 0xfd,
+	0x05, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03
+};
+
+/* both directions IT timer */
+static const u_int8_t connnection_it[] = {
+	0x00, 0x0b, 0xfd,
+	0x10, 0x01, 0x02, 0x03, 0x01, 0x02, 0x03,
+	0x00, 0x00, 0x00, 0x00,
+};
+
+/* error in both directions */
+static const u_int8_t proto_error[] = {
+	0x00, 0x05, 0xfd,
+	0x0f, 0x22, 0x33, 0x44, 0x00,
+};
+
+/* MGCP wrap... */
+static const u_int8_t mgcp_msg[] = {
+	0x00, 0x03, 0xfc,
+	0x20, 0x20, 0x20,
+};
+
+/* location updating request */
+static const u_int8_t bss_lu[] = {
+	0x00, 0x2e, 0xfd,
+	0x01, 0x91, 0x45, 0x14, 0x02, 0x02, 0x04, 0x02,
+	0x42, 0xfe, 0x0f, 0x21, 0x00, 0x1f, 0x57, 0x05,
+	0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x14, 0xc3,
+	0x50, 0x17, 0x12, 0x05, 0x08, 0x70, 0x72, 0xf4,
+	0x80, 0xff, 0xfe, 0x30, 0x08, 0x29, 0x44, 0x50,
+	0x12, 0x03, 0x24, 0x01, 0x95, 0x00
+};
+
+/* paging response */
+static const uint8_t pag_resp[] = {
+	0x00, 0x2c, 0xfd, 0x01, 0xe5, 0x68,
+	0x14, 0x02, 0x02, 0x04, 0x02, 0x42, 0xfe, 0x0f,
+	0x1f, 0x00, 0x1d, 0x57, 0x05, 0x08, 0x00, 0x72,
+	0xf4, 0x80, 0x20, 0x16, 0xc3, 0x50, 0x17, 0x10,
+	0x06, 0x27, 0x01, 0x03, 0x30, 0x18, 0x96, 0x08,
+	0x29, 0x26, 0x30, 0x32, 0x11, 0x42, 0x01, 0x19,
+	0x00
+};
+
+struct filter_result {
+	const u_int8_t *data;
+	const u_int16_t length;
+	const int dir;
+	const int result;
+};
+
+static const struct filter_result results[] = {
+	{
+		.data = ipa_id,
+		.length = ARRAY_SIZE(ipa_id),
+		.dir = DIR_MSC,
+		.result = 1,
+	},
+	{
+		.data = gsm_reset,
+		.length = ARRAY_SIZE(gsm_reset),
+		.dir = DIR_MSC,
+		.result = 1,
+	},
+	{
+		.data = gsm_reset_ack,
+		.length = ARRAY_SIZE(gsm_reset_ack),
+		.dir = DIR_BSC,
+		.result = 1,
+	},
+	{
+		.data = gsm_paging,
+		.length = ARRAY_SIZE(gsm_paging),
+		.dir = DIR_BSC,
+		.result = 0,
+	},
+	{
+		.data = bssmap_cr,
+		.length = ARRAY_SIZE(bssmap_cr),
+		.dir = DIR_MSC,
+		.result = 0,
+	},
+	{
+		.data = bssmap_cc,
+		.length = ARRAY_SIZE(bssmap_cc),
+		.dir = DIR_BSC,
+		.result = 0,
+	},
+	{
+		.data = bssmap_released,
+		.length = ARRAY_SIZE(bssmap_released),
+		.dir = DIR_MSC,
+		.result = 0,
+	},
+	{
+		.data = bssmap_release_complete,
+		.length = ARRAY_SIZE(bssmap_release_complete),
+		.dir = DIR_BSC,
+		.result = 0,
+	},
+	{
+		.data = mgcp_msg,
+		.length = ARRAY_SIZE(mgcp_msg),
+		.dir = DIR_MSC,
+		.result = 0,
+	},
+	{
+		.data = connnection_it,
+		.length = ARRAY_SIZE(connnection_it),
+		.dir = DIR_BSC,
+		.result = 0,
+	},
+	{
+		.data = connnection_it,
+		.length = ARRAY_SIZE(connnection_it),
+		.dir = DIR_MSC,
+		.result = 0,
+	},
+	{
+		.data = proto_error,
+		.length = ARRAY_SIZE(proto_error),
+		.dir = DIR_BSC,
+		.result = 0,
+	},
+	{
+		.data = proto_error,
+		.length = ARRAY_SIZE(proto_error),
+		.dir = DIR_MSC,
+		.result = 0,
+	},
+
+};
+
+static void test_filter(void)
+{
+	int i;
+
+
+	/* start testinh with proper messages */
+	fprintf(stderr, "Testing BSS Filtering.\n");
+	for (i = 0; i < ARRAY_SIZE(results); ++i) {
+		int result;
+		struct bsc_nat_parsed *parsed;
+		struct msgb *msg = msgb_alloc(4096, "test-message");
+
+		fprintf(stderr, "Going to test item: %d\n", i);
+		memcpy(msg->data, results[i].data, results[i].length);
+		msg->l2h = msgb_put(msg, results[i].length);
+
+		parsed = bsc_nat_parse(msg);
+		if (!parsed) {
+			fprintf(stderr, "FAIL: Failed to parse the message\n");
+			continue;
+		}
+
+		result = bsc_nat_filter_ipa(results[i].dir, msg, parsed);
+		if (result != results[i].result) {
+			fprintf(stderr, "FAIL: Not the expected result got: %d wanted: %d\n",
+				result, results[i].result);
+		}
+
+		msgb_free(msg);
+	}
+}
+
+#include "bsc_data.c"
+
+static void copy_to_msg(struct msgb *msg, const u_int8_t *data, unsigned int length)
+{
+	msgb_reset(msg);
+	msg->l2h = msgb_put(msg, length);
+	memcpy(msg->l2h, data, msgb_l2len(msg));
+}
+
+#define VERIFY(con_found, con, msg, ver, str) \
+	if (!con_found || con_found->bsc != con) { \
+		fprintf(stderr, "Failed to find the con: %p\n", con_found); \
+		abort(); \
+	} \
+	if (memcmp(msg->data, ver, sizeof(ver)) != 0) { \
+		fprintf(stderr, "Failed to patch the %s msg.\n", str); \
+		abort(); \
+	}
+
+/* test conn tracking once */
+static void test_contrack()
+{
+	struct bsc_nat *nat;
+	struct bsc_connection *con;
+	struct sccp_connections *con_found;
+	struct sccp_connections *rc_con;
+	struct bsc_nat_parsed *parsed;
+	struct msgb *msg;
+
+	fprintf(stderr, "Testing connection tracking.\n");
+	nat = bsc_nat_alloc();
+	con = bsc_connection_alloc(nat);
+	con->cfg = bsc_config_alloc(nat, "foo", 23);
+	msg = msgb_alloc(4096, "test");
+
+	/* 1.) create a connection */
+	copy_to_msg(msg, bsc_cr, sizeof(bsc_cr));
+	parsed = bsc_nat_parse(msg);
+	con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
+	if (con_found != NULL) {
+		fprintf(stderr, "Con should not exist %p\n", con_found);
+		abort();
+	}
+	rc_con = create_sccp_src_ref(con, parsed);
+	if (!rc_con) {
+		fprintf(stderr, "Failed to create a ref\n");
+		abort();
+	}
+	con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
+	if (!con_found || con_found->bsc != con) {
+		fprintf(stderr, "Failed to find the con: %p\n", con_found);
+		abort();
+	}
+	if (con_found != rc_con) {
+		fprintf(stderr, "Failed to find the right connection.\n");
+		abort();
+	}
+	if (memcmp(msg->data, bsc_cr_patched, sizeof(bsc_cr_patched)) != 0) {
+		fprintf(stderr, "Failed to patch the BSC CR msg.\n");
+		abort();
+	}
+	talloc_free(parsed);
+
+	/* 2.) get the cc */
+	copy_to_msg(msg, msc_cc, sizeof(msc_cc));
+	parsed = bsc_nat_parse(msg);
+	con_found = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
+	VERIFY(con_found, con, msg, msc_cc_patched, "MSC CC");
+	if (update_sccp_src_ref(con_found, parsed) != 0) {
+		fprintf(stderr, "Failed to update the SCCP con.\n");
+		abort();
+	}
+
+	/* 3.) send some data */
+	copy_to_msg(msg, bsc_dtap, sizeof(bsc_dtap));
+	parsed = bsc_nat_parse(msg);
+	con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
+	VERIFY(con_found, con, msg, bsc_dtap_patched, "BSC DTAP");
+
+	/* 4.) receive some data */
+	copy_to_msg(msg, msc_dtap, sizeof(msc_dtap));
+	parsed = bsc_nat_parse(msg);
+	con_found = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
+	VERIFY(con_found, con, msg, msc_dtap_patched, "MSC DTAP");
+
+	/* 5.) close the connection */
+	copy_to_msg(msg, msc_rlsd, sizeof(msc_rlsd));
+	parsed = bsc_nat_parse(msg);
+	con_found = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
+	VERIFY(con_found, con, msg, msc_rlsd_patched, "MSC RLSD");
+
+	/* 6.) confirm the connection close */
+	copy_to_msg(msg, bsc_rlc, sizeof(bsc_rlc));
+	parsed = bsc_nat_parse(msg);
+	con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
+	if (!con_found || con_found->bsc != con) {
+		fprintf(stderr, "Failed to find the con: %p\n", con_found);
+		abort();
+	}
+	if (memcmp(msg->data, bsc_rlc_patched, sizeof(bsc_rlc_patched)) != 0) {
+		fprintf(stderr, "Failed to patch the BSC CR msg.\n");
+		abort();
+	}
+	remove_sccp_src_ref(con, msg, parsed);
+	talloc_free(parsed);
+
+	copy_to_msg(msg, bsc_rlc, sizeof(bsc_rlc));
+	parsed = bsc_nat_parse(msg);
+	con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
+
+	/* verify that it is gone */
+	if (con_found != NULL) {
+		fprintf(stderr, "Con should be gone. %p\n", con_found);
+		abort();
+	}
+	talloc_free(parsed);
+
+
+	talloc_free(nat);
+	msgb_free(msg);
+}
+
+static void test_paging(void)
+{
+	int lac;
+	struct bsc_nat *nat;
+	struct bsc_connection *con;
+	struct bsc_nat_parsed *parsed;
+	struct bsc_config cfg;
+	struct msgb *msg;
+
+	fprintf(stderr, "Testing paging by lac.\n");
+
+	nat = bsc_nat_alloc();
+	con = bsc_connection_alloc(nat);
+	con->cfg = &cfg;
+	cfg.lac = 23;
+	con->authenticated = 1;
+	llist_add(&con->list_entry, &nat->bsc_connections);
+	msg = msgb_alloc(4096, "test");
+
+	/* Test completely bad input */
+	copy_to_msg(msg, paging_by_lac_cmd, sizeof(paging_by_lac_cmd));
+	if (bsc_nat_find_bsc(nat, msg, &lac) != 0) {
+		fprintf(stderr, "Should have not found anything.\n");
+		abort();
+	}
+
+	/* Test it by not finding it */
+	copy_to_msg(msg, paging_by_lac_cmd, sizeof(paging_by_lac_cmd));
+	parsed = bsc_nat_parse(msg);
+	if (bsc_nat_find_bsc(nat, msg, &lac) != 0) {
+		fprintf(stderr, "Should have not found aynthing.\n");
+		abort();
+	}
+	talloc_free(parsed);
+
+	/* Test by finding it */
+	cfg.lac = 8213;
+	copy_to_msg(msg, paging_by_lac_cmd, sizeof(paging_by_lac_cmd));
+	parsed = bsc_nat_parse(msg);
+	if (bsc_nat_find_bsc(nat, msg, &lac) != con) {
+		fprintf(stderr, "Should have found it.\n");
+		abort();
+	}
+	talloc_free(parsed);
+}
+
+static void test_mgcp_ass_tracking(void)
+{
+	struct bsc_connection *bsc;
+	struct bsc_nat *nat;
+	struct sccp_connections con;
+	struct bsc_nat_parsed *parsed;
+	struct msgb *msg;
+
+	fprintf(stderr, "Testing MGCP.\n");
+	memset(&con, 0, sizeof(con));
+
+	nat = bsc_nat_alloc();
+	nat->bsc_endpoints = talloc_zero_array(nat,
+					       struct bsc_endpoint,
+					       33);
+	bsc = bsc_connection_alloc(nat);
+	bsc->cfg = bsc_config_alloc(nat, "foo", 2323);
+	con.bsc = bsc;
+
+	msg = msgb_alloc(4096, "foo");
+	copy_to_msg(msg, ass_cmd, sizeof(ass_cmd));
+	parsed = bsc_nat_parse(msg);
+	if (bsc_mgcp_assign(&con, msg) != 0) {
+		fprintf(stderr, "Failed to handle assignment.\n");
+		abort();
+	}
+
+	if (con.msc_timeslot != 21) {
+		fprintf(stderr, "Timeslot should be 21.\n");
+		abort();
+	}
+
+	if (con.bsc_timeslot != 21) {
+		fprintf(stderr, "Assigned timeslot should have been 21.\n");
+		abort();
+	}
+	talloc_free(parsed);
+
+	bsc_mgcp_dlcx(&con);
+	if (con.bsc_timeslot != -1 || con.msc_timeslot != -1) {
+		fprintf(stderr, "Clearing should remove the mapping.\n");
+		abort();
+	}
+
+	talloc_free(nat);
+}
+
+/* test the code to find a given connection */
+static void test_mgcp_find(void)
+{
+	struct bsc_nat *nat;
+	struct bsc_connection *con;
+	struct sccp_connections *sccp_con;
+
+	fprintf(stderr, "Testing finding of a BSC Connection\n");
+
+	nat = bsc_nat_alloc();
+	con = bsc_connection_alloc(nat);
+	llist_add(&con->list_entry, &nat->bsc_connections);
+
+	sccp_con = talloc_zero(con, struct sccp_connections);
+	sccp_con->msc_timeslot = 12;
+	sccp_con->bsc_timeslot = 12;
+	sccp_con->bsc = con;
+	llist_add(&sccp_con->list_entry, &nat->sccp_connections);
+
+	if (bsc_mgcp_find_con(nat, 11) != NULL) {
+		fprintf(stderr, "Found the wrong connection.\n");
+		abort();
+	}
+
+	if (bsc_mgcp_find_con(nat, 12) != sccp_con) {
+		fprintf(stderr, "Didn't find the connection\n");
+		abort();
+	}
+
+	sccp_con->msc_timeslot = 0;
+	sccp_con->bsc_timeslot = 0;
+	if (bsc_mgcp_find_con(nat, 1) != sccp_con) {
+		fprintf(stderr, "Didn't find the connection\n");
+		abort();
+	}
+
+	/* free everything */
+	talloc_free(nat);
+}
+
+static void test_mgcp_rewrite(void)
+{
+	int i;
+	struct msgb *output;
+	fprintf(stderr, "Test rewriting MGCP messages.\n");
+
+	for (i = 0; i < ARRAY_SIZE(mgcp_messages); ++i) {
+		const char *orig = mgcp_messages[i].orig;
+		const char *patc = mgcp_messages[i].patch;
+		const char *ip = mgcp_messages[i].ip;
+		const int port = mgcp_messages[i].port;
+
+		char *input = strdup(orig);
+
+		output = bsc_mgcp_rewrite(input, strlen(input), ip, port);
+		if (msgb_l2len(output) != strlen(patc)) {
+			fprintf(stderr, "Wrong sizes for test: %d  %d != %d != %d\n", i, msgb_l2len(output), strlen(patc), strlen(orig));
+			fprintf(stderr, "String '%s' vs '%s'\n", (const char *) output->l2h, patc);
+			abort();
+		}
+
+		if (memcmp(output->l2h, patc, msgb_l2len(output)) != 0) {
+			fprintf(stderr, "Broken on %d msg: '%s'\n", i, (const char *) output->l2h);
+			abort();
+		}
+
+		msgb_free(output);
+		free(input);
+	}
+}
+
+static void test_mgcp_parse(void)
+{
+	int code, ci;
+	char transaction[60];
+
+	fprintf(stderr, "Test MGCP response parsing.\n");
+
+	if (bsc_mgcp_parse_response(crcx_resp, &code, transaction) != 0) {
+		fprintf(stderr, "Failed to parse CRCX resp.\n");
+		abort();
+	}
+
+	if (code != 200) {
+		fprintf(stderr, "Failed to parse the CODE properly. Got: %d\n", code);
+		abort();
+	}
+
+	if (strcmp(transaction, "23265295") != 0) {
+		fprintf(stderr, "Failed to parse transaction id: '%s'\n", transaction);
+		abort();
+	}
+
+	ci = bsc_mgcp_extract_ci(crcx_resp);
+	if (ci != 1) {
+		fprintf(stderr, "Failed to parse the CI. Got: %d\n", ci);
+		abort();
+	}
+}
+
+struct cr_filter {
+	const u_int8_t *data;
+	int length;
+	int result;
+	int contype;
+
+	const char *bsc_imsi_allow;
+	const char *bsc_imsi_deny;
+	const char *nat_imsi_deny;
+};
+
+static struct cr_filter cr_filter[] = {
+	{
+		.data = bssmap_cr,
+		.length = sizeof(bssmap_cr),
+		.result = 0,
+		.contype = NAT_CON_TYPE_CM_SERV_REQ,
+	},
+	{
+		.data = bss_lu,
+		.length = sizeof(bss_lu),
+		.result = 0,
+		.contype = NAT_CON_TYPE_LU,
+	},
+	{
+		.data = pag_resp,
+		.length = sizeof(pag_resp),
+		.result = 0,
+		.contype = NAT_CON_TYPE_PAG_RESP,
+	},
+	{
+		/* nat deny is before blank/null BSC */
+		.data = bss_lu,
+		.length = sizeof(bss_lu),
+		.result = -3,
+		.nat_imsi_deny = "[0-9]*",
+		.contype = NAT_CON_TYPE_LU,
+	},
+	{
+		/* BSC allow is before NAT deny */
+		.data = bss_lu,
+		.length = sizeof(bss_lu),
+		.result = 0,
+		.nat_imsi_deny = "[0-9]*",
+		.bsc_imsi_allow = "2440[0-9]*",
+		.contype = NAT_CON_TYPE_LU,
+	},
+	{
+		/* BSC allow is before NAT deny */
+		.data = bss_lu,
+		.length = sizeof(bss_lu),
+		.result = 0,
+		.bsc_imsi_allow = "[0-9]*",
+		.nat_imsi_deny = "[0-9]*",
+		.contype = NAT_CON_TYPE_LU,
+	},
+	{
+		/* filter as deny is first */
+		.data = bss_lu,
+		.length = sizeof(bss_lu),
+		.result = -2,
+		.bsc_imsi_deny = "[0-9]*",
+		.bsc_imsi_allow = "[0-9]*",
+		.nat_imsi_deny = "[0-9]*",
+		.contype = NAT_CON_TYPE_LU,
+	},
+
+};
+
+static void test_cr_filter()
+{
+	int i, res, contype;
+	struct msgb *msg = msgb_alloc(4096, "test_cr_filter");
+	struct bsc_nat_parsed *parsed;
+	struct bsc_nat_acc_lst *nat_lst, *bsc_lst;
+	struct bsc_nat_acc_lst_entry *nat_entry, *bsc_entry;
+
+	struct bsc_nat *nat = bsc_nat_alloc();
+	struct bsc_connection *bsc = bsc_connection_alloc(nat);
+	bsc->cfg = bsc_config_alloc(nat, "foo", 1234);
+	bsc->cfg->acc_lst_name = "bsc";
+	nat->acc_lst_name = "nat";
+
+	nat_lst = bsc_nat_acc_lst_get(nat, "nat");
+	bsc_lst = bsc_nat_acc_lst_get(nat, "bsc");
+
+	bsc_entry = bsc_nat_acc_lst_entry_create(bsc_lst);
+	nat_entry = bsc_nat_acc_lst_entry_create(nat_lst);
+
+	for (i = 0; i < ARRAY_SIZE(cr_filter); ++i) {
+		msgb_reset(msg);
+		copy_to_msg(msg, cr_filter[i].data, cr_filter[i].length);
+
+		nat_lst = bsc_nat_acc_lst_get(nat, "nat");
+		bsc_lst = bsc_nat_acc_lst_get(nat, "bsc");
+
+		bsc_parse_reg(nat_entry, &nat_entry->imsi_deny_re, &nat_entry->imsi_deny,
+			      cr_filter[i].nat_imsi_deny ? 1 : 0,
+			      &cr_filter[i].nat_imsi_deny);
+		bsc_parse_reg(bsc_entry, &bsc_entry->imsi_allow_re, &bsc_entry->imsi_allow,
+			      cr_filter[i].bsc_imsi_allow ? 1 : 0,
+			      &cr_filter[i].bsc_imsi_allow);
+		bsc_parse_reg(bsc_entry, &bsc_entry->imsi_deny_re, &bsc_entry->imsi_deny,
+			      cr_filter[i].bsc_imsi_deny ? 1 : 0,
+			      &cr_filter[i].bsc_imsi_deny);
+
+		parsed = bsc_nat_parse(msg);
+		if (!parsed) {
+			fprintf(stderr, "FAIL: Failed to parse the message\n");
+			abort();
+		}
+
+		res = bsc_nat_filter_sccp_cr(bsc, msg, parsed, &contype);
+		if (res != cr_filter[i].result) {
+			fprintf(stderr, "FAIL: Wrong result %d for test %d.\n", res, i);
+			abort();
+		}
+
+		if (contype != cr_filter[i].contype) {
+			fprintf(stderr, "FAIL: Wrong contype %d for test %d.\n", res, contype);
+			abort();
+		}
+
+		talloc_free(parsed);
+	}
+
+	msgb_free(msg);
+}
+
+int main(int argc, char **argv)
+{
+	struct log_target *stderr_target;
+
+	stderr_target = log_target_create_stderr();
+	log_add_target(stderr_target);
+	log_set_all_filter(stderr_target, 1);
+
+	test_filter();
+	test_contrack();
+	test_paging();
+	test_mgcp_ass_tracking();
+	test_mgcp_find();
+	test_mgcp_rewrite();
+	test_mgcp_parse();
+	test_cr_filter();
+	return 0;
+}
+
+void input_event()
+{}
+int nm_state_event()
+{
+	return -1;
+}
+
+int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
+{
+	return -1;
+}
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 4013211..b9248dc 100644
--- a/wireshark/abis_oml.patch
+++ b/wireshark/abis_oml.patch
@@ -1,21 +1,21 @@
-From 5857518be87641fdab45e593bc9fd5ef5595e619 Mon Sep 17 00:00:00 2001
+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 | 1382 +++++++++++++++++++++++++++++++++
- epan/dissectors/packet-gsm_abis_oml.h |  787 +++++++++++++++++++
- 3 files changed, 2170 insertions(+), 0 deletions(-)
+ 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 dbc3726..98dcdc3 100644
+index b18f42e..115fa09 100644
 --- a/epan/dissectors/Makefile.common
 +++ b/epan/dissectors/Makefile.common
-@@ -481,6 +481,7 @@ DISSECTOR_SRC = \
+@@ -485,6 +485,7 @@ DISSECTOR_SRC = \
  	packet-gsm_a_gm.c		\
  	packet-gsm_a_rp.c		\
  	packet-gsm_a_rr.c	\
@@ -25,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..fa46ab5
+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>
@@ -70,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;
 +
@@ -145,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;
 +
@@ -611,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
@@ -695,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,
@@ -715,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);
@@ -762,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:
@@ -791,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();
@@ -1413,10 +1436,10 @@
 +}
 diff --git a/epan/dissectors/packet-gsm_abis_oml.h b/epan/dissectors/packet-gsm_abis_oml.h
 new file mode 100644
-index 0000000..d523e96
+index 0000000..bdc414d
 --- /dev/null
 +++ b/epan/dissectors/packet-gsm_abis_oml.h
-@@ -0,0 +1,787 @@
+@@ -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 */
 +
@@ -2027,6 +2050,7 @@
 +
 +/* From openbsc/include/openbsc/tlv.h */
 +enum tlv_type {
++	TLV_TYPE_UNKNOWN,
 +	TLV_TYPE_FIXED,
 +	TLV_TYPE_T,
 +	TLV_TYPE_TV,
@@ -2075,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 },
@@ -2098,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 },
@@ -2142,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 },
@@ -2168,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 },
@@ -2199,7 +2233,9 @@
 +		[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 },
 +	},
 +};
 +