Compare commits

...

75 Commits

Author SHA1 Message Date
Andreas Eversberg 91ceb56495 Add dial tone detection to disable echo suppressor
3 weeks ago
Andreas Eversberg 7aa290154a Fixes missing event in LCP FSM
3 weeks ago
Andreas Eversberg 5268c0fc9b Added echo suppressor option
3 weeks ago
Andreas Eversberg c2bf2598b1 Add echo suppressor along with echo canceller
3 weeks ago
Andreas Eversberg f489ce381c Improve management process, to handle startup/blocking/unblocking correctly
3 weeks ago
Andreas Eversberg dd23410c52 Pulsed signal can have only one byte as value (3 byte IE)
3 weeks ago
Andreas Eversberg aa07ba4a48 VTY: Show single port; Use 'singular' for ports and links
3 weeks ago
Andreas Eversberg 40fddb83a7 Send to E1, only if layer 1 is active
3 weeks ago
Andreas Eversberg a53c366853 Update configure.ac to current release of libosmocore/libosmo-abis
3 weeks ago
Andreas Eversberg 56467e746e Link structure of e1inp_line directly with V5 link
3 weeks ago
Andreas Eversberg ebfab5792d Dynamically open and close b-channels depending on the usage
1 month ago
Andreas Eversberg a4483db3af Added echo cancelation option
1 month ago
Andreas Eversberg e59752a1cb Add libg711 to transcode G.711 audio
2 months ago
Andreas Eversberg c6d0c2452c Added libecho, the line-echo-canceler from spandsp
2 months ago
Andreas Eversberg 8b00969b4a Check double use of E1 interface and notify, if not defined
2 months ago
Andreas Eversberg 3aee692b1c Added GSMTAP IP option and fixed command line help output format
2 months ago
Andreas Eversberg 687e963fd4 Updated ph-socket interface
2 months ago
Andreas Eversberg 905a1b22cf Add test function to test Sa 7 bit setting and reporting
2 months ago
Andreas Eversberg 85fe6f55bb Add graph of protocol entities
2 months ago
Andreas Eversberg 61d531cedc Work on Makefile.am
2 months ago
Andreas Eversberg 9c0893403d Working on main.c
2 months ago
Andreas Eversberg 36dc03731a Introduce layer1.c to process layer1 data flow and signals
2 months ago
Andreas Eversberg ef33793758 Work on ph_socket.c
2 months ago
Andreas Eversberg 5d972a0077 Work on VTY
2 months ago
Andreas Eversberg a260178387 Work on v5x_protocol.c
2 months ago
Andreas Eversberg 3ebe29e28f Work on v5x_data.c and v5x_internal.h
2 months ago
Andreas Eversberg 5addae556a Work on v5x_le_ctrl_fsm.c
2 months ago
Andreas Eversberg ba46786de7 Work on v5x_le_port_fsm.c
2 months ago
Andreas Eversberg 58937c291b Work on management
2 months ago
Andreas Eversberg fbb97bdd73 Work on v5x_le_pstn_fsm.c
2 months ago
Andreas Eversberg 920fada1bc Completed implementation of v52_le_pp_fsm.c
2 months ago
Andreas Eversberg 276b423051 Completed implementation of v52_le_bcc_fsm.c
2 months ago
Andreas Eversberg 4994a59962 Completed implementation of v5x_l1_fsm.c
2 months ago
Andreas Eversberg 852990f2e3 Completed implementation of V52_le_lcp_fsm.c
3 months ago
Andreas Eversberg 6a4a58d4b1 Work on logging.c
3 months ago
Andreas Eversberg 513f3bba5a Fixes for lapv5
3 months ago
Andreas Eversberg aeae94c547 Added functions to create and destroy V5.1/V5.2 interface with VTY
3 months ago
Andreas Eversberg 2a23a1c9cf Added destroy function for interface
3 months ago
Andreas Eversberg 65dac95ff0 Move main.c to src/
3 months ago
Andreas Eversberg b64a17c748 Move v5x_l2_mgmt and v51_le_provisioning to src/
3 months ago
Andreas Eversberg 7b4561f7cf Move v52_lcp_fsm.c to src/
3 months ago
Andreas Eversberg ca0d2f6091 Move v5x_le_pstn_fsm.h to src/v5x_le_pstn_fsm.h
3 months ago
Andreas Eversberg ff619cc54b Move v52_le_user_port_fsm to src/v5x_le_port_fsm
3 months ago
Andreas Eversberg 595d1091bc Move v51_le_ctrl to src/v5x_le_ctrl_fsm
3 months ago
Andreas Eversberg f457d272b6 Move v51_l1_fsm.c to src/v5x_l1_fsm.c
3 months ago
Andreas Eversberg 3cabd7f1a6 Move v5x_protocol to src/
3 months ago
Andreas Eversberg ff5e1d4947 Move lapv5 to src/
3 months ago
Andreas Eversberg dec8a8adea Move ph_socket to src/
3 months ago
Andreas Eversberg d91fd97210 Move logging to src/
3 months ago
Andreas Eversberg 33eea99531 Move v5x_data.c and v5x_internal.h to src/
3 months ago
Andreas Eversberg 83d8cbdd3a Prepared autoconf/automake
3 months ago
Andreas Eversberg 3586180ae2 Jolly's hack on Makefile
3 months ago
Andreas Eversberg f5e54dfa77 Hacking on main
3 months ago
Andreas Eversberg 0325fbedc1 Work on v5x_protocol
3 months ago
Andreas Eversberg afa29770cc Work on v5x_data.c and v5x_internal.h
3 months ago
Andreas Eversberg a8428e073d Work on lapv5
3 months ago
Andreas Eversberg 331c19228e Add PSTN protocol
3 months ago
Andreas Eversberg e066033770 Add L2 management process
3 months ago
Andreas Eversberg a02b14892a Add PH-socket interface
3 months ago
Andreas Eversberg eeb77df89f Fixed and completed v52_le_user_port_fsm.c for both ISDN and PSTN ports
3 months ago
Andreas Eversberg ae1a7de2b8 Serveral fixes to v51_le_ctrl.c
3 months ago
Andreas Eversberg 537301f656 Fixed primitive handling in v5x_protocol.c
3 months ago
Andreas Eversberg d9cea69a90 Add enum type for user port data structure (PSTN or ISDN)
3 months ago
Andreas Eversberg ee6d366feb Add minimal provisioning protocol (Clause 14.5)
3 months ago
Andreas Eversberg ffeded74af Add more log levels to logging
3 months ago
Harald Welte 65dfe9080b Iniatial gsmtap support
3 months ago
Andreas Eversberg 5af684bed2 Work on control protocols
3 months ago
Andreas Eversberg fe6a4b91f8 Hacking on main.c
3 months ago
Andreas Eversberg 1560a36dfc Work on v5x_data.c and v5x_internal.h
3 months ago
Andreas Eversberg 5fd7b682f4 Several fixes for lapv5.c
3 months ago
Andreas Eversberg a77eb4020f Work on v5x_protocol.c
3 months ago
Andreas Eversberg 0bb6303c34 Changes to Makefile
3 months ago
Andreas Eversberg 04e99eb55f Rename SAP functions of lapv5 to be more conclusive
3 months ago
Andreas Eversberg 4f9292b698 Add logging.c/logging.h
3 months ago
Andreas Eversberg 10b269d24c Removed config file
3 months ago

46
.gitignore vendored

@ -0,0 +1,46 @@
Makefile
Makefile.in
.deps
.libs
*.o
*.lo
*.la
*.pc
aclocal.m4
autom4te.cache
config.h*
config.sub
config.log
config.status
config.guess
configure
compile
depcomp
missing
ltmain.sh
install-sh
stamp-h1
#libosmo-abis-*
tests/*_test
*~
# libtool and e.g. arm-poky-linux-gnueabi-libtool
*libtool
.tarball-version
.version
.dirstamp
# tests
tests/atconfig
tests/package.m4
tests/testsuite
tests/testsuite.log
# vi/vim files
*.sw?
src/libg711/libg711.a
src/libecho/libecho.a
src/osmo-v5-le
tests/answer_detect

@ -1,11 +0,0 @@
LIBS=-lasan -ltalloc -losmocore -losmovty -losmogsm -losmoctrl -losmoabis
CFLAGS=-Wall -DPACKAGE_VERSION=\"0.0\"
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $^
v5le: main.o v5x_data.o lapv5.o
$(CC) -o $@ $^ $(LIBS)
clean:
@rm v5le *.o

@ -0,0 +1,8 @@
ACLOCAL_AMFLAGS = -I m4
AM_CPPFLAGS = $(all_includes)
SUBDIRS = src tests
dist-hook:
echo $(VERSION) > $(distdir)/.tarball-version

@ -0,0 +1,116 @@
AC_INIT([osmo-v5],
m4_esyscmd([./git-version-gen .tarball-version]),
[openbsc@lists.osmocom.org])
dnl *This* is the root dir, even if an install-sh exists in ../ or ../../
AC_CONFIG_AUX_DIR([.])
AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip 1.6 subdir-objects])
AC_CONFIG_TESTDIR(tests)
CFLAGS="$CFLAGS -std=gnu11"
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl include release helper
RELMAKE='-include osmo-release.mk'
AC_SUBST([RELMAKE])
dnl checks for programs
AC_PROG_MAKE_SET
AC_PROG_CC
AC_PROG_INSTALL
LT_INIT([pic-only])
dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang
AS_CASE(["$LD"],[*clang*],
[AS_CASE(["${host_os}"],
[*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
AC_MSG_WARN([You need to install pkg-config])
fi
PKG_PROG_PKG_CONFIG([0.20])
AC_CONFIG_MACRO_DIR([m4])
CFLAGS="$CFLAGS -Wall"
CPPFLAGS="$CPPFLAGS -Wall"
AC_ARG_ENABLE(sanitize,
[AS_HELP_STRING(
[--enable-sanitize],
[Compile with address sanitizer enabled],
)],
[sanitize=$enableval], [sanitize="no"])
if test x"$sanitize" = x"yes"
then
CFLAGS="$CFLAGS -fsanitize=address -fsanitize=undefined"
CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
fi
# 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([AC_LANG_SOURCE([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)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.8.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.8.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.8.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.8.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOISDN, libosmoisdn >= 1.8.0)
AC_ARG_ENABLE(sanitize,
[AS_HELP_STRING(
[--enable-sanitize],
[Compile with address sanitizer enabled],
)],
[sanitize=$enableval], [sanitize="no"])
if test x"$sanitize" = x"yes"
then
CFLAGS="$CFLAGS -fsanitize=address -fsanitize=undefined"
CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
fi
AC_ARG_ENABLE(werror,
[AS_HELP_STRING(
[--enable-werror],
[Turn all compiler warnings into errors, with exceptions:
a) deprecation (allow upstream to mark deprecation without breaking builds);
b) "#warning" pragmas (allow to remind ourselves of errors without breaking builds)
]
)],
[werror=$enableval], [werror="no"])
if test x"$werror" = x"yes"
then
WERROR_FLAGS="-Werror"
WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
CFLAGS="$CFLAGS $WERROR_FLAGS"
CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
fi
AX_CHECK_X86_FEATURES()
AC_MSG_RESULT([CFLAGS="$CFLAGS"])
AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])
AC_OUTPUT(
src/libecho/Makefile
src/libg711/Makefile
src/Makefile
tests/Makefile
Makefile)

Binary file not shown.

Binary file not shown.

@ -0,0 +1,151 @@
#!/bin/sh
# Print a version string.
scriptversion=2010-01-28.01
# Copyright (C) 2007-2010 Free Software Foundation, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
# It may be run two ways:
# - from a git repository in which the "git describe" command below
# produces useful output (thus requiring at least one signed tag)
# - from a non-git-repo directory containing a .tarball-version file, which
# presumes this script is invoked like "./git-version-gen .tarball-version".
# In order to use intra-version strings in your project, you will need two
# separate generated version string files:
#
# .tarball-version - present only in a distribution tarball, and not in
# a checked-out repository. Created with contents that were learned at
# the last time autoconf was run, and used by git-version-gen. Must not
# be present in either $(srcdir) or $(builddir) for git-version-gen to
# give accurate answers during normal development with a checked out tree,
# but must be present in a tarball when there is no version control system.
# Therefore, it cannot be used in any dependencies. GNUmakefile has
# hooks to force a reconfigure at distribution time to get the value
# correct, without penalizing normal development with extra reconfigures.
#
# .version - present in a checked-out repository and in a distribution
# tarball. Usable in dependencies, particularly for files that don't
# want to depend on config.h but do want to track version changes.
# Delete this file prior to any autoconf run where you want to rebuild
# files to pick up a version string change; and leave it stale to
# minimize rebuild time after unrelated changes to configure sources.
#
# It is probably wise to add these two files to .gitignore, so that you
# don't accidentally commit either generated file.
#
# Use the following line in your configure.ac, so that $(VERSION) will
# automatically be up-to-date each time configure is run (and note that
# since configure.ac no longer includes a version string, Makefile rules
# should not depend on configure.ac for version updates).
#
# AC_INIT([GNU project],
# m4_esyscmd([build-aux/git-version-gen .tarball-version]),
# [bug-project@example])
#
# Then use the following lines in your Makefile.am, so that .version
# will be present for dependencies, and so that .tarball-version will
# exist in distribution tarballs.
#
# BUILT_SOURCES = $(top_srcdir)/.version
# $(top_srcdir)/.version:
# echo $(VERSION) > $@-t && mv $@-t $@
# dist-hook:
# echo $(VERSION) > $(distdir)/.tarball-version
case $# in
1) ;;
*) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version"; exit 1;;
esac
tarball_version_file=$1
nl='
'
# First see if there is a tarball-only version file.
# then try "git describe", then default.
if test -f $tarball_version_file
then
v=`cat $tarball_version_file` || exit 1
case $v in
*$nl*) v= ;; # reject multi-line output
[0-9]*) ;;
*) v= ;;
esac
test -z "$v" \
&& echo "$0: WARNING: $tarball_version_file seems to be damaged" 1>&2
fi
if test -n "$v"
then
: # use $v
elif
v=`git describe --abbrev=4 HEAD 2>/dev/null \
|| git describe --abbrev=4 --match='v*' 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:

@ -1,21 +0,0 @@
#pragma once
#include <osmocom/abis/lapd.h>
struct lapv5_instance {
struct llist_head list; /* list of LAPV5 instances */
bool network_side;
void (*transmit_cb)(struct msgb *msg, void *cbdata);
void *transmit_cbdata;
void (*receive_cb)(struct osmo_dlsap_prim *odp, uint16_t dladdr, void *rx_cbdata);
void *receive_cbdata;
struct lapd_profile profile; /* must be a copy */
struct llist_head sap_list; /* list of SAP/datalinks in this instance */
int pcap_fd; /* PCAP file descriptor */
char *name; /* human-readable name */
};
int lapv5ef_rx(struct v5x_link *link, struct msgb *msg);

@ -0,0 +1,13 @@
AC_DEFUN([AX_CHECK_X86_FEATURES],
[m4_foreach_w(
[ax_x86_feature],
[mmx popcnt sse sse2 sse3 sse4.1 sse4.2 sse4a avx avx2 avx512f fma fma4 bmi bmi2],
[AX_GCC_X86_CPU_SUPPORTS(ax_x86_feature,
[X86_FEATURE_CFLAGS="$X86_FEATURE_CFLAGS -m[]ax_x86_feature"],
[])
])
AC_SUBST([X86_FEATURE_CFLAGS])
m4_ifval([$1],[$1],
[CFLAGS="$CFLAGS $X86_FEATURE_CFLAGS"])
$2
])

@ -0,0 +1,44 @@
AC_DEFUN_ONCE([_AX_GCC_X86_CPU_INIT],
[AC_LANG_PUSH([C])
AC_CACHE_CHECK([for gcc __builtin_cpu_init function],
[ax_cv_gcc_check_x86_cpu_init],
[AC_RUN_IFELSE(
[AC_LANG_PROGRAM([#include <stdlib.h>],
[__builtin_cpu_init ();])
],
[ax_cv_gcc_check_x86_cpu_init=yes],
[ax_cv_gcc_check_x86_cpu_init=no])])
AC_LANG_POP([C])
AS_IF([test "X$ax_cv_gcc_check_x86_cpu_init" = "Xno"],
[AC_MSG_ERROR([Need GCC to support X86 CPU features tests])])
])
AC_DEFUN([AX_GCC_X86_CPU_SUPPORTS],
[AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([_AX_GCC_X86_CPU_INIT])
AC_LANG_PUSH([C])
AS_VAR_PUSHDEF([gcc_x86_feature], [AS_TR_SH([ax_cv_gcc_x86_cpu_supports_$1])])
AC_CACHE_CHECK([for x86 $1 instruction support],
[gcc_x86_feature],
[AC_RUN_IFELSE(
[AC_LANG_PROGRAM( [#include <stdlib.h> ],
[ __builtin_cpu_init ();
if (__builtin_cpu_supports("$1"))
return 0;
return 1;
])],
[gcc_x86_feature=yes],
[gcc_x86_feature=no]
)]
)
AC_LANG_POP([C])
AS_VAR_IF([gcc_x86_feature],[yes],
[AC_DEFINE(
AS_TR_CPP([HAVE_$1_INSTRUCTIONS]),
[1],
[Define if $1 instructions are supported])
$2],
[$3]
)
AS_VAR_POPDEF([gcc_x86_feature])
])

@ -1,12 +0,0 @@
e1_input
e1_line 0 driver dahdi
e1_line 0 port 7
log stderr
logging filter all 1
logging color 1
logging print category-hex 0
logging print category 1
logging print file 1
logging level llapd debug
logging level linp debug

@ -0,0 +1,31 @@
AM_CPPFLAGS = $(all_includes)
AM_CFLAGS= -Wall -Wextra -g $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMOCTRL_CFLAGS)
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
COMMONLIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCTRL_LIBS)
SUBDIRS = libecho libg711
bin_PROGRAMS = osmo-v5-le
osmo_v5_le_SOURCES = logging.c \
ph_socket.c \
v5x_data.c \
v5le_vty.c \
lapv5.c \
layer1.c \
v5x_protocol.c \
v5x_l1_fsm.c \
v5x_le_ctrl_fsm.c \
v5x_le_port_fsm.c \
v5x_le_pstn_fsm.c \
v52_le_lcp_fsm.c \
v52_le_bcc_fsm.c \
v52_le_pp_fsm.c \
v5x_le_management.c \
main.c
osmo_v5_le_LDADD = $(COMMON_LA) \
$(COMMONLIBS) \
libecho/libecho.a \
libg711/libg711.a \
-lm

@ -22,24 +22,26 @@
*
*/
#include "v5x_internal.h"
#include "v5x_protocol.h"
#include "lapv5.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/timer.h>
#include <osmocom/abis/lapd.h>
#include <osmocom/abis/lapd_pcap.h>
#define LAPD_ADDR2(sapi, cr) ((((sapi) & 0x3f) << 2) | (((cr) & 0x1) << 1))
#define LAPD_ADDR3(tei) ((((tei) & 0x7f) << 1) | 0x1)
#include "v5x_internal.h"
#include "v5x_protocol.h"
#include "v5x_le_port_fsm.h"
#include "lapv5.h"
#include "layer1.h"
#include "logging.h"
#define LAPD_ADDR1(sapi, cr) ((((sapi) & 0x3f) << 2) | (((cr) & 0x1) << 1))
#define LAPD_ADDR2(tei) ((((tei) & 0x7f) << 1) | 0x1)
#define LAPD_ADDR_SAPI(addr) ((addr) >> 2)
#define LAPD_ADDR_CR(addr) (((addr) >> 1) & 0x1)
@ -132,15 +134,16 @@ static struct lapv5_sap *lapv5_sap_alloc(struct lapv5_instance *li, uint16_t v5d
if (!sap)
return NULL;
LOGP(DLLAPD, LOGL_NOTICE, "(%s): LAPV5 Allocating SAP for V5_DLADDR=%u (dl=%p, sap=%p)\n",
LOGP(DLLAPD, LOGL_DEBUG, "(%s): LAPV5 Allocating SAP for V5_DLADDR=%u (dl=%p, sap=%p)\n",
name, v5dladdr, &sap->dl, sap);
sap->li = li;
sap->dladdr = v5dladdr;
dl = &sap->dl;
profile = &li->profile;
k = profile->k[0];
LOGP(DLLAPD, LOGL_NOTICE, "(%s): k=%d N200=%d N201=%d T200=%d.%d T203=%d.%d\n",
LOGP(DLLAPD, LOGL_DEBUG, "(%s): k=%d N200=%d N201=%d T200=%d.%d T203=%d.%d\n",
name, k, profile->n200, profile->n201, profile->t200_sec,
profile->t200_usec, profile->t203_sec, profile->t203_usec);
lapd_dl_init2(dl, k, 128, profile->n201, name);
@ -152,8 +155,8 @@ static struct lapv5_sap *lapv5_sap_alloc(struct lapv5_instance *li, uint16_t v5d
dl->t200_sec = profile->t200_sec; dl->t200_usec = profile->t200_usec;
dl->t203_sec = profile->t203_sec; dl->t203_usec = profile->t203_usec;
dl->lctx.dl = &sap->dl;
dl->lctx.sapi = v5dladdr & 0xff;
dl->lctx.tei = v5dladdr >> 8;
dl->lctx.sapi = v5dladdr >> 7;
dl->lctx.tei = v5dladdr & 0x7f;
dl->lctx.n201 = profile->n201;
lapd_set_mode(&sap->dl, (li->network_side) ? LAPD_MODE_NETWORK : LAPD_MODE_USER);
@ -166,7 +169,7 @@ static struct lapv5_sap *lapv5_sap_alloc(struct lapv5_instance *li, uint16_t v5d
/* Free SAP instance, including the datalink */
static void lapv5_sap_free(struct lapv5_sap *sap)
{
LOGSAP(sap, LOGL_NOTICE, "LAPV5 Freeing SAP for DLADDR=%u (dl=%p, sap=%p)\n", sap->dladdr, &sap->dl, sap);
LOGSAP(sap, LOGL_DEBUG, "LAPV5 Freeing SAP for DLADDR=%u (dl=%p, sap=%p)\n", sap->dladdr, &sap->dl, sap);
/* free datalink structures and timers */
lapd_dl_exit(&sap->dl);
@ -175,39 +178,41 @@ static void lapv5_sap_free(struct lapv5_sap *sap)
talloc_free(sap);
}
/* General input function for any data received for this LAPV5 instance */
int lapv5_receive(struct lapv5_instance *li, struct msgb *msg, int *error)
/* Receive Data (PH-DATA indication) on the given LAPD Instance */
int lapv5_ph_data_ind(struct lapv5_instance *li, struct msgb *msg, int *error)
{
struct lapd_msg_ctx lctx;
struct lapv5_sap *sap;
uint16_t dladdr;
bool is_isdn;
int i;
/* write to PCAP file, if enabled. */
osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_INPUT, msg);
if (!li->enabled) {
LOGLI(li, LOGL_DEBUG, "LAPV5 frame ignored, because DL is disabled.\n");
msgb_free(msg);
return -EINVAL;
}
msgb_pull(msg, msg->l2h - msg->data);
LOGLI(li, LOGL_DEBUG, "RX: %s\n", osmo_hexdump(msg->data, msg->len));
if (msg->len < 2) {
LOGLI(li, LOGL_ERROR, "LAPV5 frame receive len %d < 2, ignoring\n", msg->len);
*error = LAPD_ERR_BAD_LEN;
msgb_free(msg);
return -EINVAL;
};
msg->l2h = msg->data;
memset(&lctx, 0, sizeof(lctx));
i = 0;
/* adress field */
dladdr = v51_l3_addr_dec(msg->l2h[0] << 8 | msg->l2h[1], &is_isdn);
if (!is_isdn) {
LOGLI(li, LOGL_ERROR, "LAPV5 frame with single-octet addr not permitted\n");
*error = LAPD_ERR_BAD_LEN;
return -EINVAL;
};
dladdr = ((msg->l2h[0] & 0xfe) << 5) | (msg->l2h[1] >> 1);
lctx.lpd = 0;
lctx.tei = dladdr >> 8;
lctx.sapi = dladdr & 0xff;
lctx.sapi = dladdr >> 7;
lctx.tei = dladdr & 0x7f;
lctx.cr = LAPD_ADDR_CR(msg->l2h[0]);
i += 2;
@ -219,6 +224,7 @@ int lapv5_receive(struct lapv5_instance *li, struct msgb *msg, int *error)
if (msg->len < 4) {
LOGLI(li, LOGL_ERROR, "LAPV5 I frame receive len %d < 4, ignoring\n", msg->len);
*error = LAPD_ERR_BAD_LEN;
msgb_free(msg);
return -EINVAL;
}
lctx.n_recv = LAPD_CTRL_Nr(msg->l2h[i]);
@ -230,6 +236,7 @@ int lapv5_receive(struct lapv5_instance *li, struct msgb *msg, int *error)
if (msg->len < 4 && i == 3) {
LOGLI(li, LOGL_ERROR, "LAPV5 S frame receive len %d < 4, ignoring\n", msg->len);
*error = LAPD_ERR_BAD_LEN;
msgb_free(msg);
return -EINVAL;
}
lctx.n_recv = LAPD_CTRL_Nr(msg->l2h[i]);
@ -270,34 +277,34 @@ int lapv5_receive(struct lapv5_instance *li, struct msgb *msg, int *error)
return lapd_ph_data_ind(msg, &lctx);
}
/* Start a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */
int lapv5_sap_start(struct lapv5_instance *li, uint16_t dladdr)
/* Start a (LE-side) SAP for the specified TEI/SAPI on the LAPD instance */
int lapv5_dl_est_req(struct lapv5_instance *li, uint16_t dladdr)
{
struct lapv5_sap *sap;
struct osmo_dlsap_prim dp;
struct msgb *msg;
sap = lapv5_sap_find(li, dladdr);
if (sap)
return -EEXIST;
sap = lapv5_sap_alloc(li, dladdr);
if (!sap)
return -ENOMEM;
if (!sap) {
sap = lapv5_sap_alloc(li, dladdr);
if (!sap)
return -ENOMEM;
}
LOGSAP(sap, LOGL_NOTICE, "LAPV5 DL-ESTABLISH request DLADDR=%u\n", dladdr);
LOGSAP(sap, LOGL_DEBUG, "LAPV5 DL-ESTABLISH request DLADDR=%u\n", dladdr);
/* prepare prim */
msg = msgb_alloc_headroom(DLSAP_MSGB_SIZE, DLSAP_MSGB_HEADROOM, "DL EST");
msg->l3h = msg->data;
memset(&dp, 0, sizeof(dp));
osmo_prim_init(&dp.oph, 0, PRIM_DL_EST, PRIM_OP_REQUEST, msg);
/* send to L2 */
return lapd_recv_dlsap(&dp, &sap->dl.lctx);
}
/* Stop a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */
int lapv5_sap_stop(struct lapv5_instance *li, uint16_t dladdr)
/* Stop a (LE-side) SAP for the specified TEI/SAPI on the LAPD instance */
int lapv5_dl_rel_req(struct lapv5_instance *li, uint16_t dladdr)
{
struct lapv5_sap *sap;
struct osmo_dlsap_prim dp;
@ -307,11 +314,12 @@ int lapv5_sap_stop(struct lapv5_instance *li, uint16_t dladdr)
if (!sap)
return -ENODEV;
LOGSAP(sap, LOGL_NOTICE, "LAPV5 DL-RELEASE request DLADDR=%u\n", dladdr);
LOGSAP(sap, LOGL_DEBUG, "LAPV5 DL-RELEASE request DLADDR=%u\n", dladdr);
/* prepare prim */
msg = msgb_alloc_headroom(DLSAP_MSGB_SIZE, DLSAP_MSGB_HEADROOM, "DL REL");
msg->l3h = msg->data;
memset(&dp, 0, sizeof(dp));
osmo_prim_init(&dp.oph, 0, PRIM_DL_REL, PRIM_OP_REQUEST, msg);
/* send to L2 */
@ -319,24 +327,25 @@ int lapv5_sap_stop(struct lapv5_instance *li, uint16_t dladdr)
}
/* Transmit Data (DL-DATA request) on the given LAPD Instance / DLADDR */
void lapv5_transmit(struct lapv5_instance *li, uint8_t dladdr, struct msgb *msg)
int lapv5_dl_data_req(struct lapv5_instance *li, uint16_t dladdr, struct msgb *msg)
{
struct lapv5_sap *sap;
struct osmo_dlsap_prim dp;
sap = lapv5_sap_find(li, dladdr);
if (!sap) {
LOGLI(li, LOGL_INFO, "LAPV5 Tx on unknown DLADDR=%u\n", dladdr);
LOGLI(li, LOGL_NOTICE, "LAPV5 Tx on unknown DLADDR=%u\n", dladdr);
msgb_free(msg);
return;
return -EINVAL;
}
/* prepare prim */
msg->l3h = msg->data;
osmo_prim_init(&dp.oph, 0, PRIM_DL_DATA, PRIM_OP_REQUEST, msg);
memset(&dp, 0, sizeof(dp));
osmo_prim_init(&dp.oph, 0, PRIM_DL_DATA, PRIM_OP_REQUEST, msg);
/* send to L2 */
lapd_recv_dlsap(&dp, &sap->dl.lctx);
/* send to L2 */
return lapd_recv_dlsap(&dp, &sap->dl.lctx);
};
static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg)
@ -368,15 +377,15 @@ static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg)
}
/* address field */
msg->l2h = msgb_push(msg, 2);
msg->l2h[0] = LAPD_ADDR2(lctx->sapi, lctx->cr);
msg->l2h[1] = LAPD_ADDR3(lctx->tei);
msg->l2h[0] = LAPD_ADDR1(lctx->sapi, lctx->cr);
msg->l2h[1] = LAPD_ADDR2(lctx->tei);
/* write to PCAP file, if enabled. */
osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_OUTPUT, msg);
/* forward frame to L1 */
LOGDL(dl, LOGL_DEBUG, "TX: %s\n", osmo_hexdump(msg->data, msg->len));
li->transmit_cb(msg, li->transmit_cbdata);
li->ph_data_req_cb(msg, li->ph_data_req_cbdata);
return 0;
}
@ -392,14 +401,14 @@ static int send_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx)
li = sap->li;
dladdr = lctx->tei << 8 | lctx->sapi;
dladdr = lctx->sapi << 7 | lctx->tei;
switch (dp->oph.primitive) {
case PRIM_DL_EST:
LOGDL(dl, LOGL_NOTICE, "LAPD DL-ESTABLISH %s DLADDR=%u\n", op, dladdr);
LOGDL(dl, LOGL_DEBUG, "LAPD DL-ESTABLISH %s DLADDR=%u\n", op, dladdr);
break;
case PRIM_DL_REL:
LOGDL(dl, LOGL_NOTICE, "LAPD DL-RELEASE %s DLADDR=%u\n", op, dladdr);
LOGDL(dl, LOGL_DEBUG, "LAPD DL-RELEASE %s DLADDR=%u\n", op, dladdr);
lapv5_sap_free(sap);
/* note: sap and dl is now gone, don't use it anymore */
break;
@ -407,15 +416,15 @@ static int send_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx)
;
}
li->receive_cb(dp, dladdr, li->receive_cbdata);
li->dl_receive_cb(dp, dladdr, li->dl_receive_cbdata);
return 0;
}
/* Allocate a new LAPV5 instance */
struct lapv5_instance *lapv5_instance_alloc(int network_side,
void (*tx_cb)(struct msgb *msg, void *cbdata), void *tx_cbdata,
void (*rx_cb)(struct osmo_dlsap_prim *odp, uint16_t dladdr, void *rx_cbdata), void *rx_cbdata,
int (*ph_data_req_cb)(struct msgb *msg, void *cbdata), void *ph_data_req_cbdata,
int (*dl_receive_cb)(struct osmo_dlsap_prim *odp, uint16_t dladdr, void *rx_cbdata), void *dl_receive_cbdata,
const struct lapd_profile *profile, const char *name)
{
struct lapv5_instance *li;
@ -425,10 +434,10 @@ struct lapv5_instance *lapv5_instance_alloc(int network_side,
return NULL;
li->network_side = network_side;
li->transmit_cb = tx_cb;
li->transmit_cbdata = tx_cbdata;
li->receive_cb = rx_cb;
li->receive_cbdata = rx_cbdata;
li->ph_data_req_cb = ph_data_req_cb;
li->ph_data_req_cbdata = ph_data_req_cbdata;
li->dl_receive_cb = dl_receive_cb;
li->dl_receive_cbdata = dl_receive_cbdata;
li->pcap_fd = -1;
li->name = talloc_strdup(li, name);
memcpy(&li->profile, profile, sizeof(li->profile));
@ -470,62 +479,121 @@ void lapv5_instance_free(struct lapv5_instance *li)
* while the last octet (before msg->tail) points to the last FCS octet. */
int lapv5ef_rx(struct v5x_link *link, struct msgb *msg)
{
struct lapd_datalink *dl;
struct lapv5_instance *li = NULL;
struct v5x_user_port *v5up = NULL;
uint16_t efaddr, efaddr_enc;
bool is_isdn;
int error;
msg->l1h = msg->data;
if (msgb_length(msg) < 2) {
LOGP(DV5EF, LOGL_ERROR, "Frame too short.\n");
msgb_free(msg);
return -EINVAL;
}
msg->l2h = msg->l1h + 2;
efaddr_enc = msg->l1h[0] << 8 | msg->l1h[1];
efaddr = v51_l3_addr_dec(efaddr_enc, &is_isdn);
efaddr_enc = msg->l2h[0] << 8 | msg->l2h[1];
msg->l2h += 2;
msgb_pull(msg, msg->l2h - msg->data);
efaddr = v5x_l3_addr_dec(efaddr_enc, &is_isdn);
if (!is_isdn) {
/* EFaddr are structured like isdn-type L3 Address */
LOGP(DV5EF, LOGL_ERROR, "EFaddr are structured like isdn-type L3 Address.\n");
msgb_free(msg);
return -EINVAL;
}
switch (efaddr) {
case V51_DLADDR_PSTN:
case V5X_DLADDR_PSTN:
/* hand-over to LAPD-DL instance for PSTN */
dl = &link->interface->pstn.dl;
/* TODO */
li = link->interface->pstn.li;
break;
case V51_DLADDR_CTRL:
case V5X_DLADDR_CTRL:
/* hand-over to LAPD-DL instance for CTRL */
/* TODO */
dl = &link->interface->control.dl;
li = link->interface->control.li;
break;
case V52_DLADDR_BCC:
dl = &link->interface->bcc.dl;
/* TOOD: implement V5.2 */
msgb_free(msg);
/* hand-over to LAPD-DL instance for BCC */
li = link->interface->bcc.li;
break;
case V52_DLADDR_PROTECTION:
dl = &link->interface->protection[0].dl;
/* TOOD: implement V5.2 */
msgb_free(msg);
/* hand-over to LAPD-DL instance for PROTECTION */
if (link == link->interface->primary_link)
li = link->interface->protection.li[0];
if (link == link->interface->secondary_link)
li = link->interface->protection.li[1];
break;
case V52_DLADDR_LCP:
dl = &link->interface->lcp.dl;
/* TOOD: implement V5.2 */
msgb_free(msg);
/* hand-over to LAPD-DL instance for LCP */
li = link->interface->lcp.li;
break;
default:
if (efaddr >= 8176) {
/* reserved as per Section 9.2.2.2 of G.964 */
LOGP(DV5EF, LOGL_ERROR, "No LAPV5 protocol for EFaddr %d.\n", efaddr);
msgb_free(msg);
return -EINVAL;
}
/* relay function for LAPD of user ports */
/* TODO */
v5up = v5x_user_port_find(link->interface, efaddr, true);
if (!v5up) {
LOGP(DV5EF, LOGL_ERROR, "No ISDN user port instance for EFaddr %d created.\n", efaddr);
msgb_free(msg);
return -EINVAL;
}
if (!v5x_le_port_isdn_is_operational(v5up->port_fi)) {
LOGP(DV5EF, LOGL_NOTICE, "Dropping D-channel (AN->LE) message of non-operational ISDN port for EFaddr %d.\n", efaddr);
msgb_free(msg);
return -EIO;
}
LOGP(DV5EF, LOGL_DEBUG, "Recevied frame for EFaddr %d: %s\n", efaddr, osmo_hexdump(msg->data, msg->len));
ph_socket_tx_msg(&v5up->ph_socket, 3, PH_PRIM_DATA_IND, msg->data, msg->len);
msgb_free(msg);
return 0;
}
if (!li) {
LOGP(DV5EF, LOGL_ERROR, "No LAPV5 instance for EFaddr %d created.\n", efaddr);
msgb_free(msg);
return -EINVAL;
}
lapv5_ph_data_ind(li, msg, &error);
return 0;
}
int lapv5ef_tx(struct v5x_user_port *v5up, struct msgb *msg)
{
uint16_t efaddr = v5up->nr, efaddr_enc;
if (!v5x_le_port_isdn_is_operational(v5up->port_fi)) {
LOGP(DV5EF, LOGL_NOTICE, "Dropping D-channel (LE->AN) message of non-operational ISDN port for EFaddr %d.\n", efaddr);
msgb_free(msg);
return -EIO;
}
/* relay function for LAPD of user ports */
LOGP(DV5EF, LOGL_DEBUG, "Sending frame for EFaddr %d: %s\n", efaddr, osmo_hexdump(msg->data, msg->len));
msg->l2h = msgb_push(msg, 2);
efaddr_enc = v5x_l3_addr_enc(efaddr, 1);
msg->l2h[0] = efaddr_enc >> 8;
msg->l2h[1] = efaddr_enc;
ph_data_req_hdlc(msg, v5up->interface);
return 0;
}
/* set enabled state, also free all SAP, so it will disable/enable with a cleanly */
void lapv5_set_enabled(struct lapv5_instance *li, bool enabled)
{
struct lapv5_sap *sap;
li->enabled = enabled;
/* reset DL instances */
llist_for_each_entry(sap, &li->sap_list, list) {
lapd_dl_reset(&sap->dl);
}
}

@ -0,0 +1,43 @@
#pragma once
#include <osmocom/abis/lapd.h>
struct lapv5_instance {
struct llist_head list; /* list of LAPV5 instances */
bool network_side;
int (*ph_data_req_cb)(struct msgb *msg, void *cbdata);
void *ph_data_req_cbdata;
int (*dl_receive_cb)(struct osmo_dlsap_prim *odp, uint16_t dladdr, void *rx_cbdata);
void *dl_receive_cbdata;
struct lapd_profile profile; /* must be a copy */
struct llist_head sap_list; /* list of SAP/datalinks in this instance */
int pcap_fd; /* PCAP file descriptor */
char *name; /* human-readable name */
bool enabled; /* only receive messages when enabled */
};
extern const struct lapd_profile lapd_profile_lapv5dl;
int lapv5ef_rx(struct v5x_link *link, struct msgb *msg);
int lapv5_dl_est_req(struct lapv5_instance *li, uint16_t dladdr);
int lapv5_dl_rel_req(struct lapv5_instance *li, uint16_t dladdr);
int lapv5_dl_data_req(struct lapv5_instance *li, uint16_t dladdr, struct msgb *msg);
int lapv5_ph_data_ind(struct lapv5_instance *li, struct msgb *msg, int *error);
struct lapv5_instance *lapv5_instance_alloc(int network_side,
int (*ph_data_req_cb)(struct msgb *msg, void *cbdata), void *ph_data_req_cbdata,
int (*dl_receive_cb)(struct osmo_dlsap_prim *odp, uint16_t dladdr, void *rx_cbdata), void *dl_receive_cbdata,
const struct lapd_profile *profile, const char *name);
void lapv5_instance_set_profile(struct lapv5_instance *li, const struct lapd_profile *profile);
void lapv5_instance_free(struct lapv5_instance *li);
int lapv5ef_rx(struct v5x_link *link, struct msgb *msg);
int lapv5ef_tx(struct v5x_user_port *v5up, struct msgb *msg);
void lapv5_set_enabled(struct lapv5_instance *li, bool enabled);

@ -0,0 +1,537 @@
#include <stdio.h>
#include <errno.h>
#include <osmocom/core/gsmtap.h>
#include <osmocom/core/gsmtap_util.h>
#include <osmocom/core/signal.h>
#include "v5x_internal.h"
#include "v5x_protocol.h"
#include "lapv5.h"
#include "layer1.h"
#include "v5x_l1_fsm.h"
#include "v5x_le_management.h"
#include "logging.h"
#include "libg711/g711.h"
extern int ulaw;
extern int test_sa7;
extern const char *gsmtap_ip;
extern struct v5x_instance *v5i;
static struct gsmtap_inst *g_gti = NULL;
/* only temporarily until this is in libosmocore gsmtap.h */
#ifndef GSMTAP_E1T1_V5EF
#define GSMTAP_E1T1_V5EF 0x06
#endif
/* Callback function to receive L1 signal from E1 port */
static int inp_sig_cb(unsigned int subsys, unsigned int signal, void __attribute__((unused)) *handler_data,
void *signal_data)
{
struct input_signal_data *isd = signal_data;
struct v5x_link *v5l;
if (subsys != SS_L_INPUT)
return 0;
/* not used by any link */
if (!isd->line->ops)
return 0;
v5l = container_of(isd->line->ops, struct v5x_link, e1_line_ops);
switch (signal) {
case S_L_INP_LINE_LOS:
v5x_l1_signal_rcv(v5l, L1_SIGNAL_LOS);
break;
case S_L_INP_LINE_NOLOS:
v5x_l1_signal_rcv(v5l, L1_SIGNAL_NO_LOS);
break;
case S_L_INP_LINE_RAI:
v5x_l1_signal_rcv(v5l, L1_SIGNAL_RAI);
break;
case S_L_INP_LINE_NORAI:
v5x_l1_signal_rcv(v5l, L1_SIGNAL_NO_RAI);
break;
case S_L_INP_LINE_AIS:
v5x_l1_signal_rcv(v5l, L1_SIGNAL_AIS);
break;
case S_L_INP_LINE_NOAIS:
v5x_l1_signal_rcv(v5l, L1_SIGNAL_NO_AIS);
break;
case S_L_INP_LINE_SA_BITS:
if ((isd->sa_bits & 0x40)) {
v5x_l1_signal_rcv(v5l, L1_SIGNAL_SA7_1);
if (test_sa7) {
printf("Currently Sa 7 is set to 1, changing it to 0. (Link ID %d)\n", v5l->id);
v5x_l1_signal_snd(v5l, L1_SIGNAL_SA7_0);
}
} else {
v5x_l1_signal_rcv(v5l, L1_SIGNAL_SA7_0);
if (test_sa7) {
printf("Currently Sa 7 is set to 0, changing it to 1. (Link ID %d)\n", v5l->id);
v5x_l1_signal_snd(v5l, L1_SIGNAL_SA7_1);
}
}
break;
case S_L_INP_LINE_SLIP_RX:
printf("RX slip detected on link %d.\n", v5l->id);
break;
case S_L_INP_LINE_SLIP_TX:
printf("TX slip detected on link %d.\n", v5l->id);
break;
default:
;
}
return 0;
}
/* Send L1 signal to E1 port */
int v5x_l1_signal_snd(struct v5x_link *v5l, enum l1_signal_prim prim)
{
struct e1inp_line *e1_line = v5l->e1_line;
/* no line assigned */
if (!e1_line)
return 0;
switch (prim) {
case L1_SIGNAL_SA7_0:
e1inp_ts_set_sa_bits(e1_line, 0xbf);
break;
case L1_SIGNAL_SA7_1:
e1inp_ts_set_sa_bits(e1_line, 0xff);
break;
default:
;
}
return 0;
}
/* store TX to buffer */
static void echo_tx(struct v5x_echo_proc *ep, uint8_t *data, int len)
{
int in;
int16_t tx;
if (!ep->enabled)
return;
while (len--) {
if (ulaw)
tx = g711_ulaw_flipped_to_linear[*data++];
else
tx = g711_alaw_flipped_to_linear[*data++];
ep->tx_buffer[ep->tx_buffer_in] = tx;
in = (ep->tx_buffer_in + 1) % EC_BUFFER;
/* buffer overflow condition, should not happen, if application syncs to RX */
if (in == ep->tx_buffer_out)
break;
ep->tx_buffer_in = in;
}
}
/* remove echo from RX using TX from buffer */
static void echo_rx(struct v5x_echo_proc *ep, uint8_t *data, int len)
{
struct v5x_user_port *v5up = ep->port;
int16_t tx, rx, rx_can;
int16_t answer_buffer[len];
int i;
int rc;
if (!ep->enabled)
return;
for (i = 0; i < len; i++) {
/* buffer underrun condition, may happen before buffer was filled with first frame */
if (ep->tx_buffer_out == ep->tx_buffer_in)
tx = 0;
else {
tx = ep->tx_buffer[ep->tx_buffer_out];
ep->tx_buffer_out = (ep->tx_buffer_out + 1) % EC_BUFFER;
}
if (ulaw) {
rx = g711_ulaw_flipped_to_linear[*data];
if (ep->port->use_line_echo == USE_ECHO_CANCELER)
rx_can = echo_can_update(ep->ec, tx, rx);
else
rx_can = echo_sup_update(ep->es, tx, rx);
*data++ = g711_linear_to_ulaw_flipped[(uint16_t)rx_can];
} else {
rx = g711_alaw_flipped_to_linear[*data];
if (ep->port->use_line_echo == USE_ECHO_CANCELER)
rx_can = echo_can_update(ep->ec, tx, rx);
else
rx_can = echo_sup_update(ep->es, tx, rx);
*data++ = g711_linear_to_alaw_flipped[(uint16_t)rx_can];
}
answer_buffer[i] = rx + tx; /* yes, may overflow, but then it is no valid tone anyway */
}
rc = answertone_process(&ep->at, answer_buffer, len, (ep->port->use_line_echo == USE_ECHO_CANCELER));
if (rc > 0) {
LOGP(DV5, LOGL_NOTICE, "Detected answer tone, disable echo %s of %s port %d.\n",
(ep->port->use_line_echo == USE_ECHO_CANCELER) ? "canceler" : "suppressor",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
ep->enabled = 0;
}
}
/* data L1 -> L2 from E1 interface */
static void hdlc_rx_cb(struct e1inp_ts *ts, struct msgb *msg)
{
struct v5x_link *v5l;
/* not used by any link */
if (!ts->line->ops) {
msgb_free(msg);
return;
}
v5l = container_of(ts->line->ops, struct v5x_link, e1_line_ops);
LOGP(DLINP, LOGL_DEBUG, "Link %d L1->L2: %s\n", v5l->id, msgb_hexdump(msg));
/* send V5 data via gsmtap so wireshark can receive + decode it */
if (g_gti) {
gsmtap_send_ex(g_gti, GSMTAP_TYPE_E1T1, v5l->id, ts->num, GSMTAP_E1T1_V5EF,
0, 0, 0, 0, msgb_data(msg), msgb_length(msg));
}
lapv5ef_rx(v5l, msg);
}
/* data B-channel data from E1 interface */
static void raw_rx_cb(struct e1inp_ts *ts, struct msgb *msg)
{
struct v5x_link *v5l;
struct v5x_user_port *v5up;
/* not used by any link */
if (!ts->line->ops) {
msgb_free(msg);
return;
}
v5l = container_of(ts->line->ops, struct v5x_link, e1_line_ops);
v5up = v5l->ts[ts->num].v5up;
/* not used by any user port */
if (!v5up) {
msgb_free(msg);
return;
}
/* we want B-channel data flipped */
osmo_revbytebits_buf(msg->data, msg->len);
/* if assigned and active, send B-channel data to socket interface */
if (v5up->ts[0] && v5up->ts[0]->nr == ts->num && v5up->ts[0]->b_activated) {
echo_rx(&v5up->ep[0], msg->data, msg->len);
ph_socket_tx_msg(&v5up->ph_socket, 1, PH_PRIM_DATA_IND, msg->data, msg->len);
}
if (v5up->ts[1] && v5up->ts[1]->nr == ts->num && v5up->ts[1]->b_activated) {
echo_rx(&v5up->ep[1], msg->data, msg->len);
ph_socket_tx_msg(&v5up->ph_socket, 2, PH_PRIM_DATA_IND, msg->data, msg->len);
}
msgb_free(msg);
}
/* send HDLC frame to signaling channel (from ISDN) */
int ph_data_req_hdlc(struct msgb *msg, struct v5x_interface *v5if)
{
struct e1inp_line *e1_line = v5if->cc_link->e1_line;
if (!e1_line) {
msgb_free(msg);
return 0;
}
if (!v5x_l1_is_up(v5if->cc_link->l1)) {
LOGP(DLINP, LOGL_DEBUG, "Link %d is down!\n", v5if->cc_link->id);
msgb_free(msg);
return 0;
}
LOGP(DLINP, LOGL_DEBUG, "Link %d L2->L1: %s\n", v5if->cc_link->id, msgb_hexdump(msg));
struct e1inp_ts *ts = &e1_line->ts[v5if->cc_link->c_channel[0].ts->nr - 1];
/* send V5 data via gsmtap so wireshark can receive + decode it */
if (g_gti) {
gsmtap_send_ex(g_gti, GSMTAP_TYPE_E1T1, v5if->cc_link->id | GSMTAP_ARFCN_F_UPLINK, ts->num,
GSMTAP_E1T1_V5EF, 0, 0, 0, 0, msgb_data(msg), msgb_length(msg));
}
return e1inp_ts_send_hdlc(ts, msg);
}
/* send HDLC frame to signaling channel (from DL) */
int ph_data_req_dl_cc(struct msgb *msg, void *cbdata)
{
struct v5x_interface *v5if = (struct v5x_interface *)cbdata;
struct e1inp_line *e1_line = v5if->cc_link->e1_line;
if (!e1_line) {
msgb_free(msg);
return 0;
}
if (!v5x_l1_is_up(v5if->cc_link->l1)) {
LOGP(DLINP, LOGL_DEBUG, "Link %d is down!\n", v5if->cc_link->id);
msgb_free(msg);
return 0;