aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc')
-rw-r--r--openbsc/include/openbsc/gsm_04_08.h3
-rw-r--r--openbsc/include/openbsc/mncc.h12
-rw-r--r--openbsc/include/openbsc/rtp_proxy.h5
-rw-r--r--openbsc/include/openbsc/transaction.h2
-rw-r--r--openbsc/src/ipaccess/ipaccess-config.c6
-rw-r--r--openbsc/src/libbsc/bsc_api.c1
-rw-r--r--openbsc/src/libbsc/handover_logic.c1
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c199
-rw-r--r--openbsc/src/libmsc/mncc_sock.c14
-rw-r--r--openbsc/src/libmsc/transaction.c1
-rw-r--r--openbsc/src/libtrau/rtp_proxy.c20
-rw-r--r--openbsc/src/libtrau/trau_mux.c14
-rw-r--r--openbsc/src/utils/bs11_config.c6
-rw-r--r--openbsc/tests/abis/abis_test.c6
-rw-r--r--openbsc/tests/gbproxy/gbproxy_test.c6
15 files changed, 253 insertions, 43 deletions
diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index 8df7b735f..93348d1a8 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -6,6 +6,7 @@
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <openbsc/meas_rep.h>
+#include <openbsc/mncc.h>
struct msgb;
struct gsm_bts;
@@ -75,4 +76,6 @@ void gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd,
void release_security_operation(struct gsm_subscriber_connection *conn);
void allocate_security_operation(struct gsm_subscriber_connection *conn);
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data);
+
#endif
diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h
index ffac7fd6f..32a60e9e9 100644
--- a/openbsc/include/openbsc/mncc.h
+++ b/openbsc/include/openbsc/mncc.h
@@ -92,6 +92,9 @@ struct gsm_call {
#define MNCC_FRAME_RECV 0x0201
#define MNCC_FRAME_DROP 0x0202
#define MNCC_LCHAN_MODIFY 0x0203
+#define MNCC_RTP_CREATE 0x0204
+#define MNCC_RTP_CONNECT 0x0205
+#define MNCC_RTP_FREE 0x0206
#define GSM_TCHF_FRAME 0x0300
#define GSM_TCHF_FRAME_EFR 0x0301
@@ -163,7 +166,7 @@ struct gsm_data_frame {
unsigned char data[0];
};
-#define MNCC_SOCK_VERSION 4
+#define MNCC_SOCK_VERSION 5
struct gsm_mncc_hello {
uint32_t msg_type;
uint32_t version;
@@ -179,6 +182,13 @@ struct gsm_mncc_hello {
uint32_t lchan_type_offset;
};
+struct gsm_mncc_rtp {
+ uint32_t msg_type;
+ uint32_t callref;
+ uint32_t ip;
+ uint16_t port;
+};
+
char *get_mncc_name(int value);
void mncc_set_cause(struct gsm_mncc *data, int loc, int val);
void cc_tx_to_mncc(struct gsm_network *net, struct msgb *msg);
diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h
index 52ffefd27..a5f6a2bea 100644
--- a/openbsc/include/openbsc/rtp_proxy.h
+++ b/openbsc/include/openbsc/rtp_proxy.h
@@ -40,8 +40,9 @@
enum rtp_rx_action {
RTP_NONE,
- RTP_PROXY,
- RTP_RECV_UPSTREAM,
+ RTP_PROXY, /* forward from BTS to BTS */
+ RTP_RECV_UPSTREAM, /* forward to application */
+ RTP_RECV_APP, /* receive RTP frames from application */
};
enum rtp_tx_action {
diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h
index b6c859c71..db3a5cf99 100644
--- a/openbsc/include/openbsc/transaction.h
+++ b/openbsc/include/openbsc/transaction.h
@@ -28,6 +28,7 @@ struct gsm_trans {
/* reference from MNCC or other application */
uint32_t callref;
+ uint32_t callref_keep; /* to remember callref, even if it is removed */
/* if traffic channel receive was requested */
int tch_recv;
@@ -46,6 +47,7 @@ struct gsm_trans {
int T308_second; /* used to send release again */
struct osmo_timer_list timer;
struct gsm_mncc msg; /* stores setup/disconnect/release message */
+ struct rtp_socket *rs; /* application traffic via RTP */
} cc;
struct {
struct gsm411_smc_inst smc_inst;
diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c
index c42c7bb9c..68b9131a4 100644
--- a/openbsc/src/ipaccess/ipaccess-config.c
+++ b/openbsc/src/ipaccess/ipaccess-config.c
@@ -87,6 +87,12 @@ static uint8_t prim_oml_attr[] = { 0x95, 0x00, 7, 0x88, 192, 168, 100, 11, 0x00,
static uint8_t unit_id_attr[] = { 0x91, 0x00, 9, '2', '3', '4', '2', '/' , '0', '/', '0', 0x00 };
*/
+/* dummy function to keep rtp_proxy.c happy */
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
+{
+ return 0;
+}
+
extern int ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what);
extern struct e1inp_line_ops ipaccess_e1inp_line_ops;
diff --git a/openbsc/src/libbsc/bsc_api.c b/openbsc/src/libbsc/bsc_api.c
index e56703837..e6629ffd2 100644
--- a/openbsc/src/libbsc/bsc_api.c
+++ b/openbsc/src/libbsc/bsc_api.c
@@ -31,6 +31,7 @@
#include <openbsc/handover.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_04_08.h>
+#include <osmocom/abis/trau_frame.h>
#include <openbsc/trau_mux.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c
index 36a758be6..e20d8f73d 100644
--- a/openbsc/src/libbsc/handover_logic.c
+++ b/openbsc/src/libbsc/handover_logic.c
@@ -39,6 +39,7 @@
#include <openbsc/signal.h>
#include <osmocom/core/talloc.h>
#include <openbsc/transaction.h>
+#include <osmocom/abis/trau_frame.h>
#include <openbsc/trau_mux.h>
struct bsc_handover {
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index a0650abbf..ed3785d31 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -1359,8 +1359,15 @@ void _gsm48_cc_trans_free(struct gsm_trans *trans)
}
if (trans->cc.state != GSM_CSTATE_NULL)
new_cc_state(trans, GSM_CSTATE_NULL);
+ /* Be sure to unmap upstream traffic for our callref only. */
if (trans->conn)
- trau_mux_unmap(&trans->conn->lchan->ts->e1_link, trans->callref);
+ trau_mux_unmap(&trans->conn->lchan->ts->e1_link, trans->callref_keep);
+
+ /* free application RTP socket */
+ if (trans->cc.rs) {
+ rtp_socket_free(trans->cc.rs);
+ trans->cc.rs = NULL;
+ }
}
static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
@@ -1478,6 +1485,7 @@ static int switch_for_handover(struct gsm_lchan *old_lchan,
new_rs->receive = old_rs->receive;
break;
case RTP_NONE:
+ case RTP_RECV_APP:
break;
}
@@ -1702,6 +1710,153 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable)
return 0;
}
+static int mncc_rtp_create(struct gsm_network *net, uint32_t callref,
+ struct gsm_trans *trans, struct rtp_socket *rs,
+ struct gsm_mncc_rtp *mncc)
+{
+ /* use RTP instead of MNCC socket, for traffic
+ * open application RTP socket */
+ if (rs) {
+ LOGP(DCC, LOGL_ERROR, "RTP already created.\n");
+ return -EIO;
+ }
+ rs = trans->cc.rs = rtp_socket_create();
+ if (!rs) {
+ LOGP(DCC, LOGL_ERROR, "RTP socket creation failed.\n");
+ /* reply with IP/port = 0 */
+ mncc->ip = 0;
+ mncc->port = 0;
+ mncc_recvmsg(net, trans, MNCC_RTP_CREATE,
+ (struct gsm_mncc *)mncc);
+ return -EIO;
+ }
+ rs->rx_action = RTP_RECV_APP;
+ rs->receive.net = net;
+ rs->receive.callref = callref;
+ /* reply with bound IP/port */
+ mncc->ip = ntohl(rs->rtp.sin_local.sin_addr.s_addr);
+ mncc->port = ntohs(rs->rtp.sin_local.sin_port);
+ mncc_recvmsg(net, trans, MNCC_RTP_CREATE, (struct gsm_mncc *)mncc);
+
+ return 0;
+}
+
+static int mncc_rtp_connect(struct gsm_network *net, struct gsm_trans *trans,
+ struct rtp_socket *rs, struct gsm_mncc_rtp *mncc)
+{
+ int rc;
+
+ if (!rs) {
+ LOGP(DCC, LOGL_ERROR, "RTP not created.\n");
+ return -EIO;
+ }
+ rc = rtp_socket_connect(trans->cc.rs, mncc->ip, mncc->port);
+ if (rc < 0) {
+ LOGP(DCC, LOGL_ERROR, "RTP socket connect failed.\n");
+ /* reply with IP/port = 0 */
+ mncc->ip = 0;
+ mncc->port = 0;
+ mncc_recvmsg(net, trans, MNCC_RTP_CONNECT,
+ (struct gsm_mncc *)mncc);
+ return -EIO;
+ }
+ /* reply with local IP/port */
+ mncc->ip = ntohl(rs->rtp.sin_local.sin_addr.s_addr);
+ mncc->port = ntohs(rs->rtp.sin_local.sin_port);
+ mncc_recvmsg(net, trans, MNCC_RTP_CONNECT, (struct gsm_mncc *)mncc);
+
+ return 0;
+}
+
+static int mncc_rtp_free(struct gsm_network *net, struct gsm_trans *trans,
+ struct rtp_socket *rs, struct gsm_mncc_rtp *mncc)
+{
+ if (!rs) {
+ LOGP(DCC, LOGL_ERROR, "RTP not created.\n");
+ return -EIO;
+ }
+ rtp_socket_free(trans->cc.rs);
+ trans->cc.rs = NULL;
+ /* reply */
+ mncc_recvmsg(net, trans, MNCC_RTP_FREE, (struct gsm_mncc *)mncc);
+
+ return 0;
+}
+
+/* handle RTP requests of application */
+static int mncc_rtp(struct gsm_network *net, uint32_t callref,
+ struct gsm_mncc_rtp *mncc)
+{
+ struct rtp_socket *rs;
+ struct gsm_trans *trans;
+ int rc = -EINVAL;
+
+ /* Find callref */
+ trans = trans_find_by_callref(net, callref);
+ if (!trans) {
+ LOGP(DCC, LOGL_ERROR, "Unknown transaction for callref=%d\n",
+ callref);
+ return -EINVAL;
+ }
+
+ rs = trans->cc.rs;
+
+ switch (mncc->msg_type) {
+ case MNCC_RTP_CREATE:
+ rc = mncc_rtp_create(net, callref, trans, rs, mncc);
+ break;
+ case MNCC_RTP_CONNECT:
+ rc = mncc_rtp_connect(net, trans, rs, mncc);
+ break;
+ case MNCC_RTP_FREE:
+ rc = mncc_rtp_free(net, trans, rs, mncc);
+ break;
+ }
+
+ return rc;
+}
+
+/* handle tch frame from application */
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
+{
+ struct gsm_trans *trans;
+ struct gsm_bts *bts;
+
+ /* Find callref */
+ trans = trans_find_by_callref(net, data->callref);
+ if (!trans) {
+ LOGP(DMNCC, LOGL_ERROR, "TCH frame for non-existing trans\n");
+ return -EIO;
+ }
+ if (!trans->conn) {
+ LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without conn\n");
+ return 0;
+ }
+ if (trans->conn->lchan->type != GSM_LCHAN_TCH_F
+ && trans->conn->lchan->type != GSM_LCHAN_TCH_H) {
+ /* This should be LOGL_ERROR or NOTICE, but
+ * unfortuantely it happens for a couple of frames at
+ * the beginning of every RTP connection */
+ LOGP(DMNCC, LOGL_DEBUG, "TCH frame for lchan != TCH_F/TCH_H\n");
+ return 0;
+ }
+ bts = trans->conn->lchan->ts->trx->bts;
+ if (!is_e1_bts(bts)) {
+ if (!trans->conn->lchan->abis_ip.rtp_socket) {
+ DEBUGP(DMNCC, "TCH frame to lchan without RTP connection\n");
+ return 0;
+ }
+ if (trans->conn->lchan->abis_ip.rtp_socket->receive.callref != callref) {
+ /* Drop frame, if not our callref. This happens, if
+ * the call is on hold or retrieved by another
+ * transaction. */
+ return 0;
+ }
+ return rtp_send_frame(trans->conn->lchan->abis_ip.rtp_socket, data);
+ } else
+ return trau_send_frame(trans->conn->lchan, data);
+}
+
static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
{
DEBUGP(DCC, "-> STATUS ENQ\n");
@@ -2937,7 +3092,6 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
int i, rc = 0;
struct gsm_trans *trans = NULL, *transt;
struct gsm_subscriber_connection *conn = NULL;
- struct gsm_bts *bts = NULL;
struct gsm_mncc *data = arg, rel;
DEBUGP(DMNCC, "receive message %s\n", get_mncc_name(msg_type));
@@ -2950,46 +3104,15 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
return tch_recv_mncc(net, data->callref, 0);
case MNCC_FRAME_RECV:
return tch_recv_mncc(net, data->callref, 1);
+ case MNCC_RTP_CREATE:
+ case MNCC_RTP_CONNECT:
+ case MNCC_RTP_FREE:
+ return mncc_rtp(net, data->callref, (struct gsm_mncc_rtp *) arg);
case GSM_TCHF_FRAME:
case GSM_TCHF_FRAME_EFR:
case GSM_TCHH_FRAME:
case GSM_TCH_FRAME_AMR:
- /* Find callref */
- trans = trans_find_by_callref(net, data->callref);
- if (!trans) {
- LOGP(DMNCC, LOGL_ERROR, "TCH frame for non-existing trans\n");
- return -EIO;
- }
- log_set_context(BSC_CTX_SUBSCR, trans->subscr);
- if (!trans->conn) {
- LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without conn\n");
- return 0;
- }
- if (trans->conn->lchan->type != GSM_LCHAN_TCH_F
- && trans->conn->lchan->type != GSM_LCHAN_TCH_H) {
- /* This should be LOGL_ERROR or NOTICE, but
- * unfortuantely it happens for a couple of frames at
- * the beginning of every RTP connection */
- LOGP(DMNCC, LOGL_DEBUG, "TCH frame for lchan != TCH_F/TCH_H\n");
- return 0;
- }
- bts = trans->conn->lchan->ts->trx->bts;
- switch (bts->type) {
- case GSM_BTS_TYPE_NANOBTS:
- case GSM_BTS_TYPE_OSMO_SYSMO:
- if (!trans->conn->lchan->abis_ip.rtp_socket) {
- DEBUGP(DMNCC, "TCH frame to lchan without RTP connection\n");
- return 0;
- }
- return rtp_send_frame(trans->conn->lchan->abis_ip.rtp_socket, arg);
- case GSM_BTS_TYPE_BS11:
- case GSM_BTS_TYPE_RBS2000:
- case GSM_BTS_TYPE_NOKIA_SITE:
- return trau_send_frame(trans->conn->lchan, arg);
- default:
- LOGP(DCC, LOGL_ERROR, "Unknown BTS type %u\n", bts->type);
- }
- return -EINVAL;
+ return tch_frame_down(net, data->callref, (struct gsm_data_frame *) arg);
}
memset(&rel, 0, sizeof(struct gsm_mncc));
diff --git a/openbsc/src/libmsc/mncc_sock.c b/openbsc/src/libmsc/mncc_sock.c
index dd0a44fb5..adb56fccd 100644
--- a/openbsc/src/libmsc/mncc_sock.c
+++ b/openbsc/src/libmsc/mncc_sock.c
@@ -37,6 +37,8 @@
#include <openbsc/debug.h>
#include <openbsc/mncc.h>
#include <openbsc/gsm_data.h>
+#include <openbsc/transaction.h>
+#include <openbsc/rtp_proxy.h>
struct mncc_sock_state {
struct gsm_network *net;
@@ -50,6 +52,18 @@ int mncc_sock_from_cc(struct gsm_network *net, struct msgb *msg)
struct gsm_mncc *mncc_in = (struct gsm_mncc *) msgb_data(msg);
int msg_type = mncc_in->msg_type;
+ /* application uses RTP for this transaction, we send our data via RTP,
+ * otherwise we send it through MNCC interface */
+ if (mncc_is_data_frame(msg_type)) {
+ struct gsm_trans *trans = trans_find_by_callref(net, mncc_in->callref);
+
+ if (trans && trans->cc.rs) {
+ rtp_send_frame(trans->cc.rs, (struct gsm_data_frame *) mncc_in);
+ msgb_free(msg);
+ return 0;
+ }
+ }
+
/* Check if we currently have a MNCC handler connected */
if (net->mncc_state->conn_bfd.fd < 0) {
LOGP(DMNCC, LOGL_ERROR, "mncc_sock receives %s for external CC app "
diff --git a/openbsc/src/libmsc/transaction.c b/openbsc/src/libmsc/transaction.c
index e425e67ee..bdd3d8eb4 100644
--- a/openbsc/src/libmsc/transaction.c
+++ b/openbsc/src/libmsc/transaction.c
@@ -78,6 +78,7 @@ struct gsm_trans *trans_alloc(struct gsm_subscriber *subscr,
trans->protocol = protocol;
trans->transaction_id = trans_id;
trans->callref = callref;
+ trans->callref_keep = callref;
llist_add_tail(&trans->entry, &subscr->net->trans_list);
diff --git a/openbsc/src/libtrau/rtp_proxy.c b/openbsc/src/libtrau/rtp_proxy.c
index 22d135c3e..d2bf88dbd 100644
--- a/openbsc/src/libtrau/rtp_proxy.c
+++ b/openbsc/src/libtrau/rtp_proxy.c
@@ -473,7 +473,7 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
other_rss->bfd.when |= BSC_FD_WRITE;
break;
- case RTP_RECV_UPSTREAM:
+ case RTP_RECV_UPSTREAM: /* from BTS to application */
if (!rs->receive.callref || !rs->receive.net) {
rc = -EIO;
goto out_free;
@@ -502,6 +502,24 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
trau_tx_to_mncc(rs->receive.net, new_msg);
break;
+ case RTP_RECV_APP: /* from remote application */
+ if (!rs->receive.callref || !rs->receive.net) {
+ rc = -EIO;
+ goto out_free;
+ }
+ if (rss->bfd.priv_nr != RTP_PRIV_RTP) {
+ rc = ENOTSUP;
+ goto out_free;
+ }
+ rc = rtp_decode(msg, rs->receive.callref, &new_msg);
+ if (rc < 0)
+ goto out_free;
+ msgb_free(msg);
+ tch_frame_down(rs->receive.net, rs->receive.callref,
+ (struct gsm_data_frame *) new_msg->data);
+ msgb_free(new_msg);
+ break;
+
case RTP_NONE: /* if socket exists, but disabled by app */
msgb_free(msg);
break;
diff --git a/openbsc/src/libtrau/trau_mux.c b/openbsc/src/libtrau/trau_mux.c
index bb513cc85..15a84b086 100644
--- a/openbsc/src/libtrau/trau_mux.c
+++ b/openbsc/src/libtrau/trau_mux.c
@@ -171,7 +171,9 @@ int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_t callref)
llist_del(&ue->list);
return 0;
}
- if (ss && !memcmp(&ue->src, ss, sizeof(*ss))) {
+ /* Only release, if no callref is given. We must ensure that
+ * only the transaction's upstream is removed, if exists. */
+ if (ss && !callref && !memcmp(&ue->src, ss, sizeof(*ss))) {
llist_del(&ue->list);
return 0;
}
@@ -497,11 +499,21 @@ int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
uint8_t trau_bits_out[TRAU_FRAME_BITS];
struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
struct subch_mux *mx;
+ struct upqueue_entry *ue;
struct decoded_trau_frame tf;
mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
if (!mx)
return -EINVAL;
+ if (!(ue = lookup_trau_upqueue(dst_e1_ss))) {
+ /* Call might be on hold, so we drop frames. */
+ return 0;
+ }
+ if (ue->callref != frame->callref) {
+ /* Slot has different transaction, due to
+ * another call. (Ours is on hold.) */
+ return 0;
+ }
switch (frame->msg_type) {
case GSM_TCHF_FRAME:
diff --git a/openbsc/src/utils/bs11_config.c b/openbsc/src/utils/bs11_config.c
index e8acb461a..f459744aa 100644
--- a/openbsc/src/utils/bs11_config.c
+++ b/openbsc/src/utils/bs11_config.c
@@ -83,6 +83,12 @@ struct osmo_counter *osmo_counter_alloc(const char *name)
return NULL;
}
+/* dummy function to keep rtp_proxy.c happy */
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
+{
+ return 0;
+}
+
int handle_serial_msg(struct msgb *rx_msg);
/* create all objects for an initial configuration */
diff --git a/openbsc/tests/abis/abis_test.c b/openbsc/tests/abis/abis_test.c
index e7e78d202..6bb84cca0 100644
--- a/openbsc/tests/abis/abis_test.c
+++ b/openbsc/tests/abis/abis_test.c
@@ -27,6 +27,12 @@
#include <openbsc/abis_nm.h>
#include <openbsc/debug.h>
+/* dummy function to keep rtp_proxy.c happy */
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
+{
+ return 0;
+}
+
static const uint8_t simple_config[] = {
/*0, 13, */
66, 18, 0, 3, 1, 2, 3, 19, 0, 3, 3, 4, 5,
diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c
index d32ac8340..69ce58aa4 100644
--- a/openbsc/tests/gbproxy/gbproxy_test.c
+++ b/openbsc/tests/gbproxy/gbproxy_test.c
@@ -34,6 +34,12 @@
#define SGSN_NSEI 0x0100
+/* dummy function to keep rtp_proxy.c happy */
+int tch_frame_down()
+{
+ return 0;
+}
+
struct gbproxy_config gbcfg;
static int gprs_process_message(struct gprs_ns_inst *nsi, const char *text,