aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNeels Hofmeyr <nhofmeyr@sysmocom.de>2017-07-19 16:48:42 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2017-08-30 14:09:31 +0200
commitbecfc4cb1ba9d759915a5b430aedc0d29c67858b (patch)
tree5dcf6925ed39c2433571f3718e8350e9e69b47f0 /src
parentc4c794c6c735b63ba3b5021e016d4296ef601cca (diff)
move to osmo-mgw.git: osmo-bsc_mgcp and libmgcp as libosmo-legacy-mgcp
Rewire build and includes to libosmo-legacy-mgcp. Drop osmo-bsc_mgcp and related python tests, now found in osmo-mgw.git. libosmo-legacy-mgcp is installed from osmo-mgw, hence add the dependency to jenkins.sh (so far using the pre_release branch). Change-Id: Ic99d681759edce11564da62500c2aac5cf5fffe2
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/libfilter/bsc_msg_acc.c1
-rw-r--r--src/libmgcp/Makefile.am46
-rw-r--r--src/libmgcp/g711common.h187
-rw-r--r--src/libmgcp/mgcp_common.c54
-rw-r--r--src/libmgcp/mgcp_network.c1166
-rw-r--r--src/libmgcp/mgcp_osmux.c583
-rw-r--r--src/libmgcp/mgcp_protocol.c1639
-rw-r--r--src/libmgcp/mgcp_sdp.c305
-rw-r--r--src/libmgcp/mgcp_transcode.c612
-rw-r--r--src/libmgcp/mgcp_vty.c1555
-rw-r--r--src/libmgcp/mgcpgw_client.c616
-rw-r--r--src/libmgcp/mgcpgw_client_vty.c167
-rw-r--r--src/libmsc/a_iface.c2
-rw-r--r--src/libmsc/msc_ifaces.c6
-rw-r--r--src/libmsc/msc_vty.c2
-rw-r--r--src/osmo-bsc/osmo_bsc_bssap.c2
-rw-r--r--src/osmo-bsc_mgcp/Makefile.am36
-rw-r--r--src/osmo-bsc_mgcp/mgcp_main.c313
-rw-r--r--src/osmo-bsc_nat/Makefile.am4
-rw-r--r--src/osmo-bsc_nat/bsc_mgcp_utils.c4
-rw-r--r--src/osmo-bsc_nat/bsc_nat_ctrl.c1
-rw-r--r--src/osmo-bsc_nat/bsc_nat_vty.c8
-rw-r--r--src/osmo-bsc_nat/bsc_ussd.c1
-rw-r--r--src/osmo-msc/Makefile.am4
-rw-r--r--src/osmo-msc/msc_main.c2
26 files changed, 22 insertions, 7296 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index bd697385f..70e53ac3e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,7 +23,6 @@ AM_LDFLAGS = \
SUBDIRS = \
libcommon \
libvlr \
- libmgcp \
libbsc \
libmsc \
libtrau \
@@ -34,7 +33,6 @@ SUBDIRS = \
# Programs
SUBDIRS += \
osmo-msc \
- osmo-bsc_mgcp \
utils \
ipaccess \
gprs \
diff --git a/src/libfilter/bsc_msg_acc.c b/src/libfilter/bsc_msg_acc.c
index bfc5bdd3f..a42206db8 100644
--- a/src/libfilter/bsc_msg_acc.c
+++ b/src/libfilter/bsc_msg_acc.c
@@ -20,6 +20,7 @@
#include <openbsc/bsc_msg_filter.h>
#include <openbsc/bsc_nat.h>
+#include <openbsc/debug.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>
diff --git a/src/libmgcp/Makefile.am b/src/libmgcp/Makefile.am
deleted file mode 100644
index 5d7844da4..000000000
--- a/src/libmgcp/Makefile.am
+++ /dev/null
@@ -1,46 +0,0 @@
-AM_CPPFLAGS = \
- $(all_includes) \
- -I$(top_srcdir)/include \
- -I$(top_builddir) \
- $(NULL)
-
-AM_CFLAGS = \
- -Wall \
- $(LIBOSMOCORE_CFLAGS) \
- $(LIBOSMOVTY_CFLAGS) \
- $(LIBOSMONETIF_CFLAGS) \
- $(COVERAGE_CFLAGS) \
- $(LIBBCG729_CFLAGS) \
- $(NULL)
-
-AM_LDFLAGS = \
- $(LIBOSMOCORE_LIBS) \
- $(LIBOSMOGSM_LIBS) \
- $(LIBOSMONETIF_LIBS) \
- $(COVERAGE_LDFLAGS) \
- $(LIBBCG729_LIBS) \
- $(NULL)
-
-noinst_LIBRARIES = \
- libmgcp.a \
- $(NULL)
-
-noinst_HEADERS = \
- g711common.h \
- $(NULL)
-
-libmgcp_a_SOURCES = \
- mgcp_common.c \
- mgcp_protocol.c \
- mgcp_network.c \
- mgcp_vty.c \
- mgcp_osmux.c \
- mgcp_sdp.c \
- mgcpgw_client.c \
- mgcpgw_client_vty.c \
- $(NULL)
-if BUILD_MGCP_TRANSCODING
-libmgcp_a_SOURCES += \
- mgcp_transcode.c \
- $(NULL)
-endif
diff --git a/src/libmgcp/g711common.h b/src/libmgcp/g711common.h
deleted file mode 100644
index cb35fc651..000000000
--- a/src/libmgcp/g711common.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * PCM - A-Law conversion
- * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
- *
- * Wrapper for linphone Codec class by Simon Morlat <simon.morlat@linphone.org>
- *
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-static inline int val_seg(int val)
-{
- int r = 0;
- val >>= 7; /*7 = 4 + 3*/
- if (val & 0xf0) {
- val >>= 4;
- r += 4;
- }
- if (val & 0x0c) {
- val >>= 2;
- r += 2;
- }
- if (val & 0x02)
- r += 1;
- return r;
-}
-
-/*
- * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
- *
- * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data.
- *
- * Linear Input Code Compressed Code
- * ------------------------ ---------------
- * 0000000wxyza 000wxyz
- * 0000001wxyza 001wxyz
- * 000001wxyzab 010wxyz
- * 00001wxyzabc 011wxyz
- * 0001wxyzabcd 100wxyz
- * 001wxyzabcde 101wxyz
- * 01wxyzabcdef 110wxyz
- * 1wxyzabcdefg 111wxyz
- *
- * For further information see John C. Bellamy's Digital Telephony, 1982,
- * John Wiley & Sons, pps 98-111 and 472-476.
- * G711 is designed for 13 bits input signal, this function add extra shifting to take this into account.
- */
-
-static inline unsigned char s16_to_alaw(int pcm_val)
-{
- int mask;
- int seg;
- unsigned char aval;
-
- if (pcm_val >= 0) {
- mask = 0xD5;
- } else {
- mask = 0x55;
- pcm_val = -pcm_val;
- if (pcm_val > 0x7fff)
- pcm_val = 0x7fff;
- }
-
- if (pcm_val < 256) /*256 = 32 << 3*/
- aval = pcm_val >> 4; /*4 = 1 + 3*/
- else {
- /* Convert the scaled magnitude to segment number. */
- seg = val_seg(pcm_val);
- aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
- }
- return aval ^ mask;
-}
-
-/*
- * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM
- *
- */
-static inline int alaw_to_s16(unsigned char a_val)
-{
- int t;
- int seg;
-
- a_val ^= 0x55;
- t = a_val & 0x7f;
- if (t < 16)
- t = (t << 4) + 8;
- else {
- seg = (t >> 4) & 0x07;
- t = ((t & 0x0f) << 4) + 0x108;
- t <<= seg -1;
- }
- return ((a_val & 0x80) ? t : -t);
-}
-/*
- * s16_to_ulaw() - Convert a linear PCM value to u-law
- *
- * In order to simplify the encoding process, the original linear magnitude
- * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
- * (33 - 8191). The result can be seen in the following encoding table:
- *
- * Biased Linear Input Code Compressed Code
- * ------------------------ ---------------
- * 00000001wxyza 000wxyz
- * 0000001wxyzab 001wxyz
- * 000001wxyzabc 010wxyz
- * 00001wxyzabcd 011wxyz
- * 0001wxyzabcde 100wxyz
- * 001wxyzabcdef 101wxyz
- * 01wxyzabcdefg 110wxyz
- * 1wxyzabcdefgh 111wxyz
- *
- * Each biased linear code has a leading 1 which identifies the segment
- * number. The value of the segment number is equal to 7 minus the number
- * of leading 0's. The quantization interval is directly available as the
- * four bits wxyz. * The trailing bits (a - h) are ignored.
- *
- * Ordinarily the complement of the resulting code word is used for
- * transmission, and so the code word is complemented before it is returned.
- *
- * For further information see John C. Bellamy's Digital Telephony, 1982,
- * John Wiley & Sons, pps 98-111 and 472-476.
- */
-
-static inline unsigned char s16_to_ulaw(int pcm_val) /* 2's complement (16-bit range) */
-{
- int mask;
- int seg;
- unsigned char uval;
-
- if (pcm_val < 0) {
- pcm_val = 0x84 - pcm_val;
- mask = 0x7f;
- } else {
- pcm_val += 0x84;
- mask = 0xff;
- }
- if (pcm_val > 0x7fff)
- pcm_val = 0x7fff;
-
- /* Convert the scaled magnitude to segment number. */
- seg = val_seg(pcm_val);
-
- /*
- * Combine the sign, segment, quantization bits;
- * and complement the code word.
- */
- uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
- return uval ^ mask;
-}
-
-/*
- * ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM
- *
- * First, a biased linear code is derived from the code word. An unbiased
- * output can then be obtained by subtracting 33 from the biased code.
- *
- * Note that this function expects to be passed the complement of the
- * original code word. This is in keeping with ISDN conventions.
- */
-static inline int ulaw_to_s16(unsigned char u_val)
-{
- int t;
-
- /* Complement to obtain normal u-law value. */
- u_val = ~u_val;
-
- /*
- * Extract and bias the quantization bits. Then
- * shift up by the segment number and subtract out the bias.
- */
- t = ((u_val & 0x0f) << 3) + 0x84;
- t <<= (u_val & 0x70) >> 4;
-
- return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84));
-}
diff --git a/src/libmgcp/mgcp_common.c b/src/libmgcp/mgcp_common.c
deleted file mode 100644
index 43c866768..000000000
--- a/src/libmgcp/mgcp_common.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Media Gateway Control Protocol Media Gateway: RFC 3435 */
-/* Implementations useful both for the MGCP GW as well as MGCP GW clients */
-
-/*
- * (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <errno.h>
-
-#include <osmocom/core/utils.h>
-#include <openbsc/mgcp.h>
-
-const struct value_string mgcp_connection_mode_strs[] = {
- { MGCP_CONN_NONE, "none" },
- { MGCP_CONN_RECV_SEND, "sendrecv" },
- { MGCP_CONN_SEND_ONLY, "sendonly" },
- { MGCP_CONN_RECV_ONLY, "recvonly" },
- { MGCP_CONN_LOOPBACK, "loopback" },
- { 0, NULL }
-};
-
-/* Ensure that the msg->l2h is NUL terminated. */
-int mgcp_msg_terminate_nul(struct msgb *msg)
-{
- unsigned char *tail = msg->l2h + msgb_l2len(msg); /* char after l2 data */
- if (tail[-1] == '\0')
- /* nothing to do */;
- else if (msgb_tailroom(msg) > 0)
- tail[0] = '\0';
- else if (tail[-1] == '\r' || tail[-1] == '\n')
- tail[-1] = '\0';
- else {
- LOGP(DMGCP, LOGL_ERROR, "Cannot NUL terminate MGCP message: "
- "Length: %d, Buffer size: %d\n",
- msgb_l2len(msg), msg->data_len);
- return -ENOTSUP;
- }
- return 0;
-}
diff --git a/src/libmgcp/mgcp_network.c b/src/libmgcp/mgcp_network.c
deleted file mode 100644
index 399dc8fe1..000000000
--- a/src/libmgcp/mgcp_network.c
+++ /dev/null
@@ -1,1166 +0,0 @@
-/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
-/* The protocol implementation */
-
-/*
- * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009-2012 by On-Waves
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <time.h>
-#include <limits.h>
-
-#include <sys/socket.h>
-#include <arpa/inet.h>
-
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/select.h>
-
-#include <osmocom/netif/rtp.h>
-
-#include <openbsc/mgcp.h>
-#include <openbsc/mgcp_internal.h>
-
-#include <openbsc/osmux.h>
-
-#warning "Make use of the rtp proxy code"
-
-
-#define RTP_SEQ_MOD (1 << 16)
-#define RTP_MAX_DROPOUT 3000
-#define RTP_MAX_MISORDER 100
-#define RTP_BUF_SIZE 4096
-
-enum {
- MGCP_PROTO_RTP,
- MGCP_PROTO_RTCP,
-};
-
-/**
- * This does not need to be a precision timestamp and
- * is allowed to wrap quite fast. The returned value is
- * 1/unit seconds.
- */
-static uint32_t get_current_ts(unsigned unit)
-{
- struct timespec tp;
- uint64_t ret;
-
- if (!unit)
- return 0;
-
- memset(&tp, 0, sizeof(tp));
- if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0)
- LOGP(DMGCP, LOGL_NOTICE,
- "Getting the clock failed.\n");
-
- /* convert it to 1/unit seconds */
- ret = tp.tv_sec;
- ret *= unit;
- ret += (int64_t)tp.tv_nsec * unit / 1000 / 1000 / 1000;
-
- return ret;
-}
-
-int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
-{
- struct sockaddr_in out;
- out.sin_family = AF_INET;
- out.sin_port = port;
- memcpy(&out.sin_addr, addr, sizeof(*addr));
-
- return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
-}
-
-int mgcp_send_dummy(struct mgcp_endpoint *endp)
-{
- static char buf[] = { MGCP_DUMMY_LOAD };
- int rc;
- int was_rtcp = 0;
-
- rc = mgcp_udp_send(endp->net_end.rtp.fd, &endp->net_end.addr,
- endp->net_end.rtp_port, buf, 1);
-
- if (rc == -1)
- goto failed;
-
- if (endp->tcfg->omit_rtcp)
- return rc;
-
- was_rtcp = 1;
- rc = mgcp_udp_send(endp->net_end.rtcp.fd, &endp->net_end.addr,
- endp->net_end.rtcp_port, buf, 1);
-
- if (rc >= 0)
- return rc;
-
-failed:
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to send dummy %s packet: %s on: 0x%x to %s:%d\n",
- was_rtcp ? "RTCP" : "RTP",
- strerror(errno), ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr),
- was_rtcp ? endp->net_end.rtcp_port : endp->net_end.rtp_port);
-
- return -1;
-}
-
-static int32_t compute_timestamp_aligment_error(struct mgcp_rtp_stream_state *sstate,
- int ptime, uint32_t timestamp)
-{
- int32_t timestamp_delta;
-
- if (ptime == 0)
- return 0;
-
- /* Align according to: T - Tlast = k * Tptime */
- timestamp_delta = timestamp - sstate->last_timestamp;
-
- return timestamp_delta % ptime;
-}
-
-static int check_rtp_timestamp(struct mgcp_endpoint *endp,
- struct mgcp_rtp_state *state,
- struct mgcp_rtp_stream_state *sstate,
- struct mgcp_rtp_end *rtp_end,
- struct sockaddr_in *addr,
- uint16_t seq, uint32_t timestamp,
- const char *text, int32_t *tsdelta_out)
-{
- int32_t tsdelta;
- int32_t timestamp_error;
-
- /* Not fully intialized, skip */
- if (sstate->last_tsdelta == 0 && timestamp == sstate->last_timestamp)
- return 0;
-
- if (seq == sstate->last_seq) {
- if (timestamp != sstate->last_timestamp) {
- sstate->err_ts_counter += 1;
- LOGP(DMGCP, LOGL_ERROR,
- "The %s timestamp delta is != 0 but the sequence "
- "number %d is the same, "
- "TS offset: %d, SeqNo offset: %d "
- "on 0x%x SSRC: %u timestamp: %u "
- "from %s:%d in %d\n",
- text, seq,
- state->timestamp_offset, state->seq_offset,
- ENDPOINT_NUMBER(endp), sstate->ssrc, timestamp,
- inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
- endp->conn_mode);
- }
- return 0;
- }
-
- tsdelta =
- (int32_t)(timestamp - sstate->last_timestamp) /
- (int16_t)(seq - sstate->last_seq);
-
- if (tsdelta == 0) {
- /* Don't update *tsdelta_out */
- LOGP(DMGCP, LOGL_NOTICE,
- "The %s timestamp delta is %d "
- "on 0x%x SSRC: %u timestamp: %u "
- "from %s:%d in %d\n",
- text, tsdelta,
- ENDPOINT_NUMBER(endp), sstate->ssrc, timestamp,
- inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
- endp->conn_mode);
-
- return 0;
- }
-
- if (sstate->last_tsdelta != tsdelta) {
- if (sstate->last_tsdelta) {
- LOGP(DMGCP, LOGL_INFO,
- "The %s timestamp delta changes from %d to %d "
- "on 0x%x SSRC: %u timestamp: %u from %s:%d in %d\n",
- text, sstate->last_tsdelta, tsdelta,
- ENDPOINT_NUMBER(endp), sstate->ssrc, timestamp,
- inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
- endp->conn_mode);
- }
- }
-
- if (tsdelta_out)
- *tsdelta_out = tsdelta;
-
- timestamp_error =
- compute_timestamp_aligment_error(sstate, state->packet_duration,
- timestamp);
-
- if (timestamp_error) {
- sstate->err_ts_counter += 1;
- LOGP(DMGCP, LOGL_NOTICE,
- "The %s timestamp has an alignment error of %d "
- "on 0x%x SSRC: %u "
- "SeqNo delta: %d, TS delta: %d, dTS/dSeq: %d "
- "from %s:%d in mode %d. ptime: %d\n",
- text, timestamp_error,
- ENDPOINT_NUMBER(endp), sstate->ssrc,
- (int16_t)(seq - sstate->last_seq),
- (int32_t)(timestamp - sstate->last_timestamp),
- tsdelta,
- inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
- endp->conn_mode, state->packet_duration);
- }
- return 1;
-}
-
-/* Set the timestamp offset according to the packet duration. */
-static int adjust_rtp_timestamp_offset(struct mgcp_endpoint *endp,
- struct mgcp_rtp_state *state,
- struct mgcp_rtp_end *rtp_end,
- struct sockaddr_in *addr,
- int16_t delta_seq, uint32_t in_timestamp)
-{
- int32_t tsdelta = state->packet_duration;
- int timestamp_offset;
- uint32_t out_timestamp;
-
- if (tsdelta == 0) {
- tsdelta = state->out_stream.last_tsdelta;
- if (tsdelta != 0) {
- LOGP(DMGCP, LOGL_NOTICE,
- "A fixed packet duration is not available on 0x%x, "
- "using last output timestamp delta instead: %d "
- "from %s:%d in %d\n",
- ENDPOINT_NUMBER(endp), tsdelta,
- inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
- endp->conn_mode);
- } else {
- tsdelta = rtp_end->codec.rate * 20 / 1000;
- LOGP(DMGCP, LOGL_NOTICE,
- "Fixed packet duration and last timestamp delta "
- "are not available on 0x%x, "
- "using fixed 20ms instead: %d "
- "from %s:%d in %d\n",
- ENDPOINT_NUMBER(endp), tsdelta,
- inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
- endp->conn_mode);
- }
- }
-
- out_timestamp = state->out_stream.last_timestamp + delta_seq * tsdelta;
- timestamp_offset = out_timestamp - in_timestamp;
-
- if (state->timestamp_offset != timestamp_offset) {
- state->timestamp_offset = timestamp_offset;
-
- LOGP(DMGCP, LOGL_NOTICE,
- "Timestamp offset change on 0x%x SSRC: %u "
- "SeqNo delta: %d, TS offset: %d, "
- "from %s:%d in %d\n",
- ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
- delta_seq, state->timestamp_offset,
- inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
- endp->conn_mode);
- }
-
- return timestamp_offset;
-}
-
-/* Set the timestamp offset according to the packet duration. */
-static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp,
- struct mgcp_rtp_state *state,
- struct mgcp_rtp_end *rtp_end,
- struct sockaddr_in *addr,
- uint32_t timestamp)
-{
- int timestamp_error = 0;
- int ptime = state->packet_duration;
-
- /* Align according to: T + Toffs - Tlast = k * Tptime */
-
- timestamp_error = compute_timestamp_aligment_error(
- &state->out_stream, ptime,
- timestamp + state->timestamp_offset);
-
- if (timestamp_error) {
- state->timestamp_offset += ptime - timestamp_error;
-
- LOGP(DMGCP, LOGL_NOTICE,
- "Corrected timestamp alignment error of %d on 0x%x SSRC: %u "
- "new TS offset: %d, "
- "from %s:%d in %d\n",
- timestamp_error,
- ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
- state->timestamp_offset, inet_ntoa(addr->sin_addr),
- ntohs(addr->sin_port), endp->conn_mode);
- }
-
- OSMO_ASSERT(compute_timestamp_aligment_error(&state->out_stream, ptime,
- timestamp + state->timestamp_offset) == 0);
-
- return timestamp_error;
-}
-
-int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
- char *data, int *len, int buf_size)
-{
- return 0;
-}
-
-int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
- struct mgcp_rtp_end *dst_end,
- struct mgcp_rtp_end *src_end)
-{
- return 0;
-}
-
-void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
- int *payload_type,
- const char**audio_name,
- const char**fmtp_extra)
-{
- /* Use the BTS side parameters when passing the SDP data (for
- * downlink) to the net peer.
- */
- *payload_type = endp->bts_end.codec.payload_type;
- *audio_name = endp->bts_end.codec.audio_name;
- *fmtp_extra = endp->bts_end.fmtp_extra;
-}
-
-
-void mgcp_rtp_annex_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
- const uint16_t seq, const int32_t transit,
- const uint32_t ssrc)
-{
- int32_t d;
-
- /* initialize or re-initialize */
- if (!state->stats_initialized || state->stats_ssrc != ssrc) {
- state->stats_initialized = 1;
- state->stats_base_seq = seq;
- state->stats_max_seq = seq - 1;
- state->stats_ssrc = ssrc;
- state->stats_jitter = 0;
- state->stats_transit = transit;
- state->stats_cycles = 0;
- } else {
- uint16_t udelta;
-
- /*
- * The below takes the shape of the validation of
- * Appendix A. Check if there is something weird with
- * the sequence number, otherwise check for a wrap
- * around in the sequence number.
- * It can't wrap during the initialization so let's
- * skip it here. The Appendix A probably doesn't have
- * this issue because of the probation.
- */
- udelta = seq - state->stats_max_seq;
- if (udelta < RTP_MAX_DROPOUT) {
- if (seq < state->stats_max_seq)
- state->stats_cycles += RTP_SEQ_MOD;
- } else if (udelta <= RTP_SEQ_MOD - RTP_MAX_MISORDER) {
- LOGP(DMGCP, LOGL_NOTICE,
- "RTP seqno made a very large jump on 0x%x delta: %u\n",
- ENDPOINT_NUMBER(endp), udelta);
- }
- }
-
- /*
- * Calculate the jitter between the two packages. The TS should be
- * taken closer to the read function. This was taken from the
- * Appendix A of RFC 3550. Timestamp and arrival_time have a 1/rate
- * resolution.
- */
- d = transit - state->stats_transit;
- state->stats_transit = transit;
- if (d < 0)
- d = -d;
- state->stats_jitter += d - ((state->stats_jitter + 8) >> 4);
- state->stats_max_seq = seq;
-}
-
-
-
-/**
- * The RFC 3550 Appendix A assumes there are multiple sources but
- * some of the supported endpoints (e.g. the nanoBTS) can only handle
- * one source and this code will patch RTP header to appear as if there
- * is only one source.
- * There is also no probation period for new sources. Every RTP header
- * we receive will be seen as a switch in streams.
- */
-void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
- struct mgcp_rtp_end *rtp_end, struct sockaddr_in *addr,
- char *data, int len)
-{
- uint32_t arrival_time;
- int32_t transit;
- uint16_t seq;
- uint32_t timestamp, ssrc;
- struct rtp_hdr *rtp_hdr;
- int payload = rtp_end->codec.payload_type;
-
- if (len < sizeof(*rtp_hdr))
- return;
-
- rtp_hdr = (struct rtp_hdr *) data;
- seq = ntohs(rtp_hdr->sequence);
- timestamp = ntohl(rtp_hdr->timestamp);
- arrival_time = get_current_ts(rtp_end->codec.rate);
- ssrc = ntohl(rtp_hdr->ssrc);
- transit = arrival_time - timestamp;
-
- mgcp_rtp_annex_count(endp, state, seq, transit, ssrc);
-
- if (!state->initialized) {
- state->initialized = 1;
- state->in_stream.last_seq = seq - 1;
- state->in_stream.ssrc = state->orig_ssrc = ssrc;
- state->in_stream.last_tsdelta = 0;
- state->packet_duration = mgcp_rtp_packet_duration(endp, rtp_end);
- state->out_stream = state->in_stream;
- state->out_stream.last_timestamp = timestamp;
- state->out_stream.ssrc = ssrc - 1; /* force output SSRC change */
- LOGP(DMGCP, LOGL_INFO,
- "Initializing stream on 0x%x SSRC: %u timestamp: %u "
- "pkt-duration: %d, from %s:%d in %d\n",
- ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
- state->seq_offset, state->packet_duration,
- inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
- endp->conn_mode);
- if (state->packet_duration == 0) {
- state->packet_duration = rtp_end->codec.rate * 20 / 1000;
- LOGP(DMGCP, LOGL_NOTICE,
- "Fixed packet duration is not available on 0x%x, "
- "using fixed 20ms instead: %d from %s:%d in %d\n",
- ENDPOINT_NUMBER(endp), state->packet_duration,
- inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
- endp->conn_mode);
- }
- } else if (state->in_stream.ssrc != ssrc) {
- LOGP(DMGCP, LOGL_NOTICE,
- "The SSRC changed on 0x%x: %u -> %u "
- "from %s:%d in %d\n",
- ENDPOINT_NUMBER(endp),
- state->in_stream.ssrc, rtp_hdr->ssrc,
- inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
- endp->conn_mode);
-
- state->in_stream.ssrc = ssrc;
- if (rtp_end->force_constant_ssrc) {
- int16_t delta_seq;
-
- /* Always increment seqno by 1 */
- state->seq_offset =
- (state->out_stream.last_seq + 1) - seq;
-
- /* Estimate number of packets that would have been sent */
- delta_seq =
- (arrival_time - state->in_stream.last_arrival_time
- + state->packet_duration/2) /
- state->packet_duration;
-
- adjust_rtp_timestamp_offset(endp, state, rtp_end, addr,
- delta_seq, timestamp);
-
- state->patch_ssrc = 1;
- ssrc = state->orig_ssrc;
- if (rtp_end->force_constant_ssrc != -1)
- rtp_end->force_constant_ssrc -= 1;
-
- LOGP(DMGCP, LOGL_NOTICE,
- "SSRC patching enabled on 0x%x SSRC: %u "
- "SeqNo offset: %d, TS offset: %d "
- "from %s:%d in %d\n",
- ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
- state->seq_offset, state->timestamp_offset,
- inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
- endp->conn_mode);
- }
-
- state->in_stream.last_tsdelta = 0;
- } else {
- /* Compute current per-packet timestamp delta */
- check_rtp_timestamp(endp, state, &state->in_stream, rtp_end, addr,
- seq, timestamp, "input",
- &state->in_stream.last_tsdelta);
-
- if (state->patch_ssrc)
- ssrc = state->orig_ssrc;
- }
-
- /* Save before patching */
- state->in_stream.last_timestamp = timestamp;
- state->in_stream.last_seq = seq;
- state->in_stream.last_arrival_time = arrival_time;
-
- if (rtp_end->force_aligned_timing &&
- state->out_stream.ssrc == ssrc && state->packet_duration)
- /* Align the timestamp offset */
- align_rtp_timestamp_offset(endp, state, rtp_end, addr, timestamp);
-
- /* Store the updated SSRC back to the packet */
- if (state->patch_ssrc)
- rtp_hdr->ssrc = htonl(ssrc);
-
- /* Apply the offset and store it back to the packet.
- * This won't change anything if the offset is 0, so the conditional is
- * omitted. */
- seq += state->seq_offset;
- rtp_hdr->sequence = htons(seq);
- timestamp += state->timestamp_offset;
- rtp_hdr->timestamp = htonl(timestamp);
-
- /* Check again, whether the timestamps are still valid */
- if (state->out_stream.ssrc == ssrc)
- check_rtp_timestamp(endp, state, &state->out_stream, rtp_end,
- addr, seq, timestamp, "output",
- &state->out_stream.last_tsdelta);
-
- /* Save output values */
- state->out_stream.last_seq = seq;
- state->out_stream.last_timestamp = timestamp;
- state->out_stream.ssrc = ssrc;
-
- if (payload < 0)
- return;
-
-#if 0
- DEBUGP(DMGCP, "Payload hdr payload %u -> endp payload %u\n",
- rtp_hdr->payload_type, payload);
- rtp_hdr->payload_type = payload;
-#endif
-}
-
-/*
- * The below code is for dispatching. We have a dedicated port for
- * the data coming from the net and one to discover the BTS.
- */
-static int forward_data(int fd, struct mgcp_rtp_tap *tap, const char *buf, int len)
-{
- if (!tap->enabled)
- return 0;
-
- return sendto(fd, buf, len, 0,
- (struct sockaddr *)&tap->forward, sizeof(tap->forward));
-}
-
-static int mgcp_send_transcoder(struct mgcp_rtp_end *end,
- struct mgcp_config *cfg, int is_rtp,
- const char *buf, int len)
-{
- int rc;
- int port;
- struct sockaddr_in addr;
-
- port = is_rtp ? end->rtp_port : end->rtcp_port;
-
- addr.sin_family = AF_INET;
- addr.sin_addr = cfg->transcoder_in;
- addr.sin_port = port;
-
- rc = sendto(is_rtp ?
- end->rtp.fd :
- end->rtcp.fd, buf, len, 0,
- (struct sockaddr *) &addr, sizeof(addr));
-
- if (rc != len)
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to send data to the transcoder: %s\n",
- strerror(errno));
-
- return rc;
-}
-
-int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp,
- struct sockaddr_in *addr, char *buf, int rc)
-{
- struct mgcp_trunk_config *tcfg = endp->tcfg;
- struct mgcp_rtp_end *rtp_end;
- struct mgcp_rtp_state *rtp_state;
- int tap_idx;
-
- LOGP(DMGCP, LOGL_DEBUG,
- "endpoint %x dest %s tcfg->audio_loop %d endp->conn_mode %d (== loopback: %d)\n",
- ENDPOINT_NUMBER(endp),
- dest == MGCP_DEST_NET? "net" : "bts",
- tcfg->audio_loop,
- endp->conn_mode,
- endp->conn_mode == MGCP_CONN_LOOPBACK);
-
- /* For loop toggle the destination and then dispatch. */
- if (tcfg->audio_loop)
- dest = !dest;
-
- /* Loop based on the conn_mode, maybe undoing the above */
- if (endp->conn_mode == MGCP_CONN_LOOPBACK)
- dest = !dest;
-
- if (dest == MGCP_DEST_NET) {
- rtp_end = &endp->net_end;
- rtp_state = &endp->bts_state;
- tap_idx = MGCP_TAP_NET_OUT;
- } else {
- rtp_end = &endp->bts_end;
- rtp_state = &endp->net_state;
- tap_idx = MGCP_TAP_BTS_OUT;
- }
- LOGP(DMGCP, LOGL_DEBUG,
- "endpoint %x dest %s net_end %s %d %d bts_end %s %d %d rtp_end %s %d %d\n",
- ENDPOINT_NUMBER(endp),
- dest == MGCP_DEST_NET? "net" : "bts",
-
- inet_ntoa(endp->net_end.addr),
- ntohs(endp->net_end.rtp_port),
- ntohs(endp->net_end.rtcp_port),
-
- inet_ntoa(endp->bts_end.addr),
- ntohs(endp->bts_end.rtp_port),
- ntohs(endp->bts_end.rtcp_port),
-
- inet_ntoa(rtp_end->addr),
- ntohs(rtp_end->rtp_port),
- ntohs(rtp_end->rtcp_port)
- );
-
- if (!rtp_end->output_enabled) {
- rtp_end->dropped_packets += 1;
- LOGP(DMGCP, LOGL_DEBUG,
- "endpoint %x output disabled, drop to %s %s %d %d\n",
- ENDPOINT_NUMBER(endp),
- dest == MGCP_DEST_NET? "net" : "bts",
- inet_ntoa(rtp_end->addr),
- ntohs(rtp_end->rtp_port),
- ntohs(rtp_end->rtcp_port)
- );
- } else if (is_rtp) {
- int cont;
- int nbytes = 0;
- int len = rc;
- do {
- cont = endp->cfg->rtp_processing_cb(endp, rtp_end,
- buf, &len, RTP_BUF_SIZE);
- if (cont < 0)
- break;
-
- mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, buf, len);
- LOGP(DMGCP, LOGL_DEBUG,
- "endpoint %x process/send to %s %s %d %d\n",
- ENDPOINT_NUMBER(endp),
- (dest == MGCP_DEST_NET)? "net" : "bts",
- inet_ntoa(rtp_end->addr),
- ntohs(rtp_end->rtp_port),
- ntohs(rtp_end->rtcp_port)
- );
- forward_data(rtp_end->rtp.fd, &endp->taps[tap_idx],
- buf, len);
-
- /* FIXME: HACK HACK HACK. See OS#2459.
- * The ip.access nano3G needs the first RTP payload's first two bytes to read hex
- * 'e400', or it will reject the RAB assignment. It seems to not harm other femto
- * cells (as long as we patch only the first RTP payload in each stream).
- */
- if (tap_idx == MGCP_TAP_BTS_OUT
- && !rtp_state->patched_first_rtp_payload) {
- uint8_t *data = (uint8_t*)&buf[12];
- data[0] = 0xe4;
- data[1] = 0x00;
- rtp_state->patched_first_rtp_payload = true;
- }
-
- rc = mgcp_udp_send(rtp_end->rtp.fd,
- &rtp_end->addr,
- rtp_end->rtp_port, buf, len);
-
- if (rc <= 0)
- return rc;
- nbytes += rc;
- len = cont;
- } while (len > 0);
- return nbytes;
- } else if (!tcfg->omit_rtcp) {
- LOGP(DMGCP, LOGL_DEBUG,
- "endpoint %x send to %s %s %d %d\n",
- ENDPOINT_NUMBER(endp),
- dest == MGCP_DEST_NET? "net" : "bts",
- inet_ntoa(rtp_end->addr),
- ntohs(rtp_end->rtp_port),
- ntohs(rtp_end->rtcp_port)
- );
-
- return mgcp_udp_send(rtp_end->rtcp.fd,
- &rtp_end->addr,
- rtp_end->rtcp_port, buf, rc);
- }
-
- return 0;
-}
-
-static int receive_from(struct mgcp_endpoint *endp, int fd, struct sockaddr_in *addr,
- char *buf, int bufsize)
-{
- int rc;
- socklen_t slen = sizeof(*addr);
-
- rc = recvfrom(fd, buf, bufsize, 0,
- (struct sockaddr *) addr, &slen);
- if (rc < 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x errno: %d/%s\n",
- ENDPOINT_NUMBER(endp), errno, strerror(errno));
- return -1;
- }
-
- /* do not forward aynthing... maybe there is a packet from the bts */
- if (!endp->allocated)
- return -1;
-
- #warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
-
- return rc;
-}
-
-static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
-{
- char buf[RTP_BUF_SIZE];
- struct sockaddr_in addr;
- struct mgcp_endpoint *endp;
- int rc, proto;
-
- endp = (struct mgcp_endpoint *) fd->data;
-
- rc = receive_from(endp, fd->fd, &addr, buf, sizeof(buf));
- if (rc <= 0)
- return -1;
-
- LOGP(DMGCP, LOGL_DEBUG,
- "endpoint %x",
- ENDPOINT_NUMBER(endp));
- LOGPC(DMGCP, LOGL_DEBUG,
- " from net %s %d",
- inet_ntoa(addr.sin_addr),
- ntohs(addr.sin_port));
- LOGPC(DMGCP, LOGL_DEBUG,
- " net_end %s %d %d",
- inet_ntoa(endp->net_end.addr),
- ntohs(endp->net_end.rtp_port),
- ntohs(endp->net_end.rtcp_port));
- LOGPC(DMGCP, LOGL_DEBUG,
- " bts_end %s %d %d\n",
- inet_ntoa(endp->bts_end.addr),
- ntohs(endp->bts_end.rtp_port),
- ntohs(endp->bts_end.rtcp_port)
- );
-
- if (memcmp(&addr.sin_addr, &endp->net_end.addr, sizeof(addr.sin_addr)) != 0) {
- LOGP(DMGCP, LOGL_ERROR,
- "rtp_data_net: Endpoint 0x%x data from wrong address %s vs. ",
- ENDPOINT_NUMBER(endp), inet_ntoa(addr.sin_addr));
- LOGPC(DMGCP, LOGL_ERROR,
- "%s\n", inet_ntoa(endp->net_end.addr));
- return -1;
- }
-
- switch(endp->type) {
- case MGCP_RTP_DEFAULT:
- case MGCP_RTP_TRANSCODED:
- if (endp->net_end.rtp_port != addr.sin_port &&
- endp->net_end.rtcp_port != addr.sin_port) {
- LOGP(DMGCP, LOGL_ERROR,
- "rtp_data_net: Data from wrong source port %d on 0x%x\n",
- ntohs(addr.sin_port), ENDPOINT_NUMBER(endp));
- return -1;
- }
- break;
- case MGCP_OSMUX_BSC:
- case MGCP_OSMUX_BSC_NAT:
- break;
- }
-
- LOGP(DMGCP, LOGL_DEBUG,
- "rtp_data_net: Endpoint %x data from %s %d\n",
- ENDPOINT_NUMBER(endp),
- inet_ntoa(addr.sin_addr),
- ntohs(addr.sin_port));
-
- /* throw away the dummy message */
- if (rc == 1 && buf[0] == MGCP_DUMMY_LOAD) {
- LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy from network on 0x%x\n",
- ENDPOINT_NUMBER(endp));
- return 0;
- }
-
- proto = fd == &endp->net_end.rtp ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
- endp->net_end.packets += 1;
- endp->net_end.octets += rc;
-
- forward_data(fd->fd, &endp->taps[MGCP_TAP_NET_IN], buf, rc);
-
- switch (endp->type) {
- case MGCP_RTP_DEFAULT:
- return mgcp_send(endp, MGCP_DEST_BTS, proto == MGCP_PROTO_RTP,
- &addr, buf, rc);
- case MGCP_RTP_TRANSCODED:
- return mgcp_send_transcoder(&endp->trans_net, endp->cfg,
- proto == MGCP_PROTO_RTP, buf, rc);
- case MGCP_OSMUX_BSC_NAT:
- return osmux_xfrm_to_osmux(MGCP_DEST_BTS, buf, rc, endp);
- case MGCP_OSMUX_BSC: /* Should not happen */
- break;
- }
-
- LOGP(DMGCP, LOGL_ERROR, "Bad MGCP type %u on endpoint %u\n",
- endp->type, ENDPOINT_NUMBER(endp));
- return 0;
-}
-
-static void discover_bts(struct mgcp_endpoint *endp, int proto, struct sockaddr_in *addr)
-{
- struct mgcp_config *cfg = endp->cfg;
-
- if (proto == MGCP_PROTO_RTP && endp->bts_end.rtp_port == 0) {
- if (!cfg->bts_ip ||
- memcmp(&addr->sin_addr,
- &cfg->bts_in, sizeof(cfg->bts_in)) == 0 ||
- memcmp(&addr->sin_addr,
- &endp->bts_end.addr, sizeof(endp->bts_end.addr)) == 0) {
-
- endp->bts_end.rtp_port = addr->sin_port;
- endp->bts_end.addr = addr->sin_addr;
-
- LOGP(DMGCP, LOGL_NOTICE,
- "Found BTS for endpoint: 0x%x on port: %d/%d of %s\n",
- ENDPOINT_NUMBER(endp), ntohs(endp->bts_end.rtp_port),
- ntohs(endp->bts_end.rtcp_port), inet_ntoa(addr->sin_addr));
- }
- } else if (proto == MGCP_PROTO_RTCP && endp->bts_end.rtcp_port == 0) {
- if (memcmp(&endp->bts_end.addr, &addr->sin_addr,
- sizeof(endp->bts_end.addr)) == 0) {
- endp->bts_end.rtcp_port = addr->sin_port;
- }
- }
-}
-
-static int rtp_data_bts(struct osmo_fd *fd, unsigned int what)
-{
- char buf[RTP_BUF_SIZE];
- struct sockaddr_in addr;
- struct mgcp_endpoint *endp;
- int rc, proto;
-
- endp = (struct mgcp_endpoint *) fd->data;
-
- rc = receive_from(endp, fd->fd, &addr, buf, sizeof(buf));
- if (rc <= 0)
- return -1;
-
- proto = fd == &endp->bts_end.rtp ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
-
- /* We have no idea who called us, maybe it is the BTS. */
- /* it was the BTS... */
- discover_bts(endp, proto, &addr);
-
- if (memcmp(&endp->bts_end.addr, &addr.sin_addr, sizeof(addr.sin_addr)) != 0) {
- LOGP(DMGCP, LOGL_ERROR,
- "rtp_data_bts: Data from wrong bts %s on 0x%x\n",
- inet_ntoa(addr.sin_addr), ENDPOINT_NUMBER(endp));
- return -1;
- }
-
- if (endp->bts_end.rtp_port != addr.sin_port &&
- endp->bts_end.rtcp_port != addr.sin_port) {
- LOGP(DMGCP, LOGL_ERROR,
- "rtp_data_bts: ata from wrong bts source port %d on 0x%x\n",
- ntohs(addr.sin_port), ENDPOINT_NUMBER(endp));
- return -1;
- }
-
- LOGP(DMGCP, LOGL_DEBUG,
- "rtp_data_bts: Endpoint %x data from %s %d\n",
- ENDPOINT_NUMBER(endp),
- inet_ntoa(addr.sin_addr),
- ntohs(addr.sin_port));
-
- /* throw away the dummy message */
- if (rc == 1 && buf[0] == MGCP_DUMMY_LOAD) {
- LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy from bts on 0x%x\n",
- ENDPOINT_NUMBER(endp));
- return 0;
- }
-
- /* do this before the loop handling */
- endp->bts_end.packets += 1;
- endp->bts_end.octets += rc;
-
- forward_data(fd->fd, &endp->taps[MGCP_TAP_BTS_IN], buf, rc);
-
- switch (endp->type) {
- case MGCP_RTP_DEFAULT:
- LOGP(DMGCP, LOGL_DEBUG,
- "rtp_data_bts: Endpoint %x MGCP_RTP_DEFAULT\n",
- ENDPOINT_NUMBER(endp));
- return mgcp_send(endp, MGCP_DEST_NET, proto == MGCP_PROTO_RTP,
- &addr, buf, rc);
- case MGCP_RTP_TRANSCODED:
- return mgcp_send_transcoder(&endp->trans_bts, endp->cfg,
- proto == MGCP_PROTO_RTP, buf, rc);
- case MGCP_OSMUX_BSC:
- /* OSMUX translation: BTS -> BSC */
- return osmux_xfrm_to_osmux(MGCP_DEST_NET, buf, rc, endp);
- case MGCP_OSMUX_BSC_NAT:
- break; /* Should not happen */
- }
-
- LOGP(DMGCP, LOGL_ERROR, "Bad MGCP type %u on endpoint %u\n",
- endp->type, ENDPOINT_NUMBER(endp));
- return 0;
-}
-
-static int rtp_data_transcoder(struct mgcp_rtp_end *end, struct mgcp_endpoint *_endp,
- int dest, struct osmo_fd *fd)
-{
- char buf[RTP_BUF_SIZE];
- struct sockaddr_in addr;
- struct mgcp_config *cfg;
- int rc, proto;
-
- cfg = _endp->cfg;
- rc = receive_from(_endp, fd->fd, &addr, buf, sizeof(buf));
- if (rc <= 0)
- return -1;
-
- proto = fd == &end->rtp ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
-
- if (memcmp(&addr.sin_addr, &cfg->transcoder_in, sizeof(addr.sin_addr)) != 0) {
- LOGP(DMGCP, LOGL_ERROR,
- "Data not coming from transcoder dest: %d %s on 0x%x\n",
- dest, inet_ntoa(addr.sin_addr), ENDPOINT_NUMBER(_endp));
- return -1;
- }
-
- if (end->rtp_port != addr.sin_port &&
- end->rtcp_port != addr.sin_port) {
- LOGP(DMGCP, LOGL_ERROR,
- "Data from wrong transcoder dest %d source port %d on 0x%x\n",
- dest, ntohs(addr.sin_port), ENDPOINT_NUMBER(_endp));
- return -1;
- }
-
- /* throw away the dummy message */
- if (rc == 1 && buf[0] == MGCP_DUMMY_LOAD) {
- LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy from transcoder dest %d on 0x%x\n",
- dest, ENDPOINT_NUMBER(_endp));
- return 0;
- }
-
- end->packets += 1;
- return mgcp_send(_endp, dest, proto == MGCP_PROTO_RTP, &addr, buf, rc);
-}
-
-static int rtp_data_trans_net(struct osmo_fd *fd, unsigned int what)
-{
- struct mgcp_endpoint *endp;
- endp = (struct mgcp_endpoint *) fd->data;
-
- return rtp_data_transcoder(&endp->trans_net, endp, MGCP_DEST_NET, fd);
-}
-
-static int rtp_data_trans_bts(struct osmo_fd *fd, unsigned int what)
-{
- struct mgcp_endpoint *endp;
- endp = (struct mgcp_endpoint *) fd->data;
-
- return rtp_data_transcoder(&endp->trans_bts, endp, MGCP_DEST_BTS, fd);
-}
-
-int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port)
-{
- struct sockaddr_in addr;
- int on = 1;
-
- fd->fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (fd->fd < 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to create UDP port.\n");
- return -1;
- }
-
- setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- inet_aton(source_addr, &addr.sin_addr);
-
- if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- close(fd->fd);
- fd->fd = -1;
- return -1;
- }
-
- return 0;
-}
-
-int mgcp_set_ip_tos(int fd, int tos)
-{
- int ret;
- ret = setsockopt(fd, IPPROTO_IP, IP_TOS,
- &tos, sizeof(tos));
- return ret != 0;
-}
-
-static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
- struct mgcp_rtp_end *rtp_end, int endpno)
-{
- if (mgcp_create_bind(source_addr, &rtp_end->rtp,
- rtp_end->local_port) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to create RTP port: %s:%d on 0x%x\n",
- source_addr, rtp_end->local_port, endpno);
- goto cleanup0;
- }
-
- if (mgcp_create_bind(source_addr, &rtp_end->rtcp,
- rtp_end->local_port + 1) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to create RTCP port: %s:%d on 0x%x\n",
- source_addr, rtp_end->local_port + 1, endpno);
- goto cleanup1;
- }
-
- mgcp_set_ip_tos(rtp_end->rtp.fd, cfg->endp_dscp);
- mgcp_set_ip_tos(rtp_end->rtcp.fd, cfg->endp_dscp);
-
- rtp_end->rtp.when = BSC_FD_READ;
- if (osmo_fd_register(&rtp_end->rtp) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to register RTP port %d on 0x%x\n",
- rtp_end->local_port, endpno);
- goto cleanup2;
- }
-
- rtp_end->rtcp.when = BSC_FD_READ;
- if (osmo_fd_register(&rtp_end->rtcp) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to register RTCP port %d on 0x%x\n",
- rtp_end->local_port + 1, endpno);
- goto cleanup3;
- }
-
- return 0;
-
-cleanup3:
- osmo_fd_unregister(&rtp_end->rtp);
-cleanup2:
- close(rtp_end->rtcp.fd);
- rtp_end->rtcp.fd = -1;
-cleanup1:
- close(rtp_end->rtp.fd);
- rtp_end->rtp.fd = -1;
-cleanup0:
- return -1;
-}
-
-static int int_bind(const char *port,
- struct mgcp_rtp_end *end, int (*cb)(struct osmo_fd *, unsigned),
- struct mgcp_endpoint *_endp,
- const char *source_addr, int rtp_port)
-{
- if (end->rtp.fd != -1 || end->rtcp.fd != -1) {
- LOGP(DMGCP, LOGL_ERROR, "Previous %s was still bound on %d\n",
- port, ENDPOINT_NUMBER(_endp));
- mgcp_free_rtp_port(end);
- }
-
- end->local_port = rtp_port;
- end->rtp.cb = cb;
- end->rtp.data = _endp;
- end->rtcp.data = _endp;
- end->rtcp.cb = cb;
- return bind_rtp(_endp->cfg, source_addr, end, ENDPOINT_NUMBER(_endp));
-}
-
-int mgcp_bind_bts_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
-{
- return int_bind("bts-port", &endp->bts_end,
- rtp_data_bts, endp,
- mgcp_bts_src_addr(endp), rtp_port);
-}
-
-int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
-{
- return int_bind("net-port", &endp->net_end,
- rtp_data_net, endp,
- mgcp_net_src_addr(endp), rtp_port);
-}
-
-int mgcp_bind_trans_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
-{
- return int_bind("trans-net", &endp->trans_net,
- rtp_data_trans_net, endp,
- endp->cfg->source_addr, rtp_port);
-}
-
-int mgcp_bind_trans_bts_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
-{
- return int_bind("trans-bts", &endp->trans_bts,
- rtp_data_trans_bts, endp,
- endp->cfg->source_addr, rtp_port);
-}
-
-int mgcp_free_rtp_port(struct mgcp_rtp_end *end)
-{
- if (end->rtp.fd != -1) {
- close(end->rtp.fd);
- end->rtp.fd = -1;
- osmo_fd_unregister(&end->rtp);
- }
-
- if (end->rtcp.fd != -1) {
- close(end->rtcp.fd);
- end->rtcp.fd = -1;
- osmo_fd_unregister(&end->rtcp);
- }
-
- return 0;
-}
-
-
-void mgcp_state_calc_loss(struct mgcp_rtp_state *state,
- struct mgcp_rtp_end *end, uint32_t *expected,
- int *loss)
-{
- *expected = state->stats_cycles + state->stats_max_seq;
- *expected = *expected - state->stats_base_seq + 1;
-
- if (!state->stats_initialized) {
- *expected = 0;
- *loss = 0;
- return;
- }
-
- /*
- * Make sure the sign is correct and use the biggest
- * positive/negative number that fits.
- */
- *loss = *expected - end->packets;
- if (*expected < end->packets) {
- if (*loss > 0)
- *loss = INT_MIN;
- } else {
- if (*loss < 0)
- *loss = INT_MAX;
- }
-}
-
-uint32_t mgcp_state_calc_jitter(struct mgcp_rtp_state *state)
-{
- if (!state->stats_initialized)
- return 0;
- return state->stats_jitter >> 4;
-}
diff --git a/src/libmgcp/mgcp_osmux.c b/src/libmgcp/mgcp_osmux.c
deleted file mode 100644
index c52984b32..000000000
--- a/src/libmgcp/mgcp_osmux.c
+++ /dev/null
@@ -1,583 +0,0 @@
-/*
- * (C) 2012-2013 by Pablo Neira Ayuso <pablo@gnumonks.org>
- * (C) 2012-2013 by On Waves ehf <http://www.on-waves.com>
- * All rights not specifically granted under this license are reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by the
- * Free Software Foundation; either version 3 of the License, or (at your
- * option) any later version.
- */
-
-#include <stdio.h> /* for printf */
-#include <string.h> /* for memcpy */
-#include <stdlib.h> /* for abs */
-#include <inttypes.h> /* for PRIu64 */
-#include <netinet/in.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/talloc.h>
-
-#include <osmocom/netif/osmux.h>
-#include <osmocom/netif/rtp.h>
-
-#include <openbsc/mgcp.h>
-#include <openbsc/mgcp_internal.h>
-#include <openbsc/osmux.h>
-
-static struct osmo_fd osmux_fd;
-
-static LLIST_HEAD(osmux_handle_list);
-
-struct osmux_handle {
- struct llist_head head;
- struct osmux_in_handle *in;
- struct in_addr rem_addr;
- int rem_port;
- int refcnt;
-};
-
-static void *osmux;
-
-static void osmux_deliver(struct msgb *batch_msg, void *data)
-{
- struct osmux_handle *handle = data;
- struct sockaddr_in out = {
- .sin_family = AF_INET,
- .sin_port = handle->rem_port,
- };
-
- memcpy(&out.sin_addr, &handle->rem_addr, sizeof(handle->rem_addr));
- sendto(osmux_fd.fd, batch_msg->data, batch_msg->len, 0,
- (struct sockaddr *)&out, sizeof(out));
- msgb_free(batch_msg);
-}
-
-static struct osmux_handle *
-osmux_handle_find_get(struct in_addr *addr, int rem_port)
-{
- struct osmux_handle *h;
-
- /* Lookup for existing OSMUX handle for this destination address. */
- llist_for_each_entry(h, &osmux_handle_list, head) {
- if (memcmp(&h->rem_addr, addr, sizeof(struct in_addr)) == 0 &&
- h->rem_port == rem_port) {
- LOGP(DMGCP, LOGL_DEBUG, "using existing OSMUX handle "
- "for addr=%s:%d\n",
- inet_ntoa(*addr), ntohs(rem_port));
- h->refcnt++;
- return h;
- }
- }
-
- return NULL;
-}
-
-static void osmux_handle_put(struct osmux_in_handle *in)
-{
- struct osmux_handle *h;
-
- /* Lookup for existing OSMUX handle for this destination address. */
- llist_for_each_entry(h, &osmux_handle_list, head) {
- if (h->in == in) {
- if (--h->refcnt == 0) {
- LOGP(DMGCP, LOGL_INFO,
- "Releasing unused osmux handle for %s:%d\n",
- inet_ntoa(h->rem_addr),
- ntohs(h->rem_port));
- LOGP(DMGCP, LOGL_INFO, "Stats: "
- "input RTP msgs: %u bytes: %"PRIu64" "
- "output osmux msgs: %u bytes: %"PRIu64"\n",
- in->stats.input_rtp_msgs,
- in->stats.input_rtp_bytes,
- in->stats.output_osmux_msgs,
- in->stats.output_osmux_bytes);
- llist_del(&h->head);
- osmux_xfrm_input_fini(h->in);
- talloc_free(h);
- }
- return;
- }
- }
- LOGP(DMGCP, LOGL_ERROR, "cannot find Osmux input handle %p\n", in);
-}
-
-static struct osmux_handle *
-osmux_handle_alloc(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
-{
- struct osmux_handle *h;
-
- h = talloc_zero(osmux, struct osmux_handle);
- if (!h)
- return NULL;
- h->rem_addr = *addr;
- h->rem_port = rem_port;
- h->refcnt++;
-
- h->in = talloc_zero(h, struct osmux_in_handle);
- if (!h->in) {
- talloc_free(h);
- return NULL;
- }
-
- h->in->osmux_seq = 0; /* sequence number to start OSmux message from */
- h->in->batch_factor = cfg->osmux_batch;
- /* If batch size is zero, the library defaults to 1470 bytes. */
- h->in->batch_size = cfg->osmux_batch_size;
- h->in->deliver = osmux_deliver;
- osmux_xfrm_input_init(h->in);
- h->in->data = h;
-
- llist_add(&h->head, &osmux_handle_list);
-
- LOGP(DMGCP, LOGL_DEBUG, "created new OSMUX handle for addr=%s:%d\n",
- inet_ntoa(*addr), ntohs(rem_port));
-
- return h;
-}
-
-static struct osmux_in_handle *
-osmux_handle_lookup(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
-{
- struct osmux_handle *h;
-
- h = osmux_handle_find_get(addr, rem_port);
- if (h != NULL)
- return h->in;
-
- h = osmux_handle_alloc(cfg, addr, rem_port);
- if (h == NULL)
- return NULL;
-
- return h->in;
-}
-
-int osmux_xfrm_to_osmux(int type, char *buf, int rc, struct mgcp_endpoint *endp)
-{
- int ret;
- struct msgb *msg;
-
- msg = msgb_alloc(4096, "RTP");
- if (!msg)
- return 0;
-
- memcpy(msg->data, buf, rc);
- msgb_put(msg, rc);
-
- while ((ret = osmux_xfrm_input(endp->osmux.in, msg, endp->osmux.cid)) > 0) {
- /* batch full, build and deliver it */
- osmux_xfrm_input_deliver(endp->osmux.in);
- }
- return 0;
-}
-
-static struct mgcp_endpoint *
-endpoint_lookup(struct mgcp_config *cfg, int cid,
- struct in_addr *from_addr, int type)
-{
- struct mgcp_endpoint *tmp = NULL;
- int i;
-
- /* Lookup for the endpoint that corresponds to this port */
- for (i=0; i<cfg->trunk.number_endpoints; i++) {
- struct in_addr *this;
-
- tmp = &cfg->trunk.endpoints[i];
-
- if (!tmp->allocated)
- continue;
-
- switch(type) {
- case MGCP_DEST_NET:
- this = &tmp->net_end.addr;
- break;
- case MGCP_DEST_BTS:
- this = &tmp->bts_end.addr;
- break;
- default:
- /* Should not ever happen */
- LOGP(DMGCP, LOGL_ERROR, "Bad type %d. Fix your code.\n", type);
- return NULL;
- }
-
- if (tmp->osmux.cid == cid && this->s_addr == from_addr->s_addr)
- return tmp;
- }
-
- LOGP(DMGCP, LOGL_ERROR, "Cannot find endpoint with cid=%d\n", cid);
-
- return NULL;
-}
-
-static void scheduled_tx_net_cb(struct msgb *msg, void *data)
-{
- struct mgcp_endpoint *endp = data;
- struct sockaddr_in addr = {
- .sin_addr = endp->net_end.addr,
- .sin_port = endp->net_end.rtp_port,
- };
-
- endp->bts_end.octets += msg->len;
- endp->bts_end.packets++;
-
- mgcp_send(endp, MGCP_DEST_NET, 1, &addr, (char *)msg->data, msg->len);
- msgb_free(msg);
-}
-
-static void scheduled_tx_bts_cb(struct msgb *msg, void *data)
-{
- struct mgcp_endpoint *endp = data;
- struct sockaddr_in addr = {
- .sin_addr = endp->bts_end.addr,
- .sin_port = endp->bts_end.rtp_port,
- };
-
- endp->net_end.octets += msg->len;
- endp->net_end.packets++;
-
- mgcp_send(endp, MGCP_DEST_BTS, 1, &addr, (char *)msg->data, msg->len);
- msgb_free(msg);
-}
-
-static struct msgb *osmux_recv(struct osmo_fd *ofd, struct sockaddr_in *addr)
-{
- struct msgb *msg;
- socklen_t slen = sizeof(*addr);
- int ret;
-
- msg = msgb_alloc(4096, "OSMUX");
- if (!msg) {
- LOGP(DMGCP, LOGL_ERROR, "cannot allocate message\n");
- return NULL;
- }
- ret = recvfrom(ofd->fd, msg->data, msg->data_len, 0,
- (struct sockaddr *)addr, &slen);
- if (ret <= 0) {
- msgb_free(msg);
- LOGP(DMGCP, LOGL_ERROR, "cannot receive message\n");
- return NULL;
- }
- msgb_put(msg, ret);
-
- return msg;
-}
-
-#define osmux_chunk_length(msg, rem) (rem - msg->len);
-
-int osmux_read_from_bsc_nat_cb(struct osmo_fd *ofd, unsigned int what)
-{
- struct msgb *msg;
- struct osmux_hdr *osmuxh;
- struct llist_head list;
- struct sockaddr_in addr;
- struct mgcp_config *cfg = ofd->data;
- uint32_t rem;
-
- msg = osmux_recv(ofd, &addr);
- if (!msg)
- return -1;
-
- /* not any further processing dummy messages */
- if (msg->data[0] == MGCP_DUMMY_LOAD)
- goto out;
-
- rem = msg->len;
- while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
- struct mgcp_endpoint *endp;
-
- /* Yes, we use MGCP_DEST_NET to locate the origin */
- endp = endpoint_lookup(cfg, osmuxh->circuit_id,
- &addr.sin_addr, MGCP_DEST_NET);
- if (!endp) {
- LOGP(DMGCP, LOGL_ERROR,
- "Cannot find an endpoint for circuit_id=%d\n",
- osmuxh->circuit_id);
- goto out;
- }
- endp->osmux.stats.octets += osmux_chunk_length(msg, rem);
- endp->osmux.stats.chunks++;
- rem = msg->len;
-
- osmux_xfrm_output(osmuxh, &endp->osmux.out, &list);
- osmux_tx_sched(&list, scheduled_tx_bts_cb, endp);
- }
-out:
- msgb_free(msg);
- return 0;
-}
-
-/* This is called from the bsc-nat */
-static int osmux_handle_dummy(struct mgcp_config *cfg, struct sockaddr_in *addr,
- struct msgb *msg)
-{
- struct mgcp_endpoint *endp;
- uint8_t osmux_cid;
-
- if (msg->len < 1 + sizeof(osmux_cid)) {
- LOGP(DMGCP, LOGL_ERROR,
- "Discarding truncated Osmux dummy load\n");
- goto out;
- }
-
- LOGP(DMGCP, LOGL_DEBUG, "Received Osmux dummy load from %s\n",
- inet_ntoa(addr->sin_addr));
-
- if (!cfg->osmux) {
- LOGP(DMGCP, LOGL_ERROR,
- "bsc wants to use Osmux but bsc-nat did not request it\n");
- goto out;
- }
-
- /* extract the osmux CID from the dummy message */
- memcpy(&osmux_cid, &msg->data[1], sizeof(osmux_cid));
-
- endp = endpoint_lookup(cfg, osmux_cid, &addr->sin_addr, MGCP_DEST_BTS);
- if (!endp) {
- LOGP(DMGCP, LOGL_ERROR,
- "Cannot find endpoint for Osmux CID %d\n", osmux_cid);
- goto out;
- }
-
- if (endp->osmux.state == OSMUX_STATE_ENABLED)
- goto out;
-
- if (osmux_enable_endpoint(endp, &addr->sin_addr, addr->sin_port) < 0 ) {
- LOGP(DMGCP, LOGL_ERROR,
- "Could not enable osmux in endpoint %d\n",
- ENDPOINT_NUMBER(endp));
- goto out;
- }
-
- LOGP(DMGCP, LOGL_INFO, "Enabling osmux in endpoint %d for %s:%u\n",
- ENDPOINT_NUMBER(endp), inet_ntoa(addr->sin_addr),
- ntohs(addr->sin_port));
-out:
- msgb_free(msg);
- return 0;
-}
-
-int osmux_read_from_bsc_cb(struct osmo_fd *ofd, unsigned int what)
-{
- struct msgb *msg;
- struct osmux_hdr *osmuxh;
- struct llist_head list;
- struct sockaddr_in addr;
- struct mgcp_config *cfg = ofd->data;
- uint32_t rem;
-
- msg = osmux_recv(ofd, &addr);
- if (!msg)
- return -1;
-
- /* not any further processing dummy messages */
- if (msg->data[0] == MGCP_DUMMY_LOAD)
- return osmux_handle_dummy(cfg, &addr, msg);
-
- rem = msg->len;
- while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
- struct mgcp_endpoint *endp;
-
- /* Yes, we use MGCP_DEST_BTS to locate the origin */
- endp = endpoint_lookup(cfg, osmuxh->circuit_id,
- &addr.sin_addr, MGCP_DEST_BTS);
- if (!endp) {
- LOGP(DMGCP, LOGL_ERROR,
- "Cannot find an endpoint for circuit_id=%d\n",
- osmuxh->circuit_id);
- goto out;
- }
- endp->osmux.stats.octets += osmux_chunk_length(msg, rem);
- endp->osmux.stats.chunks++;
- rem = msg->len;
-
- osmux_xfrm_output(osmuxh, &endp->osmux.out, &list);
- osmux_tx_sched(&list, scheduled_tx_net_cb, endp);
- }
-out:
- msgb_free(msg);
- return 0;
-}
-
-int osmux_init(int role, struct mgcp_config *cfg)
-{
- int ret;
-
- switch(role) {
- case OSMUX_ROLE_BSC:
- osmux_fd.cb = osmux_read_from_bsc_nat_cb;
- break;
- case OSMUX_ROLE_BSC_NAT:
- osmux_fd.cb = osmux_read_from_bsc_cb;
- break;
- default:
- LOGP(DMGCP, LOGL_ERROR, "wrong role for OSMUX\n");
- return -1;
- }
- osmux_fd.data = cfg;
-
- ret = mgcp_create_bind(cfg->osmux_addr, &osmux_fd, cfg->osmux_port);
- if (ret < 0) {
- LOGP(DMGCP, LOGL_ERROR, "cannot bind OSMUX socket\n");
- return ret;
- }
- mgcp_set_ip_tos(osmux_fd.fd, cfg->endp_dscp);
- osmux_fd.when |= BSC_FD_READ;
-
- ret = osmo_fd_register(&osmux_fd);
- if (ret < 0) {
- LOGP(DMGCP, LOGL_ERROR, "cannot register OSMUX socket\n");
- return ret;
- }
- cfg->osmux_init = 1;
-
- return 0;
-}
-
-int osmux_enable_endpoint(struct mgcp_endpoint *endp, struct in_addr *addr, uint16_t port)
-{
- /* If osmux is enabled, initialize the output handler. This handler is
- * used to reconstruct the RTP flow from osmux. The RTP SSRC is
- * allocated based on the circuit ID (endp->osmux.cid), which is unique
- * in the local scope to the BSC/BSC-NAT. We use it to divide the RTP
- * SSRC space (2^32) by the 256 possible circuit IDs, then randomly
- * select one value from that window. Thus, we have no chance to have
- * overlapping RTP SSRC traveling to the BTSes behind the BSC,
- * similarly, for flows traveling to the MSC.
- */
- static const uint32_t rtp_ssrc_winlen = UINT32_MAX / 256;
-
- if (endp->osmux.state == OSMUX_STATE_DISABLED) {
- LOGP(DMGCP, LOGL_ERROR, "Endpoint %u didn't request Osmux\n",
- ENDPOINT_NUMBER(endp));
- return -1;
- }
-
- osmux_xfrm_output_init(&endp->osmux.out,
- (endp->osmux.cid * rtp_ssrc_winlen) +
- (random() % rtp_ssrc_winlen));
-
- endp->osmux.in = osmux_handle_lookup(endp->cfg, addr, port);
- if (!endp->osmux.in) {
- LOGP(DMGCP, LOGL_ERROR, "Cannot allocate input osmux handle\n");
- return -1;
- }
- if (!osmux_xfrm_input_open_circuit(endp->osmux.in, endp->osmux.cid,
- endp->cfg->osmux_dummy)) {
- LOGP(DMGCP, LOGL_ERROR, "Cannot open osmux circuit %u\n",
- endp->osmux.cid);
- return -1;
- }
-
- switch (endp->cfg->role) {
- case MGCP_BSC_NAT:
- endp->type = MGCP_OSMUX_BSC_NAT;
- break;
- case MGCP_BSC:
- endp->type = MGCP_OSMUX_BSC;
- break;
- }
- endp->osmux.state = OSMUX_STATE_ENABLED;
-
- return 0;
-}
-
-void osmux_disable_endpoint(struct mgcp_endpoint *endp)
-{
- LOGP(DMGCP, LOGL_INFO, "Releasing endpoint %u using Osmux CID %u\n",
- ENDPOINT_NUMBER(endp), endp->osmux.cid);
- osmux_xfrm_input_close_circuit(endp->osmux.in, endp->osmux.cid);
- endp->osmux.state = OSMUX_STATE_DISABLED;
- endp->osmux.cid = -1;
- osmux_handle_put(endp->osmux.in);
-}
-
-void osmux_release_cid(struct mgcp_endpoint *endp)
-{
- if (endp->osmux.allocated_cid >= 0)
- osmux_put_cid(endp->osmux.allocated_cid);
- endp->osmux.allocated_cid = -1;
-}
-
-void osmux_allocate_cid(struct mgcp_endpoint *endp)
-{
- osmux_release_cid(endp);
- endp->osmux.allocated_cid = osmux_get_cid();
-}
-
-/* We don't need to send the dummy load for osmux so often as another endpoint
- * may have already punched the hole in the firewall. This approach is simple
- * though.
- */
-int osmux_send_dummy(struct mgcp_endpoint *endp)
-{
- char buf[1 + sizeof(uint8_t)];
- struct in_addr addr_unset = {};
-
- buf[0] = MGCP_DUMMY_LOAD;
- memcpy(&buf[1], &endp->osmux.cid, sizeof(endp->osmux.cid));
-
- /* Wait until we have the connection information from MDCX */
- if (memcmp(&endp->net_end.addr, &addr_unset, sizeof(addr_unset)) == 0)
- return 0;
-
- if (endp->osmux.state == OSMUX_STATE_ACTIVATING) {
- if (osmux_enable_endpoint(endp, &endp->net_end.addr,
- htons(endp->cfg->osmux_port)) < 0) {
- LOGP(DMGCP, LOGL_ERROR,
- "Could not activate osmux in endpoint %d\n",
- ENDPOINT_NUMBER(endp));
- }
- LOGP(DMGCP, LOGL_ERROR,
- "Osmux CID %u for %s:%u is now enabled\n",
- endp->osmux.cid, inet_ntoa(endp->net_end.addr),
- endp->cfg->osmux_port);
- }
- LOGP(DMGCP, LOGL_DEBUG,
- "sending OSMUX dummy load to %s CID %u\n",
- inet_ntoa(endp->net_end.addr), endp->osmux.cid);
-
- return mgcp_udp_send(osmux_fd.fd, &endp->net_end.addr,
- htons(endp->cfg->osmux_port), buf, sizeof(buf));
-}
-
-/* bsc-nat allocates/releases the Osmux circuit ID */
-static uint8_t osmux_cid_bitmap[(OSMUX_CID_MAX + 1) / 8];
-
-int osmux_used_cid(void)
-{
- int i, j, used = 0;
-
- for (i = 0; i < sizeof(osmux_cid_bitmap); i++) {
- for (j = 0; j < 8; j++) {
- if (osmux_cid_bitmap[i] & (1 << j))
- used += 1;
- }
- }
-
- return used;
-}
-
-int osmux_get_cid(void)
-{
- int i, j;
-
- for (i = 0; i < sizeof(osmux_cid_bitmap); i++) {
- for (j = 0; j < 8; j++) {
- if (osmux_cid_bitmap[i] & (1 << j))
- continue;
-
- osmux_cid_bitmap[i] |= (1 << j);
- LOGP(DMGCP, LOGL_DEBUG,
- "Allocating Osmux CID %u from pool\n", (i * 8) + j);
- return (i * 8) + j;
- }
- }
-
- LOGP(DMGCP, LOGL_ERROR, "All Osmux circuits are in use!\n");
- return -1;
-}
-
-void osmux_put_cid(uint8_t osmux_cid)
-{
- LOGP(DMGCP, LOGL_DEBUG, "Osmux CID %u is back to the pool\n", osmux_cid);
- osmux_cid_bitmap[osmux_cid / 8] &= ~(1 << (osmux_cid % 8));
-}
diff --git a/src/libmgcp/mgcp_protocol.c b/src/libmgcp/mgcp_protocol.c
deleted file mode 100644
index c8b6e8660..000000000
--- a/src/libmgcp/mgcp_protocol.c
+++ /dev/null
@@ -1,1639 +0,0 @@
-/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
-/* The protocol implementation */
-
-/*
- * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009-2012 by On-Waves
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <limits.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/select.h>
-
-#include <openbsc/mgcp.h>
-#include <openbsc/mgcp_internal.h>
-
-#define for_each_non_empty_line(line, save) \
- for (line = strtok_r(NULL, "\r\n", &save); line;\
- line = strtok_r(NULL, "\r\n", &save))
-
-
-static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
-
-struct mgcp_request {
- char *name;
- struct msgb *(*handle_request) (struct mgcp_parse_data *data);
- char *debug_name;
-};
-
-#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
- { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
-
-static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *data);
-static struct msgb *handle_create_con(struct mgcp_parse_data *data);
-static struct msgb *handle_delete_con(struct mgcp_parse_data *data);
-static struct msgb *handle_modify_con(struct mgcp_parse_data *data);
-static struct msgb *handle_rsip(struct mgcp_parse_data *data);
-static struct msgb *handle_noti_req(struct mgcp_parse_data *data);
-
-static void create_transcoder(struct mgcp_endpoint *endp);
-static void delete_transcoder(struct mgcp_endpoint *endp);
-
-static int setup_rtp_processing(struct mgcp_endpoint *endp);
-
-static int mgcp_analyze_header(struct mgcp_parse_data *parse, char *data);
-
-/* Display an mgcp message on the log output */
-void display_mgcp_message(unsigned char *message, unsigned int len,
- char *preamble)
-{
- unsigned char line[80];
- unsigned char *ptr;
- unsigned int consumed = 0;
- unsigned int consumed_line = 0;
- unsigned int line_count = 0;
-
- if (!log_check_level(DMGCP, LOGL_DEBUG))
- return;
-
- while (1) {
- memset(line, 0, sizeof(line));
- ptr = line;
- consumed_line = 0;
- do {
- if (*message != '\n' && *message != '\r') {
- *ptr = *message;
- ptr++;
- }
- message++;
- consumed++;
- consumed_line++;
- } while (*message != '\n' && consumed < len
- && consumed_line < sizeof(line));
-
- if (strlen((const char *)line)) {
- LOGP(DMGCP, LOGL_DEBUG, "%s: line #%02u: %s\n",
- preamble, line_count, line);
- line_count++;
- }
-
- if (consumed >= len)
- return;
- }
-}
-
-static int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line)
-{
- const size_t line_len = strlen(line);
- if (line[0] != '\0' && line_len < 2) {
- LOGP(DMGCP, LOGL_ERROR,
- "Wrong MGCP option format: '%s' on 0x%x\n",
- line, ENDPOINT_NUMBER(endp));
- return 0;
- }
-
- return 1;
-}
-
-static uint32_t generate_call_id(struct mgcp_config *cfg)
-{
- int i;
-
- /* use the call id */
- ++cfg->last_call_id;
-
- /* handle wrap around */
- if (cfg->last_call_id == CI_UNUSED)
- ++cfg->last_call_id;
-
- /* callstack can only be of size number_of_endpoints */
- /* verify that the call id is free, e.g. in case of overrun */
- for (i = 1; i < cfg->trunk.number_endpoints; ++i)
- if (cfg->trunk.endpoints[i].ci == cfg->last_call_id)
- return generate_call_id(cfg);
-
- return cfg->last_call_id;
-}
-
-/*
- * array of function pointers for handling various
- * messages. In the future this might be binary sorted
- * for performance reasons.
- */
-static const struct mgcp_request mgcp_requests [] = {
- MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
- MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
- MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
- MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
- MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
-
- /* SPEC extension */
- MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
-};
-
-static struct msgb *mgcp_msgb_alloc(void)
-{
- struct msgb *msg;
- msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
- if (!msg)
- LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
-
- return msg;
-}
-
-static struct msgb *do_retransmission(const struct mgcp_endpoint *endp)
-{
- struct msgb *msg = mgcp_msgb_alloc();
- if (!msg)
- return NULL;
-
- msg->l2h = msgb_put(msg, strlen(endp->last_response));
- memcpy(msg->l2h, endp->last_response, msgb_l2len(msg));
- return msg;
-}
-
-static struct msgb *create_resp(struct mgcp_endpoint *endp, int code,
- const char *txt, const char *msg,
- const char *trans, const char *param,
- const char *sdp)
-{
- int len;
- struct msgb *res;
-
- res = mgcp_msgb_alloc();
- if (!res)
- return NULL;
-
- len = snprintf((char *) res->data, 2048, "%d %s%s%s\r\n%s",
- code, trans, txt, param ? param : "", sdp ? sdp : "");
- if (len < 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to sprintf MGCP response.\n");
- msgb_free(res);
- return NULL;
- }
-
- res->l2h = msgb_put(res, len);
- LOGP(DMGCP, LOGL_DEBUG, "Generated response: code=%d\n", code);
- display_mgcp_message(res->l2h, msgb_l2len(res), "Generated response");
-
- /*
- * Remember the last transmission per endpoint.
- */
- if (endp) {
- struct mgcp_trunk_config *tcfg = endp->tcfg;
- talloc_free(endp->last_response);
- talloc_free(endp->last_trans);
- endp->last_trans = talloc_strdup(tcfg->endpoints, trans);
- endp->last_response = talloc_strndup(tcfg->endpoints,
- (const char *) res->l2h,
- msgb_l2len(res));
- }
-
- return res;
-}
-
-static struct msgb *create_ok_resp_with_param(struct mgcp_endpoint *endp,
- int code, const char *msg,
- const char *trans, const char *param)
-{
- return create_resp(endp, code, " OK", msg, trans, param, NULL);
-}
-
-static struct msgb *create_ok_response(struct mgcp_endpoint *endp,
- int code, const char *msg, const char *trans)
-{
- return create_ok_resp_with_param(endp, code, msg, trans, NULL);
-}
-
-static struct msgb *create_err_response(struct mgcp_endpoint *endp,
- int code, const char *msg, const char *trans)
-{
- return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL);
-}
-
-static int write_response_sdp(struct mgcp_endpoint *endp,
- char *sdp_record, size_t size, const char *addr)
-{
- const char *fmtp_extra;
- const char *audio_name;
- int payload_type;
- int len;
- int nchars;
-
- endp->cfg->get_net_downlink_format_cb(endp, &payload_type,
- &audio_name, &fmtp_extra);
-
- len = snprintf(sdp_record, size,
- "v=0\r\n"
- "o=- %u 23 IN IP4 %s\r\n"
- "s=-\r\n"
- "c=IN IP4 %s\r\n"
- "t=0 0\r\n",
- endp->ci, addr, addr);
-
- if (len < 0 || len >= size)
- goto buffer_too_small;
-
- if (payload_type >= 0) {
- nchars = snprintf(sdp_record + len, size - len,
- "m=audio %d RTP/AVP %d\r\n",
- endp->net_end.local_port, payload_type);
- if (nchars < 0 || nchars >= size - len)
- goto buffer_too_small;
-
- len += nchars;
-
- if (audio_name && endp->tcfg->audio_send_name) {
- nchars = snprintf(sdp_record + len, size - len,
- "a=rtpmap:%d %s\r\n",
- payload_type, audio_name);
-
- if (nchars < 0 || nchars >= size - len)
- goto buffer_too_small;
-
- len += nchars;
- }
-
- if (fmtp_extra) {
- nchars = snprintf(sdp_record + len, size - len,
- "%s\r\n", fmtp_extra);
-
- if (nchars < 0 || nchars >= size - len)
- goto buffer_too_small;
-
- len += nchars;
- }
- }
- if (endp->bts_end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
- nchars = snprintf(sdp_record + len, size - len,
- "a=ptime:%d\r\n",
- endp->bts_end.packet_duration_ms);
- if (nchars < 0 || nchars >= size - len)
- goto buffer_too_small;
-
- len += nchars;
- }
-
- return len;
-
-buffer_too_small:
- LOGP(DMGCP, LOGL_ERROR, "SDP buffer too small: %zu (needed %d)\n",
- size, len);
- return -1;
-}
-
-static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
- const char *msg, const char *trans_id)
-{
- const char *addr = endp->cfg->local_ip;
- char sdp_record[4096];
- int len;
- int nchars;
- char osmux_extension[strlen("\nX-Osmux: 255") + 1];
-
- if (!addr)
- addr = mgcp_net_src_addr(endp);
-
- if (endp->osmux.state == OSMUX_STATE_NEGOTIATING) {
- sprintf(osmux_extension, "\nX-Osmux: %u", endp->osmux.cid);
- endp->osmux.state = OSMUX_STATE_ACTIVATING;
- } else {
- osmux_extension[0] = '\0';
- }
-
- len = snprintf(sdp_record, sizeof(sdp_record),
- "I: %u%s\n\n", endp->ci, osmux_extension);
- if (len < 0)
- return NULL;
-
- nchars = write_response_sdp(endp, sdp_record + len,
- sizeof(sdp_record) - len - 1, addr);
- if (nchars < 0)
- return NULL;
-
- len += nchars;
-
- sdp_record[sizeof(sdp_record) - 1] = '\0';
-
- return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record);
-}
-
-static void send_dummy(struct mgcp_endpoint *endp)
-{
- if (endp->osmux.state != OSMUX_STATE_DISABLED)
- osmux_send_dummy(endp);
- else
- mgcp_send_dummy(endp);
-}
-
-/*
- * handle incoming messages:
- * - this can be a command (four letters, space, transaction id)
- * - or a response (three numbers, space, transaction id)
- */
-struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
-{
- struct mgcp_parse_data pdata;
- int i, code, handled = 0;
- struct msgb *resp = NULL;
- char *data;
-
- if (msgb_l2len(msg) < 4) {
- LOGP(DMGCP, LOGL_ERROR, "msg too short: %d\n", msg->len);
- return NULL;
- }
-
- if (mgcp_msg_terminate_nul(msg))
- return NULL;
-
- display_mgcp_message(msg->l2h, msgb_l2len(msg), "Received message");
-
- /* attempt to treat it as a response */
- if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
- LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
- return NULL;
- }
-
- msg->l3h = &msg->l2h[4];
-
-
- /*
- * Check for a duplicate message and respond.
- */
- memset(&pdata, 0, sizeof(pdata));
- pdata.cfg = cfg;
- data = strline_r((char *) msg->l3h, &pdata.save);
- pdata.found = mgcp_analyze_header(&pdata, data);
- if (pdata.endp && pdata.trans
- && pdata.endp->last_trans
- && strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
- return do_retransmission(pdata.endp);
- }
-
- for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) {
- if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
- handled = 1;
- resp = mgcp_requests[i].handle_request(&pdata);
- break;
- }
- }
-
- if (!handled)
- LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
-
- return resp;
-}
-
-/**
- * We have a null terminated string with the endpoint name here. We only
- * support two kinds. Simple ones as seen on the BSC level and the ones
- * seen on the trunk side.
- */
-static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
- const char *mgcp)
-{
- char *rest = NULL;
- struct mgcp_trunk_config *tcfg;
- int trunk, endp;
-
- trunk = strtoul(mgcp + 6, &rest, 10);
- if (rest == NULL || rest[0] != '/' || trunk < 1) {
- LOGP(DMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
- return NULL;
- }
-
- endp = strtoul(rest + 1, &rest, 10);
- if (rest == NULL || rest[0] != '@') {
- LOGP(DMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
- return NULL;
- }
-
- /* signalling is on timeslot 1 */
- if (endp == 1)
- return NULL;
-
- tcfg = mgcp_trunk_num(cfg, trunk);
- if (!tcfg) {
- LOGP(DMGCP, LOGL_ERROR, "The trunk %d is not declared.\n", trunk);
- return NULL;
- }
-
- if (!tcfg->endpoints) {
- LOGP(DMGCP, LOGL_ERROR, "Endpoints of trunk %d not allocated.\n", trunk);
- return NULL;
- }
-
- if (endp < 1 || endp >= tcfg->number_endpoints) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
- return NULL;
- }
-
- return &tcfg->endpoints[endp];
-}
-
-static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
-{
- char *endptr = NULL;
- unsigned int gw = INT_MAX;
-
- if (strncmp(mgcp, "ds/e1", 5) == 0)
- return find_e1_endpoint(cfg, mgcp);
-
- gw = strtoul(mgcp, &endptr, 16);
- if (gw > 0 && gw < cfg->trunk.number_endpoints && endptr[0] == '@')
- return &cfg->trunk.endpoints[gw];
-
- LOGP(DMGCP, LOGL_ERROR, "Not able to find the endpoint: '%s'\n", mgcp);
- return NULL;
-}
-
-/**
- * @returns 0 when the status line was complete and transaction_id and
- * endp out parameters are set.
- */
-static int mgcp_analyze_header(struct mgcp_parse_data *pdata, char *data)
-{
- int i = 0;
- char *elem, *save = NULL;
-
- OSMO_ASSERT(data);
- pdata->trans = "000000";
-
- for (elem = strtok_r(data, " ", &save); elem;
- elem = strtok_r(NULL, " ", &save)) {
- switch (i) {
- case 0:
- pdata->trans = elem;
- break;
- case 1:
- pdata->endp = find_endpoint(pdata->cfg, elem);
- if (!pdata->endp) {
- LOGP(DMGCP, LOGL_ERROR,
- "Unable to find Endpoint `%s'\n", elem);
- return -1;
- }
- break;
- case 2:
- if (strcmp("MGCP", elem)) {
- LOGP(DMGCP, LOGL_ERROR,
- "MGCP header parsing error\n");
- return -1;
- }
- break;
- case 3:
- if (strcmp("1.0", elem)) {
- LOGP(DMGCP, LOGL_ERROR, "MGCP version `%s' "
- "not supported\n", elem);
- return -1;
- }
- break;
- }
- i++;
- }
-
- if (i != 4) {
- LOGP(DMGCP, LOGL_ERROR, "MGCP status line too short.\n");
- pdata->trans = "000000";
- pdata->endp = NULL;
- return -1;
- }
-
- return 0;
-}
-
-static int verify_call_id(const struct mgcp_endpoint *endp,
- const char *callid)
-{
- if (strcmp(endp->callid, callid) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
- ENDPOINT_NUMBER(endp), endp->callid, callid);
- return -1;
- }
-
- return 0;
-}
-
-static int verify_ci(const struct mgcp_endpoint *endp,
- const char *_ci)
-{
- uint32_t ci = strtoul(_ci, NULL, 10);
-
- if (ci != endp->ci) {
- LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
- ENDPOINT_NUMBER(endp), endp->ci, _ci);
- return -1;
- }
-
- return 0;
-}
-
-static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
-{
- if (p->found != 0)
- return create_err_response(NULL, 500, "AUEP", p->trans);
- else
- return create_ok_response(p->endp, 200, "AUEP", p->trans);
-}
-
-static int parse_conn_mode(const char *msg, struct mgcp_endpoint *endp)
-{
- int ret = 0;
- if (strcmp(msg, "recvonly") == 0)
- endp->conn_mode = MGCP_CONN_RECV_ONLY;
- else if (strcmp(msg, "sendrecv") == 0)
- endp->conn_mode = MGCP_CONN_RECV_SEND;
- else if (strcmp(msg, "sendonly") == 0)
- endp->conn_mode = MGCP_CONN_SEND_ONLY;
- else if (strcmp(msg, "loopback") == 0)
- endp->conn_mode = MGCP_CONN_LOOPBACK;
- else {
- LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
- ret = -1;
- }
-
- endp->net_end.output_enabled =
- endp->conn_mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
- endp->bts_end.output_enabled =
- endp->conn_mode & MGCP_CONN_RECV_ONLY ? 1 : 0;
-
- LOGP(DMGCP, LOGL_DEBUG, "endpoint %x connection mode '%s' %d output_enabled net %d bts %d\n",
- ENDPOINT_NUMBER(endp),
- msg, endp->conn_mode, endp->net_end.output_enabled,
- endp->bts_end.output_enabled);
-
- return ret;
-}
-
-static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
- struct mgcp_port_range *range,
- int (*alloc)(struct mgcp_endpoint *endp, int port))
-{
- int i;
-
- if (range->mode == PORT_ALLOC_STATIC) {
- end->local_alloc = PORT_ALLOC_STATIC;
- return 0;
- }
-
- /* attempt to find a port */
- for (i = 0; i < 200; ++i) {
- int rc;
-
- if (range->last_port >= range->range_end)
- range->last_port = range->range_start;
-
- rc = alloc(endp, range->last_port);
-
- range->last_port += 2;
- if (rc == 0) {
- end->local_alloc = PORT_ALLOC_DYNAMIC;
- return 0;
- }
-
- }
-
- LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
- ENDPOINT_NUMBER(endp));
- return -1;
-}
-
-static int allocate_ports(struct mgcp_endpoint *endp)
-{
- if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
- mgcp_bind_net_rtp_port) != 0)
- return -1;
-
- if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
- mgcp_bind_bts_rtp_port) != 0) {
- mgcp_rtp_end_reset(&endp->net_end);
- return -1;
- }
-
- if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
- if (allocate_port(endp, &endp->trans_net,
- &endp->cfg->transcoder_ports,
- mgcp_bind_trans_net_rtp_port) != 0) {
- mgcp_rtp_end_reset(&endp->net_end);
- mgcp_rtp_end_reset(&endp->bts_end);
- return -1;
- }
-
- if (allocate_port(endp, &endp->trans_bts,
- &endp->cfg->transcoder_ports,
- mgcp_bind_trans_bts_rtp_port) != 0) {
- mgcp_rtp_end_reset(&endp->net_end);
- mgcp_rtp_end_reset(&endp->bts_end);
- mgcp_rtp_end_reset(&endp->trans_net);
- return -1;
- }
-
- /* remember that we have set up transcoding */
- endp->type = MGCP_RTP_TRANSCODED;
- }
-
- return 0;
-}
-
-/* Set the LCO from a string (see RFC 3435).
- * The string is stored in the 'string' field. A NULL string is handled excatly
- * like an empty string, the 'string' field is never NULL after this function
- * has been called. */
-static void set_local_cx_options(void *ctx, struct mgcp_lco *lco,
- const char *options)
-{
- char *p_opt, *a_opt;
- char codec[9];
-
- talloc_free(lco->string);
- talloc_free(lco->codec);
- lco->codec = NULL;
- lco->pkt_period_min = lco->pkt_period_max = 0;
- lco->string = talloc_strdup(ctx, options ? options : "");
-
- p_opt = strstr(lco->string, "p:");
- if (p_opt && sscanf(p_opt, "p:%d-%d",
- &lco->pkt_period_min, &lco->pkt_period_max) == 1)
- lco->pkt_period_max = lco->pkt_period_min;
-
- a_opt = strstr(lco->string, "a:");
- if (a_opt && sscanf(a_opt, "a:%8[^,]", codec) == 1)
- lco->codec = talloc_strdup(ctx, codec);
-}
-
-void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
- struct mgcp_rtp_end *rtp)
-{
- struct mgcp_trunk_config *tcfg = endp->tcfg;
-
- int patch_ssrc = expect_ssrc_change && tcfg->force_constant_ssrc;
-
- rtp->force_aligned_timing = tcfg->force_aligned_timing;
- rtp->force_constant_ssrc = patch_ssrc ? 1 : 0;
-
- LOGP(DMGCP, LOGL_DEBUG,
- "Configuring RTP endpoint: local port %d%s%s\n",
- ntohs(rtp->rtp_port),
- rtp->force_aligned_timing ? ", force constant timing" : "",
- rtp->force_constant_ssrc ? ", force constant ssrc" : "");
-}
-
-uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
- struct mgcp_rtp_end *rtp)
-{
- int f = 0;
-
- /* Get the number of frames per channel and packet */
- if (rtp->frames_per_packet)
- f = rtp->frames_per_packet;
- else if (rtp->packet_duration_ms && rtp->codec.frame_duration_num) {
- int den = 1000 * rtp->codec.frame_duration_num;
- f = (rtp->packet_duration_ms * rtp->codec.frame_duration_den + den/2)
- / den;
- }
-
- return rtp->codec.rate * f * rtp->codec.frame_duration_num / rtp->codec.frame_duration_den;
-}
-
-static int mgcp_parse_osmux_cid(const char *line)
-{
- int osmux_cid;
-
- if (sscanf(line + 2, "Osmux: %u", &osmux_cid) != 1)
- return -1;
-
- if (osmux_cid > OSMUX_CID_MAX) {
- LOGP(DMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
- osmux_cid, OSMUX_CID_MAX);
- return -1;
- }
- LOGP(DMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
-
- return osmux_cid;
-}
-
-static int mgcp_osmux_setup(struct mgcp_endpoint *endp, const char *line)
-{
- if (!endp->cfg->osmux_init) {
- if (osmux_init(OSMUX_ROLE_BSC, endp->cfg) < 0) {
- LOGP(DMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
- return -1;
- }
- LOGP(DMGCP, LOGL_NOTICE, "OSMUX socket has been set up\n");
- }
-
- return mgcp_parse_osmux_cid(line);
-}
-
-static struct msgb *handle_create_con(struct mgcp_parse_data *p)
-{
- struct mgcp_trunk_config *tcfg;
- struct mgcp_endpoint *endp = p->endp;
- int error_code = 400;
-
- const char *local_options = NULL;
- const char *callid = NULL;
- const char *mode = NULL;
- char *line;
- int have_sdp = 0, osmux_cid = -1;
-
- if (p->found != 0)
- return create_err_response(NULL, 510, "CRCX", p->trans);
-
- /* parse CallID C: and LocalParameters L: */
- for_each_line(line, p->save) {
- if (!mgcp_check_param(endp, line))
- continue;
-
- switch (line[0]) {
- case 'L':
- local_options = (const char *) line + 3;
- break;
- case 'C':
- callid = (const char *) line + 3;
- break;
- case 'M':
- mode = (const char *) line + 3;
- break;
- case 'X':
- /* Osmux is not enabled in this bsc, ignore it so the
- * bsc-nat knows that we don't want to use Osmux.
- */
- if (!p->endp->cfg->osmux)
- break;
-
- if (strncmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0)
- osmux_cid = mgcp_osmux_setup(endp, line);
- break;
- case '\0':
- have_sdp = 1;
- goto mgcp_header_done;
- default:
- LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
- *line, *line, ENDPOINT_NUMBER(endp));
- break;
- }
- }
-
-mgcp_header_done:
- tcfg = p->endp->tcfg;
-
- /* Check required data */
- if (!callid || !mode) {
- LOGP(DMGCP, LOGL_ERROR, "Missing callid and mode in CRCX on 0x%x\n",
- ENDPOINT_NUMBER(endp));
- return create_err_response(endp, 400, "CRCX", p->trans);
- }
-
- if (endp->allocated) {
- if (tcfg->force_realloc) {
- LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
- ENDPOINT_NUMBER(endp));
- mgcp_release_endp(endp);
- if (p->cfg->realloc_cb)
- p->cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
- } else {
- LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
- ENDPOINT_NUMBER(endp));
- return create_err_response(endp, 400, "CRCX", p->trans);
- }
- }
-
- /* copy some parameters */
- endp->callid = talloc_strdup(tcfg->endpoints, callid);
-
- set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
- local_options);
-
- if (parse_conn_mode(mode, endp) != 0) {
- error_code = 517;
- goto error2;
- }
-
- /* initialize */
- endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0;
- mgcp_rtp_end_config(endp, 0, &endp->net_end);
- mgcp_rtp_end_config(endp, 0, &endp->bts_end);
-
- /* set to zero until we get the info */
- memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
-
- /* bind to the port now */
- if (allocate_ports(endp) != 0)
- goto error2;
-
- /* assign a local call identifier or fail */
- endp->ci = generate_call_id(p->cfg);
- if (endp->ci == CI_UNUSED)
- goto error2;
-
- /* Annotate Osmux circuit ID and set it to negotiating state until this
- * is fully set up from the dummy load.
- */
- endp->osmux.state = OSMUX_STATE_DISABLED;
- if (osmux_cid >= 0) {
- endp->osmux.cid = osmux_cid;
- endp->osmux.state = OSMUX_STATE_NEGOTIATING;
- } else if (endp->cfg->osmux == OSMUX_USAGE_ONLY) {
- LOGP(DMGCP, LOGL_ERROR,
- "Osmux only and no osmux offered on 0x%x\n", ENDPOINT_NUMBER(endp));
- goto error2;
- }
-
- endp->allocated = 1;
-
- /* set up RTP media parameters */
- mgcp_set_audio_info(p->cfg, &endp->bts_end.codec, tcfg->audio_payload, tcfg->audio_name);
- endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
- tcfg->audio_fmtp_extra);
- if (have_sdp)
- mgcp_parse_sdp_data(endp, &endp->net_end, p);
- else if (endp->local_options.codec)
- mgcp_set_audio_info(p->cfg, &endp->net_end.codec,
- PTYPE_UNDEFINED, endp->local_options.codec);
-
- if (p->cfg->bts_force_ptime) {
- endp->bts_end.packet_duration_ms = p->cfg->bts_force_ptime;
- endp->bts_end.force_output_ptime = 1;
- }
-
- if (setup_rtp_processing(endp) != 0)
- goto error2;
-
- /* policy CB */
- if (p->cfg->policy_cb) {
- int rc;
- rc = p->cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp),
- MGCP_ENDP_CRCX, p->trans);
- switch (rc) {
- case MGCP_POLICY_REJECT:
- LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
- ENDPOINT_NUMBER(endp));
- mgcp_release_endp(endp);
- return create_err_response(endp, 400, "CRCX", p->trans);
- break;
- case MGCP_POLICY_DEFER:
- /* stop processing */
- create_transcoder(endp);
- return NULL;
- break;
- case MGCP_POLICY_CONT:
- /* just continue */
- break;
- }
- }
-
- LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
- ENDPOINT_NUMBER(endp), endp->ci,
- endp->net_end.local_port, endp->bts_end.local_port);
- if (p->cfg->change_cb)
- p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
-
- if (endp->conn_mode & MGCP_CONN_RECV_ONLY && tcfg->keepalive_interval != 0) {
- send_dummy(endp);
- }
-
- create_transcoder(endp);
- return create_response_with_sdp(endp, "CRCX", p->trans);
-error2:
- mgcp_release_endp(endp);
- LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
- return create_err_response(endp, error_code, "CRCX", p->trans);
-}
-
-static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
-{
- struct mgcp_endpoint *endp = p->endp;
- int error_code = 500;
- int silent = 0;
- int have_sdp = 0;
- char *line;
- const char *local_options = NULL;
-
- if (p->found != 0)
- return create_err_response(NULL, 510, "MDCX", p->trans);
-
- if (endp->ci == CI_UNUSED) {
- LOGP(DMGCP, LOGL_ERROR, "Endpoint is not "
- "holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
- return create_err_response(endp, 400, "MDCX", p->trans);
- }
-
- for_each_line(line, p->save) {
- if (!mgcp_check_param(endp, line))
- continue;
-
- switch (line[0]) {
- case 'C': {
- if (verify_call_id(endp, line + 3) != 0)
- goto error3;
- break;
- }
- case 'I': {
- if (verify_ci(endp, line + 3) != 0)
- goto error3;
- break;
- }
- case 'L':
- local_options = (const char *) line + 3;
- break;
- case 'M':
- if (parse_conn_mode(line + 3, endp) != 0) {
- error_code = 517;
- goto error3;
- }
- endp->orig_mode = endp->conn_mode;
- break;
- case 'Z':
- silent = strcmp("noanswer", line + 3) == 0;
- break;
- case '\0':
- /* SDP file begins */
- have_sdp = 1;
- mgcp_parse_sdp_data(endp, &endp->net_end, p);
- /* This will exhaust p->save, so the loop will
- * terminate next time.
- */
- break;
- default:
- LOGP(DMGCP, LOGL_NOTICE, "Unhandled MGCP option: '%c'/%d on 0x%x\n",
- line[0], line[0], ENDPOINT_NUMBER(endp));
- break;
- }
- }
-
- set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
- local_options);
-
- if (!have_sdp && endp->local_options.codec)
- mgcp_set_audio_info(p->cfg, &endp->net_end.codec,
- PTYPE_UNDEFINED, endp->local_options.codec);
-
- if (setup_rtp_processing(endp) != 0)
- goto error3;
-
- /* policy CB */
- if (p->cfg->policy_cb) {
- int rc;
- rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
- MGCP_ENDP_MDCX, p->trans);
- switch (rc) {
- case MGCP_POLICY_REJECT:
- LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
- ENDPOINT_NUMBER(endp));
- if (silent)
- goto out_silent;
- return create_err_response(endp, 400, "MDCX", p->trans);
- break;
- case MGCP_POLICY_DEFER:
- /* stop processing */
- LOGP(DMGCP, LOGL_DEBUG, "endp %x MDCX defer\n",
- ENDPOINT_NUMBER(endp));
- return NULL;
- break;
- case MGCP_POLICY_CONT:
- /* just continue */
- break;
- }
- }
-
- mgcp_rtp_end_config(endp, 1, &endp->net_end);
- mgcp_rtp_end_config(endp, 1, &endp->bts_end);
-
- /* modify */
- LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
- ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
- if (p->cfg->change_cb)
- p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
-
- if (endp->conn_mode & MGCP_CONN_RECV_ONLY &&
- endp->tcfg->keepalive_interval != 0)
- send_dummy(endp);
-
- if (silent)
- goto out_silent;
-
- return create_response_with_sdp(endp, "MDCX", p->trans);
-
-error3:
- return create_err_response(endp, error_code, "MDCX", p->trans);
-
-
-out_silent:
- LOGP(DMGCP, LOGL_DEBUG, "endp %x Modify endpoint: silent exit\n",
- ENDPOINT_NUMBER(endp));
- return NULL;
-}
-
-static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
-{
- struct mgcp_endpoint *endp = p->endp;
- int error_code = 400;
- int silent = 0;
- char *line;
- char stats[1048];
-
- if (p->found != 0)
- return create_err_response(NULL, error_code, "DLCX", p->trans);
-
- if (!p->endp->allocated) {
- LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n",
- ENDPOINT_NUMBER(endp));
- return create_err_response(endp, 400, "DLCX", p->trans);
- }
-
- for_each_line(line, p->save) {
- if (!mgcp_check_param(endp, line))
- continue;
-
- switch (line[0]) {
- case 'C':
- if (verify_call_id(endp, line + 3) != 0)
- goto error3;
- break;
- case 'I':
- if (verify_ci(endp, line + 3) != 0)
- goto error3;
- break;
- case 'Z':
- silent = strcmp("noanswer", line + 3) == 0;
- break;
- default:
- LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
- line[0], line[0], ENDPOINT_NUMBER(endp));
- break;
- }
- }
-
- /* policy CB */
- if (p->cfg->policy_cb) {
- int rc;
- rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
- MGCP_ENDP_DLCX, p->trans);
- switch (rc) {
- case MGCP_POLICY_REJECT:
- LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
- ENDPOINT_NUMBER(endp));
- if (silent)
- goto out_silent;
- return create_err_response(endp, 400, "DLCX", p->trans);
- break;
- case MGCP_POLICY_DEFER:
- /* stop processing */
- delete_transcoder(endp);
- return NULL;
- break;
- case MGCP_POLICY_CONT:
- /* just continue */
- break;
- }
- }
-
- /* free the connection */
- LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
- ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
-
- /* save the statistics of the current call */
- mgcp_format_stats(endp, stats, sizeof(stats));
-
- delete_transcoder(endp);
- mgcp_release_endp(endp);
- if (p->cfg->change_cb)
- p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
-
- if (silent)
- goto out_silent;
- return create_ok_resp_with_param(endp, 250, "DLCX", p->trans, stats);
-
-error3:
- return create_err_response(endp, error_code, "DLCX", p->trans);
-
-out_silent:
- return NULL;
-}
-
-static struct msgb *handle_rsip(struct mgcp_parse_data *p)
-{
- if (p->found != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to find the endpoint.\n");
- return NULL;
- }
-
- if (p->cfg->reset_cb)
- p->cfg->reset_cb(p->endp->tcfg);
- return NULL;
-}
-
-static char extract_tone(const char *line)
-{
- const char *str = strstr(line, "D/");
- if (!str)
- return CHAR_MAX;
-
- return str[2];
-}
-
-/*
- * This can request like DTMF detection and forward, fax detection... it
- * can also request when the notification should be send and such. We don't
- * do this right now.
- */
-static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
-{
- int res = 0;
- char *line;
- char tone = CHAR_MAX;
-
- if (p->found != 0)
- return create_err_response(NULL, 400, "RQNT", p->trans);
-
- for_each_line(line, p->save) {
- switch (line[0]) {
- case 'S':
- tone = extract_tone(line);
- break;
- }
- }
-
- /* we didn't see a signal request with a tone */
- if (tone == CHAR_MAX)
- return create_ok_response(p->endp, 200, "RQNT", p->trans);
-
- if (p->cfg->rqnt_cb)
- res = p->cfg->rqnt_cb(p->endp, tone);
-
- return res == 0 ?
- create_ok_response(p->endp, 200, "RQNT", p->trans) :
- create_err_response(p->endp, res, "RQNT", p->trans);
-}
-
-static void mgcp_keepalive_timer_cb(void *_tcfg)
-{
- struct mgcp_trunk_config *tcfg = _tcfg;
- int i;
- LOGP(DMGCP, LOGL_DEBUG, "Triggered trunk %d keepalive timer.\n",
- tcfg->trunk_nr);
-
- if (tcfg->keepalive_interval <= 0)
- return;
-
- for (i = 1; i < tcfg->number_endpoints; ++i) {
- struct mgcp_endpoint *endp = &tcfg->endpoints[i];
- if (endp->conn_mode == MGCP_CONN_RECV_ONLY)
- send_dummy(endp);
- }
-
- LOGP(DMGCP, LOGL_DEBUG, "Rescheduling trunk %d keepalive timer.\n",
- tcfg->trunk_nr);
- osmo_timer_schedule(&tcfg->keepalive_timer, tcfg->keepalive_interval, 0);
-}
-
-void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval)
-{
- tcfg->keepalive_interval = interval;
- osmo_timer_setup(&tcfg->keepalive_timer, mgcp_keepalive_timer_cb, tcfg);
-
- if (interval <= 0)
- osmo_timer_del(&tcfg->keepalive_timer);
- else
- osmo_timer_schedule(&tcfg->keepalive_timer,
- tcfg->keepalive_interval, 0);
-}
-
-struct mgcp_config *mgcp_config_alloc(void)
-{
- struct mgcp_config *cfg;
-
- cfg = talloc_zero(NULL, struct mgcp_config);
- if (!cfg) {
- LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
- return NULL;
- }
-
- cfg->source_port = 2427;
- cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
- cfg->osmux_addr = talloc_strdup(cfg, "0.0.0.0");
-
- cfg->transcoder_remote_base = 4000;
-
- cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
- cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
-
- cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
- cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;
-
- cfg->get_net_downlink_format_cb = &mgcp_get_net_downlink_format_default;
-
- /* default trunk handling */
- cfg->trunk.cfg = cfg;
- cfg->trunk.trunk_nr = 0;
- cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
- cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
- cfg->trunk.audio_payload = 126;
- cfg->trunk.audio_send_ptime = 1;
- cfg->trunk.audio_send_name = 1;
- cfg->trunk.omit_rtcp = 0;
- mgcp_trunk_set_keepalive(&cfg->trunk, MGCP_KEEPALIVE_ONCE);
-
- INIT_LLIST_HEAD(&cfg->trunks);
-
- return cfg;
-}
-
-struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
-{
- struct mgcp_trunk_config *trunk;
-
- trunk = talloc_zero(cfg, struct mgcp_trunk_config);
- if (!trunk) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to allocate.\n");
- return NULL;
- }
-
- trunk->cfg = cfg;
- trunk->trunk_type = MGCP_TRUNK_E1;
- trunk->trunk_nr = nr;
- trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
- trunk->audio_payload = 126;
- trunk->audio_send_ptime = 1;
- trunk->audio_send_name = 1;
- trunk->number_endpoints = 33;
- trunk->omit_rtcp = 0;
- mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
- llist_add_tail(&trunk->entry, &cfg->trunks);
- return trunk;
-}
-
-struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
-{
- struct mgcp_trunk_config *trunk;
-
- llist_for_each_entry(trunk, &cfg->trunks, entry)
- if (trunk->trunk_nr == index)
- return trunk;
-
- return NULL;
-}
-
-static void mgcp_rtp_codec_reset(struct mgcp_rtp_codec *codec)
-{
- codec->payload_type = -1;
- talloc_free(codec->subtype_name);
- codec->subtype_name = NULL;
- talloc_free(codec->audio_name);
- codec->audio_name = NULL;
- codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
- codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
- codec->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
- codec->channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
-}
-
-static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
-{
- if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
- mgcp_free_rtp_port(end);
- end->local_port = 0;
- }
-
- end->packets = 0;
- end->octets = 0;
- end->dropped_packets = 0;
- memset(&end->addr, 0, sizeof(end->addr));
- end->rtp_port = end->rtcp_port = 0;
- end->local_alloc = -1;
- talloc_free(end->fmtp_extra);
- end->fmtp_extra = NULL;
- talloc_free(end->rtp_process_data);
- end->rtp_process_data = NULL;
-
- /* Set default values */
- end->frames_per_packet = 0; /* unknown */
- end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
- end->output_enabled = 0;
-
- mgcp_rtp_codec_reset(&end->codec);
- mgcp_rtp_codec_reset(&end->alt_codec);
-}
-
-static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
-{
- mgcp_rtp_end_reset(end);
- end->rtp.fd = -1;
- end->rtcp.fd = -1;
-}
-
-int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
-{
- int i;
-
- /* Initialize all endpoints */
- tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
- sizeof(struct mgcp_endpoint),
- tcfg->number_endpoints, "endpoints");
- if (!tcfg->endpoints)
- return -1;
-
- for (i = 0; i < tcfg->number_endpoints; ++i) {
- tcfg->endpoints[i].osmux.allocated_cid = -1;
- tcfg->endpoints[i].ci = CI_UNUSED;
- tcfg->endpoints[i].cfg = tcfg->cfg;
- tcfg->endpoints[i].tcfg = tcfg;
- mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
- mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
- mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
- mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
- }
-
- return 0;
-}
-
-void mgcp_release_endp(struct mgcp_endpoint *endp)
-{
- LOGP(DMGCP, LOGL_DEBUG, "Releasing endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
- endp->ci = CI_UNUSED;
- endp->allocated = 0;
-
- talloc_free(endp->callid);
- endp->callid = NULL;
-
- talloc_free(endp->local_options.string);
- endp->local_options.string = NULL;
- talloc_free(endp->local_options.codec);
- endp->local_options.codec = NULL;
-
- mgcp_rtp_end_reset(&endp->bts_end);
- mgcp_rtp_end_reset(&endp->net_end);
- mgcp_rtp_end_reset(&endp->trans_net);
- mgcp_rtp_end_reset(&endp->trans_bts);
- endp->type = MGCP_RTP_DEFAULT;
-
- memset(&endp->net_state, 0, sizeof(endp->net_state));
- memset(&endp->bts_state, 0, sizeof(endp->bts_state));
-
- endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
-
- if (endp->osmux.state == OSMUX_STATE_ENABLED)
- osmux_disable_endpoint(endp);
-
- /* release the circuit ID if it had been allocated */
- osmux_release_cid(endp);
-
- memset(&endp->taps, 0, sizeof(endp->taps));
-}
-
-void mgcp_initialize_endp(struct mgcp_endpoint *endp)
-{
- return mgcp_release_endp(endp);
-}
-
-static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
-{
- struct sockaddr_in addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr = cfg->transcoder_in;
- addr.sin_port = htons(2427);
- return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
- (struct sockaddr *) &addr, sizeof(addr));
-}
-
-static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
- const char *msg, const char *mode)
-{
- char buf[2096];
- int len;
- int nchars;
-
- /* hardcoded to AMR right now, we do not know the real type at this point */
- len = snprintf(buf, sizeof(buf),
- "%s 42 %x@mgw MGCP 1.0\r\n"
- "C: 4256\r\n"
- "M: %s\r\n"
- "\r\n",
- msg, endpoint, mode);
-
- if (len < 0)
- return;
-
- nchars = write_response_sdp(endp, buf + len, sizeof(buf) + len - 1, NULL);
- if (nchars < 0)
- return;
-
- len += nchars;
-
- buf[sizeof(buf) - 1] = '\0';
-
- send_trans(endp->cfg, buf, len);
-}
-
-static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
-{
- char buf[2096];
- int len;
-
- len = snprintf(buf, sizeof(buf),
- "DLCX 43 %x@mgw MGCP 1.0\r\n"
- "C: 4256\r\n"
- , endpoint);
-
- if (len < 0)
- return;
-
- buf[sizeof(buf) - 1] = '\0';
-
- send_trans(endp->cfg, buf, len);
-}
-
-static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
-{
- return write(cfg->gw_fd.bfd.fd, buf, len);
-}
-
-int mgcp_send_reset_all(struct mgcp_config *cfg)
-{
- static const char mgcp_reset[] = {
- "RSIP 1 *@mgw MGCP 1.0\r\n"
- };
-
- return send_agent(cfg, mgcp_reset, sizeof mgcp_reset -1);
-}
-
-int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
-{
- char buf[128];
- int len;
-
- len = snprintf(buf, sizeof(buf),
- "RSIP 39 %x@mgw MGCP 1.0\r\n"
- , endpoint);
- if (len < 0)
- return len;
-
- buf[sizeof(buf) - 1] = '\0';
-
- return send_agent(endp->cfg, buf, len);
-}
-
-static int setup_rtp_processing(struct mgcp_endpoint *endp)
-{
- int rc = 0;
- struct mgcp_config *cfg = endp->cfg;
-
- if (endp->type != MGCP_RTP_DEFAULT)
- return 0;
-
- if (endp->conn_mode == MGCP_CONN_LOOPBACK)
- return 0;
-
- if (endp->conn_mode & MGCP_CONN_SEND_ONLY)
- rc |= cfg->setup_rtp_processing_cb(endp, &endp->net_end, &endp->bts_end);
- else
- rc |= cfg->setup_rtp_processing_cb(endp, &endp->net_end, NULL);
-
- if (endp->conn_mode & MGCP_CONN_RECV_ONLY)
- rc |= cfg->setup_rtp_processing_cb(endp, &endp->bts_end, &endp->net_end);
- else
- rc |= cfg->setup_rtp_processing_cb(endp, &endp->bts_end, NULL);
- return rc;
-}
-
-static void create_transcoder(struct mgcp_endpoint *endp)
-{
- int port;
- int in_endp = ENDPOINT_NUMBER(endp);
- int out_endp = endp_back_channel(in_endp);
-
- if (endp->type != MGCP_RTP_TRANSCODED)
- return;
-
- send_msg(endp, in_endp, endp->trans_bts.local_port, "CRCX", "sendrecv");
- send_msg(endp, in_endp, endp->trans_bts.local_port, "MDCX", "sendrecv");
- send_msg(endp, out_endp, endp->trans_net.local_port, "CRCX", "sendrecv");
- send_msg(endp, out_endp, endp->trans_net.local_port, "MDCX", "sendrecv");
-
- port = rtp_calculate_port(in_endp, endp->cfg->transcoder_remote_base);
- endp->trans_bts.rtp_port = htons(port);
- endp->trans_bts.rtcp_port = htons(port + 1);
-
- port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
- endp->trans_net.rtp_port = htons(port);
- endp->trans_net.rtcp_port = htons(port + 1);
-}
-
-static void delete_transcoder(struct mgcp_endpoint *endp)
-{
- int in_endp = ENDPOINT_NUMBER(endp);
- int out_endp = endp_back_channel(in_endp);
-
- if (endp->type != MGCP_RTP_TRANSCODED)
- return;
-
- send_dlcx(endp, in_endp);
- send_dlcx(endp, out_endp);
-}
-
-int mgcp_reset_transcoder(struct mgcp_config *cfg)
-{
- if (!cfg->transcoder_ip)
- return 0;
-
- static const char mgcp_reset[] = {
- "RSIP 1 13@mgw MGCP 1.0\r\n"
- };
-
- return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
-}
-
-void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
-{
- uint32_t expected, jitter;
- int ploss;
- int nchars;
- mgcp_state_calc_loss(&endp->net_state, &endp->net_end,
- &expected, &ploss);
- jitter = mgcp_state_calc_jitter(&endp->net_state);
-
- nchars = snprintf(msg, size,
- "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
- endp->bts_end.packets, endp->bts_end.octets,
- endp->net_end.packets, endp->net_end.octets,
- ploss, jitter);
- if (nchars < 0 || nchars >= size)
- goto truncate;
-
- msg += nchars;
- size -= nchars;
-
- /* Error Counter */
- nchars = snprintf(msg, size,
- "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
- endp->net_state.in_stream.err_ts_counter,
- endp->net_state.out_stream.err_ts_counter,
- endp->bts_state.in_stream.err_ts_counter,
- endp->bts_state.out_stream.err_ts_counter);
- if (nchars < 0 || nchars >= size)
- goto truncate;
-
- msg += nchars;
- size -= nchars;
-
- if (endp->osmux.state == OSMUX_STATE_ENABLED) {
- snprintf(msg, size,
- "\r\nX-Osmux-ST: CR=%u, BR=%u",
- endp->osmux.stats.chunks,
- endp->osmux.stats.octets);
- }
-truncate:
- msg[size - 1] = '\0';
-}
-
-int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
- uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter)
-{
- char *line, *save;
- int rc;
-
- /* initialize with bad values */
- *ps = *os = *pr = *_or = *jitter = UINT_MAX;
- *loss = INT_MAX;
-
-
- line = strtok_r((char *) msg->l2h, "\r\n", &save);
- if (!line)
- return -1;
-
- /* this can only parse the message that is created above... */
- for_each_non_empty_line(line, save) {
- switch (line[0]) {
- case 'P':
- rc = sscanf(line, "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
- ps, os, pr, _or, loss, jitter);
- return rc == 6 ? 0 : -1;
- }
- }
-
- return -1;
-}
diff --git a/src/libmgcp/mgcp_sdp.c b/src/libmgcp/mgcp_sdp.c
deleted file mode 100644
index b64894496..000000000
--- a/src/libmgcp/mgcp_sdp.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Some SDP file parsing...
- *
- * (C) 2009-2015 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009-2014 by On-Waves
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <openbsc/mgcp.h>
-#include <openbsc/mgcp_internal.h>
-
-#include <errno.h>
-
-struct sdp_rtp_map {
- /* the type */
- int payload_type;
- /* null, static or later dynamic codec name */
- char *codec_name;
- /* A pointer to the original line for later parsing */
- char *map_line;
-
- int rate;
- int channels;
-};
-
-int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec,
- int payload_type, const char *audio_name)
-{
- int rate = codec->rate;
- int channels = codec->channels;
- char audio_codec[64];
-
- talloc_free(codec->subtype_name);
- codec->subtype_name = NULL;
- talloc_free(codec->audio_name);
- codec->audio_name = NULL;
-
- if (payload_type != PTYPE_UNDEFINED)
- codec->payload_type = payload_type;
-
- if (!audio_name) {
- switch (payload_type) {
- case 0: audio_name = "PCMU/8000/1"; break;
- case 3: audio_name = "GSM/8000/1"; break;
- case 8: audio_name = "PCMA/8000/1"; break;
- case 18: audio_name = "G729/8000/1"; break;
- default:
- /* Payload type is unknown, don't change rate and
- * channels. */
- /* TODO: return value? */
- return 0;
- }
- }
-
- if (sscanf(audio_name, "%63[^/]/%d/%d",
- audio_codec, &rate, &channels) < 1)
- return -EINVAL;
-
- codec->rate = rate;
- codec->channels = channels;
- codec->subtype_name = talloc_strdup(ctx, audio_codec);
- codec->audio_name = talloc_strdup(ctx, audio_name);
-
- if (!strcmp(audio_codec, "G729")) {
- codec->frame_duration_num = 10;
- codec->frame_duration_den = 1000;
- } else {
- codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
- codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
- }
-
- if (payload_type < 0) {
- payload_type = 96;
- if (rate == 8000 && channels == 1) {
- if (!strcmp(audio_codec, "GSM"))
- payload_type = 3;
- else if (!strcmp(audio_codec, "PCMA"))
- payload_type = 8;
- else if (!strcmp(audio_codec, "PCMU"))
- payload_type = 0;
- else if (!strcmp(audio_codec, "G729"))
- payload_type = 18;
- }
-
- codec->payload_type = payload_type;
- }
-
- if (channels != 1)
- LOGP(DMGCP, LOGL_NOTICE,
- "Channels != 1 in SDP: '%s'\n", audio_name);
-
- return 0;
-}
-
-void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used)
-{
- int i;
-
- for (i = 0; i < used; ++i) {
- switch (codecs[i].payload_type) {
- case 0:
- codecs[i].codec_name = "PCMU";
- codecs[i].rate = 8000;
- codecs[i].channels = 1;
- break;
- case 3:
- codecs[i].codec_name = "GSM";
- codecs[i].rate = 8000;
- codecs[i].channels = 1;
- break;
- case 8:
- codecs[i].codec_name = "PCMA";
- codecs[i].rate = 8000;
- codecs[i].channels = 1;
- break;
- case 18:
- codecs[i].codec_name = "G729";
- codecs[i].rate = 8000;
- codecs[i].channels = 1;
- break;
- }
- }
-}
-
-void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used, int payload, char *audio_name)
-{
- int i;
-
- for (i = 0; i < used; ++i) {
- char audio_codec[64];
- int rate = -1;
- int channels = -1;
- if (codecs[i].payload_type != payload)
- continue;
- if (sscanf(audio_name, "%63[^/]/%d/%d",
- audio_codec, &rate, &channels) < 1) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to parse '%s'\n", audio_name);
- continue;
- }
-
- codecs[i].map_line = talloc_strdup(ctx, audio_name);
- codecs[i].codec_name = talloc_strdup(ctx, audio_codec);
- codecs[i].rate = rate;
- codecs[i].channels = channels;
- return;
- }
-
- LOGP(DMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload, audio_name);
-}
-
-int is_codec_compatible(struct mgcp_endpoint *endp, struct sdp_rtp_map *codec)
-{
- char *bts_codec;
- char audio_codec[64];
-
- if (!codec->codec_name)
- return 0;
-
- /*
- * GSM, GSM/8000 and GSM/8000/1 should all be compatible.. let's go
- * by name first.
- */
- bts_codec = endp->tcfg->audio_name;
- if (sscanf(bts_codec, "%63[^/]/%*d/%*d", audio_codec) < 1)
- return 0;
-
- return strcasecmp(audio_codec, codec->codec_name) == 0;
-}
-
-int mgcp_parse_sdp_data(struct mgcp_endpoint *endp, struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p)
-{
- struct sdp_rtp_map codecs[10];
- int codecs_used = 0;
- char *line;
- int maxptime = -1;
- int i;
- int codecs_assigned = 0;
- void *tmp_ctx = talloc_new(NULL);
-
- memset(&codecs, 0, sizeof(codecs));
-
- for_each_line(line, p->save) {
- switch (line[0]) {
- case 'o':
- case 's':
- case 't':
- case 'v':
- /* skip these SDP attributes */
- break;
- case 'a': {
- int payload;
- int ptime, ptime2 = 0;
- char audio_name[64];
-
-
- if (sscanf(line, "a=rtpmap:%d %63s",
- &payload, audio_name) == 2) {
- codecs_update(tmp_ctx, codecs, codecs_used, payload, audio_name);
- } else if (sscanf(line, "a=ptime:%d-%d",
- &ptime, &ptime2) >= 1) {
- if (ptime2 > 0 && ptime2 != ptime)
- rtp->packet_duration_ms = 0;
- else
- rtp->packet_duration_ms = ptime;
- } else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
- maxptime = ptime2;
- }
- break;
- }
- case 'm': {
- int port, rc;
-
- rc = sscanf(line, "m=audio %d RTP/AVP %d %d %d %d %d %d %d %d %d %d",
- &port,
- &codecs[0].payload_type,
- &codecs[1].payload_type,
- &codecs[2].payload_type,
- &codecs[3].payload_type,
- &codecs[4].payload_type,
- &codecs[5].payload_type,
- &codecs[6].payload_type,
- &codecs[7].payload_type,
- &codecs[8].payload_type,
- &codecs[9].payload_type);
- if (rc >= 2) {
- rtp->rtp_port = htons(port);
- rtp->rtcp_port = htons(port + 1);
- codecs_used = rc - 1;
- codecs_initialize(tmp_ctx, codecs, codecs_used);
- }
- break;
- }
- case 'c': {
- char ipv4[16];
-
- if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
- inet_aton(ipv4, &rtp->addr);
- }
- break;
- }
- default:
- if (p->endp)
- LOGP(DMGCP, LOGL_NOTICE,
- "Unhandled SDP option: '%c'/%d on 0x%x\n",
- line[0], line[0], ENDPOINT_NUMBER(p->endp));
- else
- LOGP(DMGCP, LOGL_NOTICE,
- "Unhandled SDP option: '%c'/%d\n",
- line[0], line[0]);
- break;
- }
- }
-
- /* Now select the primary and alt_codec */
- for (i = 0; i < codecs_used && codecs_assigned < 2; ++i) {
- struct mgcp_rtp_codec *codec = codecs_assigned == 0 ?
- &rtp->codec : &rtp->alt_codec;
-
- if (endp->tcfg->no_audio_transcoding &&
- !is_codec_compatible(endp, &codecs[i])) {
- LOGP(DMGCP, LOGL_NOTICE, "Skipping codec %s\n",
- codecs[i].codec_name);
- continue;
- }
-
- mgcp_set_audio_info(p->cfg, codec,
- codecs[i].payload_type,
- codecs[i].map_line);
- codecs_assigned += 1;
- }
-
- if (codecs_assigned > 0) {
- /* TODO/XXX: Store this per codec and derive it on use */
- if (maxptime >= 0 && maxptime * rtp->codec.frame_duration_den >
- rtp->codec.frame_duration_num * 1500) {
- /* more than 1 frame */
- rtp->packet_duration_ms = 0;
- }
-
- LOGP(DMGCP, LOGL_NOTICE,
- "Got media info via SDP: port %d, payload %d (%s), "
- "duration %d, addr %s\n",
- ntohs(rtp->rtp_port), rtp->codec.payload_type,
- rtp->codec.subtype_name ? rtp->codec.subtype_name : "unknown",
- rtp->packet_duration_ms, inet_ntoa(rtp->addr));
- }
-
- talloc_free(tmp_ctx);
- return codecs_assigned > 0;
-}
-
diff --git a/src/libmgcp/mgcp_transcode.c b/src/libmgcp/mgcp_transcode.c
deleted file mode 100644
index f31e7aefb..000000000
--- a/src/libmgcp/mgcp_transcode.c
+++ /dev/null
@@ -1,612 +0,0 @@
-/*
- * (C) 2014 by On-Waves
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-
-#include "g711common.h"
-
-#include <openbsc/debug.h>
-#include <openbsc/mgcp.h>
-#include <openbsc/mgcp_internal.h>
-#include <openbsc/mgcp_transcode.h>
-
-#include <osmocom/core/talloc.h>
-#include <osmocom/netif/rtp.h>
-
-int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst)
-{
- struct mgcp_process_rtp_state *state = state_;
- if (dst)
- return (nsamples >= 0 ?
- nsamples / state->dst_samples_per_frame :
- 1) * state->dst_frame_size;
- else
- return (nsamples >= 0 ?
- nsamples / state->src_samples_per_frame :
- 1) * state->src_frame_size;
-}
-
-static enum audio_format get_audio_format(const struct mgcp_rtp_codec *codec)
-{
- if (codec->subtype_name) {
- if (!strcasecmp("GSM", codec->subtype_name))
- return AF_GSM;
- if (!strcasecmp("PCMA", codec->subtype_name))
- return AF_PCMA;
- if (!strcasecmp("PCMU", codec->subtype_name))
- return AF_PCMU;
-#ifdef HAVE_BCG729
- if (!strcasecmp("G729", codec->subtype_name))
- return AF_G729;
-#endif
- if (!strcasecmp("L16", codec->subtype_name))
- return AF_L16;
- }
-
- switch (codec->payload_type) {
- case 0 /* PCMU */:
- return AF_PCMU;
- case 3 /* GSM */:
- return AF_GSM;
- case 8 /* PCMA */:
- return AF_PCMA;
-#ifdef HAVE_BCG729
- case 18 /* G.729 */:
- return AF_G729;
-#endif
- case 11 /* L16 */:
- return AF_L16;
- default:
- return AF_INVALID;
- }
-}
-
-static void l16_encode(short *sample, unsigned char *buf, size_t n)
-{
- for (; n > 0; --n, ++sample, buf += 2) {
- buf[0] = sample[0] >> 8;
- buf[1] = sample[0] & 0xff;
- }
-}
-
-static void l16_decode(unsigned char *buf, short *sample, size_t n)
-{
- for (; n > 0; --n, ++sample, buf += 2)
- sample[0] = ((short)buf[0] << 8) | buf[1];
-}
-
-static void alaw_encode(short *sample, unsigned char *buf, size_t n)
-{
- for (; n > 0; --n)
- *(buf++) = s16_to_alaw(*(sample++));
-}
-
-static void alaw_decode(unsigned char *buf, short *sample, size_t n)
-{
- for (; n > 0; --n)
- *(sample++) = alaw_to_s16(*(buf++));
-}
-
-static void ulaw_encode(short *sample, unsigned char *buf, size_t n)
-{
- for (; n > 0; --n)
- *(buf++) = s16_to_ulaw(*(sample++));
-}
-
-static void ulaw_decode(unsigned char *buf, short *sample, size_t n)
-{
- for (; n > 0; --n)
- *(sample++) = ulaw_to_s16(*(buf++));
-}
-
-static int processing_state_destructor(struct mgcp_process_rtp_state *state)
-{
- switch (state->src_fmt) {
- case AF_GSM:
- if (state->src.gsm_handle)
- gsm_destroy(state->src.gsm_handle);
- break;
-#ifdef HAVE_BCG729
- case AF_G729:
- if (state->src.g729_dec)
- closeBcg729DecoderChannel(state->src.g729_dec);
- break;
-#endif
- default:
- break;
- }
- switch (state->dst_fmt) {
- case AF_GSM:
- if (state->dst.gsm_handle)
- gsm_destroy(state->dst.gsm_handle);
- break;
-#ifdef HAVE_BCG729
- case AF_G729:
- if (state->dst.g729_enc)
- closeBcg729EncoderChannel(state->dst.g729_enc);
- break;
-#endif
- default:
- break;
- }
- return 0;
-}
-
-int mgcp_transcoding_setup(struct mgcp_endpoint *endp,
- struct mgcp_rtp_end *dst_end,
- struct mgcp_rtp_end *src_end)
-{
- struct mgcp_process_rtp_state *state;
- enum audio_format src_fmt, dst_fmt;
- const struct mgcp_rtp_codec *dst_codec = &dst_end->codec;
-
- /* cleanup first */
- if (dst_end->rtp_process_data) {
- talloc_free(dst_end->rtp_process_data);
- dst_end->rtp_process_data = NULL;
- }
-
- if (!src_end)
- return 0;
-
- const struct mgcp_rtp_codec *src_codec = &src_end->codec;
-
- if (endp->tcfg->no_audio_transcoding) {
- LOGP(DMGCP, LOGL_NOTICE,
- "Transcoding disabled on endpoint 0x%x\n",
- ENDPOINT_NUMBER(endp));
- return 0;
- }
-
- src_fmt = get_audio_format(src_codec);
- dst_fmt = get_audio_format(dst_codec);
-
- LOGP(DMGCP, LOGL_ERROR,
- "Checking transcoding: %s (%d) -> %s (%d)\n",
- src_codec->subtype_name, src_codec->payload_type,
- dst_codec->subtype_name, dst_codec->payload_type);
-
- if (src_fmt == AF_INVALID || dst_fmt == AF_INVALID) {
- if (!src_codec->subtype_name || !dst_codec->subtype_name)
- /* Not enough info, do nothing */
- return 0;
-
- if (strcasecmp(src_codec->subtype_name, dst_codec->subtype_name) == 0)
- /* Nothing to do */
- return 0;
-
- LOGP(DMGCP, LOGL_ERROR,
- "Cannot transcode: %s codec not supported (%s -> %s).\n",
- src_fmt != AF_INVALID ? "destination" : "source",
- src_codec->audio_name, dst_codec->audio_name);
- return -EINVAL;
- }
-
- if (src_codec->rate && dst_codec->rate && src_codec->rate != dst_codec->rate) {
- LOGP(DMGCP, LOGL_ERROR,
- "Cannot transcode: rate conversion (%d -> %d) not supported.\n",
- src_codec->rate, dst_codec->rate);
- return -EINVAL;
- }
-
- state = talloc_zero(endp->tcfg->cfg, struct mgcp_process_rtp_state);
- talloc_set_destructor(state, processing_state_destructor);
- dst_end->rtp_process_data = state;
-
- state->src_fmt = src_fmt;
-
- switch (state->src_fmt) {
- case AF_L16:
- case AF_S16:
- state->src_frame_size = 80 * sizeof(short);
- state->src_samples_per_frame = 80;
- break;
- case AF_GSM:
- state->src_frame_size = sizeof(gsm_frame);
- state->src_samples_per_frame = 160;
- state->src.gsm_handle = gsm_create();
- if (!state->src.gsm_handle) {
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to initialize GSM decoder.\n");
- return -EINVAL;
- }
- break;
-#ifdef HAVE_BCG729
- case AF_G729:
- state->src_frame_size = 10;
- state->src_samples_per_frame = 80;
- state->src.g729_dec = initBcg729DecoderChannel();
- if (!state->src.g729_dec) {
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to initialize G.729 decoder.\n");
- return -EINVAL;
- }
- break;
-#endif
- case AF_PCMU:
- case AF_PCMA:
- state->src_frame_size = 80;
- state->src_samples_per_frame = 80;
- break;
- default:
- break;
- }
-
- state->dst_fmt = dst_fmt;
-
- switch (state->dst_fmt) {
- case AF_L16:
- case AF_S16:
- state->dst_frame_size = 80*sizeof(short);
- state->dst_samples_per_frame = 80;
- break;
- case AF_GSM:
- state->dst_frame_size = sizeof(gsm_frame);
- state->dst_samples_per_frame = 160;
- state->dst.gsm_handle = gsm_create();
- if (!state->dst.gsm_handle) {
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to initialize GSM encoder.\n");
- return -EINVAL;
- }
- break;
-#ifdef HAVE_BCG729
- case AF_G729:
- state->dst_frame_size = 10;
- state->dst_samples_per_frame = 80;
- state->dst.g729_enc = initBcg729EncoderChannel();
- if (!state->dst.g729_enc) {
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to initialize G.729 decoder.\n");
- return -EINVAL;
- }
- break;
-#endif
- case AF_PCMU:
- case AF_PCMA:
- state->dst_frame_size = 80;
- state->dst_samples_per_frame = 80;
- break;
- default:
- break;
- }
-
- if (dst_end->force_output_ptime)
- state->dst_packet_duration = mgcp_rtp_packet_duration(endp, dst_end);
-
- LOGP(DMGCP, LOGL_INFO,
- "Initialized RTP processing on: 0x%x "
- "conv: %d (%d, %d, %s) -> %d (%d, %d, %s)\n",
- ENDPOINT_NUMBER(endp),
- src_fmt, src_codec->payload_type, src_codec->rate, src_end->fmtp_extra,
- dst_fmt, dst_codec->payload_type, dst_codec->rate, dst_end->fmtp_extra);
-
- return 0;
-}
-
-void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp,
- int *payload_type,
- const char**audio_name,
- const char**fmtp_extra)
-{
- struct mgcp_process_rtp_state *state = endp->net_end.rtp_process_data;
- struct mgcp_rtp_codec *net_codec = &endp->net_end.codec;
- struct mgcp_rtp_codec *bts_codec = &endp->bts_end.codec;
-
- if (!state || net_codec->payload_type < 0) {
- *payload_type = bts_codec->payload_type;
- *audio_name = bts_codec->audio_name;
- *fmtp_extra = endp->bts_end.fmtp_extra;
- return;
- }
-
- *payload_type = net_codec->payload_type;
- *audio_name = net_codec->audio_name;
- *fmtp_extra = endp->net_end.fmtp_extra;
-}
-
-static int decode_audio(struct mgcp_process_rtp_state *state,
- uint8_t **src, size_t *nbytes)
-{
- while (*nbytes >= state->src_frame_size) {
- if (state->sample_cnt + state->src_samples_per_frame > ARRAY_SIZE(state->samples)) {
- LOGP(DMGCP, LOGL_ERROR,
- "Sample buffer too small: %zu > %zu.\n",
- state->sample_cnt + state->src_samples_per_frame,
- ARRAY_SIZE(state->samples));
- return -ENOSPC;
- }
- switch (state->src_fmt) {
- case AF_GSM:
- if (gsm_decode(state->src.gsm_handle,
- (gsm_byte *)*src, state->samples + state->sample_cnt) < 0) {
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to decode GSM.\n");
- return -EINVAL;
- }
- break;
-#ifdef HAVE_BCG729
- case AF_G729:
- bcg729Decoder(state->src.g729_dec, *src, 0, state->samples + state->sample_cnt);
- break;
-#endif
- case AF_PCMU:
- ulaw_decode(*src, state->samples + state->sample_cnt,
- state->src_samples_per_frame);
- break;
- case AF_PCMA:
- alaw_decode(*src, state->samples + state->sample_cnt,
- state->src_samples_per_frame);
- break;
- case AF_S16:
- memmove(state->samples + state->sample_cnt, *src,
- state->src_frame_size);
- break;
- case AF_L16:
- l16_decode(*src, state->samples + state->sample_cnt,
- state->src_samples_per_frame);
- break;
- default:
- break;
- }
- *src += state->src_frame_size;
- *nbytes -= state->src_frame_size;
- state->sample_cnt += state->src_samples_per_frame;
- }
- return 0;
-}
-
-static int encode_audio(struct mgcp_process_rtp_state *state,
- uint8_t *dst, size_t buf_size, size_t max_samples)
-{
- int nbytes = 0;
- size_t nsamples = 0;
- /* Encode samples into dst */
- while (nsamples + state->dst_samples_per_frame <= max_samples) {
- if (nbytes + state->dst_frame_size > buf_size) {
- if (nbytes > 0)
- break;
-
- /* Not even one frame fits into the buffer */
- LOGP(DMGCP, LOGL_INFO,
- "Encoding (RTP) buffer too small: %zu > %zu.\n",
- nbytes + state->dst_frame_size, buf_size);
- return -ENOSPC;
- }
- switch (state->dst_fmt) {
- case AF_GSM:
- gsm_encode(state->dst.gsm_handle,
- state->samples + state->sample_offs, dst);
- break;
-#ifdef HAVE_BCG729
- case AF_G729:
- bcg729Encoder(state->dst.g729_enc,
- state->samples + state->sample_offs, dst);
- break;
-#endif
- case AF_PCMU:
- ulaw_encode(state->samples + state->sample_offs, dst,
- state->src_samples_per_frame);
- break;
- case AF_PCMA:
- alaw_encode(state->samples + state->sample_offs, dst,
- state->src_samples_per_frame);
- break;
- case AF_S16:
- memmove(dst, state->samples + state->sample_offs,
- state->dst_frame_size);
- break;
- case AF_L16:
- l16_encode(state->samples + state->sample_offs, dst,
- state->src_samples_per_frame);
- break;
- default:
- break;
- }
- dst += state->dst_frame_size;
- nbytes += state->dst_frame_size;
- state->sample_offs += state->dst_samples_per_frame;
- nsamples += state->dst_samples_per_frame;
- }
- state->sample_cnt -= nsamples;
- return nbytes;
-}
-
-static struct mgcp_rtp_end *source_for_dest(struct mgcp_endpoint *endp,
- struct mgcp_rtp_end *dst_end)
-{
- if (&endp->bts_end == dst_end)
- return &endp->net_end;
- else if (&endp->net_end == dst_end)
- return &endp->bts_end;
- OSMO_ASSERT(0);
-}
-
-/*
- * With some modems we get offered multiple codecs
- * and we have selected one of them. It might not
- * be the right one and we need to detect this with
- * the first audio packets. One difficulty is that
- * we patch the rtp payload type in place, so we
- * need to discuss this.
- */
-struct mgcp_process_rtp_state *check_transcode_state(
- struct mgcp_endpoint *endp,
- struct mgcp_rtp_end *dst_end,
- struct rtp_hdr *rtp_hdr)
-{
- struct mgcp_rtp_end *src_end;
-
- /* Only deal with messages from net to bts */
- if (&endp->bts_end != dst_end)
- goto done;
-
- src_end = source_for_dest(endp, dst_end);
-
- /* Already patched */
- if (rtp_hdr->payload_type == dst_end->codec.payload_type)
- goto done;
- /* The payload we expect */
- if (rtp_hdr->payload_type == src_end->codec.payload_type)
- goto done;
- /* The matching alternate payload type? Then switch */
- if (rtp_hdr->payload_type == src_end->alt_codec.payload_type) {
- struct mgcp_config *cfg = endp->cfg;
- struct mgcp_rtp_codec tmp_codec = src_end->alt_codec;
- src_end->alt_codec = src_end->codec;
- src_end->codec = tmp_codec;
- cfg->setup_rtp_processing_cb(endp, &endp->net_end, &endp->bts_end);
- cfg->setup_rtp_processing_cb(endp, &endp->bts_end, &endp->net_end);
- }
-
-done:
- return dst_end->rtp_process_data;
-}
-
-int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp,
- struct mgcp_rtp_end *dst_end,
- char *data, int *len, int buf_size)
-{
- struct mgcp_process_rtp_state *state;
- const size_t rtp_hdr_size = sizeof(struct rtp_hdr);
- struct rtp_hdr *rtp_hdr = (struct rtp_hdr *) data;
- char *payload_data = (char *) &rtp_hdr->data[0];
- int payload_len = *len - rtp_hdr_size;
- uint8_t *src = (uint8_t *)payload_data;
- uint8_t *dst = (uint8_t *)payload_data;
- size_t nbytes = payload_len;
- size_t nsamples;
- size_t max_samples;
- uint32_t ts_no;
- int rc;
-
- state = check_transcode_state(endp, dst_end, rtp_hdr);
- if (!state)
- return 0;
-
- if (state->src_fmt == state->dst_fmt) {
- if (!state->dst_packet_duration)
- return 0;
-
- /* TODO: repackage without transcoding */
- }
-
- /* If the remaining samples do not fit into a fixed ptime,
- * a) discard them, if the next packet is much later
- * b) add silence and * send it, if the current packet is not
- * yet too late
- * c) append the sample data, if the timestamp matches exactly
- */
-
- /* TODO: check payload type (-> G.711 comfort noise) */
-
- if (payload_len > 0) {
- ts_no = ntohl(rtp_hdr->timestamp);
- if (!state->is_running) {
- state->next_seq = ntohs(rtp_hdr->sequence);
- state->next_time = ts_no;
- state->is_running = 1;
- }
-
-
- if (state->sample_cnt > 0) {
- int32_t delta = ts_no - state->next_time;
- /* TODO: check sequence? reordering? packet loss? */
-
- if (delta > state->sample_cnt) {
- /* There is a time gap between the last packet
- * and the current one. Just discard the
- * partial data that is left in the buffer.
- * TODO: This can be improved by adding silence
- * instead if the delta is small enough.
- */
- LOGP(DMGCP, LOGL_NOTICE,
- "0x%x dropping sample buffer due delta=%d sample_cnt=%zu\n",
- ENDPOINT_NUMBER(endp), delta, state->sample_cnt);
- state->sample_cnt = 0;
- state->next_time = ts_no;
- } else if (delta < 0) {
- LOGP(DMGCP, LOGL_NOTICE,
- "RTP time jumps backwards, delta = %d, "
- "discarding buffered samples\n",
- delta);
- state->sample_cnt = 0;
- state->sample_offs = 0;
- return -EAGAIN;
- }
-
- /* Make sure the samples start without offset */
- if (state->sample_offs && state->sample_cnt)
- memmove(&state->samples[0],
- &state->samples[state->sample_offs],
- state->sample_cnt *
- sizeof(state->samples[0]));
- }
-
- state->sample_offs = 0;
-
- /* Append decoded audio to samples */
- decode_audio(state, &src, &nbytes);
-
- if (nbytes > 0)
- LOGP(DMGCP, LOGL_NOTICE,
- "Skipped audio frame in RTP packet: %zu octets\n",
- nbytes);
- } else
- ts_no = state->next_time;
-
- if (state->sample_cnt < state->dst_packet_duration)
- return -EAGAIN;
-
- max_samples =
- state->dst_packet_duration ?
- state->dst_packet_duration : state->sample_cnt;
-
- nsamples = state->sample_cnt;
-
- rc = encode_audio(state, dst, buf_size, max_samples);
- /*
- * There were no samples to encode?
- * TODO: how does this work for comfort noise?
- */
- if (rc == 0)
- return -ENOMSG;
- /* Any other error during the encoding */
- if (rc < 0)
- return rc;
-
- nsamples -= state->sample_cnt;
-
- *len = rtp_hdr_size + rc;
- rtp_hdr->sequence = htons(state->next_seq);
- rtp_hdr->timestamp = htonl(ts_no);
-
- state->next_seq += 1;
- state->next_time = ts_no + nsamples;
-
- /*
- * XXX: At this point we should always have consumed
- * samples. So doing OSMO_ASSERT(nsamples > 0) and returning
- * rtp_hdr_size should be fine.
- */
- return nsamples ? rtp_hdr_size : 0;
-}
diff --git a/src/libmgcp/mgcp_vty.c b/src/libmgcp/mgcp_vty.c
deleted file mode 100644
index 51889d9a4..000000000
--- a/src/libmgcp/mgcp_vty.c
+++ /dev/null
@@ -1,1555 +0,0 @@
-/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
-/* The protocol implementation */
-
-/*
- * (C) 2009-2014 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009-2011 by On-Waves
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-
-#include <osmocom/core/talloc.h>
-
-#include <openbsc/mgcp.h>
-#include <openbsc/mgcp_internal.h>
-#include <openbsc/vty.h>
-
-#include <string.h>
-
-#define RTCP_OMIT_STR "Drop RTCP packets in both directions\n"
-#define RTP_PATCH_STR "Modify RTP packet header in both directions\n"
-#define RTP_KEEPALIVE_STR "Send dummy UDP packet to net RTP destination\n"
-
-static struct mgcp_config *g_cfg = NULL;
-
-static struct mgcp_trunk_config *find_trunk(struct mgcp_config *cfg, int nr)
-{
- struct mgcp_trunk_config *trunk;
-
- if (nr == 0)
- trunk = &cfg->trunk;
- else
- trunk = mgcp_trunk_num(cfg, nr);
-
- return trunk;
-}
-
-/*
- * vty code for mgcp below
- */
-struct cmd_node mgcp_node = {
- MGCP_NODE,
- "%s(config-mgcp)# ",
- 1,
-};
-
-struct cmd_node trunk_node = {
- TRUNK_NODE,
- "%s(config-mgcp-trunk)# ",
- 1,
-};
-
-static int config_write_mgcp(struct vty *vty)
-{
- vty_out(vty, "mgcp%s", VTY_NEWLINE);
- if (g_cfg->local_ip)
- vty_out(vty, " local ip %s%s", g_cfg->local_ip, VTY_NEWLINE);
- if (g_cfg->bts_ip && strlen(g_cfg->bts_ip) != 0)
- vty_out(vty, " bts ip %s%s", g_cfg->bts_ip, VTY_NEWLINE);
- vty_out(vty, " bind ip %s%s", g_cfg->source_addr, VTY_NEWLINE);
- vty_out(vty, " bind port %u%s", g_cfg->source_port, VTY_NEWLINE);
-
- if (g_cfg->bts_ports.mode == PORT_ALLOC_STATIC)
- vty_out(vty, " rtp bts-base %u%s", g_cfg->bts_ports.base_port, VTY_NEWLINE);
- else
- vty_out(vty, " rtp bts-range %u %u%s",
- g_cfg->bts_ports.range_start, g_cfg->bts_ports.range_end, VTY_NEWLINE);
- if (g_cfg->bts_ports.bind_addr)
- vty_out(vty, " rtp bts-bind-ip %s%s", g_cfg->bts_ports.bind_addr, VTY_NEWLINE);
-
- if (g_cfg->net_ports.mode == PORT_ALLOC_STATIC)
- vty_out(vty, " rtp net-base %u%s", g_cfg->net_ports.base_port, VTY_NEWLINE);
- else
- vty_out(vty, " rtp net-range %u %u%s",
- g_cfg->net_ports.range_start, g_cfg->net_ports.range_end, VTY_NEWLINE);
- if (g_cfg->net_ports.bind_addr)
- vty_out(vty, " rtp net-bind-ip %s%s", g_cfg->net_ports.bind_addr, VTY_NEWLINE);
-
- vty_out(vty, " rtp ip-dscp %d%s", g_cfg->endp_dscp, VTY_NEWLINE);
- if (g_cfg->trunk.keepalive_interval == MGCP_KEEPALIVE_ONCE)
- vty_out(vty, " rtp keep-alive once%s", VTY_NEWLINE);
- else if (g_cfg->trunk.keepalive_interval)
- vty_out(vty, " rtp keep-alive %d%s",
- g_cfg->trunk.keepalive_interval, VTY_NEWLINE);
- else
- vty_out(vty, " no rtp keep-alive%s", VTY_NEWLINE);
-
- if (g_cfg->trunk.omit_rtcp)
- vty_out(vty, " rtcp-omit%s", VTY_NEWLINE);
- else
- vty_out(vty, " no rtcp-omit%s", VTY_NEWLINE);
- if (g_cfg->trunk.force_constant_ssrc || g_cfg->trunk.force_aligned_timing) {
- vty_out(vty, " %srtp-patch ssrc%s",
- g_cfg->trunk.force_constant_ssrc ? "" : "no ", VTY_NEWLINE);
- vty_out(vty, " %srtp-patch timestamp%s",
- g_cfg->trunk.force_aligned_timing ? "" : "no ", VTY_NEWLINE);
- } else
- vty_out(vty, " no rtp-patch%s", VTY_NEWLINE);
- if (g_cfg->trunk.audio_payload != -1)
- vty_out(vty, " sdp audio-payload number %d%s",
- g_cfg->trunk.audio_payload, VTY_NEWLINE);
- if (g_cfg->trunk.audio_name)
- vty_out(vty, " sdp audio-payload name %s%s",
- g_cfg->trunk.audio_name, VTY_NEWLINE);
- if (g_cfg->trunk.audio_fmtp_extra)
- vty_out(vty, " sdp audio fmtp-extra %s%s",
- g_cfg->trunk.audio_fmtp_extra, VTY_NEWLINE);
- vty_out(vty, " %ssdp audio-payload send-ptime%s",
- g_cfg->trunk.audio_send_ptime ? "" : "no ", VTY_NEWLINE);
- vty_out(vty, " %ssdp audio-payload send-name%s",
- g_cfg->trunk.audio_send_name ? "" : "no ", VTY_NEWLINE);
- vty_out(vty, " loop %u%s", !!g_cfg->trunk.audio_loop, VTY_NEWLINE);
- vty_out(vty, " number endpoints %u%s", g_cfg->trunk.number_endpoints - 1, VTY_NEWLINE);
- vty_out(vty, " %sallow-transcoding%s",
- g_cfg->trunk.no_audio_transcoding ? "no " : "", VTY_NEWLINE);
- if (g_cfg->call_agent_addr)
- vty_out(vty, " call-agent ip %s%s", g_cfg->call_agent_addr, VTY_NEWLINE);
- if (g_cfg->transcoder_ip)
- vty_out(vty, " transcoder-mgw %s%s", g_cfg->transcoder_ip, VTY_NEWLINE);
-
- if (g_cfg->transcoder_ports.mode == PORT_ALLOC_STATIC)
- vty_out(vty, " rtp transcoder-base %u%s", g_cfg->transcoder_ports.base_port, VTY_NEWLINE);
- else
- vty_out(vty, " rtp transcoder-range %u %u%s",
- g_cfg->transcoder_ports.range_start, g_cfg->transcoder_ports.range_end, VTY_NEWLINE);
- if (g_cfg->bts_force_ptime > 0)
- vty_out(vty, " rtp force-ptime %d%s", g_cfg->bts_force_ptime, VTY_NEWLINE);
- vty_out(vty, " transcoder-remote-base %u%s", g_cfg->transcoder_remote_base, VTY_NEWLINE);
-
- switch (g_cfg->osmux) {
- case OSMUX_USAGE_ON:
- vty_out(vty, " osmux on%s", VTY_NEWLINE);
- break;
- case OSMUX_USAGE_ONLY:
- vty_out(vty, " osmux only%s", VTY_NEWLINE);
- break;
- case OSMUX_USAGE_OFF:
- default:
- vty_out(vty, " osmux off%s", VTY_NEWLINE);
- break;
- }
- if (g_cfg->osmux) {
- vty_out(vty, " osmux bind-ip %s%s",
- g_cfg->osmux_addr, VTY_NEWLINE);
- vty_out(vty, " osmux batch-factor %d%s",
- g_cfg->osmux_batch, VTY_NEWLINE);
- vty_out(vty, " osmux batch-size %u%s",
- g_cfg->osmux_batch_size, VTY_NEWLINE);
- vty_out(vty, " osmux port %u%s",
- g_cfg->osmux_port, VTY_NEWLINE);
- vty_out(vty, " osmux dummy %s%s",
- g_cfg->osmux_dummy ? "on" : "off", VTY_NEWLINE);
- }
- return CMD_SUCCESS;
-}
-
-static void dump_rtp_end(const char *end_name, struct vty *vty,
- struct mgcp_rtp_state *state, struct mgcp_rtp_end *end)
-{
- struct mgcp_rtp_codec *codec = &end->codec;
-
- vty_out(vty,
- " %s%s"
- " Timestamp Errs: %d->%d%s"
- " Dropped Packets: %d%s"
- " Payload Type: %d Rate: %u Channels: %d %s"
- " Frame Duration: %u Frame Denominator: %u%s"
- " FPP: %d Packet Duration: %u%s"
- " FMTP-Extra: %s Audio-Name: %s Sub-Type: %s%s"
- " Output-Enabled: %d Force-PTIME: %d%s",
- end_name, VTY_NEWLINE,
- state->in_stream.err_ts_counter,
- state->out_stream.err_ts_counter, VTY_NEWLINE,
- end->dropped_packets, VTY_NEWLINE,
- codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
- codec->frame_duration_num, codec->frame_duration_den, VTY_NEWLINE,
- end->frames_per_packet, end->packet_duration_ms, VTY_NEWLINE,
- end->fmtp_extra, codec->audio_name, codec->subtype_name, VTY_NEWLINE,
- end->output_enabled, end->force_output_ptime, VTY_NEWLINE);
-}
-
-static void dump_trunk(struct vty *vty, struct mgcp_trunk_config *cfg, int verbose)
-{
- int i;
-
- vty_out(vty, "%s trunk nr %d with %d endpoints:%s",
- cfg->trunk_type == MGCP_TRUNK_VIRTUAL ? "Virtual" : "E1",
- cfg->trunk_nr, cfg->number_endpoints - 1, VTY_NEWLINE);
-
- if (!cfg->endpoints) {
- vty_out(vty, "No endpoints allocated yet.%s", VTY_NEWLINE);
- return;
- }
-
- for (i = 1; i < cfg->number_endpoints; ++i) {
- struct mgcp_endpoint *endp = &cfg->endpoints[i];
- vty_out(vty,
- " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u on %s "
- "traffic received bts: %u remote: %u transcoder: %u/%u%s",
- i, endp->ci,
- ntohs(endp->net_end.rtp_port), ntohs(endp->net_end.rtcp_port),
- ntohs(endp->bts_end.rtp_port), ntohs(endp->bts_end.rtcp_port),
- inet_ntoa(endp->bts_end.addr),
- endp->bts_end.packets, endp->net_end.packets,
- endp->trans_net.packets, endp->trans_bts.packets,
- VTY_NEWLINE);
-
- if (verbose && endp->allocated) {
- dump_rtp_end("Net->BTS", vty, &endp->bts_state, &endp->bts_end);
- dump_rtp_end("BTS->Net", vty, &endp->net_state, &endp->net_end);
- }
- }
-}
-
-DEFUN(show_mcgp, show_mgcp_cmd,
- "show mgcp [stats]",
- SHOW_STR
- "Display information about the MGCP Media Gateway\n"
- "Include Statistics\n")
-{
- struct mgcp_trunk_config *trunk;
- int show_stats = argc >= 1;
-
- dump_trunk(vty, &g_cfg->trunk, show_stats);
-
- llist_for_each_entry(trunk, &g_cfg->trunks, entry)
- dump_trunk(vty, trunk, show_stats);
-
- if (g_cfg->osmux)
- vty_out(vty, "Osmux used CID: %d%s", osmux_used_cid(), VTY_NEWLINE);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp,
- cfg_mgcp_cmd,
- "mgcp",
- "Configure the MGCP")
-{
- vty->node = MGCP_NODE;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_local_ip,
- cfg_mgcp_local_ip_cmd,
- "local ip A.B.C.D",
- "Local options for the SDP record\n"
- IP_STR
- "IPv4 Address to use in SDP record\n")
-{
- osmo_talloc_replace_string(g_cfg, &g_cfg->local_ip, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_bts_ip,
- cfg_mgcp_bts_ip_cmd,
- "bts ip A.B.C.D",
- "BTS Audio source/destination options\n"
- IP_STR
- "IPv4 Address of the BTS\n")
-{
- osmo_talloc_replace_string(g_cfg, &g_cfg->bts_ip, argv[0]);
- inet_aton(g_cfg->bts_ip, &g_cfg->bts_in);
- return CMD_SUCCESS;
-}
-
-#define BIND_STR "Listen/Bind related socket option\n"
-DEFUN(cfg_mgcp_bind_ip,
- cfg_mgcp_bind_ip_cmd,
- "bind ip A.B.C.D",
- BIND_STR
- IP_STR
- "IPv4 Address to bind to\n")
-{
- osmo_talloc_replace_string(g_cfg, &g_cfg->source_addr, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_bind_port,
- cfg_mgcp_bind_port_cmd,
- "bind port <0-65534>",
- BIND_STR
- "Port information\n"
- "UDP port to listen for MGCP messages\n")
-{
- unsigned int port = atoi(argv[0]);
- g_cfg->source_port = port;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_bind_early,
- cfg_mgcp_bind_early_cmd,
- "bind early (0|1)",
- BIND_STR
- "Bind local ports on start up\n"
- "Bind on demand\n" "Bind on startup\n")
-{
- vty_out(vty, "bind early is deprecated, remove it from the config.\n");
- return CMD_WARNING;
-}
-
-static void parse_base(struct mgcp_port_range *range, const char **argv)
-{
- unsigned int port = atoi(argv[0]);
- range->mode = PORT_ALLOC_STATIC;
- range->base_port = port;
-}
-
-static void parse_range(struct mgcp_port_range *range, const char **argv)
-{
- range->mode = PORT_ALLOC_DYNAMIC;
- range->range_start = atoi(argv[0]);
- range->range_end = atoi(argv[1]);
- range->last_port = g_cfg->bts_ports.range_start;
-}
-
-
-#define RTP_STR "RTP configuration\n"
-#define BTS_START_STR "First UDP port allocated for the BTS side\n"
-#define NET_START_STR "First UDP port allocated for the NET side\n"
-#define UDP_PORT_STR "UDP Port number\n"
-DEFUN(cfg_mgcp_rtp_bts_base_port,
- cfg_mgcp_rtp_bts_base_port_cmd,
- "rtp bts-base <0-65534>",
- RTP_STR
- BTS_START_STR
- UDP_PORT_STR)
-{
- parse_base(&g_cfg->bts_ports, argv);
- return CMD_SUCCESS;
-}
-
-#define RANGE_START_STR "Start of the range of ports\n"
-#define RANGE_END_STR "End of the range of ports\n"
-DEFUN(cfg_mgcp_rtp_bts_range,
- cfg_mgcp_rtp_bts_range_cmd,
- "rtp bts-range <0-65534> <0-65534>",
- RTP_STR "Range of ports to use for the BTS side\n"
- RANGE_START_STR RANGE_END_STR)
-{
- parse_range(&g_cfg->bts_ports, argv);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_rtp_net_range,
- cfg_mgcp_rtp_net_range_cmd,
- "rtp net-range <0-65534> <0-65534>",
- RTP_STR "Range of ports to use for the NET side\n"
- RANGE_START_STR RANGE_END_STR)
-{
- parse_range(&g_cfg->net_ports, argv);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_rtp_net_base_port,
- cfg_mgcp_rtp_net_base_port_cmd,
- "rtp net-base <0-65534>",
- RTP_STR NET_START_STR UDP_PORT_STR)
-{
- parse_base(&g_cfg->net_ports, argv);
- return CMD_SUCCESS;
-}
-
-ALIAS_DEPRECATED(cfg_mgcp_rtp_bts_base_port, cfg_mgcp_rtp_base_port_cmd,
- "rtp base <0-65534>",
- RTP_STR BTS_START_STR UDP_PORT_STR)
-
-DEFUN(cfg_mgcp_rtp_transcoder_range,
- cfg_mgcp_rtp_transcoder_range_cmd,
- "rtp transcoder-range <0-65534> <0-65534>",
- RTP_STR "Range of ports to use for the Transcoder\n"
- RANGE_START_STR RANGE_END_STR)
-{
- parse_range(&g_cfg->transcoder_ports, argv);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_rtp_transcoder_base,
- cfg_mgcp_rtp_transcoder_base_cmd,
- "rtp transcoder-base <0-65534>",
- RTP_STR "First UDP port allocated for the Transcoder side\n"
- UDP_PORT_STR)
-{
- parse_base(&g_cfg->transcoder_ports, argv);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_rtp_bts_bind_ip,
- cfg_mgcp_rtp_bts_bind_ip_cmd,
- "rtp bts-bind-ip A.B.C.D",
- RTP_STR "Bind endpoints facing the BTS\n" "Address to bind to\n")
-{
- osmo_talloc_replace_string(g_cfg, &g_cfg->bts_ports.bind_addr, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_rtp_no_bts_bind_ip,
- cfg_mgcp_rtp_no_bts_bind_ip_cmd,
- "no rtp bts-bind-ip",
- NO_STR RTP_STR "Bind endpoints facing the BTS\n" "Address to bind to\n")
-{
- talloc_free(g_cfg->bts_ports.bind_addr);
- g_cfg->bts_ports.bind_addr = NULL;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_rtp_net_bind_ip,
- cfg_mgcp_rtp_net_bind_ip_cmd,
- "rtp net-bind-ip A.B.C.D",
- RTP_STR "Bind endpoints facing the Network\n" "Address to bind to\n")
-{
- osmo_talloc_replace_string(g_cfg, &g_cfg->net_ports.bind_addr, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_rtp_no_net_bind_ip,
- cfg_mgcp_rtp_no_net_bind_ip_cmd,
- "no rtp net-bind-ip",
- NO_STR RTP_STR "Bind endpoints facing the Network\n" "Address to bind to\n")
-{
- talloc_free(g_cfg->net_ports.bind_addr);
- g_cfg->net_ports.bind_addr = NULL;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_rtp_ip_dscp,
- cfg_mgcp_rtp_ip_dscp_cmd,
- "rtp ip-dscp <0-255>",
- RTP_STR
- "Apply IP_TOS to the audio stream (including Osmux)\n" "The DSCP value\n")
-{
- int dscp = atoi(argv[0]);
- g_cfg->endp_dscp = dscp;
- return CMD_SUCCESS;
-}
-
-ALIAS_DEPRECATED(cfg_mgcp_rtp_ip_dscp, cfg_mgcp_rtp_ip_tos_cmd,
- "rtp ip-tos <0-255>",
- RTP_STR
- "Apply IP_TOS to the audio stream\n" "The DSCP value\n")
-
-#define FORCE_PTIME_STR "Force a fixed ptime for packets sent to the BTS"
-DEFUN(cfg_mgcp_rtp_force_ptime,
- cfg_mgcp_rtp_force_ptime_cmd,
- "rtp force-ptime (10|20|40)",
- RTP_STR FORCE_PTIME_STR
- "The required ptime (packet duration) in ms\n"
- "10 ms\n20 ms\n40 ms\n")
-{
- g_cfg->bts_force_ptime = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_no_rtp_force_ptime,
- cfg_mgcp_no_rtp_force_ptime_cmd,
- "no rtp force-ptime",
- NO_STR RTP_STR FORCE_PTIME_STR)
-{
- g_cfg->bts_force_ptime = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_sdp_fmtp_extra,
- cfg_mgcp_sdp_fmtp_extra_cmd,
- "sdp audio fmtp-extra .NAME",
- "Add extra fmtp for the SDP file\n" "Audio\n" "Fmtp-extra\n"
- "Extra Information\n")
-{
- char *txt = argv_concat(argv, argc, 0);
- if (!txt)
- return CMD_WARNING;
-
- osmo_talloc_replace_string(g_cfg, &g_cfg->trunk.audio_fmtp_extra, txt);
- talloc_free(txt);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_allow_transcoding,
- cfg_mgcp_allow_transcoding_cmd,
- "allow-transcoding",
- "Allow transcoding\n")
-{
- g_cfg->trunk.no_audio_transcoding = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_no_allow_transcoding,
- cfg_mgcp_no_allow_transcoding_cmd,
- "no allow-transcoding",
- NO_STR "Allow transcoding\n")
-{
- g_cfg->trunk.no_audio_transcoding = 1;
- return CMD_SUCCESS;
-}
-
-#define SDP_STR "SDP File related options\n"
-#define AUDIO_STR "Audio payload options\n"
-DEFUN(cfg_mgcp_sdp_payload_number,
- cfg_mgcp_sdp_payload_number_cmd,
- "sdp audio-payload number <0-255>",
- SDP_STR AUDIO_STR
- "Number\n" "Payload number\n")
-{
- unsigned int payload = atoi(argv[0]);
- g_cfg->trunk.audio_payload = payload;
- return CMD_SUCCESS;
-}
-
-ALIAS_DEPRECATED(cfg_mgcp_sdp_payload_number, cfg_mgcp_sdp_payload_number_cmd_old,
- "sdp audio payload number <0-255>",
- SDP_STR AUDIO_STR AUDIO_STR "Number\n" "Payload number\n")
-
-
-DEFUN(cfg_mgcp_sdp_payload_name,
- cfg_mgcp_sdp_payload_name_cmd,
- "sdp audio-payload name NAME",
- SDP_STR AUDIO_STR "Name\n" "Payload name\n")
-{
- osmo_talloc_replace_string(g_cfg, &g_cfg->trunk.audio_name, argv[0]);
- return CMD_SUCCESS;
-}
-
-ALIAS_DEPRECATED(cfg_mgcp_sdp_payload_name, cfg_mgcp_sdp_payload_name_cmd_old,
- "sdp audio payload name NAME",
- SDP_STR AUDIO_STR AUDIO_STR "Name\n" "Payload name\n")
-
-DEFUN(cfg_mgcp_sdp_payload_send_ptime,
- cfg_mgcp_sdp_payload_send_ptime_cmd,
- "sdp audio-payload send-ptime",
- SDP_STR AUDIO_STR
- "Send SDP ptime (packet duration) attribute\n")
-{
- g_cfg->trunk.audio_send_ptime = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_no_sdp_payload_send_ptime,
- cfg_mgcp_no_sdp_payload_send_ptime_cmd,
- "no sdp audio-payload send-ptime",
- NO_STR SDP_STR AUDIO_STR
- "Send SDP ptime (packet duration) attribute\n")
-{
- g_cfg->trunk.audio_send_ptime = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_sdp_payload_send_name,
- cfg_mgcp_sdp_payload_send_name_cmd,
- "sdp audio-payload send-name",
- SDP_STR AUDIO_STR
- "Send SDP rtpmap with the audio name\n")
-{
- g_cfg->trunk.audio_send_name = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_no_sdp_payload_send_name,
- cfg_mgcp_no_sdp_payload_send_name_cmd,
- "no sdp audio-payload send-name",
- NO_STR SDP_STR AUDIO_STR
- "Send SDP rtpmap with the audio name\n")
-{
- g_cfg->trunk.audio_send_name = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_loop,
- cfg_mgcp_loop_cmd,
- "loop (0|1)",
- "Loop audio for all endpoints on main trunk\n"
- "Don't Loop\n" "Loop\n")
-{
- if (g_cfg->osmux) {
- vty_out(vty, "Cannot use `loop' with `osmux'.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- g_cfg->trunk.audio_loop = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_force_realloc,
- cfg_mgcp_force_realloc_cmd,
- "force-realloc (0|1)",
- "Force endpoint reallocation when the endpoint is still seized\n"
- "Don't force reallocation\n" "force reallocation\n")
-{
- g_cfg->trunk.force_realloc = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_number_endp,
- cfg_mgcp_number_endp_cmd,
- "number endpoints <0-65534>",
- "Number options\n" "Endpoints available\n" "Number endpoints\n")
-{
- /* + 1 as we start counting at one */
- g_cfg->trunk.number_endpoints = atoi(argv[0]) + 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_omit_rtcp,
- cfg_mgcp_omit_rtcp_cmd,
- "rtcp-omit",
- RTCP_OMIT_STR)
-{
- g_cfg->trunk.omit_rtcp = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_no_omit_rtcp,
- cfg_mgcp_no_omit_rtcp_cmd,
- "no rtcp-omit",
- NO_STR RTCP_OMIT_STR)
-{
- g_cfg->trunk.omit_rtcp = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_patch_rtp_ssrc,
- cfg_mgcp_patch_rtp_ssrc_cmd,
- "rtp-patch ssrc",
- RTP_PATCH_STR
- "Force a fixed SSRC\n"
- )
-{
- g_cfg->trunk.force_constant_ssrc = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_no_patch_rtp_ssrc,
- cfg_mgcp_no_patch_rtp_ssrc_cmd,
- "no rtp-patch ssrc",
- NO_STR RTP_PATCH_STR
- "Force a fixed SSRC\n"
- )
-{
- g_cfg->trunk.force_constant_ssrc = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_patch_rtp_ts,
- cfg_mgcp_patch_rtp_ts_cmd,
- "rtp-patch timestamp",
- RTP_PATCH_STR
- "Adjust RTP timestamp\n"
- )
-{
- g_cfg->trunk.force_aligned_timing = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_no_patch_rtp_ts,
- cfg_mgcp_no_patch_rtp_ts_cmd,
- "no rtp-patch timestamp",
- NO_STR RTP_PATCH_STR
- "Adjust RTP timestamp\n"
- )
-{
- g_cfg->trunk.force_aligned_timing = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_no_patch_rtp,
- cfg_mgcp_no_patch_rtp_cmd,
- "no rtp-patch",
- NO_STR RTP_PATCH_STR)
-{
- g_cfg->trunk.force_constant_ssrc = 0;
- g_cfg->trunk.force_aligned_timing = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_rtp_keepalive,
- cfg_mgcp_rtp_keepalive_cmd,
- "rtp keep-alive <1-120>",
- RTP_STR RTP_KEEPALIVE_STR
- "Keep alive interval in secs\n"
- )
-{
- mgcp_trunk_set_keepalive(&g_cfg->trunk, atoi(argv[0]));
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_rtp_keepalive_once,
- cfg_mgcp_rtp_keepalive_once_cmd,
- "rtp keep-alive once",
- RTP_STR RTP_KEEPALIVE_STR
- "Send dummy packet only once after CRCX/MDCX\n"
- )
-{
- mgcp_trunk_set_keepalive(&g_cfg->trunk, MGCP_KEEPALIVE_ONCE);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_no_rtp_keepalive,
- cfg_mgcp_no_rtp_keepalive_cmd,
- "no rtp keep-alive",
- NO_STR RTP_STR RTP_KEEPALIVE_STR
- )
-{
- mgcp_trunk_set_keepalive(&g_cfg->trunk, 0);
- return CMD_SUCCESS;
-}
-
-
-
-#define CALL_AGENT_STR "Callagent information\n"
-DEFUN(cfg_mgcp_agent_addr,
- cfg_mgcp_agent_addr_cmd,
- "call-agent ip A.B.C.D",
- CALL_AGENT_STR IP_STR
- "IPv4 Address of the callagent\n")
-{
- osmo_talloc_replace_string(g_cfg, &g_cfg->call_agent_addr, argv[0]);
- return CMD_SUCCESS;
-}
-
-ALIAS_DEPRECATED(cfg_mgcp_agent_addr, cfg_mgcp_agent_addr_cmd_old,
- "call agent ip A.B.C.D",
- CALL_AGENT_STR CALL_AGENT_STR IP_STR
- "IPv4 Address of the callagent\n")
-
-
-DEFUN(cfg_mgcp_transcoder,
- cfg_mgcp_transcoder_cmd,
- "transcoder-mgw A.B.C.D",
- "Use a MGW to detranscoder RTP\n"
- "The IP address of the MGW")
-{
- osmo_talloc_replace_string(g_cfg, &g_cfg->transcoder_ip, argv[0]);
- inet_aton(g_cfg->transcoder_ip, &g_cfg->transcoder_in);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_no_transcoder,
- cfg_mgcp_no_transcoder_cmd,
- "no transcoder-mgw",
- NO_STR "Disable the transcoding\n")
-{
- if (g_cfg->transcoder_ip) {
- LOGP(DMGCP, LOGL_NOTICE, "Disabling transcoding on future calls.\n");
- talloc_free(g_cfg->transcoder_ip);
- g_cfg->transcoder_ip = NULL;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_transcoder_remote_base,
- cfg_mgcp_transcoder_remote_base_cmd,
- "transcoder-remote-base <0-65534>",
- "Set the base port for the transcoder\n" "The RTP base port on the transcoder")
-{
- g_cfg->transcoder_remote_base = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_trunk, cfg_mgcp_trunk_cmd,
- "trunk <1-64>",
- "Configure a SS7 trunk\n" "Trunk Nr\n")
-{
- struct mgcp_trunk_config *trunk;
- int index = atoi(argv[0]);
-
- trunk = mgcp_trunk_num(g_cfg, index);
- if (!trunk)
- trunk = mgcp_trunk_alloc(g_cfg, index);
-
- if (!trunk) {
- vty_out(vty, "%%Unable to allocate trunk %u.%s",
- index, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- vty->node = TRUNK_NODE;
- vty->index = trunk;
- return CMD_SUCCESS;
-}
-
-static int config_write_trunk(struct vty *vty)
-{
- struct mgcp_trunk_config *trunk;
-
- llist_for_each_entry(trunk, &g_cfg->trunks, entry) {
- vty_out(vty, " trunk %d%s", trunk->trunk_nr, VTY_NEWLINE);
- vty_out(vty, " sdp audio-payload number %d%s",
- trunk->audio_payload, VTY_NEWLINE);
- vty_out(vty, " sdp audio-payload name %s%s",
- trunk->audio_name, VTY_NEWLINE);
- vty_out(vty, " %ssdp audio-payload send-ptime%s",
- trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE);
- vty_out(vty, " %ssdp audio-payload send-name%s",
- trunk->audio_send_name ? "" : "no ", VTY_NEWLINE);
-
- if (trunk->keepalive_interval == MGCP_KEEPALIVE_ONCE)
- vty_out(vty, " rtp keep-alive once%s", VTY_NEWLINE);
- else if (trunk->keepalive_interval)
- vty_out(vty, " rtp keep-alive %d%s",
- trunk->keepalive_interval, VTY_NEWLINE);
- else
- vty_out(vty, " no rtp keep-alive%s", VTY_NEWLINE);
- vty_out(vty, " loop %d%s",
- trunk->audio_loop, VTY_NEWLINE);
- vty_out(vty, " force-realloc %d%s",
- trunk->force_realloc, VTY_NEWLINE);
- if (trunk->omit_rtcp)
- vty_out(vty, " rtcp-omit%s", VTY_NEWLINE);
- else
- vty_out(vty, " no rtcp-omit%s", VTY_NEWLINE);
- if (trunk->force_constant_ssrc || trunk->force_aligned_timing) {
- vty_out(vty, " %srtp-patch ssrc%s",
- trunk->force_constant_ssrc ? "" : "no ", VTY_NEWLINE);
- vty_out(vty, " %srtp-patch timestamp%s",
- trunk->force_aligned_timing ? "" : "no ", VTY_NEWLINE);
- } else
- vty_out(vty, " no rtp-patch%s", VTY_NEWLINE);
- if (trunk->audio_fmtp_extra)
- vty_out(vty, " sdp audio fmtp-extra %s%s",
- trunk->audio_fmtp_extra, VTY_NEWLINE);
- vty_out(vty, " %sallow-transcoding%s",
- trunk->no_audio_transcoding ? "no " : "", VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_sdp_fmtp_extra,
- cfg_trunk_sdp_fmtp_extra_cmd,
- "sdp audio fmtp-extra .NAME",
- "Add extra fmtp for the SDP file\n" "Audio\n" "Fmtp-extra\n"
- "Extra Information\n")
-{
- struct mgcp_trunk_config *trunk = vty->index;
- char *txt = argv_concat(argv, argc, 0);
- if (!txt)
- return CMD_WARNING;
-
- osmo_talloc_replace_string(g_cfg, &trunk->audio_fmtp_extra, txt);
- talloc_free(txt);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_payload_number,
- cfg_trunk_payload_number_cmd,
- "sdp audio-payload number <0-255>",
- SDP_STR AUDIO_STR "Number\n" "Payload Number\n")
-{
- struct mgcp_trunk_config *trunk = vty->index;
- unsigned int payload = atoi(argv[0]);
-
- trunk->audio_payload = payload;
- return CMD_SUCCESS;
-}
-
-ALIAS_DEPRECATED(cfg_trunk_payload_number, cfg_trunk_payload_number_cmd_old,
- "sdp audio payload number <0-255>",
- SDP_STR AUDIO_STR AUDIO_STR "Number\n" "Payload Number\n")
-
-DEFUN(cfg_trunk_payload_name,
- cfg_trunk_payload_name_cmd,
- "sdp audio-payload name NAME",
- SDP_STR AUDIO_STR "Payload\n" "Payload Name\n")
-{
- struct mgcp_trunk_config *trunk = vty->index;
-
- osmo_talloc_replace_string(g_cfg, &trunk->audio_name, argv[0]);
- return CMD_SUCCESS;
-}
-
-ALIAS_DEPRECATED(cfg_trunk_payload_name, cfg_trunk_payload_name_cmd_old,
- "sdp audio payload name NAME",
- SDP_STR AUDIO_STR AUDIO_STR "Payload\n" "Payload Name\n")
-
-
-DEFUN(cfg_trunk_loop,
- cfg_trunk_loop_cmd,
- "loop (0|1)",
- "Loop audio for all endpoints on this trunk\n"
- "Don't Loop\n" "Loop\n")
-{
- struct mgcp_trunk_config *trunk = vty->index;
-
- if (g_cfg->osmux) {
- vty_out(vty, "Cannot use `loop' with `osmux'.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- trunk->audio_loop = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_sdp_payload_send_ptime,
- cfg_trunk_sdp_payload_send_ptime_cmd,
- "sdp audio-payload send-ptime",
- SDP_STR AUDIO_STR
- "Send SDP ptime (packet duration) attribute\n")
-{
- struct mgcp_trunk_config *trunk = vty->index;
- trunk->audio_send_ptime = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_no_sdp_payload_send_ptime,
- cfg_trunk_no_sdp_payload_send_ptime_cmd,
- "no sdp audio-payload send-ptime",
- NO_STR SDP_STR AUDIO_STR
- "Send SDP ptime (packet duration) attribute\n")
-{
- struct mgcp_trunk_config *trunk = vty->index;
- trunk->audio_send_ptime = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_sdp_payload_send_name,
- cfg_trunk_sdp_payload_send_name_cmd,
- "sdp audio-payload send-name",
- SDP_STR AUDIO_STR
- "Send SDP rtpmap with the audio name\n")
-{
- struct mgcp_trunk_config *trunk = vty->index;
- trunk->audio_send_name = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_no_sdp_payload_send_name,
- cfg_trunk_no_sdp_payload_send_name_cmd,
- "no sdp audio-payload send-name",
- NO_STR SDP_STR AUDIO_STR
- "Send SDP rtpmap with the audio name\n")
-{
- struct mgcp_trunk_config *trunk = vty->index;
- trunk->audio_send_name = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_omit_rtcp,
- cfg_trunk_omit_rtcp_cmd,
- "rtcp-omit",
- RTCP_OMIT_STR)
-{
- struct mgcp_trunk_config *trunk = vty->index;
- trunk->omit_rtcp = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_no_omit_rtcp,
- cfg_trunk_no_omit_rtcp_cmd,
- "no rtcp-omit",
- NO_STR RTCP_OMIT_STR)
-{
- struct mgcp_trunk_config *trunk = vty->index;
- trunk->omit_rtcp = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_patch_rtp_ssrc,
- cfg_trunk_patch_rtp_ssrc_cmd,
- "rtp-patch ssrc",
- RTP_PATCH_STR
- "Force a fixed SSRC\n"
- )
-{
- struct mgcp_trunk_config *trunk = vty->index;
- trunk->force_constant_ssrc = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_no_patch_rtp_ssrc,
- cfg_trunk_no_patch_rtp_ssrc_cmd,
- "no rtp-patch ssrc",
- NO_STR RTP_PATCH_STR
- "Force a fixed SSRC\n"
- )
-{
- struct mgcp_trunk_config *trunk = vty->index;
- trunk->force_constant_ssrc = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_patch_rtp_ts,
- cfg_trunk_patch_rtp_ts_cmd,
- "rtp-patch timestamp",
- RTP_PATCH_STR
- "Adjust RTP timestamp\n"
- )
-{
- struct mgcp_trunk_config *trunk = vty->index;
- trunk->force_aligned_timing = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_no_patch_rtp_ts,
- cfg_trunk_no_patch_rtp_ts_cmd,
- "no rtp-patch timestamp",
- NO_STR RTP_PATCH_STR
- "Adjust RTP timestamp\n"
- )
-{
- struct mgcp_trunk_config *trunk = vty->index;
- trunk->force_aligned_timing = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_no_patch_rtp,
- cfg_trunk_no_patch_rtp_cmd,
- "no rtp-patch",
- NO_STR RTP_PATCH_STR)
-{
- struct mgcp_trunk_config *trunk = vty->index;
- trunk->force_constant_ssrc = 0;
- trunk->force_aligned_timing = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_rtp_keepalive,
- cfg_trunk_rtp_keepalive_cmd,
- "rtp keep-alive <1-120>",
- RTP_STR RTP_KEEPALIVE_STR
- "Keep-alive interval in secs\n"
- )
-{
- struct mgcp_trunk_config *trunk = vty->index;
- mgcp_trunk_set_keepalive(trunk, atoi(argv[0]));
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_rtp_keepalive_once,
- cfg_trunk_rtp_keepalive_once_cmd,
- "rtp keep-alive once",
- RTP_STR RTP_KEEPALIVE_STR
- "Send dummy packet only once after CRCX/MDCX\n"
- )
-{
- struct mgcp_trunk_config *trunk = vty->index;
- mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_no_rtp_keepalive,
- cfg_trunk_no_rtp_keepalive_cmd,
- "no rtp keep-alive",
- NO_STR RTP_STR RTP_KEEPALIVE_STR
- )
-{
- struct mgcp_trunk_config *trunk = vty->index;
- mgcp_trunk_set_keepalive(trunk, 0);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_allow_transcoding,
- cfg_trunk_allow_transcoding_cmd,
- "allow-transcoding",
- "Allow transcoding\n")
-{
- struct mgcp_trunk_config *trunk = vty->index;
- trunk->no_audio_transcoding = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trunk_no_allow_transcoding,
- cfg_trunk_no_allow_transcoding_cmd,
- "no allow-transcoding",
- NO_STR "Allow transcoding\n")
-{
- struct mgcp_trunk_config *trunk = vty->index;
- trunk->no_audio_transcoding = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(loop_endp,
- loop_endp_cmd,
- "loop-endpoint <0-64> NAME (0|1)",
- "Loop a given endpoint\n" "Trunk number\n"
- "The name in hex of the endpoint\n" "Disable the loop\n" "Enable the loop\n")
-{
- struct mgcp_trunk_config *trunk;
- struct mgcp_endpoint *endp;
-
- trunk = find_trunk(g_cfg, atoi(argv[0]));
- if (!trunk) {
- vty_out(vty, "%%Trunk %d not found in the config.%s",
- atoi(argv[0]), VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!trunk->endpoints) {
- vty_out(vty, "%%Trunk %d has no endpoints allocated.%s",
- trunk->trunk_nr, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- int endp_no = strtoul(argv[1], NULL, 16);
- if (endp_no < 1 || endp_no >= trunk->number_endpoints) {
- vty_out(vty, "Loopback number %s/%d is invalid.%s",
- argv[1], endp_no, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
-
- endp = &trunk->endpoints[endp_no];
- int loop = atoi(argv[2]);
-
- if (loop)
- endp->conn_mode = MGCP_CONN_LOOPBACK;
- else
- endp->conn_mode = endp->orig_mode;
-
- /* Handle it like a MDCX, switch on SSRC patching if enabled */
- mgcp_rtp_end_config(endp, 1, &endp->bts_end);
- mgcp_rtp_end_config(endp, 1, &endp->net_end);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(tap_call,
- tap_call_cmd,
- "tap-call <0-64> ENDPOINT (bts-in|bts-out|net-in|net-out) A.B.C.D <0-65534>",
- "Forward data on endpoint to a different system\n" "Trunk number\n"
- "The endpoint in hex\n"
- "Forward the data coming from the bts\n"
- "Forward the data coming from the bts leaving to the network\n"
- "Forward the data coming from the net\n"
- "Forward the data coming from the net leaving to the bts\n"
- "destination IP of the data\n" "destination port\n")
-{
- struct mgcp_rtp_tap *tap;
- struct mgcp_trunk_config *trunk;
- struct mgcp_endpoint *endp;
- int port = 0;
-
- trunk = find_trunk(g_cfg, atoi(argv[0]));
- if (!trunk) {
- vty_out(vty, "%%Trunk %d not found in the config.%s",
- atoi(argv[0]), VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!trunk->endpoints) {
- vty_out(vty, "%%Trunk %d has no endpoints allocated.%s",
- trunk->trunk_nr, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- int endp_no = strtoul(argv[1], NULL, 16);
- if (endp_no < 1 || endp_no >= trunk->number_endpoints) {
- vty_out(vty, "Endpoint number %s/%d is invalid.%s",
- argv[1], endp_no, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- endp = &trunk->endpoints[endp_no];
-
- if (strcmp(argv[2], "bts-in") == 0) {
- port = MGCP_TAP_BTS_IN;
- } else if (strcmp(argv[2], "bts-out") == 0) {
- port = MGCP_TAP_BTS_OUT;
- } else if (strcmp(argv[2], "net-in") == 0) {
- port = MGCP_TAP_NET_IN;
- } else if (strcmp(argv[2], "net-out") == 0) {
- port = MGCP_TAP_NET_OUT;
- } else {
- vty_out(vty, "Unknown mode... tricked vty?%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- tap = &endp->taps[port];
- memset(&tap->forward, 0, sizeof(tap->forward));
- inet_aton(argv[3], &tap->forward.sin_addr);
- tap->forward.sin_port = htons(atoi(argv[4]));
- tap->enabled = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(free_endp, free_endp_cmd,
- "free-endpoint <0-64> NUMBER",
- "Free the given endpoint\n" "Trunk number\n"
- "Endpoint number in hex.\n")
-{
- struct mgcp_trunk_config *trunk;
- struct mgcp_endpoint *endp;
-
- trunk = find_trunk(g_cfg, atoi(argv[0]));
- if (!trunk) {
- vty_out(vty, "%%Trunk %d not found in the config.%s",
- atoi(argv[0]), VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!trunk->endpoints) {
- vty_out(vty, "%%Trunk %d has no endpoints allocated.%s",
- trunk->trunk_nr, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- int endp_no = strtoul(argv[1], NULL, 16);
- if (endp_no < 1 || endp_no >= trunk->number_endpoints) {
- vty_out(vty, "Endpoint number %s/%d is invalid.%s",
- argv[1], endp_no, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- endp = &trunk->endpoints[endp_no];
- mgcp_release_endp(endp);
- return CMD_SUCCESS;
-}
-
-DEFUN(reset_endp, reset_endp_cmd,
- "reset-endpoint <0-64> NUMBER",
- "Reset the given endpoint\n" "Trunk number\n"
- "Endpoint number in hex.\n")
-{
- struct mgcp_trunk_config *trunk;
- struct mgcp_endpoint *endp;
- int endp_no, rc;
-
- trunk = find_trunk(g_cfg, atoi(argv[0]));
- if (!trunk) {
- vty_out(vty, "%%Trunk %d not found in the config.%s",
- atoi(argv[0]), VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!trunk->endpoints) {
- vty_out(vty, "%%Trunk %d has no endpoints allocated.%s",
- trunk->trunk_nr, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- endp_no = strtoul(argv[1], NULL, 16);
- if (endp_no < 1 || endp_no >= trunk->number_endpoints) {
- vty_out(vty, "Endpoint number %s/%d is invalid.%s",
- argv[1], endp_no, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- endp = &trunk->endpoints[endp_no];
- rc = mgcp_send_reset_ep(endp, ENDPOINT_NUMBER(endp));
- if (rc < 0) {
- vty_out(vty, "Error %d sending reset.%s", rc, VTY_NEWLINE);
- return CMD_WARNING;
- }
- return CMD_SUCCESS;
-}
-
-DEFUN(reset_all_endp, reset_all_endp_cmd,
- "reset-all-endpoints",
- "Reset all endpoints\n")
-{
- int rc;
-
- rc = mgcp_send_reset_all(g_cfg);
- if (rc < 0) {
- vty_out(vty, "Error %d during endpoint reset.%s",
- rc, VTY_NEWLINE);
- return CMD_WARNING;
- }
- return CMD_SUCCESS;
-}
-
-#define OSMUX_STR "RTP multiplexing\n"
-DEFUN(cfg_mgcp_osmux,
- cfg_mgcp_osmux_cmd,
- "osmux (on|off|only)",
- OSMUX_STR "Enable OSMUX\n" "Disable OSMUX\n" "Only use OSMUX\n")
-{
- if (strcmp(argv[0], "off") == 0) {
- g_cfg->osmux = OSMUX_USAGE_OFF;
- return CMD_SUCCESS;
- }
-
- if (strcmp(argv[0], "on") == 0)
- g_cfg->osmux = OSMUX_USAGE_ON;
- else if (strcmp(argv[0], "only") == 0)
- g_cfg->osmux = OSMUX_USAGE_ONLY;
-
- if (g_cfg->trunk.audio_loop) {
- vty_out(vty, "Cannot use `loop' with `osmux'.%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_osmux_ip,
- cfg_mgcp_osmux_ip_cmd,
- "osmux bind-ip A.B.C.D",
- OSMUX_STR IP_STR "IPv4 Address to bind to\n")
-{
- osmo_talloc_replace_string(g_cfg, &g_cfg->osmux_addr, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_osmux_batch_factor,
- cfg_mgcp_osmux_batch_factor_cmd,
- "osmux batch-factor <1-8>",
- OSMUX_STR "Batching factor\n" "Number of messages in the batch\n")
-{
- g_cfg->osmux_batch = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_osmux_batch_size,
- cfg_mgcp_osmux_batch_size_cmd,
- "osmux batch-size <1-65535>",
- OSMUX_STR "batch size\n" "Batch size in bytes\n")
-{
- g_cfg->osmux_batch_size = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_osmux_port,
- cfg_mgcp_osmux_port_cmd,
- "osmux port <1-65535>",
- OSMUX_STR "port\n" "UDP port\n")
-{
- g_cfg->osmux_port = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_osmux_dummy,
- cfg_mgcp_osmux_dummy_cmd,
- "osmux dummy (on|off)",
- OSMUX_STR "Dummy padding\n" "Enable dummy padding\n" "Disable dummy padding\n")
-{
- if (strcmp(argv[0], "on") == 0)
- g_cfg->osmux_dummy = 1;
- else if (strcmp(argv[0], "off") == 0)
- g_cfg->osmux_dummy = 0;
-
- return CMD_SUCCESS;
-}
-
-int mgcp_vty_init(void)
-{
- install_element_ve(&show_mgcp_cmd);
- install_element(ENABLE_NODE, &loop_endp_cmd);
- install_element(ENABLE_NODE, &tap_call_cmd);
- install_element(ENABLE_NODE, &free_endp_cmd);
- install_element(ENABLE_NODE, &reset_endp_cmd);
- install_element(ENABLE_NODE, &reset_all_endp_cmd);
-
- install_element(CONFIG_NODE, &cfg_mgcp_cmd);
- install_node(&mgcp_node, config_write_mgcp);
-
- vty_install_default(MGCP_NODE);
- install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_bts_base_port_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_net_base_port_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_bts_range_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_bts_bind_ip_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_no_bts_bind_ip_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_net_range_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_net_bind_ip_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_no_net_bind_ip_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_transcoder_range_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_transcoder_base_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_tos_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_force_ptime_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_no_rtp_force_ptime_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_once_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_no_rtp_keepalive_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd_old);
- install_element(MGCP_NODE, &cfg_mgcp_transcoder_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_no_transcoder_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_transcoder_remote_base_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd_old);
- install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd_old);
- install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_force_realloc_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_omit_rtcp_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_no_omit_rtcp_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_patch_rtp_ssrc_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_ssrc_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_patch_rtp_ts_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_ts_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_sdp_fmtp_extra_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_send_ptime_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_ptime_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_send_name_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_name_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_osmux_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_factor_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_size_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_osmux_port_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_osmux_dummy_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_allow_transcoding_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_no_allow_transcoding_cmd);
-
-
- install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd);
- install_node(&trunk_node, config_write_trunk);
- vty_install_default(TRUNK_NODE);
- install_element(TRUNK_NODE, &cfg_trunk_rtp_keepalive_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_rtp_keepalive_once_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_no_rtp_keepalive_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_payload_number_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_payload_name_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_payload_number_cmd_old);
- install_element(TRUNK_NODE, &cfg_trunk_payload_name_cmd_old);
- install_element(TRUNK_NODE, &cfg_trunk_loop_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_omit_rtcp_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_no_omit_rtcp_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_patch_rtp_ssrc_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_ssrc_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_patch_rtp_ts_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_ts_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_sdp_fmtp_extra_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_sdp_payload_send_ptime_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_no_sdp_payload_send_ptime_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_sdp_payload_send_name_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_no_sdp_payload_send_name_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_allow_transcoding_cmd);
- install_element(TRUNK_NODE, &cfg_trunk_no_allow_transcoding_cmd);
-
- return 0;
-}
-
-static int allocate_trunk(struct mgcp_trunk_config *trunk)
-{
- int i;
- struct mgcp_config *cfg = trunk->cfg;
-
- if (mgcp_endpoints_allocate(trunk) != 0) {
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to allocate %d endpoints on trunk %d.\n",
- trunk->number_endpoints, trunk->trunk_nr);
- return -1;
- }
-
- /* early bind */
- for (i = 1; i < trunk->number_endpoints; ++i) {
- struct mgcp_endpoint *endp = &trunk->endpoints[i];
-
- if (cfg->bts_ports.mode == PORT_ALLOC_STATIC) {
- cfg->last_bts_port += 2;
- if (mgcp_bind_bts_rtp_port(endp, cfg->last_bts_port) != 0) {
- LOGP(DMGCP, LOGL_FATAL,
- "Failed to bind: %d\n", cfg->last_bts_port);
- return -1;
- }
- endp->bts_end.local_alloc = PORT_ALLOC_STATIC;
- }
-
- if (cfg->net_ports.mode == PORT_ALLOC_STATIC) {
- cfg->last_net_port += 2;
- if (mgcp_bind_net_rtp_port(endp, cfg->last_net_port) != 0) {
- LOGP(DMGCP, LOGL_FATAL,
- "Failed to bind: %d\n", cfg->last_net_port);
- return -1;
- }
- endp->net_end.local_alloc = PORT_ALLOC_STATIC;
- }
-
- if (trunk->trunk_type == MGCP_TRUNK_VIRTUAL &&
- cfg->transcoder_ip && cfg->transcoder_ports.mode == PORT_ALLOC_STATIC) {
- int rtp_port;
-
- /* network side */
- rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp),
- cfg->transcoder_ports.base_port);
- if (mgcp_bind_trans_net_rtp_port(endp, rtp_port) != 0) {
- LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", rtp_port);
- return -1;
- }
- endp->trans_net.local_alloc = PORT_ALLOC_STATIC;
-
- /* bts side */
- rtp_port = rtp_calculate_port(endp_back_channel(ENDPOINT_NUMBER(endp)),
- cfg->transcoder_ports.base_port);
- if (mgcp_bind_trans_bts_rtp_port(endp, rtp_port) != 0) {
- LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", rtp_port);
- return -1;
- }
- endp->trans_bts.local_alloc = PORT_ALLOC_STATIC;
- }
- }
-
- return 0;
-}
-
-int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
- enum mgcp_role role)
-{
- int rc;
- struct mgcp_trunk_config *trunk;
-
- cfg->osmux_port = OSMUX_PORT;
- cfg->osmux_batch = 4;
- cfg->osmux_batch_size = OSMUX_BATCH_DEFAULT_MAX;
-
- g_cfg = cfg;
- rc = vty_read_config_file(config_file, NULL);
- if (rc < 0) {
- fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
- return rc;
- }
-
-
- if (!g_cfg->bts_ip)
- fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n");
-
- if (!g_cfg->source_addr) {
- fprintf(stderr, "You need to specify a bind address.\n");
- return -1;
- }
-
- /* initialize the last ports */
- g_cfg->last_bts_port = rtp_calculate_port(0, g_cfg->bts_ports.base_port);
- g_cfg->last_net_port = rtp_calculate_port(0, g_cfg->net_ports.base_port);
-
- if (allocate_trunk(&g_cfg->trunk) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to initialize the virtual trunk.\n");
- return -1;
- }
-
- llist_for_each_entry(trunk, &g_cfg->trunks, entry) {
- if (allocate_trunk(trunk) != 0) {
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to initialize E1 trunk %d.\n", trunk->trunk_nr);
- return -1;
- }
- }
- cfg->role = role;
-
- return 0;
-}
-
diff --git a/src/libmgcp/mgcpgw_client.c b/src/libmgcp/mgcpgw_client.c
deleted file mode 100644
index 1910a9f35..000000000
--- a/src/libmgcp/mgcpgw_client.c
+++ /dev/null
@@ -1,616 +0,0 @@
-/* mgcp_utils - common functions to setup an MGCP connection
- */
-/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <osmocom/core/select.h>
-#include <osmocom/core/write_queue.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/logging.h>
-
-#include <openbsc/mgcpgw_client.h>
-#include <openbsc/mgcp.h>
-#include <openbsc/mgcp_internal.h>
-#include <openbsc/debug.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-
-void mgcpgw_client_conf_init(struct mgcpgw_client_conf *conf)
-{
- /* NULL and -1 default to MGCPGW_CLIENT_*_DEFAULT values */
- *conf = (struct mgcpgw_client_conf){
- .local_addr = NULL,
- .local_port = -1,
- .remote_addr = NULL,
- .remote_port = -1,
- .first_endpoint = 0,
- .last_endpoint = 0,
- .bts_base = 0,
- };
-}
-
-/* Test if a given endpoint id is currently in use */
-static bool endpoint_in_use(uint16_t id, struct mgcpgw_client *client)
-{
- struct mgcp_inuse_endpoint *endpoint;
- llist_for_each_entry(endpoint, &client->inuse_endpoints, entry) {
- if (endpoint->id == id)
- return true;
- }
-
- return false;
-}
-
-/* Find and seize an unsused endpoint id */
-int mgcpgw_client_next_endpoint(struct mgcpgw_client *client)
-{
- int i;
- uint16_t first_endpoint = client->actual.first_endpoint;
- uint16_t last_endpoint = client->actual.last_endpoint;
- struct mgcp_inuse_endpoint *endpoint;
-
- /* Use the maximum permitted range if the VTY
- * configuration does not specify a range */
- if (client->actual.last_endpoint == 0) {
- first_endpoint = 1;
- last_endpoint = 65534;
- }
-
- /* Test the permitted endpoint range for an endpoint
- * number that is not in use. When a suitable endpoint
- * number can be found, seize it by adding it to the
- * inuse list. */
- for (i=first_endpoint;i<last_endpoint;i++)
- {
- if (endpoint_in_use(i,client) == false) {
- endpoint = talloc_zero(client, struct mgcp_inuse_endpoint);
- endpoint->id = i;
- llist_add_tail(&endpoint->entry, &client->inuse_endpoints);
- return endpoint->id;
- }
- }
-
- /* All endpoints are busy! */
- return -EINVAL;
-}
-
-/* Release a seized endpoint id to make it available again for other calls */
-void mgcpgw_client_release_endpoint(uint16_t id, struct mgcpgw_client *client)
-{
- struct mgcp_inuse_endpoint *endpoint;
- struct mgcp_inuse_endpoint *endpoint_tmp;
- llist_for_each_entry_safe(endpoint, endpoint_tmp, &client->inuse_endpoints, entry) {
- if (endpoint->id == id) {
- llist_del(&endpoint->entry);
- talloc_free(endpoint);
- }
- }
-}
-
-static void mgcpgw_client_handle_response(struct mgcpgw_client *mgcp,
- struct mgcp_response_pending *pending,
- struct mgcp_response *response)
-{
- if (!pending) {
- LOGP(DMGCP, LOGL_ERROR,
- "Cannot handle NULL response\n");
- return;
- }
- if (pending->response_cb)
- pending->response_cb(response, pending->priv);
- else
- LOGP(DMGCP, LOGL_INFO, "MGCP response ignored (NULL cb)\n");
- talloc_free(pending);
-}
-
-static int mgcp_response_parse_head(struct mgcp_response *r, struct msgb *msg)
-{
- int comment_pos;
- char *end;
-
- if (mgcp_msg_terminate_nul(msg))
- goto response_parse_failure;
-
- r->body = (char *)msg->data;
-
- if (sscanf(r->body, "%3d %u %n",
- &r->head.response_code, &r->head.trans_id,
- &comment_pos) != 2)
- goto response_parse_failure;
-
- r->head.comment = r->body + comment_pos;
- end = strchr(r->head.comment, '\r');
- if (!end)
- goto response_parse_failure;
- /* Mark the end of the comment */
- *end = '\0';
- r->body = end + 1;
- if (r->body[0] == '\n')
- r->body ++;
- return 0;
-
-response_parse_failure:
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to parse MGCP response header\n");
- return -EINVAL;
-}
-
-/* TODO undup against mgcp_protocol.c:mgcp_check_param() */
-static bool mgcp_line_is_valid(const char *line)
-{
- const size_t line_len = strlen(line);
- if (line[0] == '\0')
- return true;
-
- if (line_len < 2
- || line[1] != '=') {
- LOGP(DMGCP, LOGL_ERROR,
- "Wrong MGCP option format: '%s'\n",
- line);
- return false;
- }
-
- return true;
-}
-
-/* Parse a line like "m=audio 16002 RTP/AVP 98" */
-static int mgcp_parse_audio(struct mgcp_response *r, const char *line)
-{
- if (sscanf(line, "m=audio %hu",
- &r->audio_port) != 1)
- goto response_parse_failure;
-
- return 0;
-
-response_parse_failure:
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to parse MGCP response header\n");
- return -EINVAL;
-}
-
-int mgcp_response_parse_params(struct mgcp_response *r)
-{
- char *line;
- int rc;
- OSMO_ASSERT(r->body);
- char *data = strstr(r->body, "\n\n");
-
- if (!data) {
- LOGP(DMGCP, LOGL_ERROR,
- "MGCP response: cannot find start of parameters\n");
- return -EINVAL;
- }
-
- /* Advance to after the \n\n, replace the second \n with \0. That's
- * where the parameters start. */
- data ++;
- *data = '\0';
- data ++;
-
- for_each_line(line, data) {
- if (!mgcp_line_is_valid(line))
- return -EINVAL;
-
- switch (line[0]) {
- case 'm':
- rc = mgcp_parse_audio(r, line);
- if (rc)
- return rc;
- break;
- default:
- /* skip unhandled parameters */
- break;
- }
- }
- return 0;
-}
-
-static struct mgcp_response_pending *mgcpgw_client_response_pending_get(
- struct mgcpgw_client *mgcp,
- struct mgcp_response *r)
-{
- struct mgcp_response_pending *pending;
- if (!r)
- return NULL;
- llist_for_each_entry(pending, &mgcp->responses_pending, entry) {
- if (pending->trans_id == r->head.trans_id) {
- llist_del(&pending->entry);
- return pending;
- }
- }
- return NULL;
-}
-
-/* Feed an MGCP message into the receive processing.
- * Parse the head and call any callback registered for the transaction id found
- * in the MGCP message. This is normally called directly from the internal
- * mgcp_do_read that reads from the socket connected to the MGCP gateway. This
- * function is published mainly to be able to feed data from the test suite.
- */
-int mgcpgw_client_rx(struct mgcpgw_client *mgcp, struct msgb *msg)
-{
- struct mgcp_response r = { 0 };
- struct mgcp_response_pending *pending;
- int rc;
-
- rc = mgcp_response_parse_head(&r, msg);
- if (rc) {
- LOGP(DMGCP, LOGL_ERROR, "Cannot parse MGCP response\n");
- return -1;
- }
-
- pending = mgcpgw_client_response_pending_get(mgcp, &r);
- if (!pending) {
- LOGP(DMGCP, LOGL_ERROR,
- "Cannot find matching MGCP transaction for trans_id %d\n",
- r.head.trans_id);
- return -1;
- }
-
- mgcpgw_client_handle_response(mgcp, pending, &r);
- return 0;
-}
-
-static int mgcp_do_read(struct osmo_fd *fd)
-{
- struct mgcpgw_client *mgcp = fd->data;
- struct msgb *msg;
- int ret;
-
- msg = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
- if (!msg) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to allocate MGCP message.\n");
- return -1;
- }
-
- ret = read(fd->fd, msg->data, 4096 - 128);
- if (ret <= 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to read: %d/%s\n", errno, strerror(errno));
- msgb_free(msg);
- return -1;
- } else if (ret > 4096 - 128) {
- LOGP(DMGCP, LOGL_ERROR, "Too much data: %d\n", ret);
- msgb_free(msg);
- return -1;
- }
-
- msg->l2h = msgb_put(msg, ret);
- ret = mgcpgw_client_rx(mgcp, msg);
- talloc_free(msg);
- return ret;
-}
-
-static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
-{
- int ret;
- static char strbuf[4096];
- unsigned int l = msg->len < sizeof(strbuf) ? msg->len : sizeof(strbuf);
- unsigned int i;
-
- strncpy(strbuf, (const char*)msg->data, l);
- for (i = 0; i < sizeof(strbuf); i++) {
- if (strbuf[i] == '\n' || strbuf[i] == '\r') {
- strbuf[i] = '\0';
- break;
- }
- }
- DEBUGP(DMGCP, "Tx MGCP msg to MGCP GW: '%s'\n", strbuf);
-
- LOGP(DMGCP, LOGL_DEBUG, "Sending msg to MGCP GW size: %u\n", msg->len);
-
- ret = write(fd->fd, msg->data, msg->len);
- if (ret != msg->len)
- LOGP(DMGCP, LOGL_ERROR, "Failed to forward message to MGCP"
- " GW: %s\n", strerror(errno));
-
- return ret;
-}
-
-struct mgcpgw_client *mgcpgw_client_init(void *ctx,
- struct mgcpgw_client_conf *conf)
-{
- struct mgcpgw_client *mgcp;
-
- mgcp = talloc_zero(ctx, struct mgcpgw_client);
-
- INIT_LLIST_HEAD(&mgcp->responses_pending);
- INIT_LLIST_HEAD(&mgcp->inuse_endpoints);
-
- mgcp->next_trans_id = 1;
-
- mgcp->actual.local_addr = conf->local_addr ? conf->local_addr :
- MGCPGW_CLIENT_LOCAL_ADDR_DEFAULT;
- mgcp->actual.local_port = conf->local_port >= 0 ? (uint16_t)conf->local_port :
- MGCPGW_CLIENT_LOCAL_PORT_DEFAULT;
-
- mgcp->actual.remote_addr = conf->remote_addr ? conf->remote_addr :
- MGCPGW_CLIENT_REMOTE_ADDR_DEFAULT;
- mgcp->actual.remote_port = conf->remote_port >= 0 ? (uint16_t)conf->remote_port :
- MGCPGW_CLIENT_REMOTE_PORT_DEFAULT;
-
- mgcp->actual.first_endpoint = conf->first_endpoint > 0 ? (uint16_t)conf->first_endpoint : 0;
- mgcp->actual.last_endpoint = conf->last_endpoint > 0 ? (uint16_t)conf->last_endpoint : 0;
- mgcp->actual.bts_base = conf->bts_base > 0 ? (uint16_t)conf->bts_base : 4000;
-
- return mgcp;
-}
-
-int mgcpgw_client_connect(struct mgcpgw_client *mgcp)
-{
- int on;
- struct sockaddr_in addr;
- struct osmo_wqueue *wq;
- int rc;
-
- if (!mgcp) {
- LOGP(DMGCP, LOGL_FATAL, "MGCPGW client not initialized properly\n");
- return -EINVAL;
- }
-
- wq = &mgcp->wq;
-
- wq->bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (wq->bfd.fd < 0) {
- LOGP(DMGCP, LOGL_FATAL, "Failed to create UDP socket errno: %d\n", errno);
- return -errno;
- }
-
- on = 1;
- if (setsockopt(wq->bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
- LOGP(DMGCP, LOGL_FATAL,
- "Failed to initialize socket for MGCP GW: %s\n",
- strerror(errno));
- rc = -errno;
- goto error_close_fd;
- }
-
- /* bind socket */
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- inet_aton(mgcp->actual.local_addr, &addr.sin_addr);
- addr.sin_port = htons(mgcp->actual.local_port);
- if (bind(wq->bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- LOGP(DMGCP, LOGL_FATAL,
- "Failed to bind for MGCP GW to %s %u\n",
- mgcp->actual.local_addr, mgcp->actual.local_port);
- rc = -errno;
- goto error_close_fd;
- }
-
- /* connect to the remote */
- inet_aton(mgcp->actual.remote_addr, &addr.sin_addr);
- addr.sin_port = htons(mgcp->actual.remote_port);
- if (connect(wq->bfd.fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- LOGP(DMGCP, LOGL_FATAL,
- "Failed to connect to MGCP GW at %s %u: %s\n",
- mgcp->actual.remote_addr, mgcp->actual.remote_port,
- strerror(errno));
- rc = -errno;
- goto error_close_fd;
- }
-
- mgcp->remote_addr = htonl(addr.sin_addr.s_addr);
-
- osmo_wqueue_init(wq, 10);
- wq->bfd.when = BSC_FD_READ;
- wq->bfd.data = mgcp;
- wq->read_cb = mgcp_do_read;
- wq->write_cb = mgcp_do_write;
-
- if (osmo_fd_register(&wq->bfd) != 0) {
- LOGP(DMGCP, LOGL_FATAL, "Failed to register BFD\n");
- rc = -EIO;
- goto error_close_fd;
- }
- LOGP(DMGCP, LOGL_INFO, "MGCP GW connection: %s:%u -> %s:%u\n",
- mgcp->actual.local_addr, mgcp->actual.local_port,
- mgcp->actual.remote_addr, mgcp->actual.remote_port);
-
- return 0;
-error_close_fd:
- close(wq->bfd.fd);
- wq->bfd.fd = -1;
- return rc;
-}
-
-const char *mgcpgw_client_remote_addr_str(struct mgcpgw_client *mgcp)
-{
- return mgcp->actual.remote_addr;
-}
-
-uint16_t mgcpgw_client_remote_port(struct mgcpgw_client *mgcp)
-{
- return mgcp->actual.remote_port;
-}
-
-/* Return the MGCP GW binary IPv4 address in network byte order. */
-uint32_t mgcpgw_client_remote_addr_n(struct mgcpgw_client *mgcp)
-{
- return mgcp->remote_addr;
-}
-
-struct mgcp_response_pending * mgcpgw_client_pending_add(
- struct mgcpgw_client *mgcp,
- mgcp_trans_id_t trans_id,
- mgcp_response_cb_t response_cb,
- void *priv)
-{
- struct mgcp_response_pending *pending;
-
- pending = talloc_zero(mgcp, struct mgcp_response_pending);
- pending->trans_id = trans_id;
- pending->response_cb = response_cb;
- pending->priv = priv;
- llist_add_tail(&pending->entry, &mgcp->responses_pending);
-
- return pending;
-}
-
-/* Send the MGCP message in msg to the MGCP GW and handle a response with
- * response_cb. NOTE: the response_cb still needs to call
- * mgcp_response_parse_params(response) to get the parsed parameters -- to
- * potentially save some CPU cycles, only the head line has been parsed when
- * the response_cb is invoked. */
-int mgcpgw_client_tx(struct mgcpgw_client *mgcp, struct msgb *msg,
- mgcp_response_cb_t response_cb, void *priv)
-{
- struct mgcp_response_pending *pending;
- mgcp_trans_id_t trans_id;
- int rc;
-
- trans_id = msg->cb[MSGB_CB_MGCP_TRANS_ID];
- if (!trans_id) {
- LOGP(DMGCP, LOGL_ERROR,
- "Unset transaction id in mgcp send request\n");
- talloc_free(msg);
- return -EINVAL;
- }
-
- pending = mgcpgw_client_pending_add(mgcp, trans_id, response_cb, priv);
-
- if (msgb_l2len(msg) > 4096) {
- LOGP(DMGCP, LOGL_ERROR,
- "Cannot send, MGCP message too large: %u\n",
- msgb_l2len(msg));
- msgb_free(msg);
- rc = -EINVAL;
- goto mgcp_tx_error;
- }
-
- rc = osmo_wqueue_enqueue(&mgcp->wq, msg);
- if (rc) {
- LOGP(DMGCP, LOGL_FATAL, "Could not queue message to MGCP GW\n");
- msgb_free(msg);
- goto mgcp_tx_error;
- } else
- LOGP(DMGCP, LOGL_INFO, "Queued %u bytes for MGCP GW\n",
- msgb_l2len(msg));
- return 0;
-
-mgcp_tx_error:
- /* Pass NULL to response cb to indicate an error */
- mgcpgw_client_handle_response(mgcp, pending, NULL);
- return -1;
-}
-
-static struct msgb *mgcp_msg_from_buf(mgcp_trans_id_t trans_id,
- const char *buf, int len)
-{
- struct msgb *msg;
-
- if (len > (4096 - 128)) {
- LOGP(DMGCP, LOGL_ERROR, "Cannot send to MGCP GW:"
- " message too large: %d\n", len);
- return NULL;
- }
-
- msg = msgb_alloc_headroom(4096, 128, "MGCP tx");
- OSMO_ASSERT(msg);
-
- char *dst = (char*)msgb_put(msg, len);
- memcpy(dst, buf, len);
- msg->l2h = msg->data;
- msg->cb[MSGB_CB_MGCP_TRANS_ID] = trans_id;
-
- return msg;
-}
-
-static struct msgb *mgcp_msg_from_str(mgcp_trans_id_t trans_id,
- const char *fmt, ...)
-{
- static char compose[4096 - 128];
- va_list ap;
- int len;
- OSMO_ASSERT(fmt);
-
- va_start(ap, fmt);
- len = vsnprintf(compose, sizeof(compose), fmt, ap);
- va_end(ap);
- if (len >= sizeof(compose)) {
- LOGP(DMGCP, LOGL_ERROR,
- "Message too large: trans_id=%u len=%d\n",
- trans_id, len);
- return NULL;
- }
- if (len < 1) {
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to compose message: trans_id=%u len=%d\n",
- trans_id, len);
- return NULL;
- }
- return mgcp_msg_from_buf(trans_id, compose, len);
-}
-
-static mgcp_trans_id_t mgcpgw_client_next_trans_id(struct mgcpgw_client *mgcp)
-{
- /* avoid zero trans_id to distinguish from unset trans_id */
- if (!mgcp->next_trans_id)
- mgcp->next_trans_id ++;
- return mgcp->next_trans_id ++;
-}
-
-struct msgb *mgcp_msg_crcx(struct mgcpgw_client *mgcp,
- uint16_t rtp_endpoint, unsigned int call_id,
- enum mgcp_connection_mode mode)
-{
- mgcp_trans_id_t trans_id = mgcpgw_client_next_trans_id(mgcp);
- return mgcp_msg_from_str(trans_id,
- "CRCX %u %x@mgw MGCP 1.0\r\n"
- "C: %x\r\n"
- "L: p:20, a:AMR, nt:IN\r\n"
- "M: %s\r\n"
- ,
- trans_id,
- rtp_endpoint,
- call_id,
- mgcp_cmode_name(mode));
-}
-
-struct msgb *mgcp_msg_mdcx(struct mgcpgw_client *mgcp,
- uint16_t rtp_endpoint, const char *rtp_conn_addr,
- uint16_t rtp_port, enum mgcp_connection_mode mode)
-
-{
- mgcp_trans_id_t trans_id = mgcpgw_client_next_trans_id(mgcp);
- return mgcp_msg_from_str(trans_id,
- "MDCX %u %x@mgw MGCP 1.0\r\n"
- "M: %s\r\n"
- "\r\n"
- "c=IN IP4 %s\r\n"
- "m=audio %u RTP/AVP 255\r\n"
- ,
- trans_id,
- rtp_endpoint,
- mgcp_cmode_name(mode),
- rtp_conn_addr,
- rtp_port);
-}
-
-struct msgb *mgcp_msg_dlcx(struct mgcpgw_client *mgcp, uint16_t rtp_endpoint,
- unsigned int call_id)
-{
- mgcp_trans_id_t trans_id = mgcpgw_client_next_trans_id(mgcp);
- return mgcp_msg_from_str(trans_id,
- "DLCX %u %x@mgw MGCP 1.0\r\n"
- "C: %x\r\n", trans_id, rtp_endpoint, call_id);
-}
diff --git a/src/libmgcp/mgcpgw_client_vty.c b/src/libmgcp/mgcpgw_client_vty.c
deleted file mode 100644
index 806800078..000000000
--- a/src/libmgcp/mgcpgw_client_vty.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/* MGCPGW client interface to quagga VTY */
-/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
- * Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
- * (C) 2009 by Harald Welte <laforge@gnumonks.org>
- * (C) 2009-2011 by Holger Hans Peter Freyther
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <inttypes.h>
-#include <stdlib.h>
-#include <talloc.h>
-
-#include <osmocom/vty/command.h>
-
-#include <openbsc/vty.h>
-#include <openbsc/mgcpgw_client.h>
-
-#define MGCPGW_STR "MGCP gateway configuration for RTP streams\n"
-
-struct mgcpgw_client_conf *global_mgcpgw_client_conf = NULL;
-
-DEFUN(cfg_mgcpgw_local_ip, cfg_mgcpgw_local_ip_cmd,
- "mgcpgw local-ip A.B.C.D",
- MGCPGW_STR "local bind to connect to MGCP gateway with\n"
- "local bind IP address\n")
-{
- if (!global_mgcpgw_client_conf)
- return CMD_ERR_NOTHING_TODO;
- global_mgcpgw_client_conf->local_addr =
- talloc_strdup(gsmnet_from_vty(vty), argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcpgw_local_port, cfg_mgcpgw_local_port_cmd,
- "mgcpgw local-port <0-65535>",
- MGCPGW_STR "local bind to connect to MGCP gateway with\n"
- "local bind port\n")
-{
- if (!global_mgcpgw_client_conf)
- return CMD_ERR_NOTHING_TODO;
- global_mgcpgw_client_conf->local_port = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcpgw_remote_ip, cfg_mgcpgw_remote_ip_cmd,
- "mgcpgw remote-ip A.B.C.D",
- MGCPGW_STR "remote bind to connect to MGCP gateway with\n"
- "remote bind IP address\n")
-{
- if (!global_mgcpgw_client_conf)
- return CMD_ERR_NOTHING_TODO;
- global_mgcpgw_client_conf->remote_addr =
- talloc_strdup(gsmnet_from_vty(vty), argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcpgw_remote_port, cfg_mgcpgw_remote_port_cmd,
- "mgcpgw remote-port <0-65535>",
- MGCPGW_STR "remote bind to connect to MGCP gateway with\n"
- "remote bind port\n")
-{
- if (!global_mgcpgw_client_conf)
- return CMD_ERR_NOTHING_TODO;
- global_mgcpgw_client_conf->remote_port = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcpgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
- "mgcpgw endpoint-range <1-65534> <1-65534>",
- MGCPGW_STR "usable range of endpoint identifiers\n"
- "set first useable endpoint identifier\n"
- "set the last useable endpoint identifier\n")
-{
- uint16_t first_endpoint = atoi(argv[0]);
- uint16_t last_endpoint = atoi(argv[1]);
-
- if (last_endpoint < first_endpoint) {
- vty_out(vty, "last endpoint must be greater than first endpoint!%s",
- VTY_NEWLINE);
- return CMD_SUCCESS;
- }
-
- global_mgcpgw_client_conf->first_endpoint = first_endpoint;
- global_mgcpgw_client_conf->last_endpoint = last_endpoint;
- return CMD_SUCCESS;
-}
-
-#define BTS_START_STR "First UDP port allocated for the BTS side\n"
-#define UDP_PORT_STR "UDP Port number\n"
-DEFUN(cfg_mgcp_rtp_bts_base_port,
- cfg_mgcp_rtp_bts_base_port_cmd,
- "mgcpgw bts-base <0-65534>",
- MGCPGW_STR
- BTS_START_STR
- UDP_PORT_STR)
-{
- global_mgcpgw_client_conf->bts_base = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-int mgcpgw_client_config_write(struct vty *vty, const char *indent)
-{
- const char *addr;
- int port;
- uint16_t first_endpoint;
- uint16_t last_endpoint;
- uint16_t bts_base;
-
- addr = global_mgcpgw_client_conf->local_addr;
- if (addr)
- vty_out(vty, "%smgcpgw local-ip %s%s", indent, addr,
- VTY_NEWLINE);
- port = global_mgcpgw_client_conf->local_port;
- if (port >= 0)
- vty_out(vty, "%smgcpgw local-port %u%s", indent,
- (uint16_t)port, VTY_NEWLINE);
-
- addr = global_mgcpgw_client_conf->remote_addr;
- if (addr)
- vty_out(vty, "%smgcpgw remote-ip %s%s", indent, addr,
- VTY_NEWLINE);
- port = global_mgcpgw_client_conf->remote_port;
- if (port >= 0)
- vty_out(vty, "%smgcpgw remote-port %u%s", indent,
- (uint16_t)port, VTY_NEWLINE);
-
- first_endpoint = global_mgcpgw_client_conf->first_endpoint;
- last_endpoint = global_mgcpgw_client_conf->last_endpoint;
- if (last_endpoint != 0) {
- vty_out(vty, "%smgcpgw endpoint-range %u %u%s", indent,
- first_endpoint, last_endpoint, VTY_NEWLINE);
- }
-
- bts_base = global_mgcpgw_client_conf->bts_base;
- if (bts_base) {
- vty_out(vty, "%smgcpgw bts-base %u%s", indent,
- bts_base, VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
-void mgcpgw_client_vty_init(int node, struct mgcpgw_client_conf *conf)
-{
- global_mgcpgw_client_conf = conf;
-
- install_element(node, &cfg_mgcpgw_local_ip_cmd);
- install_element(node, &cfg_mgcpgw_local_port_cmd);
- install_element(node, &cfg_mgcpgw_remote_ip_cmd);
- install_element(node, &cfg_mgcpgw_remote_port_cmd);
- install_element(node, &cfg_mgcpgw_endpoint_range_cmd);
- install_element(node, &cfg_mgcp_rtp_bts_base_port_cmd);
-}
diff --git a/src/libmsc/a_iface.c b/src/libmsc/a_iface.c
index 93e8ab5e9..e473b7526 100644
--- a/src/libmsc/a_iface.c
+++ b/src/libmsc/a_iface.c
@@ -34,7 +34,7 @@
#include <openbsc/a_iface.h>
#include <openbsc/a_iface_bssap.h>
#include <openbsc/transaction.h>
-#include <openbsc/mgcpgw_client.h>
+#include <osmocom/legacy_mgcp/mgcpgw_client.h>
#include <osmocom/core/byteswap.h>
#include <osmocom/sccp/sccp_types.h>
#include <openbsc/a_reset.h>
diff --git a/src/libmsc/msc_ifaces.c b/src/libmsc/msc_ifaces.c
index 262bf98a3..161a10019 100644
--- a/src/libmsc/msc_ifaces.c
+++ b/src/libmsc/msc_ifaces.c
@@ -25,8 +25,8 @@
#include <openbsc/msc_ifaces.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/transaction.h>
-#include <openbsc/mgcp.h>
-#include <openbsc/mgcpgw_client.h>
+#include <osmocom/legacy_mgcp/mgcp.h>
+#include <osmocom/legacy_mgcp/mgcpgw_client.h>
#include <openbsc/vlr.h>
#include <openbsc/a_iface.h>
@@ -249,7 +249,7 @@ int msc_call_assignment(struct gsm_trans *trans)
* its RTP traffic to that port on the MGCPGW side. The MGCPGW only
* gets the endpoint ID via the CRCX. It will do the same calculation
* on his side too to get knowledge of the rtp port. */
- bts_base = mgcp->actual.bts_base;
+ bts_base = mgcpgw_client_conf_actual(mgcp)->bts_base;
conn->rtp.port_subscr = bts_base + 2 * conn->rtp.mgcp_rtp_endpoint;
/* Establish the RTP stream first as looping back to the originator.
diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c
index 6ae4529a1..50679aa01 100644
--- a/src/libmsc/msc_vty.c
+++ b/src/libmsc/msc_vty.c
@@ -155,7 +155,7 @@ void msc_vty_init(struct gsm_network *msc_network)
install_element(MSC_NODE, &cfg_msc_cs7_instance_a_cmd);
install_element(MSC_NODE, &cfg_msc_cs7_instance_iu_cmd);
- mgcpgw_client_vty_init(MSC_NODE, &msc_network->mgcpgw.conf);
+ mgcpgw_client_vty_init(msc_network, MSC_NODE, &msc_network->mgcpgw.conf);
#ifdef BUILD_IU
ranap_iu_vty_init(MSC_NODE, &msc_network->iu.rab_assign_addr_enc);
#endif
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index 4353b9ad0..9a5288bdc 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -24,7 +24,7 @@
#include <openbsc/bsc_msc_data.h>
#include <openbsc/debug.h>
#include <openbsc/bsc_subscriber.h>
-#include <openbsc/mgcp.h>
+#include <osmocom/legacy_mgcp/mgcp.h>
#include <openbsc/paging.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
diff --git a/src/osmo-bsc_mgcp/Makefile.am b/src/osmo-bsc_mgcp/Makefile.am
deleted file mode 100644
index b4e0d8564..000000000
--- a/src/osmo-bsc_mgcp/Makefile.am
+++ /dev/null
@@ -1,36 +0,0 @@
-AM_CPPFLAGS = \
- $(all_includes) \
- -I$(top_srcdir)/include \
- -I$(top_builddir) \
- $(NULL)
-
-AM_CFLAGS = \
- -Wall \
- $(LIBOSMOCORE_CFLAGS) \
- $(LIBOSMOGSM_CFLAGS) \
- $(LIBOSMOVTY_CFLAGS) \
- $(LIBOSMOABIS_CFLAGS) \
- $(LIBOSMONETIF_CFLAGS) \
- $(COVERAGE_CFLAGS) \
- $(NULL)
-
-bin_PROGRAMS = \
- osmo-bsc_mgcp \
- $(NULL)
-
-osmo_bsc_mgcp_SOURCES = \
- mgcp_main.c \
- $(NULL)
-
-osmo_bsc_mgcp_LDADD = \
- $(top_builddir)/src/libcommon/libcommon.a \
- $(top_builddir)/src/libmgcp/libmgcp.a \
- $(LIBOSMOVTY_LIBS) \
- $(LIBOSMOCORE_LIBS) \
- $(LIBOSMOGSM_LIBS) \
- $(LIBOSMONETIF_LIBS) \
- $(LIBBCG729_LIBS) \
- $(LIBRARY_GSM) \
- $(LIBOSMOSIGTRAN_LIBS) \
- -lrt \
- $(NULL)
diff --git a/src/osmo-bsc_mgcp/mgcp_main.c b/src/osmo-bsc_mgcp/mgcp_main.c
deleted file mode 100644
index 6cf9ab786..000000000
--- a/src/osmo-bsc_mgcp/mgcp_main.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
-/* The main method to drive it as a standalone process */
-
-/*
- * (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009-2011 by On-Waves
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <limits.h>
-#include <unistd.h>
-
-#include <sys/socket.h>
-
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/mgcp.h>
-#include <openbsc/mgcp_internal.h>
-#include <openbsc/vty.h>
-
-#include <osmocom/core/application.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/select.h>
-#include <osmocom/core/stats.h>
-#include <osmocom/core/rate_ctr.h>
-
-#include <osmocom/vty/telnet_interface.h>
-#include <osmocom/vty/logging.h>
-#include <osmocom/vty/ports.h>
-#include <osmocom/vty/command.h>
-#include <osmocom/vty/stats.h>
-
-#include "../../bscconfig.h"
-
-#ifdef BUILD_MGCP_TRANSCODING
-#include "openbsc/mgcp_transcode.h"
-#endif
-
-#define _GNU_SOURCE
-#include <getopt.h>
-
-#warning "Make use of the rtp proxy code"
-
-static struct mgcp_config *cfg;
-static struct mgcp_trunk_config *reset_trunk;
-static int reset_endpoints = 0;
-static int daemonize = 0;
-
-const char *openbsc_copyright =
- "Copyright (C) 2009-2010 Holger Freyther and On-Waves\r\n"
- "Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\r\n"
- "Dieter Spaar, Andreas Eversberg, Harald Welte\r\n\r\n"
- "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
- "This is free software: you are free to change and redistribute it.\r\n"
- "There is NO WARRANTY, to the extent permitted by law.\r\n";
-
-static char *config_file = "mgcp.cfg";
-
-/* used by msgb and mgcp */
-void *tall_bsc_ctx = NULL;
-
-static void print_help()
-{
- printf("Some useful help...\n");
- printf(" -h --help is printing this text.\n");
- printf(" -c --config-file filename The config file to use.\n");
- printf(" -s --disable-color\n");
- printf(" -D --daemonize Fork the process into a background daemon\n");
- printf(" -V --version Print the version number\n");
-}
-
-static void handle_options(int argc, char **argv)
-{
- while (1) {
- int option_index = 0, c;
- static struct option long_options[] = {
- {"help", 0, 0, 'h'},
- {"config-file", 1, 0, 'c'},
- {"daemonize", 0, 0, 'D'},
- {"version", 0, 0, 'V'},
- {"disable-color", 0, 0, 's'},
- {0, 0, 0, 0},
- };
-
- c = getopt_long(argc, argv, "hc:VD", long_options, &option_index);
-
- if (c == -1)
- break;
-
- switch(c) {
- case 'h':
- print_help();
- exit(0);
- break;
- case 'c':
- config_file = talloc_strdup(tall_bsc_ctx, optarg);
- break;
- case 's':
- log_set_use_color(osmo_stderr_target, 0);
- break;
- case 'V':
- print_version(1);
- exit(0);
- break;
- case 'D':
- daemonize = 1;
- break;
- default:
- /* ignore */
- break;
- };
- }
-}
-
-/* simply remember this */
-static int mgcp_rsip_cb(struct mgcp_trunk_config *tcfg)
-{
- reset_endpoints = 1;
- reset_trunk = tcfg;
-
- return 0;
-}
-
-static int read_call_agent(struct osmo_fd *fd, unsigned int what)
-{
- struct sockaddr_in addr;
- socklen_t slen = sizeof(addr);
- struct msgb *msg;
- struct msgb *resp;
- int i;
-
- msg = (struct msgb *) fd->data;
-
- /* read one less so we can use it as a \0 */
- int rc = recvfrom(cfg->gw_fd.bfd.fd, msg->data, msg->data_len - 1, 0,
- (struct sockaddr *) &addr, &slen);
- if (rc < 0) {
- perror("Gateway failed to read");
- return -1;
- } else if (slen > sizeof(addr)) {
- fprintf(stderr, "Gateway received message from outerspace: %zu %zu\n",
- (size_t) slen, sizeof(addr));
- return -1;
- }
-
- /* handle message now */
- msg->l2h = msgb_put(msg, rc);
- resp = mgcp_handle_message(cfg, msg);
- msgb_reset(msg);
-
- if (resp) {
- sendto(cfg->gw_fd.bfd.fd, resp->l2h, msgb_l2len(resp), 0, (struct sockaddr *) &addr, sizeof(addr));
- msgb_free(resp);
- }
-
- if (reset_endpoints) {
- LOGP(DMGCP, LOGL_NOTICE,
- "Asked to reset endpoints: %d/%d\n",
- reset_trunk->trunk_nr, reset_trunk->trunk_type);
- reset_endpoints = 0;
-
- /* is checking in_addr.s_addr == INADDR_LOOPBACK making it more secure? */
- for (i = 1; i < reset_trunk->number_endpoints; ++i)
- mgcp_release_endp(&reset_trunk->endpoints[i]);
- }
-
- return 0;
-}
-
-extern int bsc_vty_go_parent(struct vty *vty);
-
-static struct vty_app_info vty_info = {
- .name = "OpenBSC MGCP",
- .version = PACKAGE_VERSION,
- .go_parent_cb = bsc_vty_go_parent,
- .is_config_node = bsc_vty_is_config_node,
-};
-
-int main(int argc, char **argv)
-{
- struct gsm_network dummy_network;
- struct sockaddr_in addr;
- int on = 1, rc;
-
- tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
- msgb_talloc_ctx_init(tall_bsc_ctx, 0);
-
- osmo_init_ignore_signals();
- osmo_init_logging(&log_info);
-
- cfg = mgcp_config_alloc();
- if (!cfg)
- return -1;
-
-#ifdef BUILD_MGCP_TRANSCODING
- cfg->setup_rtp_processing_cb = &mgcp_transcoding_setup;
- cfg->rtp_processing_cb = &mgcp_transcoding_process_rtp;
- cfg->get_net_downlink_format_cb = &mgcp_transcoding_net_downlink_format;
-#endif
-
- cfg->trunk.force_realloc = 1;
-
- vty_info.copyright = openbsc_copyright;
- vty_init(&vty_info);
- logging_vty_add_cmds(NULL);
- osmo_stats_vty_add_cmds(&log_info);
- mgcp_vty_init();
-
- handle_options(argc, argv);
-
- rate_ctr_init(tall_bsc_ctx);
- osmo_stats_init(tall_bsc_ctx);
-
- rc = mgcp_parse_config(config_file, cfg, MGCP_BSC);
- if (rc < 0)
- return rc;
-
- /* start telnet after reading config for vty_get_bind_addr() */
- rc = telnet_init_dynif(tall_bsc_ctx, &dummy_network,
- vty_get_bind_addr(), OSMO_VTY_PORT_BSC_MGCP);
- if (rc < 0)
- return rc;
-
- /* set some callbacks */
- cfg->reset_cb = mgcp_rsip_cb;
-
- /* we need to bind a socket */
- if (rc == 0) {
- cfg->gw_fd.bfd.when = BSC_FD_READ;
- cfg->gw_fd.bfd.cb = read_call_agent;
- cfg->gw_fd.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (cfg->gw_fd.bfd.fd < 0) {
- perror("Gateway failed to listen");
- return -1;
- }
-
- setsockopt(cfg->gw_fd.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(cfg->source_port);
- inet_aton(cfg->source_addr, &addr.sin_addr);
-
- if (bind(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("Gateway failed to bind");
- return -1;
- }
-
- cfg->gw_fd.bfd.data = msgb_alloc(4096, "mgcp-msg");
- if (!cfg->gw_fd.bfd.data) {
- fprintf(stderr, "Gateway memory error.\n");
- return -1;
- }
-
- if (cfg->call_agent_addr) {
- addr.sin_port = htons(2727);
- inet_aton(cfg->call_agent_addr, &addr.sin_addr);
- if (connect(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to connect to: '%s'. errno: %d\n",
- cfg->call_agent_addr, errno);
- close(cfg->gw_fd.bfd.fd);
- cfg->gw_fd.bfd.fd = -1;
- return -1;
- }
- }
-
- if (osmo_fd_register(&cfg->gw_fd.bfd) != 0) {
- LOGP(DMGCP, LOGL_FATAL, "Failed to register the fd\n");
- return -1;
- }
-
- LOGP(DMGCP, LOGL_NOTICE, "Configured for MGCP.\n");
- }
-
- /* initialisation */
- srand(time(NULL));
-
- if (daemonize) {
- rc = osmo_daemonize();
- if (rc < 0) {
- perror("Error during daemonize");
- exit(1);
- }
- }
-
- /* main loop */
- while (1) {
- osmo_select_main(0);
- }
-
-
- return 0;
-}
diff --git a/src/osmo-bsc_nat/Makefile.am b/src/osmo-bsc_nat/Makefile.am
index b7c13ad3e..1eec7aa1c 100644
--- a/src/osmo-bsc_nat/Makefile.am
+++ b/src/osmo-bsc_nat/Makefile.am
@@ -13,6 +13,7 @@ AM_CFLAGS = \
$(LIBOSMOSCCP_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \
$(LIBOSMONETIF_CFLAGS) \
+ $(LIBOSMOLEGACYMGCP_CFLAGS) \
$(LIBCRYPTO_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
@@ -40,7 +41,6 @@ osmo_bsc_nat_SOURCES = \
$(NULL)
osmo_bsc_nat_LDADD = \
- $(top_builddir)/src/libmgcp/libmgcp.a \
$(top_builddir)/src/libfilter/libfilter.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libcommon-cs/libcommon-cs.a \
@@ -54,6 +54,8 @@ osmo_bsc_nat_LDADD = \
$(LIBOSMOABIS_LIBS) \
$(LIBOSMONETIF_LIBS) \
$(LIBOSMOSIGTRAN_LIBS) \
+ $(LIBOSMOLEGACYMGCP_LIBS) \
$(LIBCRYPTO_LIBS) \
+ $(LIBRARY_GSM) \
-lrt \
$(NULL)
diff --git a/src/osmo-bsc_nat/bsc_mgcp_utils.c b/src/osmo-bsc_nat/bsc_mgcp_utils.c
index 7df362f89..49050fc89 100644
--- a/src/osmo-bsc_nat/bsc_mgcp_utils.c
+++ b/src/osmo-bsc_nat/bsc_mgcp_utils.c
@@ -48,8 +48,8 @@
#include <openbsc/gsm_data.h>
#include <openbsc/debug.h>
#include <openbsc/ipaccess.h>
-#include <openbsc/mgcp.h>
-#include <openbsc/mgcp_internal.h>
+#include <osmocom/legacy_mgcp/mgcp.h>
+#include <osmocom/legacy_mgcp/mgcp_internal.h>
#include <openbsc/osmux.h>
#include <osmocom/ctrl/control_cmd.h>
diff --git a/src/osmo-bsc_nat/bsc_nat_ctrl.c b/src/osmo-bsc_nat/bsc_nat_ctrl.c
index 128ea6518..ff6a73978 100644
--- a/src/osmo-bsc_nat/bsc_nat_ctrl.c
+++ b/src/osmo-bsc_nat/bsc_nat_ctrl.c
@@ -32,6 +32,7 @@
#include <openbsc/bsc_msg_filter.h>
#include <openbsc/vty.h>
#include <openbsc/gsm_data.h>
+#include <openbsc/debug.h>
#include <unistd.h>
#include <string.h>
diff --git a/src/osmo-bsc_nat/bsc_nat_vty.c b/src/osmo-bsc_nat/bsc_nat_vty.c
index a11ae151e..fed530676 100644
--- a/src/osmo-bsc_nat/bsc_nat_vty.c
+++ b/src/osmo-bsc_nat/bsc_nat_vty.c
@@ -25,7 +25,7 @@
#include <openbsc/bsc_msg_filter.h>
#include <openbsc/bsc_msc.h>
#include <openbsc/gsm_04_08.h>
-#include <openbsc/mgcp.h>
+#include <osmocom/legacy_mgcp/mgcp.h>
#include <openbsc/vty.h>
#include <openbsc/nat_rewrite_trie.h>
@@ -1213,15 +1213,15 @@ DEFUN(cfg_bsc_osmux,
conf->osmux = OSMUX_USAGE_ONLY;
if (old == 0 && conf->osmux > 0 && !conf->nat->mgcp_cfg->osmux_init) {
- LOGP(DMGCP, LOGL_NOTICE, "Setting up OSMUX socket\n");
+ LOGP(DLMGCP, LOGL_NOTICE, "Setting up OSMUX socket\n");
if (osmux_init(OSMUX_ROLE_BSC_NAT, conf->nat->mgcp_cfg) < 0) {
- LOGP(DMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
+ LOGP(DLMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
vty_out(vty, "%% failed to create Osmux socket%s",
VTY_NEWLINE);
return CMD_WARNING;
}
} else if (old > 0 && conf->osmux == 0) {
- LOGP(DMGCP, LOGL_NOTICE, "Disabling OSMUX socket\n");
+ LOGP(DLMGCP, LOGL_NOTICE, "Disabling OSMUX socket\n");
/* Don't stop the socket, we may already have ongoing voice
* flows already using Osmux. This just switch indicates that
* new upcoming flows should use RTP.
diff --git a/src/osmo-bsc_nat/bsc_ussd.c b/src/osmo-bsc_nat/bsc_ussd.c
index 0ba63270d..9769bbd39 100644
--- a/src/osmo-bsc_nat/bsc_ussd.c
+++ b/src/osmo-bsc_nat/bsc_ussd.c
@@ -25,6 +25,7 @@
#include <openbsc/bsc_msg_filter.h>
#include <openbsc/ipaccess.h>
#include <openbsc/socket.h>
+#include <openbsc/debug.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
#include <osmocom/gsm/gsm0480.h>
diff --git a/src/osmo-msc/Makefile.am b/src/osmo-msc/Makefile.am
index 87b6133f9..0d4876fa9 100644
--- a/src/osmo-msc/Makefile.am
+++ b/src/osmo-msc/Makefile.am
@@ -17,6 +17,7 @@ AM_CFLAGS = \
$(LIBOSMORANAP_CFLAGS) \
$(LIBASN1C_CFLAGS) \
$(LIBOSMOSIGTRAN_CFLAGS) \
+ $(LIBOSMOLEGACYMGCP_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
@@ -37,7 +38,6 @@ osmo_msc_LDADD = \
$(top_builddir)/src/libcommon-cs/libcommon-cs.a \
$(top_builddir)/src/libtrau/libtrau.a \
$(top_builddir)/src/libcommon/libcommon.a \
- $(top_builddir)/src/libmgcp/libmgcp.a \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMOCORE_LIBS) \
@@ -46,6 +46,8 @@ osmo_msc_LDADD = \
$(LIBSMPP34_LIBS) \
$(LIBCRYPTO_LIBS) \
$(LIBOSMOSIGTRAN_LIBS) \
+ $(LIBOSMOLEGACYMGCP_LIBS) \
+ $(LIBRARY_GSM) \
-ldbi \
$(NULL)
if BUILD_IU
diff --git a/src/osmo-msc/msc_main.c b/src/osmo-msc/msc_main.c
index de6af5dd6..30b11d983 100644
--- a/src/osmo-msc/msc_main.c
+++ b/src/osmo-msc/msc_main.c
@@ -64,7 +64,7 @@
#include <openbsc/osmo_bsc_rf.h>
#include <openbsc/smpp.h>
#include <osmocom/sigtran/osmo_ss7.h>
-#include <openbsc/mgcpgw_client.h>
+#include <osmocom/legacy_mgcp/mgcpgw_client.h>
#ifdef BUILD_IU
#include <osmocom/ranap/iu_client.h>