Import upstream version 0.9.13
diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am
new file mode 100644
index 0000000..2351f8a
--- /dev/null
+++ b/src/utils/Makefile.am
@@ -0,0 +1,12 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
+AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS)
+AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(COVERAGE_LDFLAGS)
+
+bin_PROGRAMS = bs11_config isdnsync
+
+bs11_config_SOURCES = bs11_config.c rs232.c
+bs11_config_LDADD = $(top_builddir)/src/libcommon/libcommon.a \
+		    $(top_builddir)/src/libabis/libabis.a \
+		    $(top_builddir)/src/libbsc/libbsc.a
+
+isdnsync_SOURCES = isdnsync.c
diff --git a/src/utils/Makefile.in b/src/utils/Makefile.in
new file mode 100644
index 0000000..17e8ad6
--- /dev/null
+++ b/src/utils/Makefile.in
@@ -0,0 +1,496 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+bin_PROGRAMS = bs11_config$(EXEEXT) isdnsync$(EXEEXT)
+subdir = src/utils
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/bscconfig.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_bs11_config_OBJECTS = bs11_config.$(OBJEXT) rs232.$(OBJEXT)
+bs11_config_OBJECTS = $(am_bs11_config_OBJECTS)
+bs11_config_DEPENDENCIES = $(top_builddir)/src/libcommon/libcommon.a \
+	$(top_builddir)/src/libabis/libabis.a \
+	$(top_builddir)/src/libbsc/libbsc.a
+am_isdnsync_OBJECTS = isdnsync.$(OBJEXT)
+isdnsync_OBJECTS = $(am_isdnsync_OBJECTS)
+isdnsync_LDADD = $(LDADD)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo "  CC    " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo "  CCLD  " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN   " $@;
+SOURCES = $(bs11_config_SOURCES) $(isdnsync_SOURCES)
+DIST_SOURCES = $(bs11_config_SOURCES) $(isdnsync_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COVERAGE_CFLAGS = @COVERAGE_CFLAGS@
+COVERAGE_LDFLAGS = @COVERAGE_LDFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GPRS_LIBGTP = @GPRS_LIBGTP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBOSMOCORE_CFLAGS = @LIBOSMOCORE_CFLAGS@
+LIBOSMOCORE_LIBS = @LIBOSMOCORE_LIBS@
+LIBOSMOSCCP_CFLAGS = @LIBOSMOSCCP_CFLAGS@
+LIBOSMOSCCP_LIBS = @LIBOSMOSCCP_LIBS@
+LIBOSMOVTY_CFLAGS = @LIBOSMOVTY_CFLAGS@
+LIBOSMOVTY_LIBS = @LIBOSMOVTY_LIBS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SYMBOL_VISIBILITY = @SYMBOL_VISIBILITY@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
+AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS)
+AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(COVERAGE_LDFLAGS)
+bs11_config_SOURCES = bs11_config.c rs232.c
+bs11_config_LDADD = $(top_builddir)/src/libcommon/libcommon.a \
+		    $(top_builddir)/src/libabis/libabis.a \
+		    $(top_builddir)/src/libbsc/libbsc.a
+
+isdnsync_SOURCES = isdnsync.c
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/utils/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu src/utils/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	for p in $$list; do echo "$$p $$p"; done | \
+	sed 's/$(EXEEXT)$$//' | \
+	while read p p1; do if test -f $$p; \
+	  then echo "$$p"; echo "$$p"; else :; fi; \
+	done | \
+	sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+	    -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+	sed 'N;N;N;s,\n, ,g' | \
+	$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+	  { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+	    if ($$2 == $$4) files[d] = files[d] " " $$1; \
+	    else { print "f", $$3 "/" $$4, $$1; } } \
+	  END { for (d in files) print "f", d, files[d] }' | \
+	while read type dir files; do \
+	    if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+	    test -z "$$files" || { \
+	      echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+	      $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+	    } \
+	; done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	files=`for p in $$list; do echo "$$p"; done | \
+	  sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+	      -e 's/$$/$(EXEEXT)/' `; \
+	test -n "$$list" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+	-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+bs11_config$(EXEEXT): $(bs11_config_OBJECTS) $(bs11_config_DEPENDENCIES) 
+	@rm -f bs11_config$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(bs11_config_OBJECTS) $(bs11_config_LDADD) $(LIBS)
+isdnsync$(EXEEXT): $(isdnsync_OBJECTS) $(isdnsync_DEPENDENCIES) 
+	@rm -f isdnsync$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(isdnsync_OBJECTS) $(isdnsync_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bs11_config.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isdnsync.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rs232.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+	for dir in "$(DESTDIR)$(bindir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+	clean-generic ctags distclean distclean-compile \
+	distclean-generic distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-binPROGRAMS \
+	install-data install-data-am install-dvi install-dvi-am \
+	install-exec install-exec-am install-html install-html-am \
+	install-info install-info-am install-man install-pdf \
+	install-pdf-am install-ps install-ps-am install-strip \
+	installcheck installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+	uninstall-am uninstall-binPROGRAMS
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/utils/bs11_config.c b/src/utils/bs11_config.c
new file mode 100644
index 0000000..eaed8b7
--- /dev/null
+++ b/src/utils/bs11_config.c
@@ -0,0 +1,918 @@
+/* Siemens BS-11 microBTS configuration tool */
+
+/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
+ * All Rights Reserved
+ *
+ * This software is based on ideas (but not code) of BS11Config
+ * (C) 2009 by Dieter Spaar <spaar@mirider.augusta.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <openbsc/gsm_data.h>
+#include <openbsc/abis_nm.h>
+#include <osmocore/msgb.h>
+#include <osmocore/tlv.h>
+#include <openbsc/debug.h>
+#include <osmocore/select.h>
+#include <openbsc/rs232.h>
+
+/* state of our bs11_config application */
+enum bs11cfg_state {
+	STATE_NONE,
+	STATE_LOGON_WAIT,
+	STATE_LOGON_ACK,
+	STATE_SWLOAD,
+	STATE_QUERY,
+};
+static enum bs11cfg_state bs11cfg_state = STATE_NONE;
+static char *command, *value;
+struct timer_list status_timer;
+
+static const u_int8_t obj_li_attr[] = {
+	NM_ATT_BS11_BIT_ERR_THESH, 0x09, 0x00,
+	NM_ATT_BS11_L1_PROT_TYPE, 0x00,
+	NM_ATT_BS11_LINE_CFG, 0x00,
+};
+static const u_int8_t obj_bbsig0_attr[] = {
+	NM_ATT_BS11_RSSI_OFFS, 0x02, 0x00, 0x00,
+	NM_ATT_BS11_DIVERSITY, 0x01, 0x00,
+};
+static const u_int8_t obj_pa0_attr[] = {
+	NM_ATT_BS11_TXPWR, 0x01, BS11_TRX_POWER_GSM_30mW,
+};
+static const char *trx1_password = "1111111111";
+#define TEI_OML	25
+
+static const u_int8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 };
+
+static struct log_target *stderr_target;
+
+/* dummy function to keep gsm_data.c happy */
+struct counter *counter_alloc(const char *name)
+{
+	return NULL;
+}
+
+int handle_serial_msg(struct msgb *rx_msg);
+
+/* create all objects for an initial configuration */
+static int create_objects(struct gsm_bts *bts)
+{
+	fprintf(stdout, "Crating Objects for minimal config\n");
+	abis_nm_bs11_create_object(bts, BS11_OBJ_LI, 0, sizeof(obj_li_attr),
+				   obj_li_attr);
+	abis_nm_bs11_create_object(bts, BS11_OBJ_GPSU, 0, 0, NULL);
+	abis_nm_bs11_create_object(bts, BS11_OBJ_ALCO, 0, 0, NULL);
+	abis_nm_bs11_create_object(bts, BS11_OBJ_CCLK, 0, 0, NULL);
+	abis_nm_bs11_create_object(bts, BS11_OBJ_BBSIG, 0,
+				   sizeof(obj_bbsig0_attr), obj_bbsig0_attr);
+	abis_nm_bs11_create_object(bts, BS11_OBJ_PA, 0,
+				   sizeof(obj_pa0_attr), obj_pa0_attr);
+	abis_nm_bs11_create_envaBTSE(bts, 0);
+	abis_nm_bs11_create_envaBTSE(bts, 1);
+	abis_nm_bs11_create_envaBTSE(bts, 2);
+	abis_nm_bs11_create_envaBTSE(bts, 3);
+
+	abis_nm_bs11_conn_oml_tei(bts, 0, 1, 0xff, TEI_OML);
+
+	abis_nm_bs11_set_trx_power(bts->c0, BS11_TRX_POWER_GSM_30mW);
+	
+	sleep(1);
+
+	abis_nm_bs11_set_trx1_pw(bts, trx1_password);
+
+	sleep(1);
+
+	return 0;
+}
+
+static int create_trx1(struct gsm_bts *bts)
+{
+	u_int8_t bbsig1_attr[sizeof(obj_bbsig0_attr)+12];
+	u_int8_t *cur = bbsig1_attr;
+	struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, 1);
+
+	if (!trx)
+		trx = gsm_bts_trx_alloc(bts);
+
+	fprintf(stdout, "Crating Objects for TRX1\n");
+
+	abis_nm_bs11_set_trx1_pw(bts, trx1_password);
+
+	sleep(1);
+
+	cur = tlv_put(cur, NM_ATT_BS11_PASSWORD, 10,
+		      (u_int8_t *)trx1_password);
+	memcpy(cur, obj_bbsig0_attr, sizeof(obj_bbsig0_attr));
+	abis_nm_bs11_create_object(bts, BS11_OBJ_BBSIG, 1,
+				   sizeof(bbsig1_attr), bbsig1_attr);
+	abis_nm_bs11_create_object(bts, BS11_OBJ_PA, 1,
+				   sizeof(obj_pa0_attr), obj_pa0_attr);
+	abis_nm_bs11_set_trx_power(trx, BS11_TRX_POWER_GSM_30mW);
+	
+	return 0;
+}
+
+static char *serial_port = "/dev/ttyUSB0";
+static char *fname_safety = "BTSBMC76.SWI";
+static char *fname_software = "HS011106.SWL";
+static int delay_ms = 0;
+static int win_size = 8;
+static int param_disconnect = 0;
+static int param_restart = 0;
+static int param_forced = 0;
+static struct gsm_bts *g_bts;
+
+static int file_is_readable(const char *fname)
+{
+	int rc;
+	struct stat st;
+
+	rc = stat(fname, &st);
+	if (rc < 0)
+		return 0;
+
+	if (S_ISREG(st.st_mode) && (st.st_mode & S_IRUSR))
+		return 1;
+
+	return 0;
+}
+
+static int percent;
+static int percent_old;
+
+/* callback function passed to the ABIS OML code */
+static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *msg,
+		       void *data, void *param)
+{
+	if (hook != GSM_HOOK_NM_SWLOAD)
+		return 0;
+
+	switch (event) {
+	case NM_MT_LOAD_INIT_ACK:
+		fprintf(stdout, "Software Load Initiate ACK\n");
+		break;
+	case NM_MT_LOAD_INIT_NACK:
+		fprintf(stderr, "ERROR: Software Load Initiate NACK\n");
+		exit(5);
+		break;
+	case NM_MT_LOAD_END_ACK:
+		if (data) {
+			/* we did a safety load and must activate it */
+			abis_nm_software_activate(g_bts, fname_safety,
+						  swload_cbfn, g_bts);
+			sleep(5);
+		}
+		break;
+	case NM_MT_LOAD_END_NACK:
+		fprintf(stderr, "ERROR: Software Load End NACK\n");
+		exit(3);
+		break;
+	case NM_MT_ACTIVATE_SW_NACK:
+		fprintf(stderr, "ERROR: Activate Software NACK\n");
+		exit(4);
+		break;
+	case NM_MT_ACTIVATE_SW_ACK:
+		bs11cfg_state = STATE_NONE;
+		
+		break;
+	case NM_MT_LOAD_SEG_ACK:
+		percent = abis_nm_software_load_status(g_bts);
+		if (percent > percent_old)
+			printf("Software Download Progress: %d%%\n", percent);
+		percent_old = percent;
+		break;
+	}
+	return 0;
+}
+
+static const char *bs11_link_state[] = {
+	[0x00]	= "Down",
+	[0x01]	= "Up",
+	[0x02]	= "Restoring",
+};
+
+static const char *linkstate_name(u_int8_t linkstate)
+{
+	if (linkstate > ARRAY_SIZE(bs11_link_state))
+		return "Unknown";
+
+	return bs11_link_state[linkstate];
+}
+
+static const char *mbccu_load[] = {
+	[0]	= "No Load",
+	[1]	= "Load BTSCAC",
+	[2]	= "Load BTSDRX",
+	[3]	= "Load BTSBBX",
+	[4]	= "Load BTSARC",
+	[5]	= "Load",
+};
+
+static const char *mbccu_load_name(u_int8_t linkstate)
+{
+	if (linkstate > ARRAY_SIZE(mbccu_load))
+		return "Unknown";
+
+	return mbccu_load[linkstate];
+}
+
+static const char *bts_phase_name(u_int8_t phase)
+{
+	switch (phase) {
+	case BS11_STATE_WARM_UP:
+	case BS11_STATE_WARM_UP_2:
+		return "Warm Up";
+		break;
+	case BS11_STATE_LOAD_SMU_SAFETY:
+		return "Load SMU Safety";
+		break;
+	case BS11_STATE_LOAD_SMU_INTENDED:
+		return "Load SMU Intended";
+		break;
+	case BS11_STATE_LOAD_MBCCU:
+		return "Load MBCCU";
+		break;
+	case BS11_STATE_SOFTWARE_RQD:
+		return "Software required";
+		break;
+	case BS11_STATE_WAIT_MIN_CFG:
+	case BS11_STATE_WAIT_MIN_CFG_2:
+		return "Wait minimal config";
+		break;
+	case BS11_STATE_MAINTENANCE:
+		return "Maintenance";
+		break;
+	case BS11_STATE_NORMAL:
+		return "Normal";
+		break;
+	case BS11_STATE_ABIS_LOAD:
+		return "Abis load";
+		break;
+	default:
+		return "Unknown";
+		break;
+	}
+}
+
+static const char *trx_power_name(u_int8_t pwr)
+{
+	switch (pwr) {
+	case BS11_TRX_POWER_GSM_2W:	
+		return "2W (GSM)";
+	case BS11_TRX_POWER_GSM_250mW:
+		return "250mW (GSM)";
+	case BS11_TRX_POWER_GSM_80mW:
+		return "80mW (GSM)";
+	case BS11_TRX_POWER_GSM_30mW:
+		return "30mW (GSM)";
+	case BS11_TRX_POWER_DCS_3W:
+		return "3W (DCS)";
+	case BS11_TRX_POWER_DCS_1W6:
+		return "1.6W (DCS)";
+	case BS11_TRX_POWER_DCS_500mW:
+		return "500mW (DCS)";
+	case BS11_TRX_POWER_DCS_160mW:
+		return "160mW (DCS)";
+	default:
+		return "unknown value";
+	}
+}
+
+static const char *pll_mode_name(u_int8_t mode)
+{
+	switch (mode) {
+	case BS11_LI_PLL_LOCKED:
+		return "E1 Locked";
+	case BS11_LI_PLL_STANDALONE:
+		return "Standalone";
+	default:
+		return "unknown";
+	}
+}
+
+static const char *cclk_acc_name(u_int8_t acc)
+{
+	switch (acc) {
+	case 0:
+		/* Out of the demanded +/- 0.05ppm */
+		return "Medium";
+	case 1:
+		/* Synchronized with Abis, within demanded tolerance +/- 0.05ppm */
+		return "High";
+	default:
+		return "unknown";
+	}
+}
+
+static const char *bport_lcfg_name(u_int8_t lcfg)
+{
+	switch (lcfg) {
+	case BS11_LINE_CFG_STAR:
+		return "Star";
+	case BS11_LINE_CFG_MULTIDROP:
+		return "Multi-Drop";
+	default:
+		return "unknown";
+	}
+}
+
+static const char *obj_name(struct abis_om_fom_hdr *foh)
+{
+	static char retbuf[256];
+
+	retbuf[0] = 0;
+
+	switch (foh->obj_class) {
+	case NM_OC_BS11:
+		strcat(retbuf, "BS11 ");
+		switch (foh->obj_inst.bts_nr) {
+		case BS11_OBJ_PA:
+			sprintf(retbuf+strlen(retbuf), "Power Amplifier %d ",
+				foh->obj_inst.ts_nr);
+			break;
+		case BS11_OBJ_LI:
+			sprintf(retbuf+strlen(retbuf), "Line Interface ");
+			break;
+		case BS11_OBJ_CCLK:
+			sprintf(retbuf+strlen(retbuf), "CCLK ");
+			break;
+		}
+		break;
+	case NM_OC_SITE_MANAGER:
+		strcat(retbuf, "SITE MANAGER ");
+		break;
+	case NM_OC_BS11_BPORT:
+		sprintf(retbuf+strlen(retbuf), "BPORT%u ",
+			foh->obj_inst.bts_nr);
+		break;
+	}
+	return retbuf;
+}
+
+static void print_state(struct tlv_parsed *tp)
+{
+	if (TLVP_PRESENT(tp, NM_ATT_BS11_BTS_STATE)) {
+		u_int8_t phase, mbccu;
+		if (TLVP_LEN(tp, NM_ATT_BS11_BTS_STATE) >= 1) {
+			phase = *TLVP_VAL(tp, NM_ATT_BS11_BTS_STATE);
+			printf("PHASE: %u %-20s ", phase & 0xf,
+				bts_phase_name(phase));
+		}
+		if (TLVP_LEN(tp, NM_ATT_BS11_BTS_STATE) >= 2) {
+			mbccu = *(TLVP_VAL(tp, NM_ATT_BS11_BTS_STATE)+1);
+			printf("MBCCU0: %-11s MBCCU1: %-11s ",
+				mbccu_load_name(mbccu & 0xf), mbccu_load_name(mbccu >> 4));
+		}
+	}
+	if (TLVP_PRESENT(tp, NM_ATT_BS11_E1_STATE) &&
+	    TLVP_LEN(tp, NM_ATT_BS11_E1_STATE) >= 1) {
+		u_int8_t e1_state = *TLVP_VAL(tp, NM_ATT_BS11_E1_STATE);
+		printf("Abis-link: %-9s ", linkstate_name(e1_state & 0xf));
+	}
+	printf("\n");
+}
+
+static int print_attr(struct tlv_parsed *tp)
+{
+	if (TLVP_PRESENT(tp, NM_ATT_BS11_ESN_PCB_SERIAL)) {
+		printf("\tBS-11 ESN PCB Serial Number: %s\n",
+			TLVP_VAL(tp, NM_ATT_BS11_ESN_PCB_SERIAL));
+	}
+	if (TLVP_PRESENT(tp, NM_ATT_BS11_ESN_HW_CODE_NO)) {
+		printf("\tBS-11 ESN Hardware Code Number: %s\n",
+			TLVP_VAL(tp, NM_ATT_BS11_ESN_HW_CODE_NO)+6);
+	}
+	if (TLVP_PRESENT(tp, NM_ATT_BS11_ESN_FW_CODE_NO)) {
+		printf("\tBS-11 ESN Firmware Code Number: %s\n",
+			TLVP_VAL(tp, NM_ATT_BS11_ESN_FW_CODE_NO)+6);
+	}
+#if 0
+	if (TLVP_PRESENT(tp, NM_ATT_BS11_BOOT_SW_VERS)) {
+		printf("BS-11 Boot Software Version: %s\n",
+			TLVP_VAL(tp, NM_ATT_BS11_BOOT_SW_VERS)+6);
+	}
+#endif
+	if (TLVP_PRESENT(tp, NM_ATT_ABIS_CHANNEL) &&
+	    TLVP_LEN(tp, NM_ATT_ABIS_CHANNEL) >= 3) {
+		const u_int8_t *chan = TLVP_VAL(tp, NM_ATT_ABIS_CHANNEL);
+		printf("\tE1 Channel: Port=%u Timeslot=%u ",
+			chan[0], chan[1]);
+		if (chan[2] == 0xff)
+			printf("(Full Slot)\n");
+		else
+			printf("Subslot=%u\n", chan[2]);
+	}
+	if (TLVP_PRESENT(tp, NM_ATT_TEI))
+		printf("\tTEI: %d\n", *TLVP_VAL(tp, NM_ATT_TEI));
+	if (TLVP_PRESENT(tp, NM_ATT_BS11_TXPWR) &&
+	    TLVP_LEN(tp, NM_ATT_BS11_TXPWR) >= 1) {
+		printf("\tTRX Power: %s\n",
+			trx_power_name(*TLVP_VAL(tp, NM_ATT_BS11_TXPWR)));
+	}
+	if (TLVP_PRESENT(tp, NM_ATT_BS11_PLL_MODE) &&
+	    TLVP_LEN(tp, NM_ATT_BS11_PLL_MODE) >= 1) {
+		printf("\tPLL Mode: %s\n",
+			pll_mode_name(*TLVP_VAL(tp, NM_ATT_BS11_PLL_MODE)));
+	}
+	if (TLVP_PRESENT(tp, NM_ATT_BS11_PLL) &&
+	    TLVP_LEN(tp, NM_ATT_BS11_PLL) >= 4) {
+		const u_int8_t *vp = TLVP_VAL(tp, NM_ATT_BS11_PLL);
+		printf("\tPLL Set Value=%d, Work Value=%d\n",
+			vp[0] << 8 | vp[1], vp[2] << 8 | vp[3]);
+	}
+	if (TLVP_PRESENT(tp, NM_ATT_BS11_CCLK_ACCURACY) &&
+	    TLVP_LEN(tp, NM_ATT_BS11_CCLK_ACCURACY) >= 1) {
+		const u_int8_t *acc = TLVP_VAL(tp, NM_ATT_BS11_CCLK_ACCURACY);
+		printf("\tCCLK Accuracy: %s (%d)\n", cclk_acc_name(*acc), *acc);
+	}
+	if (TLVP_PRESENT(tp, NM_ATT_BS11_CCLK_TYPE) &&
+	    TLVP_LEN(tp, NM_ATT_BS11_CCLK_TYPE) >= 1) {
+		const u_int8_t *acc = TLVP_VAL(tp, NM_ATT_BS11_CCLK_TYPE);
+		printf("\tCCLK Type=%d\n", *acc);
+	}
+	if (TLVP_PRESENT(tp, NM_ATT_BS11_LINE_CFG) &&
+	    TLVP_LEN(tp, NM_ATT_BS11_LINE_CFG) >= 1) {
+		const u_int8_t *lcfg = TLVP_VAL(tp, NM_ATT_BS11_LINE_CFG);
+		printf("\tLine Configuration: %s (%d)\n",
+			bport_lcfg_name(*lcfg), *lcfg);
+	}
+
+
+
+	return 0;
+}
+
+static void cmd_query(void)
+{
+	struct gsm_bts_trx *trx = g_bts->c0;
+
+	bs11cfg_state = STATE_QUERY;
+	abis_nm_bs11_get_serno(g_bts);
+	abis_nm_bs11_get_oml_tei_ts(g_bts);
+	abis_nm_bs11_get_pll_mode(g_bts);
+	abis_nm_bs11_get_cclk(g_bts);
+	abis_nm_bs11_get_trx_power(trx);
+	trx = gsm_bts_trx_num(g_bts, 1);
+	if (trx)
+		abis_nm_bs11_get_trx_power(trx);
+	abis_nm_bs11_get_bport_line_cfg(g_bts, 0);
+	abis_nm_bs11_get_bport_line_cfg(g_bts, 1);
+	sleep(1);
+	abis_nm_bs11_factory_logon(g_bts, 0);
+	command = NULL;
+}
+
+/* handle a response from the BTS to a GET STATE command */
+static int handle_state_resp(enum abis_bs11_phase state)
+{
+	int rc = 0;
+
+	switch (state) {
+	case BS11_STATE_WARM_UP:
+	case BS11_STATE_LOAD_SMU_SAFETY:
+	case BS11_STATE_LOAD_SMU_INTENDED:
+	case BS11_STATE_LOAD_MBCCU:
+		break;
+	case BS11_STATE_SOFTWARE_RQD:
+		bs11cfg_state = STATE_SWLOAD;
+		/* send safety load. Use g_bts as private 'param'
+		 * argument, so our swload_cbfn can distinguish
+		 * a safety load from a regular software */
+		if (file_is_readable(fname_safety))
+			rc = abis_nm_software_load(g_bts, 0xff, fname_safety,
+						   win_size, param_forced,
+						   swload_cbfn, g_bts);
+		else
+			fprintf(stderr, "No valid Safety Load file \"%s\"\n",
+				fname_safety);
+		break;
+	case BS11_STATE_WAIT_MIN_CFG:
+	case BS11_STATE_WAIT_MIN_CFG_2:
+		bs11cfg_state = STATE_SWLOAD;
+		rc = create_objects(g_bts);
+		break;
+	case BS11_STATE_MAINTENANCE:
+		if (command) {
+			if (!strcmp(command, "disconnect"))
+				abis_nm_bs11_factory_logon(g_bts, 0);
+			else if (!strcmp(command, "reconnect"))
+				rc = abis_nm_bs11_bsc_disconnect(g_bts, 1);
+			else if (!strcmp(command, "software")
+			    && bs11cfg_state != STATE_SWLOAD) {
+				bs11cfg_state = STATE_SWLOAD;
+				/* send software (FIXME: over A-bis?) */
+				if (file_is_readable(fname_software))
+					rc = abis_nm_bs11_load_swl(g_bts, fname_software,
+								   win_size, param_forced,
+								   swload_cbfn);
+				else
+					fprintf(stderr, "No valid Software file \"%s\"\n",
+						fname_software);
+			} else if (!strcmp(command, "delete-trx1")) {
+				printf("Locing BBSIG and PA objects of TRX1\n");
+				abis_nm_chg_adm_state(g_bts, NM_OC_BS11,
+						      BS11_OBJ_BBSIG, 0, 1,
+						      NM_STATE_LOCKED);
+				abis_nm_chg_adm_state(g_bts, NM_OC_BS11,
+						      BS11_OBJ_PA, 0, 1,
+						      NM_STATE_LOCKED);
+				sleep(1);
+				printf("Deleting BBSIG and PA objects of TRX1\n");
+				abis_nm_bs11_delete_object(g_bts, BS11_OBJ_BBSIG, 1);
+				abis_nm_bs11_delete_object(g_bts, BS11_OBJ_PA, 1);
+				sleep(1);
+				abis_nm_bs11_factory_logon(g_bts, 0);
+				command = NULL;
+			} else if (!strcmp(command, "create-trx1")) {
+				create_trx1(g_bts);
+				sleep(1);
+				abis_nm_bs11_factory_logon(g_bts, 0);
+				command = NULL;
+			} else if (!strcmp(command, "pll-e1-locked")) {
+				abis_nm_bs11_set_pll_locked(g_bts, 1);
+				sleep(1);
+				abis_nm_bs11_factory_logon(g_bts, 0);
+				command = NULL;
+			} else if (!strcmp(command, "pll-standalone")) {
+				abis_nm_bs11_set_pll_locked(g_bts, 0);
+				sleep(1);
+				abis_nm_bs11_factory_logon(g_bts, 0);
+				command = NULL;
+			} else if (!strcmp(command, "pll-setvalue")) {
+				abis_nm_bs11_set_pll(g_bts, atoi(value));
+				sleep(1);
+				abis_nm_bs11_factory_logon(g_bts, 0);
+				command = NULL;
+			} else if (!strcmp(command, "pll-workvalue")) {
+				/* To set the work value we need to login as FIELD */
+				abis_nm_bs11_factory_logon(g_bts, 0);
+				sleep(1);
+				abis_nm_bs11_infield_logon(g_bts, 1);
+				sleep(1);
+				abis_nm_bs11_set_pll(g_bts, atoi(value));
+				sleep(1);
+				abis_nm_bs11_infield_logon(g_bts, 0);
+				command = NULL;
+			} else if (!strcmp(command, "oml-tei")) {
+				abis_nm_bs11_conn_oml_tei(g_bts, 0, 1, 0xff, TEI_OML);
+				command = NULL;
+			} else if (!strcmp(command, "restart")) {
+				abis_nm_bs11_restart(g_bts);
+				command = NULL;
+			} else if (!strcmp(command, "query")) {
+				cmd_query();
+			} else if (!strcmp(command, "create-bport1")) {
+				abis_nm_bs11_create_bport(g_bts, 1);
+				sleep(1);
+				abis_nm_bs11_factory_logon(g_bts, 0);
+				command = NULL;
+			} else if (!strcmp(command, "delete-bport1")) {
+				abis_nm_chg_adm_state(g_bts, NM_OC_BS11_BPORT, 1, 0xff, 0xff, NM_STATE_LOCKED);
+				sleep(1);
+				abis_nm_bs11_delete_bport(g_bts, 1);
+				sleep(1);
+				abis_nm_bs11_factory_logon(g_bts, 0);
+				command = NULL;
+			} else if (!strcmp(command, "bport0-star")) {
+				abis_nm_bs11_set_bport_line_cfg(g_bts, 0, BS11_LINE_CFG_STAR);
+				sleep(1);
+				abis_nm_bs11_factory_logon(g_bts, 0);
+				command = NULL;
+			} else if (!strcmp(command, "bport0-multidrop")) {
+				abis_nm_bs11_set_bport_line_cfg(g_bts, 0, BS11_LINE_CFG_MULTIDROP);
+				sleep(1);
+				abis_nm_bs11_factory_logon(g_bts, 0);
+				command = NULL;
+			} else if (!strcmp(command, "bport1-multidrop")) {
+				abis_nm_bs11_set_bport_line_cfg(g_bts, 1, BS11_LINE_CFG_MULTIDROP);
+				sleep(1);
+				abis_nm_bs11_factory_logon(g_bts, 0);
+				command = NULL;
+			}
+
+		}
+		break;
+	case BS11_STATE_NORMAL:
+		if (command) {
+			if (!strcmp(command, "reconnect"))
+				abis_nm_bs11_factory_logon(g_bts, 0);
+			else if (!strcmp(command, "disconnect"))
+				abis_nm_bs11_bsc_disconnect(g_bts, 0);
+			else if (!strcmp(command, "query")) {
+				cmd_query();
+			}
+		} else if (param_disconnect) {
+			param_disconnect = 0;
+			abis_nm_bs11_bsc_disconnect(g_bts, 0);
+			if (param_restart) {
+				param_restart = 0;
+				abis_nm_bs11_restart(g_bts);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+	return rc;
+}
+
+/* handle a fully-received message/packet from the RS232 port */
+int handle_serial_msg(struct msgb *rx_msg)
+{
+	struct abis_om_hdr *oh;
+	struct abis_om_fom_hdr *foh;
+	struct tlv_parsed tp;
+	int rc = -1;
+
+#if 0
+	if (rx_msg->len < LAPD_HDR_LEN
+			  + sizeof(struct abis_om_fom_hdr)
+			  + sizeof(struct abis_om_hdr)) {
+		if (!memcmp(rx_msg->data + 2, too_fast,
+			    sizeof(too_fast))) {
+			fprintf(stderr, "BS11 tells us we're too "
+				"fast, try --delay bigger than %u\n",
+				delay_ms);
+			return -E2BIG;
+		} else
+			fprintf(stderr, "unknown BS11 message\n");
+	}
+#endif
+
+	oh = (struct abis_om_hdr *) msgb_l2(rx_msg);
+	foh = (struct abis_om_fom_hdr *) oh->data;
+	switch (foh->msg_type) {
+	case NM_MT_BS11_LMT_LOGON_ACK:
+		printf("LMT LOGON: ACK\n\n");
+		if (bs11cfg_state == STATE_NONE)
+			bs11cfg_state = STATE_LOGON_ACK;
+		rc = abis_nm_bs11_get_state(g_bts);
+		break;
+	case NM_MT_BS11_LMT_LOGOFF_ACK:
+		printf("LMT LOGOFF: ACK\n");
+		exit(0);
+		break;
+	case NM_MT_BS11_GET_STATE_ACK:
+		rc = abis_nm_tlv_parse(&tp, g_bts, foh->data, oh->length-sizeof(*foh));
+		print_state(&tp);
+		if (TLVP_PRESENT(&tp, NM_ATT_BS11_BTS_STATE) &&
+		    TLVP_LEN(&tp, NM_ATT_BS11_BTS_STATE) >= 1)
+			rc = handle_state_resp(*TLVP_VAL(&tp, NM_ATT_BS11_BTS_STATE));
+		break;
+	case NM_MT_GET_ATTR_RESP:
+		printf("\n%sATTRIBUTES:\n", obj_name(foh));
+		abis_nm_tlv_parse(&tp, g_bts, foh->data, oh->length-sizeof(*foh));
+		rc = print_attr(&tp);
+		//hexdump(foh->data, oh->length-sizeof(*foh));
+		break;
+	case NM_MT_BS11_SET_ATTR_ACK:
+		printf("SET ATTRIBUTE ObjClass=0x%02x ObjInst=(%d,%d,%d) ACK\n",
+			foh->obj_class, foh->obj_inst.bts_nr,
+			foh->obj_inst.trx_nr, foh->obj_inst.ts_nr);
+		rc = 0;
+		break;
+	case NM_MT_BS11_SET_ATTR_NACK:
+		printf("SET ATTRIBUTE ObjClass=0x%02x ObjInst=(%d,%d,%d) NACK\n",
+			foh->obj_class, foh->obj_inst.bts_nr,
+			foh->obj_inst.trx_nr, foh->obj_inst.ts_nr);
+		break;
+	case NM_MT_GET_ATTR_NACK:
+		printf("\n%sGET ATTR NACK\n", obj_name(foh));
+		break;
+	case NM_MT_BS11_CREATE_OBJ_ACK:
+		printf("\n%sCREATE OBJECT ACK\n", obj_name(foh));
+		break;
+	case NM_MT_BS11_CREATE_OBJ_NACK:
+		printf("\n%sCREATE OBJECT NACK\n", obj_name(foh));
+		break;
+	case NM_MT_BS11_DELETE_OBJ_ACK:
+		printf("\n%sDELETE OBJECT ACK\n", obj_name(foh));
+		break;
+	case NM_MT_BS11_DELETE_OBJ_NACK:
+		printf("\n%sDELETE OBJECT NACK\n", obj_name(foh));
+		break;
+	default:
+		rc = abis_nm_rcvmsg(rx_msg);
+	}
+	if (rc < 0) {
+		perror("ERROR in main loop");
+		//break;
+	}
+	if (rc == 1)
+		return rc;
+
+	switch (bs11cfg_state) {
+	case STATE_NONE:
+		abis_nm_bs11_factory_logon(g_bts, 1);
+		break;
+	case STATE_LOGON_ACK:
+		bsc_schedule_timer(&status_timer, 5, 0);
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+void status_timer_cb(void *data)
+{
+	abis_nm_bs11_get_state(g_bts);
+}
+
+static void print_banner(void)
+{
+	printf("bs11_config (C) 2009-2010 by Harald Welte and Dieter Spaar\n");
+	printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n");
+}
+
+static void print_help(void)
+{
+	printf("bs11_config [options] [command]\n");
+	printf("\nSupported options:\n");
+	printf("\t-h --help\t\t\tPrint this help text\n");
+	printf("\t-p --port </dev/ttyXXX>\t\tSpecify serial port\n");
+	printf("\t-s --software <file>\t\tSpecify Software file\n");
+	printf("\t-S --safety <file>\t\tSpecify Safety Load file\n");
+	printf("\t-d --delay <ms>\t\t\tSpecify delay in milliseconds\n");
+	printf("\t-D --disconnect\t\t\tDisconnect BTS from BSC\n");
+	printf("\t-w --win-size <num>\t\tSpecify Window Size\n");
+	printf("\t-f --forced\t\t\tForce Software Load\n");
+	printf("\nSupported commands:\n");
+	printf("\tquery\t\t\tQuery the BS-11 about serial number and configuration\n");
+	printf("\tdisconnect\t\tDisconnect A-bis link (go into administrative state)\n");
+	printf("\tresconnect\t\tReconnect A-bis link (go into normal state)\n");
+	printf("\trestart\t\t\tRestart the BTS\n");
+	printf("\tsoftware\t\tDownload Software (only in administrative state)\n");
+	printf("\tcreate-trx1\t\tCreate objects for TRX1 (Danger: Your BS-11 might overheat)\n");
+	printf("\tdelete-trx1\t\tDelete objects for TRX1\n");
+	printf("\tpll-e1-locked\t\tSet the PLL to be locked to E1 clock\n");
+	printf("\tpll-standalone\t\tSet the PLL to be in standalone mode\n");
+	printf("\tpll-setvalue <value>\tSet the PLL set value\n");
+	printf("\tpll-workvalue <value>\tSet the PLL work value\n");
+	printf("\toml-tei\t\t\tSet OML E1 TS and TEI\n");
+	printf("\tbport0-star\t\tSet BPORT0 line config to star\n");
+	printf("\tbport0-multidrop\tSet BPORT0 line config to multidrop\n");
+	printf("\tbport1-multidrop\tSet BPORT1 line config to multidrop\n");
+	printf("\tcreate-bport1\t\tCreate BPORT1 object\n");
+	printf("\tdelete-bport1\t\tDelete BPORT1 object\n");
+}
+
+static void handle_options(int argc, char **argv)
+{
+	int option_index = 0;
+	print_banner();
+
+	while (1) {
+		int c;
+		static struct option long_options[] = {
+			{ "help", 0, 0, 'h' },
+			{ "port", 1, 0, 'p' },
+			{ "software", 1, 0, 's' },
+			{ "safety", 1, 0, 'S' },
+			{ "delay", 1, 0, 'd' },
+			{ "disconnect", 0, 0, 'D' },
+			{ "win-size", 1, 0, 'w' },
+			{ "forced", 0, 0, 'f' },
+			{ "restart", 0, 0, 'r' },
+			{ "debug", 1, 0, 'b'},
+		};
+
+		c = getopt_long(argc, argv, "hp:s:S:td:Dw:fra:",
+				long_options, &option_index);
+
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'h':
+			print_help();
+			exit(0);
+		case 'p':
+			serial_port = optarg;
+			break;
+		case 'b':
+			log_parse_category_mask(stderr_target, optarg);
+			break;
+		case 's':
+			fname_software = optarg;
+			break;
+		case 'S':
+			fname_safety = optarg;
+			break;
+		case 'd':
+			delay_ms = atoi(optarg);
+			break;
+		case 'w':
+			win_size = atoi(optarg);
+			break;
+		case 'D':
+			param_disconnect = 1;
+			break;
+		case 'f':
+			param_forced = 1;
+			break;
+		case 'r':
+			param_disconnect = 1;
+			param_restart = 1;
+			break;
+		default:
+			break;
+		}
+	}
+	if (optind < argc)
+		command = argv[optind];
+	        if (optind+1 < argc)
+			value = argv[optind+1];
+
+}
+
+static int num_sigint;
+
+static void signal_handler(int signal)
+{
+	fprintf(stdout, "\nsignal %u received\n", signal);
+
+	switch (signal) {
+	case SIGINT:
+		num_sigint++;
+		abis_nm_bs11_factory_logon(g_bts, 0);
+		if (num_sigint >= 3)
+			exit(0);
+		break;
+	}
+}
+
+extern int bts_model_bs11_init(void);
+int main(int argc, char **argv)
+{
+	struct gsm_network *gsmnet;
+	int rc;
+
+	log_init(&log_info);
+	stderr_target = log_target_create_stderr();
+	log_add_target(stderr_target);
+	log_set_all_filter(stderr_target, 1);
+	handle_options(argc, argv);
+	bts_model_bs11_init();
+
+	gsmnet = gsm_network_init(1, 1, NULL);
+	if (!gsmnet) {
+		fprintf(stderr, "Unable to allocate gsm network\n");
+		exit(1);
+	}
+	g_bts = gsm_bts_alloc(gsmnet, GSM_BTS_TYPE_BS11, HARDCODED_TSC,
+				HARDCODED_BSIC);
+
+	rc = rs232_setup(serial_port, delay_ms, g_bts);
+	if (rc < 0) {
+		fprintf(stderr, "Problem setting up serial port\n");
+		exit(1);
+	}
+
+	signal(SIGINT, &signal_handler);
+
+	abis_nm_bs11_factory_logon(g_bts, 1);
+	//abis_nm_bs11_get_serno(g_bts);
+
+	status_timer.cb = status_timer_cb;
+
+	while (1) {
+		bsc_select_main(0);
+	}
+
+	abis_nm_bs11_factory_logon(g_bts, 0);
+
+	exit(0);
+}
+
+/* dummy to be able to compile */
+void gsm_net_update_ctype(struct gsm_network *net)
+{
+}
diff --git a/src/utils/isdnsync.c b/src/utils/isdnsync.c
new file mode 100644
index 0000000..1c4aa5d
--- /dev/null
+++ b/src/utils/isdnsync.c
@@ -0,0 +1,191 @@
+/* isdnsync.c
+ *
+ * Author       Andreas Eversberg <jolly@eversberg.eu>
+ *
+ * All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include "mISDNif.h"
+#define MISDN_OLD_AF_COMPATIBILITY
+#define AF_COMPATIBILITY_FUNC
+#include "compat_af_isdn.h"
+
+int card = 0;
+int sock = -1;
+
+int mISDN_open(void)
+{
+	int			fd, ret;
+	struct mISDN_devinfo	devinfo;
+	struct sockaddr_mISDN	l2addr;
+
+	fd = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
+	if (fd < 0) {
+		fprintf(stderr, "could not open socket (%s)\n", strerror(errno));
+		return fd;
+	}
+	devinfo.id = card;
+	ret = ioctl(fd, IMGETDEVINFO, &devinfo);
+	if (ret < 0) {
+		fprintf(stderr,"could not send IOCTL IMGETCOUNT (%s)\n", strerror(errno));
+		close(fd);
+		return ret;
+	}
+	close(fd);
+	if (!(devinfo.Dprotocols & (1 << ISDN_P_TE_S0))
+	 && !(devinfo.Dprotocols & (1 << ISDN_P_TE_E1))) {
+		fprintf(stderr,"Interface does not support TE mode (%s)\n", strerror(errno));
+		close(fd);
+		return ret;
+	}
+	fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_LAPD_TE);
+	if (fd < 0) {
+		fprintf(stderr,"could not open ISDN_P_LAPD_TE socket (%s)\n", strerror(errno));
+		return fd;
+	}
+	l2addr.family = AF_ISDN;
+	l2addr.dev = card;
+	l2addr.channel = 0;
+	l2addr.sapi = 0;
+	l2addr.tei = 0;
+	ret = bind(fd, (struct sockaddr *)&l2addr, sizeof(l2addr));
+	if (ret < 0) {
+		fprintf(stderr,"could not bind socket for card %d (%s)\n", card, strerror(errno));
+		close(fd);
+		return ret;
+	}
+	sock = fd;
+
+	return sock;
+}
+
+
+void mISDN_handle(void)
+{
+	int ret;
+	fd_set rfd;
+	struct timeval tv;
+	struct sockaddr_mISDN addr;
+	socklen_t alen;
+	unsigned char buffer[2048];
+	struct mISDNhead *hh = (struct mISDNhead *)buffer;
+	int l1 = 0, l2 = 0, tei = 0;
+
+	while(1) {
+again:
+		FD_ZERO(&rfd);
+		FD_SET(sock, &rfd);
+		tv.tv_sec = 2;
+		tv.tv_usec = 0;
+		ret = select(sock+1, &rfd, NULL, NULL, &tv);
+		if (ret < 0) {
+			if (errno == EINTR)
+				continue;
+			fprintf(stderr, "%s aborted: %s\n", __FUNCTION__, strerror(errno));
+			break;
+		}
+		if (FD_ISSET(sock, &rfd)) {
+			alen = sizeof(addr);
+			ret = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *) &addr, &alen);
+			if (ret < 0) {
+				fprintf(stderr, "%s read socket error %s\n", __FUNCTION__, strerror(errno));
+			} else if (ret < MISDN_HEADER_LEN) {
+					fprintf(stderr, "%s read socket shor frame\n", __FUNCTION__);
+			} else {
+				switch(hh->prim) {
+					case MPH_ACTIVATE_IND:
+					case PH_ACTIVATE_IND:
+						if (!l1) {
+							printf("PH_ACTIVATE\n");
+							printf("*** Sync available from interface :-)\n");
+							l1 = 1;
+						}
+						goto again;
+					break;
+					case MPH_DEACTIVATE_IND:
+					case PH_DEACTIVATE_IND:
+						if (l1) {
+							printf("PH_DEACTIVATE\n");
+							printf("*** Lost sync on interface        :-(\n");
+							l1 = 0;
+						}
+						goto again;
+					break;
+					case DL_ESTABLISH_IND:
+					case DL_ESTABLISH_CNF:
+						printf("DL_ESTABLISH\n");
+						l2 = 1;
+						goto again;
+					break;
+					case DL_RELEASE_IND:
+					case DL_RELEASE_CNF:
+						printf("DL_RELEASE\n");
+						l2 = 0;
+						goto again;
+					break;
+					case DL_INFORMATION_IND:
+						printf("DL_INFORMATION (tei %d sapi %d)\n", addr.tei, addr.sapi);
+						tei = 1;
+					break;
+					default:
+//						printf("prim %x\n", hh->prim);
+						goto again;
+				}
+			}
+		}
+		if (tei && !l2) {
+			hh->prim = DL_ESTABLISH_REQ;
+			printf("-> activating layer 2\n");
+			sendto(sock, buffer, MISDN_HEADER_LEN, 0, (struct sockaddr *) &addr, alen);
+		}
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	int ret;
+
+	if (argc <= 1)
+	{
+		printf("Usage: %s <card>\n\n", argv[0]);
+		printf("Opens given card number in TE-mode PTP and tries to keep layer 2 established.\n");
+		printf("This keeps layer 1 activated to retrieve a steady sync signal from network.\n");
+		return(0);
+	}
+
+	card = atoi(argv[1]);
+
+	init_af_isdn();
+
+	if ((ret = mISDN_open() < 0))
+		return(ret);
+
+	mISDN_handle();
+
+	close(sock);
+
+	return 0;
+}
diff --git a/src/utils/rs232.c b/src/utils/rs232.c
new file mode 100644
index 0000000..7550571
--- /dev/null
+++ b/src/utils/rs232.c
@@ -0,0 +1,248 @@
+/* OpenBSC BS-11 T-Link interface using POSIX serial port */
+
+/* (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 Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <termios.h>
+#include <fcntl.h>
+
+#include <osmocore/select.h>
+#include <osmocore/msgb.h>
+#include <openbsc/debug.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/rs232.h>
+
+/* adaption layer from GSM 08.59 + 12.21 to RS232 */
+
+struct serial_handle {
+	struct bsc_fd fd;
+	struct llist_head tx_queue;
+
+	struct msgb *rx_msg;
+	unsigned int rxmsg_bytes_missing;
+
+	unsigned int delay_ms;
+	struct gsm_bts *bts;
+};
+
+/* FIXME: this needs to go */
+static struct serial_handle _ser_handle, *ser_handle = &_ser_handle;
+
+#define LAPD_HDR_LEN	10
+
+static int handle_ser_write(struct bsc_fd *bfd);
+
+/* callback from abis_nm */
+int _abis_nm_sendmsg(struct msgb *msg, int to_trx_oml)
+{
+	struct serial_handle *sh = ser_handle;
+	u_int8_t *lapd;
+	unsigned int len;
+
+	msg->l2h = msg->data;
+
+	/* prepend LAPD header */
+	lapd = msgb_push(msg, LAPD_HDR_LEN);
+
+	len = msg->len - 2;
+
+	lapd[0] = (len >> 8) & 0xff;
+	lapd[1] = len & 0xff; /* length of bytes startign at lapd[2] */
+	lapd[2] = 0x00;
+	lapd[3] = 0x07;
+	lapd[4] = 0x01;
+	lapd[5] = 0x3e;
+	lapd[6] = 0x00;
+	lapd[7] = 0x00;
+	lapd[8] = msg->len - 10; /* length of bytes starting at lapd[10] */
+	lapd[9] = lapd[8] ^ 0x38;
+
+	msgb_enqueue(&sh->tx_queue, msg);
+	sh->fd.when |= BSC_FD_WRITE;
+
+	/* we try to immediately send */
+	handle_ser_write(&sh->fd);
+
+	return 0;
+}
+
+/* select.c callback in case we can write to the RS232 */
+static int handle_ser_write(struct bsc_fd *bfd)
+{
+	struct serial_handle *sh = bfd->data;
+	struct msgb *msg;
+	int written;
+
+	msg = msgb_dequeue(&sh->tx_queue);
+	if (!msg) {
+		bfd->when &= ~BSC_FD_WRITE;
+		return 0;
+	}
+
+	DEBUGP(DMI, "RS232 TX: %s\n", hexdump(msg->data, msg->len));
+
+	/* send over serial line */
+	written = write(bfd->fd, msg->data, msg->len);
+	if (written < msg->len) {
+		perror("short write:");
+		msgb_free(msg);
+		return -1;
+	}
+
+	msgb_free(msg);
+	usleep(sh->delay_ms*1000);
+
+	return 0;
+}
+
+#define SERIAL_ALLOC_SIZE	300
+
+/* select.c callback in case we can read from the RS232 */
+static int handle_ser_read(struct bsc_fd *bfd)
+{
+	struct serial_handle *sh = bfd->data;
+	struct msgb *msg;
+	int rc = 0;
+
+	if (!sh->rx_msg) {
+		sh->rx_msg = msgb_alloc(SERIAL_ALLOC_SIZE, "RS232 Rx");
+		sh->rx_msg->l2h = NULL;
+		sh->rx_msg->trx = sh->bts->c0;
+	}
+	msg = sh->rx_msg;
+
+	/* first read two byes to obtain length */
+	if (msg->len < 2) {
+		rc = read(sh->fd.fd, msg->tail, 2 - msg->len);
+		if (rc < 0) {
+			perror("ERROR reading from serial port");
+			msgb_free(msg);
+			return rc;
+		}
+		msgb_put(msg, rc);
+
+		if (msg->len >= 2) {
+			/* parse LAPD payload length */
+			if (msg->data[0] != 0)
+				fprintf(stderr, "Suspicious header byte 0: 0x%02x\n",
+					msg->data[0]);
+
+			sh->rxmsg_bytes_missing = msg->data[0] << 8;
+			sh->rxmsg_bytes_missing += msg->data[1];
+
+			if (sh->rxmsg_bytes_missing < LAPD_HDR_LEN -2)
+				fprintf(stderr, "Invalid length in hdr: %u\n",
+					sh->rxmsg_bytes_missing);
+		}
+	} else {
+		/* try to read as many of the missing bytes as are available */
+		rc = read(sh->fd.fd, msg->tail, sh->rxmsg_bytes_missing);
+		if (rc < 0) {
+			perror("ERROR reading from serial port");
+			msgb_free(msg);
+			return rc;
+		}
+		msgb_put(msg, rc);
+		sh->rxmsg_bytes_missing -= rc;
+
+		if (sh->rxmsg_bytes_missing == 0) {
+			/* we have one complete message now */
+			sh->rx_msg = NULL;
+
+			if (msg->len > LAPD_HDR_LEN)
+				msg->l2h = msg->data + LAPD_HDR_LEN;
+
+			DEBUGP(DMI, "RS232 RX: %s\n", hexdump(msg->data, msg->len));
+			rc = handle_serial_msg(msg);
+		}
+	}
+
+	return rc;
+}
+
+/* select.c callback */
+static int serial_fd_cb(struct bsc_fd *bfd, unsigned int what)
+{
+	int rc = 0;
+
+	if (what & BSC_FD_READ)
+		rc = handle_ser_read(bfd);
+
+	if (rc < 0)
+		return rc;
+
+	if (what & BSC_FD_WRITE)
+		rc = handle_ser_write(bfd);
+
+	return rc;
+}
+
+int rs232_setup(const char *serial_port, unsigned int delay_ms,
+		struct gsm_bts *bts)
+{
+	int rc, serial_fd;
+	struct termios tio;
+
+	serial_fd = open(serial_port, O_RDWR);
+	if (serial_fd < 0) {
+		perror("cannot open serial port:");
+		return serial_fd;
+	}
+
+	/* set baudrate */
+	rc = tcgetattr(serial_fd, &tio);
+	if (rc < 0) {
+		perror("tcgetattr()");
+		return rc;
+	}
+	cfsetispeed(&tio, B19200);
+	cfsetospeed(&tio, B19200);
+	tio.c_cflag |=  (CREAD | CLOCAL | CS8);
+	tio.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
+	tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+	tio.c_iflag |=  (INPCK | ISTRIP);
+	tio.c_iflag &= ~(ISTRIP | IXON | IXOFF | IGNBRK | INLCR | ICRNL | IGNCR);
+	tio.c_oflag &= ~(OPOST);
+	rc = tcsetattr(serial_fd, TCSADRAIN, &tio);
+	if (rc < 0) {
+		perror("tcsetattr()");
+		return rc;
+	}
+
+	INIT_LLIST_HEAD(&ser_handle->tx_queue);
+	ser_handle->fd.fd = serial_fd;
+	ser_handle->fd.when = BSC_FD_READ;
+	ser_handle->fd.cb = serial_fd_cb;
+	ser_handle->fd.data = ser_handle;
+	ser_handle->delay_ms = delay_ms;
+	ser_handle->bts = bts;
+	rc = bsc_register_fd(&ser_handle->fd);
+	if (rc < 0) {
+		fprintf(stderr, "could not register FD: %s\n",
+			strerror(rc));
+		return rc;
+	}
+
+	return 0;
+}