aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/libmgcp
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2017-07-04 23:08:44 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2017-08-27 03:52:43 +0200
commit218e4b4aa0fc6de842ff820dec8e97d1f083268a (patch)
tree268a6e509270b1c80a36dd1a526da41a9b01a8e0 /openbsc/src/libmgcp
parent5ea6bfce56d6ae7be6d85e05b5e4eaebc94d1005 (diff)
move openbsc/* to repos root
This is the first step in creating this repository from the legacy openbsc.git. Like all other Osmocom repositories, keep the autoconf and automake files in the repository root. openbsc.git has been the sole exception, which ends now. Change-Id: I9c6f2a448d9cb1cc088cf1cf6918b69d7e69b4e7
Diffstat (limited to 'openbsc/src/libmgcp')
-rw-r--r--openbsc/src/libmgcp/Makefile.am43
-rw-r--r--openbsc/src/libmgcp/g711common.h187
-rw-r--r--openbsc/src/libmgcp/mgcp_network.c1064
-rw-r--r--openbsc/src/libmgcp/mgcp_osmux.c586
-rw-r--r--openbsc/src/libmgcp/mgcp_protocol.c1598
-rw-r--r--openbsc/src/libmgcp/mgcp_sdp.c305
-rw-r--r--openbsc/src/libmgcp/mgcp_transcode.c612
-rw-r--r--openbsc/src/libmgcp/mgcp_vty.c1543
8 files changed, 0 insertions, 5938 deletions
diff --git a/openbsc/src/libmgcp/Makefile.am b/openbsc/src/libmgcp/Makefile.am
deleted file mode 100644
index 5faf6027a..000000000
--- a/openbsc/src/libmgcp/Makefile.am
+++ /dev/null
@@ -1,43 +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_protocol.c \
- mgcp_network.c \
- mgcp_vty.c \
- mgcp_osmux.c \
- mgcp_sdp.c \
- $(NULL)
-if BUILD_MGCP_TRANSCODING
-libmgcp_a_SOURCES += \
- mgcp_transcode.c \
- $(NULL)
-endif
diff --git a/openbsc/src/libmgcp/g711common.h b/openbsc/src/libmgcp/g711common.h
deleted file mode 100644
index cb35fc651..000000000
--- a/openbsc/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/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c
deleted file mode 100644
index abce6e49d..000000000
--- a/openbsc/src/libmgcp/mgcp_network.c
+++ /dev/null
@@ -1,1064 +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;
-
- rtp_hdr->payload_type = payload;
-}
-
-/*
- * 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;
-
- /* 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;
- }
-
- if (!rtp_end->output_enabled)
- rtp_end->dropped_packets += 1;
- 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);
- forward_data(rtp_end->rtp.fd, &endp->taps[tap_idx],
- buf, len);
- 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) {
- 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;
-
- if (memcmp(&addr.sin_addr, &endp->net_end.addr, sizeof(addr.sin_addr)) != 0) {
- LOGP(DMGCP, LOGL_ERROR,
- "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,
- "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;
- }
-
- /* 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,
- "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,
- "Data from wrong bts source port %d on 0x%x\n",
- 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 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:
- 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/openbsc/src/libmgcp/mgcp_osmux.c b/openbsc/src/libmgcp/mgcp_osmux.c
deleted file mode 100644
index b46a80e7f..000000000
--- a/openbsc/src/libmgcp/mgcp_osmux.c
+++ /dev/null
@@ -1,586 +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, OSMUX_ROLE_BSC_NAT,
- &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, int role,
- 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, OSMUX_ROLE_BSC,
- &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/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c
deleted file mode 100644
index 4fcadd949..000000000
--- a/openbsc/src/libmgcp/mgcp_protocol.c
+++ /dev/null
@@ -1,1598 +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);
-
-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 for '%s'\n", code, res->l2h);
-
- /*
- * 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);
- 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;
- unsigned char *tail = msg->l2h + msgb_l2len(msg); /* char after l2 data */
-
- if (msgb_l2len(msg) < 4) {
- LOGP(DMGCP, LOGL_ERROR, "msg too short: %d\n", msg->len);
- return NULL;
- }
-
- /* Ensure that the msg->l2h is NUL terminated. */
- 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 NULL;
- }
-
- /* 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;
-
- 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 */
- 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:
- 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/openbsc/src/libmgcp/mgcp_sdp.c b/openbsc/src/libmgcp/mgcp_sdp.c
deleted file mode 100644
index b64894496..000000000
--- a/openbsc/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/openbsc/src/libmgcp/mgcp_transcode.c b/openbsc/src/libmgcp/mgcp_transcode.c
deleted file mode 100644
index f31e7aefb..000000000
--- a/openbsc/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/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c
deleted file mode 100644
index 7d4b2da84..000000000
--- a/openbsc/src/libmgcp/mgcp_vty.c
+++ /dev/null
@@ -1,1543 +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_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);
- 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_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;
-}
-