diff options
author | Thorsten Alteholz <debian@alteholz.de> | 2018-04-09 19:46:24 +0200 |
---|---|---|
committer | Thorsten Alteholz <debian@alteholz.de> | 2018-04-09 19:46:24 +0200 |
commit | 2ad447fb95a63d80584b2792a4f4fbb6ddbfd55d (patch) | |
tree | 7d8c2eaeea7e9e39e15a19ca975dc8c884d11330 | |
parent | 5d0d8129bbf6c41346205c4654149187d134eef0 (diff) |
Import Upstream version 0.4.0
32 files changed, 1526 insertions, 186 deletions
@@ -21,10 +21,12 @@ missing ltmain.sh install-sh stamp-h1 -libtool #libosmo-abis-* tests/*_test +# libtool and e.g. arm-poky-linux-gnueabi-libtool +*libtool + .tarball-version .version .dirstamp diff --git a/.gitreview b/.gitreview new file mode 100644 index 0000000..2e575db --- /dev/null +++ b/.gitreview @@ -0,0 +1,3 @@ +[gerrit] +host=gerrit.osmocom.org +project=libosmo-abis diff --git a/Makefile.am b/Makefile.am index 9c82f09..a8774c4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,3 +11,7 @@ $(top_srcdir)/.version: echo $(VERSION) > $@-t && mv $@-t $@ dist-hook: echo $(VERSION) > $(distdir)/.tarball-version + +EXTRA_DIST = .version README.md + +@RELMAKE@ diff --git a/README.md b/README.md new file mode 100644 index 0000000..c5df874 --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +libosmo-abis - Osmocom Abis interface library +============================================= + +This repository contains a set of C-language libraries that form the +A-bis interface library of [Osmocom](https://osmocom.org/) Open Source +Mobile Communications projects such as OpenBSC / OsmoBSC. + +Historically, a lot of this code was developed as part of the +[OpenBSC](https://osmocom.org/projects/openbsc) project, but which are +of a more generic nature and thus useful to (at least) other programs +that we develop in the sphere of Free Software / Open Source mobile +communications. + +The libosmo-abis.git repository build multiple libraries: + +* **libosmoabis** contains some abstraction layer over E1/T1 and IP + based ETSI/3GPP A-bis interface. It can use mISDN and DAHDI as + underlying driver/hardware. +* **libosmotrau** contains routines related to A-bis TRAU frame handling + +Homepage +-------- + +The official homepage of the project is +<https://osmocom.org/projects/libosmo-abis> + +GIT Repository +-------------- + +You can clone from the official libosmo-abis.git repository using + + git clone git://git.osmocom.org/libosmo-abis.git + +There is a cgit interface at <http://git.osmocom.org/libosmo-abis/> + +Documentation +------------- + +There is no Doxygen-generated API documentation yet for this library. It +would be great to some day have it, comparable to libosmocore. + +Mailing List +------------ + +Discussions related to libosmo-abis are happening on the +openbsc@lists.osmocom.org mailing list, please see +<https://lists.osmocom.org/mailman/listinfo/openbsc> for subscription +options and the list archive. + +Please observe the [Osmocom Mailing List +Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules) +when posting. + +Contributing +------------ + +Our coding standards are described at +<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards> + +We us a gerrit based patch submission/review process for managing +contributions. Please see +<https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit> for +more details + +The current patch queue for libosmo-abis can be seen at +<https://gerrit.osmocom.org/#/q/project:libosmo-abis+status:open> diff --git a/TODO-RELEASE b/TODO-RELEASE index 43b1e8e..d0852fc 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -1 +1,9 @@ +# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install +# according to https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info +# In short: +# LIBVERSION=c:r:a +# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a. +# If any interfaces have been added, removed, or changed since the last update: c + 1:0:0. +# If any interfaces have been added since the last public release: c:r:a + 1. +# If any interfaces have been removed or changed since the last public release: c:r:0. #library what description / commit summary line diff --git a/configure.ac b/configure.ac index 7d88eb4..eb7733e 100644 --- a/configure.ac +++ b/configure.ac @@ -2,20 +2,37 @@ AC_INIT([libosmo-abis], 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) 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 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" + # The following test is taken from WebKit's webkit.m4 saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fvisibility=hidden " @@ -33,18 +50,50 @@ AM_CONFIG_HEADER(config.h) PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.3.0) PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0) PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.3.10) -PKG_CHECK_MODULES([ORTP], [ortp >= 0.13.1], - [ - PKG_CHECK_MODULES([ORTP_VERSION], [ortp >= 0.21], - [AC_DEFINE(HAVE_ORTP_021, 1, - [libortp >= 0.21])], - [AC_DEFINE(HAVE_ORTP_021, 0, - [libortp < 0.21])]) - ] -) +PKG_CHECK_MODULES(ORTP, ortp >= 0.22.0) AC_CHECK_HEADERS(dahdi/user.h,,AC_MSG_WARN(DAHDI input driver will not be built)) +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 + +_cflags_save=$CFLAGS +CFLAGS="$CFLAGS $ORTP_CFLAGS" +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include <ortp/ortp.h>]], + [[ortp_set_log_level_mask(NULL, 0xffff);]] + )], + [AC_DEFINE([HAVE_ORTP_LOG_DOMAIN], [1], + [ortp_set_log_level_mask requires domain parameter])], + [AC_DEFINE([HAVE_ORTP_LOG_DOMAIN], [0], + [ortp_set_log_level_mask has no domain parameter])]) +CFLAGS=$_cflags_save + +_cflags_save=$CFLAGS +CFLAGS="$CFLAGS $ORTP_CFLAGS" +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include <ortp/ortp.h> + void fake_cb(struct _RtpSession *r, void *arg1, void *arg2, void *arg3) { return; }]], + [[rtp_session_signal_connect(NULL, "", fake_cb, (void*) fake_cb);]] + )], + [AC_DEFINE([RTP_SIGNAL_PTR_CAST(arg)], [(void*)(arg)], + [rtp_session_signal_connect requires pointer parameter])], + [AC_DEFINE([RTP_SIGNAL_PTR_CAST(arg)], [(unsigned long)(arg)], + [rtp_session_signal_connect requires ulong parameter])]) +CFLAGS=$_cflags_save + + AC_OUTPUT( libosmoabis.pc libosmotrau.pc diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh new file mode 100755 index 0000000..769d5a7 --- /dev/null +++ b/contrib/jenkins.sh @@ -0,0 +1,38 @@ +#!/bin/sh +# jenkins build helper script for libosmo-abis. This is how we build on jenkins.osmocom.org + +if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then + echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !" + exit 2 +fi + +set -ex + +base="$PWD" +deps="$base/deps" +inst="$deps/install" +export deps inst + +mkdir "$deps" || true +rm -rf "$inst" + +osmo-build-dep.sh libosmocore + +"$deps"/libosmocore/contrib/verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]") + +export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH" +export LD_LIBRARY_PATH="$inst/lib" + +set +x +echo +echo +echo +echo " =============================== libosmo-abis ===============================" +echo +set -x + +autoreconf --install --force +./configure --enable-sanitize CFLAGS="-Werror" CPPFLAGS="-Werror" +$MAKE $PARALLEL_MAKE +$MAKE distcheck \ + || cat-testlogs.sh diff --git a/debian/changelog b/debian/changelog index f1842fa..13c0996 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,14 @@ -libosmo-abis (0.3.2) UNRELEASED; urgency=medium +libosmo-abis (0.4.0) unstable; urgency=medium + + * Move forward towards a new release. + * libosmo-abis API change major: add parameter to struct + input_signal_data + * libosmo-trau API change major: add parameters to rx_cb() + callack in osmo_ortp.h + + -- Holger Hans Peter Freyther <holger@moiji-mobile.com> Fri, 25 Aug 2017 16:09:46 +0200 + +libosmo-abis (0.3.2) unstable; urgency=medium * Bump so version to re-link libosmovty diff --git a/debian/control b/debian/control index eed3a4c..5df6c95 100644 --- a/debian/control +++ b/debian/control @@ -1,12 +1,22 @@ Source: libosmo-abis +Maintainer: Harald Welte <laforge@gnumonks.org> Section: libs Priority: optional -Maintainer: Harald Welte <laforge@gnumonks.org> -Build-Depends: debhelper (>= 9), autotools-dev, autoconf, automake, libtool, dh-autoreconf, libdpkg-perl, git, libosmocore-dev (>= 0.6.4), pkg-config, libortp-dev -Standards-Version: 3.9.6 -Homepage: http://openbsc.osmocom.org/trac/wiki/libosmo-abis +Build-Depends: debhelper (>= 9), + autotools-dev, + autoconf, + automake, + libtool, + dh-autoreconf, + libdpkg-perl, + git, + libosmocore-dev (>= 0.6.4), + pkg-config, + libortp-dev +Standards-Version: 3.9.7 Vcs-Git: git://git.osmocom.org/libosmo-abis.git Vcs-Browser: http://git.osmocom.org/gitweb?p=libosmo-abis.git;a=summary +Homepage: https://projects.osmocom.org/projects/libosmo-abis Package: libosmo-abis Section: oldlibs @@ -20,28 +30,51 @@ Description: Legacy package for libosmo-abis Package: libosmoabis5 Section: libs Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} Multi-Arch: same +Depends: ${shlibs:Depends}, + ${misc:Depends} Description: GSM A-bis handling + This library contains common/shared code regarding the A-bis interface between + the GSM Base transceiver station (BTS) and the GSM Base station controller BSC. + . + It also implements drivers for mISDN and DAHDI based E1 cards, as well as some + A-bis/IP dialects. Package: libosmotrau1 Section: libs Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} Multi-Arch: same +Depends: ${shlibs:Depends}, + ${misc:Depends} Description: GSM trau handling + This library implements the Transcoder and Rate Adaptation Unit (TRAU) for + GSM systems. It is closely related to the libosmo-abis library. + . + TRAU performs transcoding function for speech channels and rate adaptation (RA) + for data channels in the GSM network. Package: libosmo-abis-dev -Section: libdevel Architecture: any -Depends: ${misc:Depends}, libosmotrau1 (= ${binary:Version}), libosmoabis5 (= ${binary:Version}) Multi-Arch: same -Description: Development headers for A-bis interface. +Section: libdevel +Depends: ${misc:Depends}, + libosmotrau1 (= ${binary:Version}), + libosmoabis5 (= ${binary:Version}) +Description: Development headers for A-bis interface + The libosmo-abis library contains common/shared code regarding the A-bis + interface between GSM BTS and BSC. This package in particular contains the + development files needed to develop with the libosmoabis and libosmotrau + libraries. Package: libosmo-abis-dbg -Section: debug Architecture: any -Priority: extra -Depends: libosmoabis5 (= ${binary:Version}), libosmotrau1 (= ${binary:Version}), ${misc:Depends} Multi-Arch: same -Description: Debug symbols for A-bis interface. +Section: debug +Priority: extra +Depends: libosmoabis5 (= ${binary:Version}), + libosmotrau1 (= ${binary:Version}), + ${misc:Depends} +Description: Debug symbols for A-bis interface + The libosmo-abis library contains common/shared code regarding the A-bis + interface between GSM BTS and BSC. This package in particular contains the + debug symbols for the two libraries libosmoabis and libosmotrau. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..fdcf686 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,83 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: libosmocore +Source: git://git.osmocom.org/libosmo-abis.git + +Files: * +Copyright: 2008 Daniel Willmann <daniel@totalueberwachung.de> + 2008-2012 Harald Welte <laforge@gnumonks.org> + 2009-2010 Holger Hans Peter Freyther <zecke@selfish.org> + 2010,2014 On-Waves + 2011-2014 Pablo Neira Ayuso <pablo@gnumonks.org> + 2012 Tobias Engel + 2014 Sysmocom s.f.m.c. GmBH +License: AGPL-3+ + +Files: src/input/lapd.c + src/trau/osmo_ortp.c + src/input/dahdi.c +Copyright: 2008-2011 Harald Welte <laforge@gnumonks.org> + 2009 oystein@homelien.no + 2009 Holger Hans Peter Freyther <zecke@selfish.org> + 2010 Digium and Matthew Fredrickson <creslin@digium.com> + 2011 Andreas Everberg <jolly@eversberg.eu> +License: GPL-2+ + +Files: include/mISDNif.h +Copyright: 2008 Karsten Keil <kkeil@novell.com> +License: LGPL-2.1 + +Files: debian/* +Copyright: 2012 Eric Butler <eric@codebutler.com> + 2012-2015 Holger Hans Peter Freyther <holger@moiji-mobile.com> + 2015 Ruben Undheim <ruben.undheim@gmail.com> +License: AGPL-3+ + + +License: AGPL-3+ + 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 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/>. + + +License: GPL-2+ + This package 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, version 2 of the License, or + (at your option) any later version. + . + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + . + On Debian systems, the complete text of the GNU General + Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". + +License: LGPL-2.1 + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; + version 2.1 of the License. + . + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + . + On Debian systems, the complete text of the GNU Lesser General + Public License version 2.1 can be found in "/usr/share/common-licenses/LGPL-2.1". diff --git a/debian/rules b/debian/rules index d3f1534..cec3c9f 100755 --- a/debian/rules +++ b/debian/rules @@ -4,8 +4,9 @@ DEBIAN := $(shell dpkg-parsechangelog | grep ^Version: | cut -d' ' -f2) DEBVERS := $(shell echo '$(DEBIAN)' | cut -d- -f1) VERSION := $(shell echo '$(DEBVERS)' | sed -e 's/[+-].*//' -e 's/~//g') +export DEB_BUILD_MAINT_OPTIONS = hardening=+all #export DH_VERBOSE=1 -export DEB_BUILD_HARDENING=1 + %: dh $@ --with autoreconf --fail-missing @@ -16,3 +17,7 @@ override_dh_strip: override_dh_autoreconf: echo $(VERSION) > .tarball-version dh_autoreconf + +override_dh_clean: + dh_clean + rm -f tests/package.m4 tests/testsuite .version .tarball-version diff --git a/include/Makefile.am b/include/Makefile.am index 16fa506..2048520 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -3,4 +3,5 @@ noinst_HEADERS=mISDNif.h internal.h nobase_include_HEADERS = osmocom/abis/ipa.h osmocom/abis/trau_frame.h \ osmocom/abis/ipa_proxy.h osmocom/abis/ipaccess.h osmocom/abis/abis.h \ osmocom/abis/subchan_demux.h osmocom/abis/e1_input.h \ - osmocom/abis/lapd.h osmocom/abis/lapd_pcap.h osmocom/trau/osmo_ortp.h + osmocom/abis/lapd.h osmocom/abis/lapd_pcap.h osmocom/trau/osmo_ortp.h \ + osmocom/abis/unixsocket_proto.h diff --git a/include/internal.h b/include/internal.h index 7f6e31a..c931d4f 100644 --- a/include/internal.h +++ b/include/internal.h @@ -13,6 +13,9 @@ extern void *libosmo_abis_ctx; /* use libosmo_abis_init, this is only for internal use. */ void e1inp_init(void); +void e1inp_ipa_set_bind_addr(const char *ip_bind_addr); +const char *e1inp_ipa_get_bind_addr(void); + /* ipaccess.c requires these functions defined here */ struct msgb; struct msgb *ipa_msg_alloc(int headroom); diff --git a/include/osmocom/abis/e1_input.h b/include/osmocom/abis/e1_input.h index e5d2991..1a701f9 100644 --- a/include/osmocom/abis/e1_input.h +++ b/include/osmocom/abis/e1_input.h @@ -21,6 +21,7 @@ enum e1inp_sign_type { E1INP_SIGN_OSMO, /* IPA CCM OSMO sub-type */ }; const char *e1inp_signtype_name(enum e1inp_sign_type tp); +extern const struct value_string e1inp_sign_type_names[5]; enum e1inp_ctr { E1I_CTR_HDLC_ABORT, @@ -63,8 +64,11 @@ enum e1inp_ts_type { E1INP_TS_TYPE_NONE, E1INP_TS_TYPE_SIGN, E1INP_TS_TYPE_TRAU, + E1INP_TS_TYPE_RAW, + E1INP_TS_TYPE_HDLC, }; const char *e1inp_tstype_name(enum e1inp_ts_type tp); +extern const struct value_string e1inp_ts_type_names[6]; /* A timeslot in the E1 interface */ struct e1inp_ts { @@ -92,6 +96,18 @@ struct e1inp_ts { /* subchannel muxer for frames to E1 */ struct subch_mux mux; } trau; + struct { + /* call-back for every received frame */ + void (*recv_cb)(struct e1inp_ts *ts, struct msgb *msg); + /* queue of pending to-be-transmitted msgbs */ + struct llist_head tx_queue; + } raw; + struct { + /* call-back for every received frame */ + void (*recv_cb)(struct e1inp_ts *ts, struct msgb *msg); + /* queue of pending to-be-transmitted msgbs */ + struct llist_head tx_queue; + } hdlc; }; union { struct { @@ -139,6 +155,7 @@ struct e1inp_driver { void (*vty_show)(struct vty *vty, struct e1inp_line *line); int default_delay; int has_keepalive; + const char *bind_addr; }; struct e1inp_line_ops { @@ -166,6 +183,7 @@ struct e1inp_line { unsigned int num; const char *name; unsigned int port_nr; + char *sock_path; struct rate_ctr_group *rate_ctr; /* keepalive configuration */ @@ -194,15 +212,14 @@ enum e1inp_signal_input { S_L_INP_LINE_NOALARM, }; +extern const struct value_string e1inp_signal_names[]; + /* register a driver with the E1 core */ int e1inp_driver_register(struct e1inp_driver *drv); /* fine a previously registered driver */ struct e1inp_driver *e1inp_driver_find(const char *name); -/* register a line with the E1 core */ -int e1inp_line_register(struct e1inp_line *line); - /* get a line by its ID */ struct e1inp_line *e1inp_line_find(uint8_t e1_nr); @@ -240,8 +257,15 @@ int e1inp_ts_config_trau(struct e1inp_ts *ts, struct e1inp_line *line, int (*trau_rcv_cb)(struct subch_demux *dmx, int ch, uint8_t *data, int len, void *_priv)); -/* Call from the Stack: configuration of this TS has changed */ -int e1inp_update_ts(struct e1inp_ts *ts); +/* configure and initialize one timeslot dedicated to RAW frames */ +int e1inp_ts_config_raw(struct e1inp_ts *ts, struct e1inp_line *line, + void (*raw_recv_cb)(struct e1inp_ts *ts, + struct msgb *msg)); + +/* configure and initialize one timeslot dedicated to HDLC frames */ +int e1inp_ts_config_hdlc(struct e1inp_ts *ts, struct e1inp_line *line, + void (*hdlc_recv_cb)(struct e1inp_ts *ts, + struct msgb *msg)); /* Receive a packet from the E1 driver */ int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg, @@ -282,6 +306,9 @@ int e1inp_vty_init(void); struct gsm_network; int ipaccess_setup(struct gsm_network *gsmnet); +/* activate superchannel or deactive to use timeslots. only valid for unixsocket driver */ +void e1inp_ericsson_set_altc(struct e1inp_line *unixlinue, int superchannel); + extern struct llist_head e1inp_driver_list; extern struct llist_head e1inp_line_list; @@ -290,6 +317,7 @@ struct input_signal_data { int link_type; uint8_t tei; uint8_t sapi; + uint8_t ts_nr; struct gsm_bts_trx *trx; struct e1inp_line *line; }; diff --git a/include/osmocom/abis/ipa.h b/include/osmocom/abis/ipa.h index 6e9f9dd..a157889 100644 --- a/include/osmocom/abis/ipa.h +++ b/include/osmocom/abis/ipa.h @@ -35,9 +35,14 @@ struct ipa_server_conn { struct osmo_fd ofd; struct llist_head tx_queue; int (*closed_cb)(struct ipa_server_conn *peer); + int (*ccm_cb)(struct ipa_server_conn *peer, struct msgb *msg, + struct tlv_parsed *tlvp, struct ipaccess_unit *ud); int (*cb)(struct ipa_server_conn *peer, struct msgb *msg); void *data; struct msgb *pending_msg; + /* remote address information */ + const char *addr; + uint16_t port; }; struct ipa_server_conn * @@ -48,6 +53,7 @@ ipa_server_conn_create(void *ctx, struct ipa_server_link *link, int fd, void ipa_server_conn_destroy(struct ipa_server_conn *peer); void ipa_server_conn_send(struct ipa_server_conn *peer, struct msgb *msg); +int ipa_server_conn_ccm(struct ipa_server_conn *conn, struct msgb *msg); enum ipa_client_conn_state { IPA_CLIENT_LINK_STATE_NONE = 0, diff --git a/include/osmocom/abis/lapd.h b/include/osmocom/abis/lapd.h index 2987633..d618187 100644 --- a/include/osmocom/abis/lapd.h +++ b/include/osmocom/abis/lapd.h @@ -18,8 +18,10 @@ struct lapd_profile { int short_address; }; +/* predefined lapd profiles (see lapd.c for definition) */ extern const struct lapd_profile lapd_profile_isdn; extern const struct lapd_profile lapd_profile_abis; +extern const struct lapd_profile lapd_profile_abis_ericsson; extern const struct lapd_profile lapd_profile_sat; struct lapd_instance { @@ -63,6 +65,13 @@ struct lapd_instance *lapd_instance_alloc(int network_side, void *rx_cbdata), void *rx_cbdata, const struct lapd_profile *profile); +/* In rare cases (e.g. Ericsson's lapd dialect), it may be necessary to + * exchange the lapd profile on the fly. lapd_instance_set_profile() + * allwos to set the lapd profile on a lapd instance danymically to + * one of the lapd profiles define above. */ +void lapd_instance_set_profile(struct lapd_instance *li, + const struct lapd_profile *profile); + void lapd_instance_free(struct lapd_instance *li); /* Start a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */ diff --git a/include/osmocom/abis/lapd_pcap.h b/include/osmocom/abis/lapd_pcap.h index 1c0d555..36ddd7f 100644 --- a/include/osmocom/abis/lapd_pcap.h +++ b/include/osmocom/abis/lapd_pcap.h @@ -1,10 +1,14 @@ #ifndef _LAPD_PCAP_H_ #define _LAPD_PCAP_H_ +#include <sys/types.h> +#include <osmocom/core/msgb.h> + #define OSMO_LAPD_PCAP_INPUT 0 #define OSMO_LAPD_PCAP_OUTPUT 1 int osmo_pcap_lapd_open(char *filename, mode_t mode); +int osmo_pcap_lapd_set_fd(int fd); int osmo_pcap_lapd_write(int fd, int direction, struct msgb *msg); int osmo_pcap_lapd_close(int fd); diff --git a/include/osmocom/abis/unixsocket_proto.h b/include/osmocom/abis/unixsocket_proto.h new file mode 100644 index 0000000..25718ff --- /dev/null +++ b/include/osmocom/abis/unixsocket_proto.h @@ -0,0 +1,31 @@ + +#ifndef UNIXSOCKET_PROTO_H +#define UNIXSOCKET_PROTO_H + +/* The unix socket protocol is using a 2 byte header + * containg the version and type. + * + * header: | 1b version | 1b type | + * + * for data packets it would be + * + * data: | 0x1 | 0x0 | lapd ..| + * control: | 0x1 | 0x1 | control payload | + * + * Atm there is only one control packet: + * - set_altc (superchannel or timeslot) + * + * set_altc payload: + * | 4b magic | 1b new_state| + * | 0x23004200 | 0x0 | to timeslot + * | 0x23004200 | 0x1 | to superchannel + */ + +#define UNIXSOCKET_PROTO_VERSION 0x1 + +enum { + UNIXSOCKET_PROTO_DATA = 0x0, + UNIXSOCKET_PROTO_CONTROL = 0x1, +}; + +#endif /* UNIXSOCKET_PROTO_H */ diff --git a/include/osmocom/trau/osmo_ortp.h b/include/osmocom/trau/osmo_ortp.h index c02cca8..578b1cb 100644 --- a/include/osmocom/trau/osmo_ortp.h +++ b/include/osmocom/trau/osmo_ortp.h @@ -2,6 +2,7 @@ #define _OSMO_ORTP_H #include <stdint.h> +#include <stdbool.h> #include <osmocom/core/linuxlist.h> #include <osmocom/core/select.h> @@ -21,6 +22,15 @@ struct _RtpSession; /*! \brief Osmocom pseudo-static paylaod type for Adaptive Multi Rate (AMR) */ #define RTP_PT_AMR 98 +#define GSM_VOICE_SAMPLE_RATE_HZ 8000 +#define GSM_VOICE_SAMPLES_PER_MS (GSM_VOICE_SAMPLE_RATE_HZ / 1000) +#define GSM_VOICE_MULTIFRAME 26 +#define GSM_RTP_FRAME_DURATION_MS 20 +#define GSM_SAMPLES_PER_RTP_FRAME (GSM_RTP_FRAME_DURATION_MS * GSM_VOICE_SAMPLES_PER_MS) +#define GSM_TDMA_FRAME_MS (120 / GSM_VOICE_MULTIFRAME) +#define GSM_MS_TO_SAMPLES(ms) ((ms) * GSM_VOICE_SAMPLES_PER_MS) +#define GSM_FN_TO_MS(fn) ((fn) * GSM_TDMA_FRAME_MS) + /*! \brief Parameter to osmo_rtp_socket_param_set() */ enum osmo_rtp_param { OSMO_RTP_P_JITBUF = 1, @@ -29,6 +39,7 @@ enum osmo_rtp_param { /*! \brief Flag to indicate the socket is in polling-only mode */ #define OSMO_RTP_F_POLL 0x0001 +#define OSMO_RTP_F_DISABLED 0x0002 /*! \brief A structure representing one RTP socket */ struct osmo_rtp_socket { @@ -44,7 +55,8 @@ struct osmo_rtp_socket { /*! \brief callback for incoming data */ void (*rx_cb)(struct osmo_rtp_socket *rs, const uint8_t *payload, - unsigned int payload_len); + unsigned int payload_len, uint16_t seq_number, + uint32_t timestamp, bool marker); /*! \brief Receive user timestamp, to be incremented by user */ uint32_t rx_user_ts; @@ -64,8 +76,12 @@ int osmo_rtp_socket_bind(struct osmo_rtp_socket *rs, const char *ip, int port); int osmo_rtp_socket_connect(struct osmo_rtp_socket *rs, const char *ip, uint16_t port); int osmo_rtp_socket_set_pt(struct osmo_rtp_socket *rs, int payload_type); int osmo_rtp_socket_free(struct osmo_rtp_socket *rs); +int osmo_rtp_skipped_frame(struct osmo_rtp_socket *rs, unsigned int duration); int osmo_rtp_send_frame(struct osmo_rtp_socket *rs, const uint8_t *payload, unsigned int payload_len, unsigned int duration); +int osmo_rtp_send_frame_ext(struct osmo_rtp_socket *rs, const uint8_t *payload, + unsigned int payload_len, unsigned int duration, + bool marker); int osmo_rtp_socket_poll(struct osmo_rtp_socket *rs); int osmo_rtp_get_bound_ip_port(struct osmo_rtp_socket *rs, diff --git a/src/Makefile.am b/src/Makefile.am index b24f2cf..7395d17 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,8 @@ # This is _NOT_ the library release version, it's an API version. -# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification -ABIS_LIBVERSION=5:0:0 -TRAU_LIBVERSION=1:0:0 +# Please read chapter "Library interface versions" of the libtool documentation +# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html +ABIS_LIBVERSION=6:0:0 +TRAU_LIBVERSION=2:0:0 AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS= -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) @@ -24,7 +25,8 @@ libosmoabis_la_SOURCES = init.c \ input/lapd.c \ input/lapd_pcap.c \ input/misdn.c \ - input/rs232.c + input/rs232.c \ + input/unixsocket.c libosmotrau_la_CFLAGS = $(AM_CFLAGS) $(ORTP_CFLAGS) libosmotrau_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(TRAU_LIBVERSION) diff --git a/src/e1_input.c b/src/e1_input.c index c454b4a..3cf810f 100644 --- a/src/e1_input.c +++ b/src/e1_input.c @@ -28,21 +28,13 @@ #include <errno.h> #include <string.h> #include <time.h> -#include <sys/fcntl.h> +#include <fcntl.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <arpa/inet.h> -#include <mISDNif.h> #include <osmocom/abis/lapd.h> -//#define AF_COMPATIBILITY_FUNC -//#include <compat_af_isdn.h> -#ifndef AF_ISDN -#define AF_ISDN 34 -#define PF_ISDN AF_ISDN -#endif - #include <osmocom/core/linuxlist.h> #include <osmocom/core/talloc.h> #include <osmocom/core/rate_ctr.h> @@ -200,30 +192,31 @@ static void write_pcap_packet(int direction, int sapi, int tei, write(pcap_fd, msg->l2h, msgb_l2len(msg)); } -static const char *sign_types[] = { - [E1INP_SIGN_NONE] = "None", - [E1INP_SIGN_OML] = "OML", - [E1INP_SIGN_RSL] = "RSL", - [E1INP_SIGN_OSMO] = "OSMO", +const struct value_string e1inp_sign_type_names[5] = { + { E1INP_SIGN_NONE, "None" }, + { E1INP_SIGN_OML, "OML" }, + { E1INP_SIGN_RSL, "RSL" }, + { E1INP_SIGN_OSMO, "OSMO" }, + { 0, NULL } }; + const char *e1inp_signtype_name(enum e1inp_sign_type tp) { - if (tp >= ARRAY_SIZE(sign_types)) - return "undefined"; - return sign_types[tp]; + return get_value_string(e1inp_sign_type_names, tp); } -static const char *ts_types[] = { - [E1INP_TS_TYPE_NONE] = "None", - [E1INP_TS_TYPE_SIGN] = "Signalling", - [E1INP_TS_TYPE_TRAU] = "TRAU", +const struct value_string e1inp_ts_type_names[6] = { + { E1INP_TS_TYPE_NONE, "None" }, + { E1INP_TS_TYPE_SIGN, "Signalling" }, + { E1INP_TS_TYPE_TRAU, "TRAU" }, + { E1INP_TS_TYPE_RAW, "RAW" }, + { E1INP_TS_TYPE_HDLC, "HDLC" }, + { 0, NULL } }; const char *e1inp_tstype_name(enum e1inp_ts_type tp) { - if (tp >= ARRAY_SIZE(ts_types)) - return "undefined"; - return ts_types[tp]; + return get_value_string(e1inp_ts_type_names, tp); } int abis_sendmsg(struct msgb *msg) @@ -231,7 +224,7 @@ int abis_sendmsg(struct msgb *msg) struct e1inp_sign_link *sign_link = msg->dst; struct e1inp_driver *e1inp_driver; struct e1inp_ts *e1i_ts; -; + msg->l2h = msg->data; /* don't know how to route this message. */ @@ -249,8 +242,14 @@ int abis_sendmsg(struct msgb *msg) } msgb_enqueue(&sign_link->tx_list, msg); - /* dump it */ - write_pcap_packet(PCAP_OUTPUT, sign_link->sapi, sign_link->tei, msg); + /* we only need to write a 'Fake LAPD' packet here, if the + * underlying driver hides LAPD from us. If we use the + * libosmocore LAPD implementation, it will take care of writing + * the _actual_ LAPD packet */ + if (!e1i_ts->lapd) { + write_pcap_packet(PCAP_OUTPUT, sign_link->sapi, + sign_link->tei, msg); + } return 0; } @@ -294,6 +293,36 @@ int e1inp_ts_config_sign(struct e1inp_ts *ts, struct e1inp_line *line) return 0; } +int e1inp_ts_config_raw(struct e1inp_ts *ts, struct e1inp_line *line, + void (*raw_recv_cb)(struct e1inp_ts *ts, + struct msgb *msg)) +{ + if (ts->type == E1INP_TS_TYPE_RAW && ts->line && line) + return 0; + + ts->type = E1INP_TS_TYPE_RAW; + ts->line = line; + ts->raw.recv_cb = raw_recv_cb; + INIT_LLIST_HEAD(&ts->raw.tx_queue); + + return 0; +} + +int e1inp_ts_config_hdlc(struct e1inp_ts *ts, struct e1inp_line *line, + void (*hdlc_recv_cb)(struct e1inp_ts *ts, + struct msgb *msg)) +{ + if (ts->type == E1INP_TS_TYPE_HDLC && ts->line && line) + return 0; + + ts->type = E1INP_TS_TYPE_HDLC; + ts->line = line; + ts->hdlc.recv_cb = hdlc_recv_cb; + INIT_LLIST_HEAD(&ts->hdlc.tx_queue); + + return 0; +} + struct e1inp_line *e1inp_line_find(uint8_t e1_nr) { struct e1inp_line *e1i_line; @@ -335,6 +364,11 @@ e1inp_line_create(uint8_t e1_nr, const char *driver_name) line->num = e1_nr; line->rate_ctr = rate_ctr_group_alloc(line, &e1inp_ctr_g_d, line->num); + if (!line->rate_ctr) { + LOGP(DLINP, LOGL_ERROR, "Cannot allocate counter group\n"); + talloc_free(line); + return NULL; + } line->num_ts = NUM_E1_TS; for (i = 0; i < line->num_ts; i++) { @@ -499,8 +533,13 @@ int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg, switch (ts->type) { case E1INP_TS_TYPE_SIGN: + /* we only need to write a 'Fake LAPD' packet here, if + * the underlying driver hides LAPD from us. If we use + * the libosmocore LAPD implementation, it will take + * care of writing the _actual_ LAPD packet */ + if (!ts->lapd) + write_pcap_packet(PCAP_INPUT, sapi, tei, msg); /* consult the list of signalling links */ - write_pcap_packet(PCAP_INPUT, sapi, tei, msg); link = e1inp_lookup_sign_link(ts, tei, sapi); if (!link) { LOGP(DLMI, LOGL_ERROR, "didn't find signalling link for " @@ -521,6 +560,12 @@ int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg, ret = subch_demux_in(&ts->trau.demux, msg->l2h, msgb_l2len(msg)); msgb_free(msg); break; + case E1INP_TS_TYPE_RAW: + ts->raw.recv_cb(ts, msg); + break; + case E1INP_TS_TYPE_HDLC: + ts->hdlc.recv_cb(ts, msg); + break; default: ret = -EINVAL; LOGP(DLMI, LOGL_ERROR, "unknown TS type %u\n", ts->type); @@ -644,6 +689,14 @@ struct msgb *e1inp_tx_ts(struct e1inp_ts *e1i_ts, } msgb_put(msg, 40); break; + case E1INP_TS_TYPE_RAW: + /* Get msgb from tx_queue */ + msg = msgb_dequeue(&e1i_ts->raw.tx_queue); + break; + case E1INP_TS_TYPE_HDLC: + /* Get msgb from tx_queue */ + msg = msgb_dequeue(&e1i_ts->hdlc.tx_queue); + break; default: LOGP(DLMI, LOGL_ERROR, "unsupported E1 TS type %u\n", e1i_ts->type); return NULL; @@ -656,6 +709,7 @@ static int e1inp_int_snd_event(struct e1inp_ts *ts, { struct input_signal_data isd; isd.line = ts->line; + isd.ts_nr = ts->num; isd.link_type = link->type; isd.trx = link->trx; isd.tei = link->tei; @@ -712,7 +766,7 @@ struct e1inp_driver *e1inp_driver_find(const char *name) int e1inp_line_update(struct e1inp_line *line) { struct input_signal_data isd; - int rc; + int i, rc; e1inp_line_get(line); @@ -721,6 +775,15 @@ int e1inp_line_update(struct e1inp_line *line) } else rc = 0; + /* Set the PCAP file descriptor for all timeslots that have + * software LAPD instances, to ensure the osmo_lapd_pcap code is + * used to write PCAP files (if requested) */ + for (i = 0; i < ARRAY_SIZE(line->ts); i++) { + struct e1inp_ts *e1i_ts = &line->ts[i]; + if (e1i_ts->lapd) + e1i_ts->lapd->pcap_fd = pcap_fd; + } + /* Send a signal to anyone who is interested in new lines being * configured */ memset(&isd, 0, sizeof(isd)); @@ -745,10 +808,22 @@ static int e1i_sig_cb(unsigned int subsys, unsigned int signal, return 0; } +const struct value_string e1inp_signal_names[] = { + { S_L_INP_NONE, "NONE" }, + { S_L_INP_TEI_UP, "TEI-UP" }, + { S_L_INP_TEI_DN, "TEI-DOWN" }, + { S_L_INP_TEI_UNKNOWN, "TEI-UNKNOWN" }, + { S_L_INP_LINE_INIT, "LINE-INIT" }, + { S_L_INP_LINE_ALARM, "LINE-ALARM" }, + { S_L_INP_LINE_NOALARM, "LINE-NOALARM" }, + { 0, NULL } +}; + void e1inp_misdn_init(void); void e1inp_dahdi_init(void); void e1inp_ipaccess_init(void); void e1inp_rs232_init(void); +void e1inp_unixsocket_init(void); void e1inp_init(void) { @@ -763,4 +838,5 @@ void e1inp_init(void) #endif e1inp_ipaccess_init(); e1inp_rs232_init(); + e1inp_unixsocket_init(); } diff --git a/src/e1_input_vty.c b/src/e1_input_vty.c index 0b4adb2..9d69586 100644 --- a/src/e1_input_vty.c +++ b/src/e1_input_vty.c @@ -38,12 +38,13 @@ /* CONFIG */ -#define E1_DRIVER_NAMES "(misdn|misdn_lapd|dahdi|ipa)" +#define E1_DRIVER_NAMES "(misdn|misdn_lapd|dahdi|ipa|unixsocket)" #define E1_DRIVER_HELP "mISDN supported E1 Card (kernel LAPD)\n" \ "mISDN supported E1 Card (userspace LAPD)\n" \ "DAHDI supported E1/T1/J1 Card\n" \ "IPA TCP/IP input\n" \ - "HSL TCP/IP input" + "HSL TCP/IP input\n" \ + "Unix socket input\n" #define E1_LINE_HELP "Configure E1/T1/J1 Line\n" "Line Number\n" @@ -88,6 +89,25 @@ DEFUN(cfg_e1line_port, cfg_e1_line_port_cmd, return CMD_SUCCESS; } +DEFUN(cfg_e1line_socket, cfg_e1_line_socket_cmd, + "e1_line <0-255> socket .SOCKET", + E1_LINE_HELP "Set socket path for unixsocket\n" + "socket path\n") +{ + struct e1inp_line *line; + int e1_nr = atoi(argv[0]); + + line = e1inp_line_find(e1_nr); + if (!line) { + vty_out(vty, "%% Line %d doesn't exist%s", e1_nr, VTY_NEWLINE); + return CMD_WARNING; + } + + line->sock_path = talloc_strdup(line, argv[1]); + + return CMD_SUCCESS; +} + #define KEEPALIVE_HELP "Enable keep-alive probing\n" static int set_keepalive_params(struct vty *vty, int e1_nr, int idle, int num_probes, int probe_interval) @@ -168,6 +188,17 @@ DEFUN(cfg_e1inp, cfg_e1inp_cmd, return CMD_SUCCESS; } +DEFUN(cfg_ipa_bind, + cfg_ipa_bind_cmd, + "ipa bind A.B.C.D", + "ipa driver config\n" + "Set ipa local bind address\n" + "Listen on this IP address (default 0.0.0.0)\n") +{ + e1inp_ipa_set_bind_addr(argv[0]); + return CMD_SUCCESS; +} + static int e1inp_config_write(struct vty *vty) { struct e1inp_line *line; @@ -202,6 +233,12 @@ static int e1inp_config_write(struct vty *vty) VTY_NEWLINE); } + + const char *ipa_bind = e1inp_ipa_get_bind_addr(); + if (ipa_bind && (strcmp(ipa_bind, "0.0.0.0") != 0)) + vty_out(vty, " ipa bind %s%s", + ipa_bind, VTY_NEWLINE); + return CMD_SUCCESS; } @@ -346,11 +383,14 @@ int e1inp_vty_init(void) vty_install_default(L_E1INP_NODE); install_element(L_E1INP_NODE, &cfg_e1_line_driver_cmd); install_element(L_E1INP_NODE, &cfg_e1_line_port_cmd); + install_element(L_E1INP_NODE, &cfg_e1_line_socket_cmd); install_element(L_E1INP_NODE, &cfg_e1_line_name_cmd); install_element(L_E1INP_NODE, &cfg_e1_line_keepalive_cmd); install_element(L_E1INP_NODE, &cfg_e1_line_keepalive_params_cmd); install_element(L_E1INP_NODE, &cfg_e1_line_no_keepalive_cmd); + install_element(L_E1INP_NODE, &cfg_ipa_bind_cmd); + install_element_ve(&show_e1drv_cmd); install_element_ve(&show_e1line_cmd); install_element_ve(&show_e1ts_cmd); diff --git a/src/input/dahdi.c b/src/input/dahdi.c index 9f1f2bb..911f862 100644 --- a/src/input/dahdi.c +++ b/src/input/dahdi.c @@ -139,6 +139,7 @@ static void handle_dahdi_exception(struct e1inp_ts *ts) get_value_string(dahdi_evt_names, evt)); isd.line = ts->line; + isd.ts_nr = ts->num; switch (evt) { case DAHDI_EVENT_ALARM: @@ -251,13 +252,57 @@ static int handle_ts1_write(struct osmo_fd *bfd) sign_link->sapi, msg); /* set tx delay timer for next event */ - e1i_ts->sign.tx_timer.cb = timeout_ts1_write; - e1i_ts->sign.tx_timer.data = e1i_ts; + osmo_timer_setup(&e1i_ts->sign.tx_timer, timeout_ts1_write, e1i_ts); osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, 50000); return 0; } +static void handle_hdlc_write(struct osmo_fd *bfd) +{ + struct e1inp_line *line = bfd->data; + unsigned int ts_nr = bfd->priv_nr; + struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; + struct msgb *msg; + int ret; + + /* get the next msg for this timeslot */ + msg = e1inp_tx_ts(e1i_ts, NULL); + if (!msg) + return; + + ret = write(bfd->fd, msg->data, msg->len + 2); + msgb_free(msg); + if (ret == -1) + handle_dahdi_exception(e1i_ts); + else if (ret < 0) + LOGP(DLMI, LOGL_NOTICE, "%s write failed %d\n", __func__, ret); +} + +static int handle_hdlc_read(struct osmo_fd *bfd) +{ + struct e1inp_line *line = bfd->data; + unsigned int ts_nr = bfd->priv_nr; + struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; + struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "DAHDI HDLC Rx"); + int ret; + + if (!msg) + return -ENOMEM; + + ret = read(bfd->fd, msg->data, TS1_ALLOC_SIZE - 16); + if (ret == -1) + handle_dahdi_exception(e1i_ts); + else if (ret < 0) { + perror("read "); + } + msgb_put(msg, ret - 2); + if (ret <= 3) { + perror("read "); + } + + return e1inp_rx_ts(e1i_ts, msg, 0, 0); +} static int invertbits = 1; @@ -359,6 +404,79 @@ static int handle_tsX_read(struct osmo_fd *bfd) return ret; } +/* write to a raw channel TS */ +static int handle_ts_raw_write(struct osmo_fd *bfd) +{ + struct e1inp_line *line = bfd->data; + unsigned int ts_nr = bfd->priv_nr; + struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; + struct msgb *msg; + int ret; + + /* get the next msg for this timeslot */ + msg = e1inp_tx_ts(e1i_ts, NULL); + if (!msg) + return 0; + + if (msg->len != D_BCHAN_TX_GRAN) { + /* This might lead to a transmit underrun, as we call tx + * from the rx path, as there's no select/poll on dahdi + * */ + LOGP(DLINP, LOGL_NOTICE, "unexpected msg->len = %u, " + "expected %u\n", msg->len, D_BCHAN_TX_GRAN); + } + + DEBUGP(DLMIB, "RAW CHAN TX: %s\n", + osmo_hexdump(msg->data, msg->len)); + + if (0/*invertbits*/) { + flip_buf_bits(msg->data, msg->len); + } + + ret = write(bfd->fd, msg->data, msg->len); + if (ret < msg->len) + LOGP(DLINP, LOGL_DEBUG, "send returns %d instead of %d\n", + ret, msg->len); + msgb_free(msg); + + return ret; +} + +static int handle_ts_raw_read(struct osmo_fd *bfd) +{ + struct e1inp_line *line = bfd->data; + unsigned int ts_nr = bfd->priv_nr; + struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; + struct msgb *msg = msgb_alloc(D_TSX_ALLOC_SIZE, "DAHDI Raw TS"); + int ret; + + if (!msg) + return -ENOMEM; + + ret = read(bfd->fd, msg->data, D_TSX_ALLOC_SIZE); + if (ret < 0 || ret != D_TSX_ALLOC_SIZE) { + LOGP(DLINP, LOGL_DEBUG, "read error %d %s\n", + ret, strerror(errno)); + return ret; + } + + if (0/*invertbits*/) { + flip_buf_bits(msg->data, ret); + } + + msgb_put(msg, ret); + + msg->l2h = msg->data; + DEBUGP(DLMIB, "RAW CHAN RX: %s\n", + osmo_hexdump(msgb_l2(msg), ret)); + ret = e1inp_rx_ts(e1i_ts, msg, 0, 0); + /* physical layer indicates that data has been sent, + * we thus can send some more data */ + ret = handle_ts_raw_write(bfd); + + return ret; +} + /* callback from select.c in case one of the fd's can be read/written */ static int dahdi_fd_cb(struct osmo_fd *bfd, unsigned int what) { @@ -377,6 +495,14 @@ static int dahdi_fd_cb(struct osmo_fd *bfd, unsigned int what) if (what & BSC_FD_WRITE) rc = handle_ts1_write(bfd); break; + case E1INP_TS_TYPE_HDLC: + if (what & BSC_FD_EXCEPT) + handle_dahdi_exception(e1i_ts); + if (what & BSC_FD_READ) + rc = handle_hdlc_read(bfd); + if (what & BSC_FD_WRITE) + handle_hdlc_write(bfd); + break; case E1INP_TS_TYPE_TRAU: if (what & BSC_FD_EXCEPT) handle_dahdi_exception(e1i_ts); @@ -388,6 +514,17 @@ static int dahdi_fd_cb(struct osmo_fd *bfd, unsigned int what) * writeset, since it doesn't support poll() based * write flow control */ break; + case E1INP_TS_TYPE_RAW: + if (what & BSC_FD_EXCEPT) + handle_dahdi_exception(e1i_ts); + if (what & BSC_FD_READ) + rc = handle_ts_raw_read(bfd); + if (what & BSC_FD_WRITE) + rc = handle_ts_raw_write(bfd); + /* We never include the DAHDI B-Channel FD into the + * writeset, since it doesn't support poll() based + * write flow control */ + break; default: LOGP(DLINP, LOGL_NOTICE, "unknown E1 TS type %u\n", e1i_ts->type); @@ -535,7 +672,22 @@ static int dahdi_e1_setup(struct e1inp_line *line) dahdi_write_msg, bfd, e1inp_dlsap_up, e1i_ts, &lapd_profile_abis); break; + case E1INP_TS_TYPE_HDLC: + if (!bfd->fd) + bfd->fd = open(openstr, O_RDWR | O_NONBLOCK); + if (bfd->fd == -1) { + LOGP(DLINP, LOGL_ERROR, + "%s could not open %s %s\n", + __func__, openstr, strerror(errno)); + return -EIO; + } + bfd->when = BSC_FD_READ | BSC_FD_EXCEPT; + ret = dahdi_set_bufinfo(bfd->fd, 1); + if (ret < 0) + return ret; + break; case E1INP_TS_TYPE_TRAU: + case E1INP_TS_TYPE_RAW: /* close/release LAPD instance, if any */ if (e1i_ts->lapd) { lapd_instance_free(e1i_ts->lapd); diff --git a/src/input/ipa.c b/src/input/ipa.c index a10a418..ce155ce 100644 --- a/src/input/ipa.c +++ b/src/input/ipa.c @@ -213,10 +213,8 @@ int ipa_client_conn_open(struct ipa_client_conn *link) ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP, link->addr, link->port, OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK); - if (ret < 0) { - if (errno != EINPROGRESS) - return ret; - } + if (ret < 0) + return ret; link->ofd->fd = ret; link->ofd->when |= BSC_FD_WRITE; if (osmo_fd_register(link->ofd) < 0) { @@ -401,6 +399,8 @@ ipa_server_conn_create(void *ctx, struct ipa_server_link *link, int fd, int (*closed_cb)(struct ipa_server_conn *conn), void *data) { struct ipa_server_conn *conn; + struct sockaddr_in sa; + socklen_t sa_len = sizeof(sa); conn = talloc_zero(ctx, struct ipa_server_conn); if (conn == NULL) { @@ -418,6 +418,12 @@ ipa_server_conn_create(void *ctx, struct ipa_server_link *link, int fd, conn->data = data; INIT_LLIST_HEAD(&conn->tx_queue); + if (!getpeername(fd, (struct sockaddr *)&sa, &sa_len)) { + char *str = inet_ntoa(sa.sin_addr); + conn->addr = talloc_strdup(conn, str); + conn->port = ntohs(sa.sin_port); + } + if (osmo_fd_register(&conn->ofd) < 0) { LOGP(DLINP, LOGL_ERROR, "could not register FD\n"); talloc_free(conn); @@ -426,6 +432,73 @@ ipa_server_conn_create(void *ctx, struct ipa_server_link *link, int fd, return conn; } +int ipa_server_conn_ccm(struct ipa_server_conn *conn, struct msgb *msg) +{ + struct tlv_parsed tlvp; + uint8_t msg_type = *(msg->l2h); + struct ipaccess_unit unit_data = {}; + char *unitid; + int len, rc; + + /* shared CCM handling on both server and client */ + rc = ipa_ccm_rcvmsg_base(msg, &conn->ofd); + switch (rc) { + case -1: + /* error in IPA CCM processing */ + goto err; + case 1: + /* IPA CCM message that was handled in _base */ + return 0; + case 0: + /* IPA CCM message that we need to handle */ + break; + default: + /* Error */ + LOGP(DLINP, LOGL_ERROR, "Unexpected return from " + "ipa_ccm_rcvmsg_base: %d\n", rc); + goto err; + } + + switch (msg_type) { + case IPAC_MSGT_ID_RESP: + rc = ipa_ccm_idtag_parse(&tlvp, (uint8_t *)msg->l2h + 2, + msgb_l2len(msg)-2); + if (rc < 0) { + LOGP(DLINP, LOGL_ERROR, "IPA CCM RESPonse with " + "malformed TLVs\n"); + goto err; + } + if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) { + LOGP(DLINP, LOGL_ERROR, "IPA CCM RESP without " + "unit ID\n"); + goto err; + } + len = TLVP_LEN(&tlvp, IPAC_IDTAG_UNIT); + if (len < 1) { + LOGP(DLINP, LOGL_ERROR, "IPA CCM RESP with short" + "unit ID\n"); + goto err; + } + unitid = (char *) TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT); + unitid[len-1] = '\0'; + ipa_parse_unitid(unitid, &unit_data); + + /* FIXME */ + rc = conn->ccm_cb(conn, msg, &tlvp, &unit_data); + if (rc < 0) + goto err; + break; + default: + LOGP(DLINP, LOGL_ERROR, "Unknown IPA message type\n"); + break; + } + return 0; +err: + /* in case of any error, we close the connection */ + ipa_server_conn_destroy(conn); + return -1; +} + void ipa_server_conn_destroy(struct ipa_server_conn *conn) { close(conn->ofd.fd); diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c index 8ffdb19..63ee167 100644 --- a/src/input/ipaccess.c +++ b/src/input/ipaccess.c @@ -31,7 +31,7 @@ #include <netinet/tcp.h> #include <string.h> #include <time.h> -#include <sys/fcntl.h> +#include <fcntl.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <arpa/inet.h> @@ -196,7 +196,12 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, newbfd->priv_nr = E1INP_SIGN_RSL + unit_data.trx_id; osmo_fd_unregister(bfd); bfd->fd = -1; - osmo_fd_register(newbfd); + ret = osmo_fd_register(newbfd); + if (ret < 0) { + LOGP(DLINP, LOGL_ERROR, + "could not register FD\n"); + goto err; + } /* now we can release the dummy RSL line. */ e1inp_line_put(line); } @@ -223,7 +228,7 @@ static int handle_ts1_read(struct osmo_fd *bfd) struct e1inp_sign_link *link; struct ipaccess_head *hh; struct msgb *msg = NULL; - int ret; + int ret, rc; ret = ipa_msg_recv_buffered(bfd->fd, &msg, &e1i_ts->pending_msg); if (ret < 0) { @@ -268,13 +273,14 @@ static int handle_ts1_read(struct osmo_fd *bfd) ret = -EINVAL; goto err_msg; } - if (e1i_ts->line->ops->sign_link(msg) < 0) { + rc = e1i_ts->line->ops->sign_link(msg); + if (rc < 0) { /* Don't close the signalling link if the upper layers report * an error, that's too strict. BTW, the signalling layer is * resposible for releasing the message. */ LOGP(DLINP, LOGL_ERROR, "Bad signalling message," - "sign_link returned error\n"); + " sign_link returned error: %s.\n", strerror(-rc)); } return 0; @@ -348,8 +354,7 @@ static int __handle_ts1_write(struct osmo_fd *bfd, struct e1inp_line *line) } /* set tx delay timer for next event */ - e1i_ts->sign.tx_timer.cb = timeout_ts1_write; - e1i_ts->sign.tx_timer.data = e1i_ts; + osmo_timer_setup(&e1i_ts->sign.tx_timer, timeout_ts1_write, e1i_ts); /* Reducing this might break the nanoBTS 900 init. */ osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay); @@ -570,6 +575,8 @@ ipa_bts_id_resp(struct ipaccess_unit *dev, uint8_t *data, int len, int trx_nr) char str[IPA_STRING_MAX]; uint8_t *tag; + memset(str, 0, sizeof(str)); + nmsg = ipa_msg_alloc(0); if (!nmsg) return NULL; @@ -595,16 +602,20 @@ ipa_bts_id_resp(struct ipaccess_unit *dev, uint8_t *data, int len, int trx_nr) dev->mac_addr[4], dev->mac_addr[5]); break; case IPAC_IDTAG_LOCATION1: - strncpy(str, dev->location1, IPA_STRING_MAX); + if (dev->location1) + strncpy(str, dev->location1, IPA_STRING_MAX); break; case IPAC_IDTAG_LOCATION2: - strncpy(str, dev->location2, IPA_STRING_MAX); + if (dev->location2) + strncpy(str, dev->location2, IPA_STRING_MAX); break; case IPAC_IDTAG_EQUIPVERS: - strncpy(str, dev->equipvers, IPA_STRING_MAX); + if (dev->equipvers) + strncpy(str, dev->equipvers, IPA_STRING_MAX); break; case IPAC_IDTAG_SWVERSION: - strncpy(str, dev->swversion, IPA_STRING_MAX); + if (dev->swversion) + strncpy(str, dev->swversion, IPA_STRING_MAX); break; case IPAC_IDTAG_UNITNAME: snprintf(str, sizeof(str), @@ -615,7 +626,8 @@ ipa_bts_id_resp(struct ipaccess_unit *dev, uint8_t *data, int len, int trx_nr) dev->mac_addr[4], dev->mac_addr[5]); break; case IPAC_IDTAG_SERNR: - strncpy(str, dev->serno, IPA_STRING_MAX); + if (dev->serno) + strncpy(str, dev->serno, IPA_STRING_MAX); break; default: LOGP(DLINP, LOGL_NOTICE, @@ -827,11 +839,14 @@ static int ipaccess_line_update(struct e1inp_line *line) switch(line->ops->cfg.ipa.role) { case E1INP_LINE_R_BSC: { struct ipa_server_link *oml_link, *rsl_link; + const char *ipa = e1inp_ipa_get_bind_addr(); - LOGP(DLINP, LOGL_NOTICE, "enabling ipaccess BSC mode\n"); + LOGP(DLINP, LOGL_NOTICE, "enabling ipaccess BSC mode on %s " + "with OML %u and RSL %u TCP ports\n", ipa, + IPA_TCP_PORT_OML, IPA_TCP_PORT_RSL); - oml_link = ipa_server_link_create(tall_ipa_ctx, line, - "0.0.0.0", IPA_TCP_PORT_OML, + oml_link = ipa_server_link_create(tall_ipa_ctx, line, ipa, + IPA_TCP_PORT_OML, ipaccess_bsc_oml_cb, NULL); if (oml_link == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot create OML " @@ -844,8 +859,8 @@ static int ipaccess_line_update(struct e1inp_line *line) ipa_server_link_destroy(oml_link); return -EIO; } - rsl_link = ipa_server_link_create(tall_ipa_ctx, line, - "0.0.0.0", IPA_TCP_PORT_RSL, + rsl_link = ipa_server_link_create(tall_ipa_ctx, line, ipa, + IPA_TCP_PORT_RSL, ipaccess_bsc_rsl_cb, NULL); if (rsl_link == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot create RSL " @@ -864,7 +879,9 @@ static int ipaccess_line_update(struct e1inp_line *line) case E1INP_LINE_R_BTS: { struct ipa_client_conn *link; - LOGP(DLINP, LOGL_NOTICE, "enabling ipaccess BTS mode\n"); + LOGP(DLINP, LOGL_NOTICE, "enabling ipaccess BTS mode, " + "OML connecting to %s:%u\n", line->ops->cfg.ipa.addr, + IPA_TCP_PORT_OML); link = ipa_client_conn_create(tall_ipa_ctx, &line->ts[E1INP_SIGN_OML-1], @@ -944,3 +961,20 @@ void e1inp_ipaccess_init(void) tall_ipa_ctx = talloc_named_const(libosmo_abis_ctx, 1, "ipa"); e1inp_driver_register(&ipaccess_driver); } + +void e1inp_ipa_set_bind_addr(const char *ip_bind_addr) +{ + talloc_free((char*)ipaccess_driver.bind_addr); + ipaccess_driver.bind_addr = NULL; + + if (ip_bind_addr) + ipaccess_driver.bind_addr = talloc_strdup(tall_ipa_ctx, + ip_bind_addr); +} + +const char *e1inp_ipa_get_bind_addr(void) +{ + return ipaccess_driver.bind_addr? + ipaccess_driver.bind_addr + : "0.0.0.0"; +} diff --git a/src/input/lapd.c b/src/input/lapd.c index ac24fd8..4b5077b 100644 --- a/src/input/lapd.c +++ b/src/input/lapd.c @@ -95,6 +95,27 @@ const struct lapd_profile lapd_profile_abis = { .short_address = 0 }; +/* Ericssons OM2000 lapd dialect requires a sabm frame retransmission + * timeout of exactly 300 msek. Shorter or longer retransmission will + * cause the link establishment to fail permanently. Since the BTS is + * periodically scanning through all timeslots to find the timeslot + * where the bsc is transmitting its sabm frames the normal maximum + * retransmission (n200) of 3 is not enough. In order not to miss + * the bts, n200 has been increased to 50, which is an educated + * guess. */ + +const struct lapd_profile lapd_profile_abis_ericsson = { + .k = LAPD_SET_K(2,1), + .n200 = 50, + .n201 = 260, + .n202 = 0, /* infinite */ + .t200_sec = 0, .t200_usec = 300000, + .t201_sec = 1, .t201_usec = 0, + .t202_sec = 2, .t202_usec = 0, + .t203_sec = 10, .t203_usec = 0, + .short_address = 0 +}; + const struct lapd_profile lapd_profile_sat = { .k = LAPD_SET_K(15,15), .n200 = 5, @@ -208,8 +229,9 @@ static struct lapd_sap *lapd_sap_alloc(struct lapd_tei *teip, uint8_t sapi) if (!sap) return NULL; - LOGP(DLLAPD, LOGL_NOTICE, "LAPD Allocating SAP for SAPI=%u / TEI=%u\n", - sapi, teip->tei); + LOGP(DLLAPD, LOGL_NOTICE, + "LAPD Allocating SAP for SAPI=%u / TEI=%u (dl=%p, sap=%p)\n", + sapi, teip->tei, &sap->dl, sap); sap->sapi = sapi; sap->tei = teip; @@ -245,6 +267,10 @@ static struct lapd_sap *lapd_sap_alloc(struct lapd_tei *teip, uint8_t sapi) /* Free SAP instance, including the datalink */ static void lapd_sap_free(struct lapd_sap *sap) { + LOGP(DLLAPD, LOGL_NOTICE, + "LAPD Freeing SAP for SAPI=%u / TEI=%u (dl=%p, sap=%p)\n", + sap->sapi, sap->tei->tei, &sap->dl, sap); + /* free datalink structures and timers */ lapd_dl_exit(&sap->dl); @@ -664,6 +690,13 @@ struct lapd_instance *lapd_instance_alloc(int network_side, return li; } +/* Change lapd-profile on the fly (use with caution!) */ +void lapd_instance_set_profile(struct lapd_instance *li, + const struct lapd_profile *profile) +{ + memcpy(&li->profile, profile, sizeof(li->profile)); +} + void lapd_instance_free(struct lapd_instance *li) { struct lapd_tei *teip, *teip2; diff --git a/src/input/lapd_pcap.c b/src/input/lapd_pcap.c index c83bc60..7374694 100644 --- a/src/input/lapd_pcap.c +++ b/src/input/lapd_pcap.c @@ -43,6 +43,8 @@ * pcap format is from http://wiki.wireshark.org/Development/LibpcapFileFormat */ #define DLT_LINUX_LAPD 177 +#define LINUX_SLL_HOST 0 +#define LINUX_SLL_OUTGOING 4 struct pcap_hdr { uint32_t magic_number; @@ -65,7 +67,7 @@ struct pcap_lapdhdr { uint16_t pkttype; uint16_t hatype; uint16_t halen; - uint64_t addr; + uint8_t addr[8]; int16_t protocol; } __attribute__((packed)); @@ -75,10 +77,9 @@ osmo_static_assert(offsetof(struct pcap_lapdhdr, addr) == 6, addr_offset); osmo_static_assert(offsetof(struct pcap_lapdhdr, protocol) == 14, proto_offset); osmo_static_assert(sizeof(struct pcap_lapdhdr) == 16, lapd_header_size); -int osmo_pcap_lapd_open(char *filename, mode_t mode) +int osmo_pcap_lapd_set_fd(int fd) { - int fd; - struct pcap_hdr pcap_header = { + struct pcap_hdr pcap_header = { .magic_number = 0xa1b2c3d4, .version_major = 2, .version_minor = 4, @@ -88,6 +89,21 @@ int osmo_pcap_lapd_open(char *filename, mode_t mode) .network = DLT_LINUX_LAPD, }; + if (write(fd, &pcap_header, sizeof(pcap_header)) + != sizeof(pcap_header)) { + LOGP(DLLAPD, LOGL_ERROR, "cannot write PCAP header: %s\n", + strerror(errno)); + close(fd); + return -1; + } + + return 0; +} + +int osmo_pcap_lapd_open(char *filename, mode_t mode) +{ + int fd, rc; + LOGP(DLLAPD, LOGL_NOTICE, "opening LAPD pcap file `%s'\n", filename); fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, mode); @@ -96,13 +112,13 @@ int osmo_pcap_lapd_open(char *filename, mode_t mode) strerror(errno)); return -1; } - if (write(fd, &pcap_header, sizeof(pcap_header)) - != sizeof(pcap_header)) { - LOGP(DLLAPD, LOGL_ERROR, "cannot write PCAP header: %s\n", - strerror(errno)); + + rc = osmo_pcap_lapd_set_fd(fd); + if (rc < 0) { close(fd); - return -1; + return rc; } + return fd; } @@ -125,10 +141,13 @@ int osmo_pcap_lapd_write(int fd, int direction, struct msgb *msg) pcap_rechdr.incl_len = msg->len + sizeof(struct pcap_lapdhdr); pcap_rechdr.orig_len = msg->len + sizeof(struct pcap_lapdhdr); - header.pkttype = 4; + if (direction == OSMO_LAPD_PCAP_OUTPUT) + header.pkttype = htons(LINUX_SLL_OUTGOING); + else + header.pkttype = htons(LINUX_SLL_HOST); header.hatype = 0; header.halen = 0; - header.addr = direction == OSMO_LAPD_PCAP_OUTPUT ? 0x0 : 0x1; + header.addr[0] = 0x01; /* we are the network side */ header.protocol = ntohs(48); gettimeofday(&tv, NULL); diff --git a/src/input/misdn.c b/src/input/misdn.c index 330e3b3..347b7bf 100644 --- a/src/input/misdn.c +++ b/src/input/misdn.c @@ -41,8 +41,8 @@ #include <errno.h> #include <string.h> #include <time.h> -#include <sys/fcntl.h> #include <sys/socket.h> +#include <sys/types.h> #include <sys/ioctl.h> #include <arpa/inet.h> #include <mISDNif.h> @@ -283,8 +283,7 @@ static int handle_ts1_write(struct osmo_fd *bfd) /* set tx delay timer for next event */ - e1i_ts->sign.tx_timer.cb = timeout_ts1_write; - e1i_ts->sign.tx_timer.data = e1i_ts; + osmo_timer_setup(&e1i_ts->sign.tx_timer, timeout_ts1_write, e1i_ts); osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay); return ret; @@ -391,6 +390,92 @@ static int handle_tsX_read(struct osmo_fd *bfd) return ret; } +/* write to a raw channel TS */ +static int handle_ts_raw_write(struct osmo_fd *bfd, unsigned int len) +{ + struct e1inp_line *line = bfd->data; + unsigned int ts_nr = bfd->priv_nr; + struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; + struct msgb *msg; + struct mISDNhead *hh; + int ret; + + /* get the next msg for this timeslot */ + msg = e1inp_tx_ts(e1i_ts, NULL); + if (!msg) + return 0; + + if (msg->len != len) { + /* This might lead to a transmit underrun, as we call tx + * from the rx path, as there's no select/poll on dahdi + * */ + LOGP(DLINP, LOGL_NOTICE, "unexpected msg->len = %u, " + "expected %u\n", msg->len, len); + } + + DEBUGP(DLMIB, "RAW CHAN TX: %s\n", + osmo_hexdump(msg->data, msg->len)); + + hh = (struct mISDNhead *) msgb_push(msg, sizeof(*hh)); + hh->prim = PH_DATA_REQ; + hh->id = 0; + + ret = write(bfd->fd, msg->data, msg->len); + if (ret < msg->len) + LOGP(DLINP, LOGL_DEBUG, "send returns %d instead of %d\n", + ret, msg->len); + msgb_free(msg); + + return ret; +} + +static int handle_ts_raw_read(struct osmo_fd *bfd) +{ + struct e1inp_line *line = bfd->data; + unsigned int ts_nr = bfd->priv_nr; + struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; + struct msgb *msg = msgb_alloc(TSX_ALLOC_SIZE, "mISDN Tx RAW"); + struct mISDNhead *hh; + int ret; + + if (!msg) + return -ENOMEM; + + hh = (struct mISDNhead *) msg->data; + + ret = recv(bfd->fd, msg->data, TSX_ALLOC_SIZE, 0); + if (ret < 0) { + fprintf(stderr, "recvfrom error %s\n", strerror(errno)); + return ret; + } + + msgb_put(msg, ret); + + if (hh->prim != PH_CONTROL_IND) + DEBUGP(DLMIB, "<= RAW CHAN len = %d, prim(0x%x) id(0x%x): %s\n", + ret, hh->prim, hh->id, + get_value_string(prim_names, hh->prim)); + + switch (hh->prim) { + case PH_DATA_IND: + msg->l2h = msg->data + MISDN_HEADER_LEN; + DEBUGP(DLMIB, "RAW CHAN RX: %s\n", + osmo_hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN)); + /* the number of bytes received indicates that data to send */ + handle_ts_raw_write(bfd, msgb_l2len(msg)); + return e1inp_rx_ts(e1i_ts, msg, 0, 0); + case PH_ACTIVATE_IND: + case PH_DATA_CNF: + break; + default: + break; + } + /* FIXME: why do we free signalling msgs in the caller, and trau not? */ + msgb_free(msg); + + return ret; +} + /* callback from select.c in case one of the fd's can be read/written */ static int misdn_fd_cb(struct osmo_fd *bfd, unsigned int what) { @@ -414,6 +499,13 @@ static int misdn_fd_cb(struct osmo_fd *bfd, unsigned int what) * writeset, since it doesn't support poll() based * write flow control */ break; + case E1INP_TS_TYPE_RAW: + if (what & BSC_FD_READ) + rc = handle_ts_raw_read(bfd); + /* We never include the mISDN B-Channel FD into the + * writeset, since it doesn't support poll() based + * write flow control */ + break; default: fprintf(stderr, "unknown E1 TS type %u\n", e1i_ts->type); break; @@ -514,6 +606,11 @@ static int mi_e1_setup(struct e1inp_line *line, int release_l2) case E1INP_TS_TYPE_NONE: continue; break; + case E1INP_TS_TYPE_HDLC: + bfd->fd = socket(PF_ISDN, SOCK_DGRAM, + ISDN_P_B_HDLC); + bfd->when = BSC_FD_READ; + break; case E1INP_TS_TYPE_SIGN: if (mline->use_userspace_lapd) bfd->fd = socket(PF_ISDN, SOCK_DGRAM, @@ -524,6 +621,7 @@ static int mi_e1_setup(struct e1inp_line *line, int release_l2) bfd->when = BSC_FD_READ; break; case E1INP_TS_TYPE_TRAU: + case E1INP_TS_TYPE_RAW: bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW); /* We never include the mISDN B-Channel FD into the * writeset, since it doesn't support poll() based @@ -556,6 +654,7 @@ static int mi_e1_setup(struct e1inp_line *line, int release_l2) addr.tei = GROUP_TEI; } break; + case E1INP_TS_TYPE_HDLC: case E1INP_TS_TYPE_TRAU: addr.channel = ts; break; @@ -591,7 +690,7 @@ static int mi_e1_setup(struct e1inp_line *line, int release_l2) ret = osmo_fd_register(bfd); if (ret < 0) { fprintf(stderr, "could not register FD: %s\n", - strerror(ret)); + strerror(-ret)); return ret; } } diff --git a/src/input/rs232.c b/src/input/rs232.c index 2fd2a09..9da01a3 100644 --- a/src/input/rs232.c +++ b/src/input/rs232.c @@ -270,7 +270,7 @@ rs232_setup(struct e1inp_line *line, const char *serial_port, unsigned int delay if (rc < 0) { close(bfd->fd); LOGP(DLMI, LOGL_ERROR, "rs232: could not register FD: %s\n", - strerror(rc)); + strerror(-rc)); return rc; } diff --git a/src/input/unixsocket.c b/src/input/unixsocket.c new file mode 100644 index 0000000..63bd796 --- /dev/null +++ b/src/input/unixsocket.c @@ -0,0 +1,346 @@ +/* OpenBSC Abis receive lapd over a unix socket */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * + * Author: Alexander Couzens <lynxis@fe80.eu> + * Based on other e1_input drivers. + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/socket.h> +#include <limits.h> +#include <string.h> + +#include <osmocom/core/talloc.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/socket.h> + +#include <osmocom/abis/e1_input.h> +#include <osmocom/abis/lapd.h> +#include <osmocom/abis/e1_input.h> + +#include <osmocom/abis/unixsocket_proto.h> +#include "internal.h" + +void *tall_unixsocket_ctx; +#define UNIXSOCKET_ALLOC_SIZE 1600 +#define UNIXSOCKET_SOCK_PATH_DEFAULT "/tmp/osmo_abis_line_" + +struct unixsocket_line { + struct osmo_fd fd; +}; + +static int unixsocket_line_update(struct e1inp_line *line); +static int ts_want_write(struct e1inp_ts *e1i_ts); + +static int unixsocket_exception_cb(struct osmo_fd *bfd) +{ + struct e1inp_line *line = bfd->data; + + LOGP(DLINP, LOGL_ERROR, + "Socket connection failure, reconnecting... (line=%p, fd=%d)\n", + line, bfd->fd); + + /* Unregister faulty file descriptor from select loop */ + if(osmo_fd_is_registered(bfd)) { + LOGP(DLINP, LOGL_DEBUG, + "removing inactive socket from select loop... (line=%p, fd=%d)\n", + line, bfd->fd); + osmo_fd_unregister(bfd); + } + + /* Close faulty file descriptor */ + close(bfd->fd); + + unixsocket_line_update(line); + + return 0; +} + +static int unixsocket_read_cb(struct osmo_fd *bfd) +{ + struct e1inp_line *line = bfd->data; + struct msgb *msg = msgb_alloc(UNIXSOCKET_ALLOC_SIZE, "UNIXSOCKET TS"); + uint8_t version; + uint8_t controldata; + int ret; + + if (!msg) + return -ENOMEM; + + ret = read(bfd->fd, msg->data, UNIXSOCKET_ALLOC_SIZE - 16); + if (ret == 0) { + unixsocket_exception_cb(bfd); + goto fail; + } else if (ret < 0) { + perror("read "); + goto fail; + } else if (ret < 2) { + /* packet must be at least 2 byte long to hold version + control/data header */ + LOGP(DLMI, LOGL_ERROR, "received to small packet: %d < 2", ret); + ret = -1; + goto fail; + } + msgb_put(msg, ret); + + LOGP(DLMI, LOGL_DEBUG, "rx msg: %s (fd=%d)\n", + osmo_hexdump_nospc(msg->data, msg->len), bfd->fd); + + /* check version header */ + version = msgb_pull_u8(msg); + controldata = msgb_pull_u8(msg); + + if (version != UNIXSOCKET_PROTO_VERSION) { + LOGP(DLMI, LOGL_ERROR, "received message with invalid version %d. valid: %d", + ret, UNIXSOCKET_PROTO_VERSION); + ret = -1; + goto fail; + } + + switch (controldata) { + case UNIXSOCKET_PROTO_DATA: + return e1inp_rx_ts_lapd(&line->ts[0], msg); + case UNIXSOCKET_PROTO_CONTROL: + LOGP(DLMI, LOGL_ERROR, "received (invalid) control message."); + ret = -1; + break; + default: + LOGP(DLMI, LOGL_ERROR, "received invalid message."); + ret = -1; + break; + } +fail: + msgb_free(msg); + return ret; +} + +static void timeout_ts1_write(void *data) +{ + struct e1inp_ts *e1i_ts = (struct e1inp_ts *)data; + + /* trigger write of ts1, due to tx delay timer */ + ts_want_write(e1i_ts); +} + +static int unixsocket_write_cb(struct osmo_fd *bfd) +{ + struct e1inp_line *line = bfd->data; + struct e1inp_ts *e1i_ts = &line->ts[0]; + struct msgb *msg; + struct e1inp_sign_link *sign_link; + + bfd->when &= ~BSC_FD_WRITE; + + /* get the next msg for this timeslot */ + msg = e1inp_tx_ts(e1i_ts, &sign_link); + if (!msg) { + /* no message after tx delay timer */ + LOGP(DLINP, LOGL_INFO, + "no message available (line=%p)\n", line); + return 0; + } + + /* set tx delay timer for next event */ + osmo_timer_setup(&e1i_ts->sign.tx_timer, timeout_ts1_write, e1i_ts); + + osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay); + + LOGP(DLINP, LOGL_DEBUG, "sending: %s (line=%p)\n", + msgb_hexdump(msg), line); + lapd_transmit(e1i_ts->lapd, sign_link->tei, + sign_link->sapi, msg); + + return 0; +} + +static int unixsocket_cb(struct osmo_fd *bfd, unsigned int what) +{ + int ret = 0; + + if (what & BSC_FD_READ) + ret = unixsocket_read_cb(bfd); + if (what & BSC_FD_WRITE) + ret = unixsocket_write_cb(bfd); + + return ret; +} + +static int ts_want_write(struct e1inp_ts *e1i_ts) +{ + struct unixsocket_line *line = e1i_ts->line->driver_data; + + line->fd.when |= BSC_FD_WRITE; + + return 0; +} + +static void unixsocket_write_msg(struct msgb *msg, struct osmo_fd *bfd) { + int ret; + + LOGP(DLMI, LOGL_DEBUG, "tx msg: %s (fd=%d)\n", + osmo_hexdump_nospc(msg->data, msg->len), bfd->fd); + + ret = write(bfd->fd, msg->data, msg->len); + msgb_free(msg); + if (ret == -1) + unixsocket_exception_cb(bfd); + else if (ret < 0) + LOGP(DLMI, LOGL_NOTICE, "%s write failed %d\n", __func__, ret); +} + +/*! + * \brief unixsocket_write_msg lapd callback for data to unixsocket + * \param msg + * \param cbdata + */ +static void unixsocket_write_msg_lapd_cb(struct msgb *msg, void *cbdata) +{ + struct osmo_fd *bfd = cbdata; + + /* data|control */ + msgb_push_u8(msg, UNIXSOCKET_PROTO_DATA); + /* add version header */ + msgb_push_u8(msg, UNIXSOCKET_PROTO_VERSION); + + unixsocket_write_msg(msg, bfd); +} + +static int unixsocket_line_update(struct e1inp_line *line) +{ + struct unixsocket_line *config; + char sock_path[PATH_MAX]; + int ret = 0; + int i; + + if (line->sock_path) + strcpy(sock_path, line->sock_path); + else + sprintf(sock_path, "%s%d", UNIXSOCKET_SOCK_PATH_DEFAULT, + line->num); + + LOGP(DLINP, LOGL_NOTICE, "line update (line=%p)\n", line); + + if (!line->driver_data) + line->driver_data = talloc_zero(line, struct unixsocket_line); + + if (!line->driver_data) { + LOGP(DLINP, LOGL_ERROR, + "OOM in line update (line=%p)\n", line); + return -ENOMEM; + } + + config = line->driver_data; + config->fd.data = line; + config->fd.when = BSC_FD_READ; + config->fd.cb = unixsocket_cb; + + /* Open unix domain socket */ + ret = osmo_sock_unix_init(SOCK_SEQPACKET, 0, sock_path, + OSMO_SOCK_F_CONNECT); + if (ret < 0) { + /* Note: We will not free the allocated driver_data memory if + * opening the socket fails. The caller may want to call this + * function multiple times using config->fd.data as line + * parameter. Freeing now would destroy that reference. */ + LOGP(DLINP, LOGL_ERROR, + "unable to open socket: %s (line=%p, fd=%d)\n", sock_path, + line, config->fd.fd); + return ret; + } + LOGP(DLINP, LOGL_DEBUG, + "successfully opend (new) socket: %s (line=%p, fd=%d, ret=%d)\n", + sock_path, line, config->fd.fd, ret); + config->fd.fd = ret; + + /* Register socket in select loop */ + if (osmo_fd_register(&config->fd) < 0) { + LOGP(DLINP, LOGL_ERROR, + "error registering new socket (line=%p, fd=%d)\n", + line, config->fd.fd); + close(config->fd.fd); + return -EIO; + } + + /* Set line parameter */ + for (i = 0; i < ARRAY_SIZE(line->ts); i++) { + struct e1inp_ts *e1i_ts = &line->ts[i]; + if (!e1i_ts->lapd) { + e1i_ts->lapd = lapd_instance_alloc(1, + unixsocket_write_msg_lapd_cb, &config->fd, + e1inp_dlsap_up, e1i_ts, &lapd_profile_abis); + } + } + + /* Ensure ericsson-superchannel is turned of when + * a new connection is made */ + e1inp_ericsson_set_altc(line, 0); + + return ret; +} + +struct e1inp_driver unixsocket_driver = { + .name = "unixsocket", + .want_write = ts_want_write, + .line_update = unixsocket_line_update, + .default_delay = 0, +}; + +void e1inp_unixsocket_init(void) +{ + tall_unixsocket_ctx = talloc_named_const(libosmo_abis_ctx, 1, "unixsocket"); + e1inp_driver_register(&unixsocket_driver); +} + +void e1inp_ericsson_set_altc(struct e1inp_line *unixline, int superchannel) +{ + struct unixsocket_line *config; + struct msgb *msg; + + if (!unixline) + return; + + if (unixline->driver != &unixsocket_driver) { + LOGP(DLMI, LOGL_NOTICE, "altc is only supported by unixsocket\n"); + return; + } + + config = unixline->driver_data; + if (!config) { + LOGP(DLMI, LOGL_NOTICE, "e1inp driver not yet initialized.\n"); + return; + } + + + msg = msgb_alloc_headroom(200, 100, "ALTC"); + + /* version header */ + msgb_put_u8(msg, UNIXSOCKET_PROTO_VERSION); + /* data|control */ + msgb_put_u8(msg, UNIXSOCKET_PROTO_CONTROL); + + /* magic */ + msgb_put_u32(msg, 0x23004200); + msgb_put_u8(msg, superchannel ? 1 : 0); + + unixsocket_write_msg(msg, &config->fd); +} + diff --git a/src/subchan_demux.c b/src/subchan_demux.c index f965490..238056c 100644 --- a/src/subchan_demux.c +++ b/src/subchan_demux.c @@ -289,17 +289,6 @@ int subchan_mux_out(struct subch_mux *mx, uint8_t *data, int len) return i; } -static int llist_len(struct llist_head *head) -{ - struct llist_head *entry; - int i = 0; - - llist_for_each(entry, head) - i++; - - return i; -} - /* evict the 'num_evict' number of oldest entries in the queue */ static void tx_queue_evict(struct mux_subch *sch, int num_evict) { @@ -327,7 +316,7 @@ int subchan_mux_enqueue(struct subch_mux *mx, int s_nr, const uint8_t *data, int len) { struct mux_subch *sch = &mx->subch[s_nr]; - int list_len = llist_len(&sch->tx_queue); + unsigned int list_len = llist_count(&sch->tx_queue); struct subch_txq_entry *tqe = talloc_zero_size(tall_tqe_ctx, sizeof(*tqe) + len); if (!tqe) diff --git a/src/trau/osmo_ortp.c b/src/trau/osmo_ortp.c index 65ec269..c49a23d 100644 --- a/src/trau/osmo_ortp.c +++ b/src/trau/osmo_ortp.c @@ -23,6 +23,7 @@ */ #include <stdint.h> +#include <stdbool.h> #include <inttypes.h> #include <netdb.h> @@ -93,8 +94,11 @@ static int ortp_to_osmo_lvl(OrtpLogLevel lev) return LOGL_ERROR; } -static void my_ortp_logfn(OrtpLogLevel lev, const char *fmt, - va_list args) +static void my_ortp_logfn( +#if HAVE_ORTP_LOG_DOMAIN + const char *domain, +#endif + OrtpLogLevel lev, const char *fmt, va_list args) { osmo_vlogp(DLMIB, ortp_to_osmo_lvl(lev), __FILE__, 0, 0, fmt, args); @@ -105,11 +109,7 @@ static void my_ortp_logfn(OrtpLogLevel lev, const char *fmt, static void ortp_sig_cb_ssrc(RtpSession *rs, void *data) { int port = rtp_session_get_local_port(rs); -#if 0 /* post 0.20.0 ORTP has this function */ uint32_t ssrc = rtp_session_get_recv_ssrc(rs); -#else - uint32_t ssrc = rs->rcv.ssrc; -#endif LOGP(DLMIB, LOGL_INFO, "osmo-ortp(%d): ssrc_changed to 0x%08x\n", port, ssrc); @@ -129,7 +129,7 @@ static void ortp_sig_cb_net(RtpSession *rs, void *data) int port = rtp_session_get_local_port(rs); LOGP(DLMIB, LOGL_ERROR, - "osmo-ortp(%d): network_error\n", port); + "osmo-ortp(%d): network_error %s\n", port, (char *)data); } static void ortp_sig_cb_ts(RtpSession *rs, void *data) @@ -138,9 +138,27 @@ static void ortp_sig_cb_ts(RtpSession *rs, void *data) uint32_t ts = rtp_session_get_current_recv_ts(rs); LOGP(DLMIB, LOGL_NOTICE, - "osmo-ortp(%d): timestamp_jump, new TS %d\n", port, ts); + "osmo-ortp(%d): timestamp_jump, new TS %d, resyncing\n", port, ts); + rtp_session_resync(rs); } +static inline bool recv_with_cb(struct osmo_rtp_socket *rs) +{ + uint8_t *payload; + mblk_t *mblk = rtp_session_recvm_with_ts(rs->sess, rs->rx_user_ts); + if (!mblk) + return false; + + int plen = rtp_get_payload(mblk, &payload); + /* hand into receiver */ + if (rs->rx_cb && plen > 0) + rs->rx_cb(rs, payload, plen, rtp_get_seqnumber(mblk), + rtp_get_timestamp(mblk), rtp_get_markbit(mblk)); + freemsg(mblk); + if (plen > 0) + return true; + return false; +} /*! \brief poll the socket for incoming data * \param[in] rs the socket to be polled @@ -148,23 +166,15 @@ static void ortp_sig_cb_ts(RtpSession *rs, void *data) */ int osmo_rtp_socket_poll(struct osmo_rtp_socket *rs) { - mblk_t *mblk; + if (rs->flags & OSMO_RTP_F_DISABLED) + return 0; - mblk = rtp_session_recvm_with_ts(rs->sess, rs->rx_user_ts); - if (mblk) { - rtp_get_payload(mblk, &mblk->b_rptr); - /* hand into receiver */ - if (rs->rx_cb) - rs->rx_cb(rs, mblk->b_rptr, - mblk->b_wptr - mblk->b_rptr); - //rs->rx_user_ts += 160; - freemsg(mblk); + if (recv_with_cb(rs)) return 1; - } else { - LOGP(DLMIB, LOGL_INFO, "osmo_rtp_poll(%u): ERROR!\n", - rs->rx_user_ts); - return 0; - } + + LOGP(DLMIB, LOGL_INFO, "osmo_rtp_socket_poll(%u): ERROR!\n", + rs->rx_user_ts); + return 0; } /* Osmo FD callbacks */ @@ -172,7 +182,6 @@ int osmo_rtp_socket_poll(struct osmo_rtp_socket *rs) static int osmo_rtp_fd_cb(struct osmo_fd *fd, unsigned int what) { struct osmo_rtp_socket *rs = fd->data; - mblk_t *mblk; if (what & BSC_FD_READ) { /* in polling mode, we don't want to be called here */ @@ -180,15 +189,7 @@ static int osmo_rtp_fd_cb(struct osmo_fd *fd, unsigned int what) fd->when &= ~BSC_FD_READ; return 0; } - mblk = rtp_session_recvm_with_ts(rs->sess, rs->rx_user_ts); - if (mblk) { - rtp_get_payload(mblk, &mblk->b_rptr); - /* hand into receiver */ - if (rs->rx_cb) - rs->rx_cb(rs, mblk->b_rptr, - mblk->b_wptr - mblk->b_rptr); - freemsg(mblk); - } else + if (!recv_with_cb(rs)) LOGP(DLMIB, LOGL_INFO, "recvm_with_ts(%u): ERROR!\n", rs->rx_user_ts); rs->rx_user_ts += 160; @@ -198,6 +199,10 @@ static int osmo_rtp_fd_cb(struct osmo_fd *fd, unsigned int what) return 0; } +/* Internal API coming from rtpsession_priv.h, used in osmo_rtcp_fd_cb */ +#pragma message ("Using internal ortp API: rtp_session_rtcp_rec") +int rtp_session_rtcp_recv(RtpSession * session); + static int osmo_rtcp_fd_cb(struct osmo_fd *fd, unsigned int what) { struct osmo_rtp_socket *rs = fd->data; @@ -210,16 +215,24 @@ static int osmo_rtcp_fd_cb(struct osmo_fd *fd, unsigned int what) static int osmo_rtp_socket_fdreg(struct osmo_rtp_socket *rs) { + int rc; + rs->rtp_bfd.fd = rtp_session_get_rtp_socket(rs->sess); rs->rtcp_bfd.fd = rtp_session_get_rtcp_socket(rs->sess); rs->rtp_bfd.when = rs->rtcp_bfd.when = BSC_FD_READ; - rs->rtp_bfd.when = rs->rtcp_bfd.when = 0; rs->rtp_bfd.data = rs->rtcp_bfd.data = rs; rs->rtp_bfd.cb = osmo_rtp_fd_cb; rs->rtcp_bfd.cb = osmo_rtcp_fd_cb; - osmo_fd_register(&rs->rtp_bfd); - osmo_fd_register(&rs->rtcp_bfd); + rc = osmo_fd_register(&rs->rtp_bfd); + if (rc < 0) + return rc; + + rc = osmo_fd_register(&rs->rtcp_bfd); + if (rc < 0) { + osmo_fd_unregister(&rs->rtp_bfd); + return rc; + } return 0; } @@ -267,33 +280,45 @@ void osmo_rtp_init(void *ctx) tall_rtp_ctx = ctx; ortp_set_memory_functions(&osmo_ortp_memfn); ortp_init(); - ortp_set_log_level_mask(0xffff); + ortp_set_log_level_mask( +#if HAVE_ORTP_LOG_DOMAIN + ORTP_LOG_DOMAIN, +#endif + 0xffff); + ortp_set_log_handler(my_ortp_logfn); create_payload_types(); } +/*! \brief Set Osmocom RTP socket parameters + * \param[in] rs OsmoRTP socket + * \param[in] param defined which parameter to set + OSMO_RTP_P_JITBUF - enables regular jitter buffering + OSMO_RTP_P_JIT_ADAP - enables adaptive jitter buffering + * \param[in] val Size of jitter buffer (in ms), 0 means disable buffering + * \returns negative value on error, 0 or 1 otherwise + (depending on whether given jitter buffering is enabled) + */ int osmo_rtp_socket_set_param(struct osmo_rtp_socket *rs, enum osmo_rtp_param param, int val) { - int rc = 0; - switch (param) { + case OSMO_RTP_P_JIT_ADAP: + rtp_session_enable_adaptive_jitter_compensation(rs->sess, + (bool)val); + /* fall-through on-purpose - we have to set val anyway */ case OSMO_RTP_P_JITBUF: rtp_session_enable_jitter_buffer(rs->sess, (val) ? TRUE : FALSE); if (val) rtp_session_set_jitter_compensation(rs->sess, val); break; -#if 0 - case OSMO_RTP_P_JIT_ADAP: - rc = jitter_control_enable_adaptive(rs->sess, val); - break; -#endif default: return -EINVAL; } - - return rc; + if (param == OSMO_RTP_P_JIT_ADAP) + return rtp_session_adaptive_jitter_compensation_enabled(rs->sess); + return rtp_session_jitter_buffer_enabled(rs->sess); } /*! \brief Create a new RTP socket @@ -313,7 +338,7 @@ struct osmo_rtp_socket *osmo_rtp_socket_create(void *talloc_ctx, unsigned int fl if (!rs) return NULL; - rs->flags = flags; + rs->flags = OSMO_RTP_F_DISABLED | flags; rs->sess = rtp_session_new(RTP_SESSION_SENDRECV); if (!rs->sess) { talloc_free(rs); @@ -322,25 +347,27 @@ struct osmo_rtp_socket *osmo_rtp_socket_create(void *talloc_ctx, unsigned int fl rtp_session_set_data(rs->sess, rs); rtp_session_set_profile(rs->sess, osmo_pt_profile); rtp_session_set_jitter_compensation(rs->sess, 100); - //jitter_control_enable_adaptive(rs->sess, 0); rtp_session_signal_connect(rs->sess, "ssrc_changed", (RtpCallback) ortp_sig_cb_ssrc, - (unsigned long) rs); + RTP_SIGNAL_PTR_CAST(rs)); + rtp_session_signal_connect(rs->sess, "payload_type_changed", (RtpCallback) ortp_sig_cb_pt, - (unsigned long) rs); + RTP_SIGNAL_PTR_CAST(rs)); + rtp_session_signal_connect(rs->sess, "network_error", (RtpCallback) ortp_sig_cb_net, - (unsigned long) rs); + RTP_SIGNAL_PTR_CAST(rs)); + rtp_session_signal_connect(rs->sess, "timestamp_jump", (RtpCallback) ortp_sig_cb_ts, - (unsigned long) rs); + RTP_SIGNAL_PTR_CAST(rs)); /* initialize according to the RFC */ rtp_session_set_seq_number(rs->sess, random()); rs->tx_timestamp = random(); - + return rs; } @@ -353,12 +380,9 @@ struct osmo_rtp_socket *osmo_rtp_socket_create(void *talloc_ctx, unsigned int fl */ int osmo_rtp_socket_bind(struct osmo_rtp_socket *rs, const char *ip, int port) { - int rc; -#if HAVE_ORTP_021 - rc = rtp_session_set_local_addr(rs->sess, ip, port, port+1); -#else - rc = rtp_session_set_local_addr(rs->sess, ip, port); -#endif + int rc, rtcp = (-1 != port) ? port + 1 : -1; + rc = rtp_session_set_local_addr(rs->sess, ip, port, rtcp); + if (rc < 0) return rc; @@ -382,22 +406,58 @@ int osmo_rtp_socket_bind(struct osmo_rtp_socket *rs, const char *ip, int port) int osmo_rtp_socket_connect(struct osmo_rtp_socket *rs, const char *ip, uint16_t port) { int rc; + if (!port) { + LOGP(DLMIB, LOGL_INFO, "osmo_rtp_socket_connect() refused to " + "set remote %s:%u\n", ip, port); + return 0; + } - /* enable the use of connect() so later getsockname() will - * actually return the IP address that was chosen for the local - * sid of the connection */ - rtp_session_set_connected_mode(rs->sess, 1); + /* We don't want the connected mode enabled during + * rtp_session_set_remote_addr(), because that will already setup a + * connection and updating the remote address will no longer have an + * effect. Contrary to what one may expect, this must be 0 at first, + * and we're setting to 1 further down to establish a connection once + * the first RTP packet is received (OS#1661). */ + rtp_session_set_connected_mode(rs->sess, 0); rc = rtp_session_set_remote_addr(rs->sess, ip, port); if (rc < 0) return rc; + /* enable the use of connect() so later getsockname() will + * actually return the IP address that was chosen for the local + * sid of the connection */ + rtp_session_set_connected_mode(rs->sess, 1); + rs->flags &= ~OSMO_RTP_F_DISABLED; + if (rs->flags & OSMO_RTP_F_POLL) return rc; else return osmo_rtp_socket_fdreg(rs); } +/*! \brief Increment timestamp on a RTP socket without sending any packet + * \param[in] rs OsmoRTP socket + * \param[in] duration duration in number of RTP clock ticks + * + * Useful to keep the RTP internal clock up to date if an RTP frame should be + * send at a given time but no audio content is available. When next packet is + * sent, the receiver will see a different increase on the sequence number and + * the timestamp, and it should then take it as a synchronization point. For + * that same reason, it is advisable to enable the marker bit on the next RTP + * packet to be sent after calling this function. + * + * \returns 0 on success, <0 in case of error. + */ +int osmo_rtp_skipped_frame(struct osmo_rtp_socket *rs, unsigned int duration) +{ + if (rs->flags & OSMO_RTP_F_DISABLED) + return 0; + + rs->tx_timestamp += duration; + return 0; +} + /*! \brief Send one RTP frame via a RTP socket * \param[in] rs OsmoRTP socket * \param[in] payload pointer to buffer with RTP payload data @@ -408,14 +468,34 @@ int osmo_rtp_socket_connect(struct osmo_rtp_socket *rs, const char *ip, uint16_t int osmo_rtp_send_frame(struct osmo_rtp_socket *rs, const uint8_t *payload, unsigned int payload_len, unsigned int duration) { + return osmo_rtp_send_frame_ext(rs, payload, payload_len, duration, + false); +} + +/*! \brief Send one RTP frame via a RTP socket + * \param[in] rs OsmoRTP socket + * \param[in] payload pointer to buffer with RTP payload data + * \param[in] payload_len length of \a payload in bytes + * \param[in] duration duration in number of RTP clock ticks + * \param[in] marker the status of Marker bit in RTP header + * \returns 0 on success, <0 in case of error. + */ +int osmo_rtp_send_frame_ext(struct osmo_rtp_socket *rs, const uint8_t *payload, + unsigned int payload_len, unsigned int duration, + bool marker) +{ mblk_t *mblk; int rc; + if (rs->flags & OSMO_RTP_F_DISABLED) + return 0; + mblk = rtp_session_create_packet(rs->sess, RTP_FIXED_HEADER_SIZE, payload, payload_len); if (!mblk) return -ENOMEM; + rtp_set_markbit(mblk, marker); rc = rtp_session_sendm_with_ts(rs->sess, mblk, rs->tx_timestamp); rs->tx_timestamp += duration; @@ -567,11 +647,9 @@ void osmo_rtp_socket_stats(struct osmo_rtp_socket *rs, *recv_lost = stats->cum_packet_loss; } -#if HAVE_ORTP_021 const jitter_stats_t *jitter; jitter = rtp_session_get_jitter_stats(rs->sess); if (jitter) *last_jitter = jitter->jitter; -#endif } |