diff options
Diffstat (limited to 'openbsc/src')
-rw-r--r-- | openbsc/src/ipaccess/ipaccess-config.c | 6 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_08.c | 175 | ||||
-rw-r--r-- | openbsc/src/libmsc/mncc_builtin.c | 2 | ||||
-rw-r--r-- | openbsc/src/libmsc/mncc_sock.c | 21 | ||||
-rw-r--r-- | openbsc/src/libmsc/transaction.c | 1 | ||||
-rw-r--r-- | openbsc/src/libtrau/rtp_proxy.c | 42 | ||||
-rw-r--r-- | openbsc/src/libtrau/trau_mux.c | 14 | ||||
-rw-r--r-- | openbsc/src/utils/bs11_config.c | 6 |
8 files changed, 226 insertions, 41 deletions
diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index e66771a1a..c778469d4 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/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index eea073614..649a77090 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -1323,8 +1323,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 L4 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); @@ -1442,6 +1449,7 @@ static int switch_for_handover(struct gsm_lchan *old_lchan, new_rs->receive = old_rs->receive; break; case RTP_NONE: + case RTP_RECV_L4: break; } @@ -1648,6 +1656,129 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable) return 0; } +/* handle RTP requests of L4 */ +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; + + /* 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: + /* use RTP instead of MNCC socket, for traffic + * open L4 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_L4; + 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); + break; + case MNCC_RTP_CONNECT: + 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); + break; + case MNCC_RTP_FREE: + 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); + break; + } + + return 0; +} + +/* handle tch frame from L4 */ +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) { + /* 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\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; + } + 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); + case GSM_BTS_TYPE_BS11: + case GSM_BTS_TYPE_RBS2000: + case GSM_BTS_TYPE_NOKIA_SITE: + return trau_send_frame(trans->conn->lchan, data); + default: + LOGP(DCC, LOGL_ERROR, "Unknown BTS type %u\n", bts->type); + } + return -EINVAL; +} + static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg) { DEBUGP(DCC, "-> STATUS ENQ\n"); @@ -2880,7 +3011,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)); @@ -2893,41 +3023,14 @@ 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: - /* 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) { - /* 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\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; + case GSM_TCHF_FRAME_EFR: + case GSM_TCHF_FRAME_HR: + 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_builtin.c b/openbsc/src/libmsc/mncc_builtin.c index 617cbf25f..5f909f739 100644 --- a/openbsc/src/libmsc/mncc_builtin.c +++ b/openbsc/src/libmsc/mncc_builtin.c @@ -342,6 +342,7 @@ int int_mncc_recv(struct gsm_network *net, struct msgb *msg) switch (msg_type) { case GSM_TCHF_FRAME: case GSM_TCHF_FRAME_EFR: + case GSM_TCHF_FRAME_HR: break; default: DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref, @@ -410,6 +411,7 @@ int int_mncc_recv(struct gsm_network *net, struct msgb *msg) break; case GSM_TCHF_FRAME: case GSM_TCHF_FRAME_EFR: + case GSM_TCHF_FRAME_HR: rc = mncc_rcv_tchf(call, msg_type, arg); break; default: diff --git a/openbsc/src/libmsc/mncc_sock.c b/openbsc/src/libmsc/mncc_sock.c index cf4bca87a..ad0f27f63 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,12 +52,27 @@ 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; + /* L4 uses RTP for this transaction, we send our data via RTP, + * otherwise we send it through MNCC interface */ + if (msg_type == GSM_TCHF_FRAME + || msg_type == GSM_TCHF_FRAME_EFR + || msg_type == GSM_TCHF_FRAME_HR) { + 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 " "but socket is gone\n", get_mncc_name(msg_type)); - if (msg_type != GSM_TCHF_FRAME && - msg_type != GSM_TCHF_FRAME_EFR) { + if (msg_type != GSM_TCHF_FRAME + && msg_type != GSM_TCHF_FRAME_EFR + && msg_type != GSM_TCHF_FRAME_HR) { /* release the request */ struct gsm_mncc mncc_out; memset(&mncc_out, 0, sizeof(mncc_out)); diff --git a/openbsc/src/libmsc/transaction.c b/openbsc/src/libmsc/transaction.c index c1441969d..5967d9935 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 0074b4a04..8ad248843 100644 --- a/openbsc/src/libtrau/rtp_proxy.c +++ b/openbsc/src/libtrau/rtp_proxy.c @@ -169,13 +169,28 @@ static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data) msg_type = GSM_TCHF_FRAME; if (payload_len != 33) { DEBUGPC(DLMUX, "received RTP full rate frame with " - "payload length != 32 (len = %d)\n", + "payload length != 33 (len = %d)\n", payload_len); return -EINVAL; } break; case RTP_PT_GSM_EFR: msg_type = GSM_TCHF_FRAME_EFR; + if (payload_len != 31) { + DEBUGPC(DLMUX, "received RTP extended full rate frame " + "with payload length != 31 (len = %d)\n", + payload_len); + return -EINVAL; + } + break; + case RTP_PT_GSM_HALF: + msg_type = GSM_TCHF_FRAME_HR; + if (payload_len != 14) { + DEBUGPC(DLMUX, "received RTP half rate frame with " + "payload length != 14 (len = %d)\n", + payload_len); + return -EINVAL; + } break; default: DEBUGPC(DLMUX, "received RTP frame with unknown payload " @@ -244,6 +259,11 @@ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame) payload_len = 31; duration = 160; break; + case GSM_TCHF_FRAME_HR: + payload_type = RTP_PT_GSM_HALF; + payload_len = 14; + duration = 160; + break; default: DEBUGPC(DLMUX, "unsupported message type %d\n", frame->msg_type); @@ -426,7 +446,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; @@ -455,6 +475,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_L4: /* from L4 */ + 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 9272ac04f..ac410c3fc 100644 --- a/openbsc/src/libtrau/trau_mux.c +++ b/openbsc/src/libtrau/trau_mux.c @@ -122,7 +122,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; } @@ -280,6 +282,7 @@ 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; int i, j, k, l, o; unsigned char *data = frame->data; struct decoded_trau_frame tf; @@ -287,6 +290,15 @@ int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame) 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 */ |