aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@netfilter.org>2009-12-19 22:23:05 +0100
committerHarald Welte <laforge@netfilter.org>2009-12-19 22:23:05 +0100
commitda7ab74298b9fdb5eb27d6575e8a15683b69889f (patch)
tree88569305679abbd891724aa3004af5ea529034d0
parentbc814501e8a28f72e16a4662250af01aaa2a1489 (diff)
RTP-enable MNCC API for LCR + ip.access
Instead of passing TRAU frames down the MNCC API to the call control application like MNCC, we now decode the TRAU frame into the actual codec frame. We do the same with the RTP packets in case of ip.access and thus have a unified format of passing codec data from the BTS to an application, independent of the BTS type. This is only implemented for V1 full-rate at the moment, and needs to be fixed.
-rw-r--r--openbsc/include/openbsc/mncc.h4
-rw-r--r--openbsc/include/openbsc/rtp_proxy.h16
-rw-r--r--openbsc/include/openbsc/transaction.h3
-rw-r--r--openbsc/include/openbsc/trau_mux.h2
-rw-r--r--openbsc/src/gsm_04_08.c117
-rw-r--r--openbsc/src/rtp_proxy.c227
-rw-r--r--openbsc/src/trau_mux.c92
7 files changed, 409 insertions, 52 deletions
diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h
index 766c09f1d..16fa05365 100644
--- a/openbsc/include/openbsc/mncc.h
+++ b/openbsc/include/openbsc/mncc.h
@@ -87,7 +87,7 @@ struct gsm_call {
#define MNCC_FRAME_DROP 0x0202
#define MNCC_LCHAN_MODIFY 0x0203
-#define GSM_TRAU_FRAME 0x0300
+#define GSM_TCHF_FRAME 0x0300
#define GSM_MAX_FACILITY 128
#define GSM_MAX_SSVERSION 128
@@ -207,7 +207,7 @@ struct gsm_mncc {
unsigned char lchan_mode;
};
-struct gsm_trau_frame {
+struct gsm_data_frame {
u_int32_t msg_type;
u_int32_t callref;
unsigned char data[0];
diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h
index e9fc157cf..a3e45964c 100644
--- a/openbsc/include/openbsc/rtp_proxy.h
+++ b/openbsc/include/openbsc/rtp_proxy.h
@@ -34,6 +34,11 @@ enum rtp_rx_action {
RTP_RECV_UPSTREAM,
};
+enum rtp_tx_action {
+ RTP_SEND_NONE,
+ RTP_SEND_DOWNSTREAM,
+};
+
struct rtp_sub_socket {
struct sockaddr_in sin_local;
struct sockaddr_in sin_remote;
@@ -56,15 +61,24 @@ struct rtp_socket {
struct rtp_socket *other_sock;
} proxy;
struct {
- void (*recv_cb)(struct msgb *msg);
+ struct gsm_network *net;
+ u_int32_t callref;
} receive;
};
+ enum rtp_tx_action tx_action;
+ struct {
+ u_int16_t sequence;
+ u_int32_t timestamp;
+ u_int32_t ssrc;
+ } transmit;
};
struct rtp_socket *rtp_socket_create(void);
int rtp_socket_bind(struct rtp_socket *rs, u_int32_t ip);
int rtp_socket_connect(struct rtp_socket *rs, u_int32_t ip, u_int16_t port);
int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other);
+int rtp_socket_upstream(struct rtp_socket *this, struct gsm_network *net, u_int32_t callref);
int rtp_socket_free(struct rtp_socket *rs);
+int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame);
#endif /* _RTP_PROXY_H */
diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h
index 6314f987f..cf9410082 100644
--- a/openbsc/include/openbsc/transaction.h
+++ b/openbsc/include/openbsc/transaction.h
@@ -26,6 +26,9 @@ struct gsm_trans {
/* reference from MNCC or other application */
u_int32_t callref;
+ /* if traffic channel receive was requested */
+ int tch_recv;
+
union {
struct {
diff --git a/openbsc/include/openbsc/trau_mux.h b/openbsc/include/openbsc/trau_mux.h
index 90535add4..8deb708de 100644
--- a/openbsc/include/openbsc/trau_mux.h
+++ b/openbsc/include/openbsc/trau_mux.h
@@ -46,4 +46,4 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
int trau_recv_lchan(struct gsm_lchan *lchan, u_int32_t callref);
/* send trau from application */
-int trau_send_lchan(struct gsm_lchan *lchan, struct decoded_trau_frame *tf);
+int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame);
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index d59d7d7ca..f36723937 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -1864,12 +1864,16 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
return 0;
}
+static int tch_recv_mncc(struct gsm_network *net, u_int32_t callref, int enable);
+
/* some other part of the code sends us a signal */
static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
struct gsm_lchan *lchan = signal_data;
int rc;
+ struct gsm_network *net;
+ struct gsm_trans *trans;
if (subsys != SS_ABISIP)
return 0;
@@ -1896,6 +1900,15 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
lchan->abis_ip.bound_port);
if (rc < 0)
goto out_err;
+ /* check if any transactions on this lchan still have
+ * a tch_recv_mncc request pending */
+ net = lchan->ts->trx->bts->network;
+ llist_for_each_entry(trans, &net->trans_list, entry) {
+ if (trans->lchan == lchan && trans->tch_recv) {
+ DEBUGP(DCC, "pending tch_recv_mncc request\n");
+ tch_recv_mncc(net, trans->callref, 1);
+ }
+ }
break;
case S_ABISIP_DLCX_IND:
/* the BTS tells us a RTP stream has been disconnected */
@@ -1941,7 +1954,8 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n");
return -EINVAL;
}
-
+
+ // todo: map between different bts types
switch (bts->type) {
case GSM_BTS_TYPE_NANOBTS:
if (!ipacc_rtp_direct) {
@@ -1950,6 +1964,7 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
if (rc < 0)
return rc;
rc = ipacc_connect_proxy_bind(remote_lchan);
+#warning do we need a check of rc here?
/* connect them with each other */
rtp_socket_proxy(lchan->abis_ip.rtp_socket,
@@ -1971,8 +1986,7 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
break;
default:
DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
- rc = -EINVAL;
- break;
+ return -EINVAL;
}
return 0;
@@ -1994,45 +2008,61 @@ static int tch_bridge(struct gsm_network *net, u_int32_t *refs)
return tch_map(trans1->lchan, trans2->lchan);
}
-/* enable receive of channels to upqueue */
-static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable)
+/* enable receive of channels to MNCC upqueue */
+static int tch_recv_mncc(struct gsm_network *net, u_int32_t callref, int enable)
{
struct gsm_trans *trans;
+ struct gsm_lchan *lchan;
+ struct gsm_bts *bts;
+ int rc;
/* Find callref */
- trans = trans_find_by_callref(net, data->callref);
+ trans = trans_find_by_callref(net, callref);
if (!trans)
return -EIO;
if (!trans->lchan)
return 0;
+ lchan = trans->lchan;
+ bts = lchan->ts->trx->bts;
- // todo IPACCESS
- if (enable)
- return trau_recv_lchan(trans->lchan, data->callref);
- return trau_mux_unmap(NULL, data->callref);
-}
-
-/* send a frame to channel */
-static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame)
-{
- struct gsm_trans *trans;
-
- /* Find callref */
- trans = trans_find_by_callref(net, frame->callref);
- if (!trans)
- return -EIO;
- if (!trans->lchan)
- return 0;
- if (trans->lchan->type != GSM_LCHAN_TCH_F &&
- trans->lchan->type != GSM_LCHAN_TCH_H)
- return 0;
+ switch (bts->type) {
+ case GSM_BTS_TYPE_NANOBTS:
+ if (ipacc_rtp_direct) {
+ DEBUGP(DCC, "Error: RTP proxy is disabled\n");
+ return -EINVAL;
+ }
+ /* in case, we don't have a RTP socket yet, we note this
+ * in the transaction and try later */
+ if (!lchan->abis_ip.rtp_socket) {
+ trans->tch_recv = enable;
+ DEBUGP(DCC, "queue tch_recv_mncc request (%d)\n", enable);
+ return 0;
+ }
+ if (enable) {
+ /* connect the TCH's to our RTP proxy */
+ rc = ipacc_connect_proxy_bind(lchan);
+ if (rc < 0)
+ return rc;
+ /* assign socket to application interface */
+ rtp_socket_upstream(lchan->abis_ip.rtp_socket,
+ net, callref);
+ } else
+ rtp_socket_upstream(lchan->abis_ip.rtp_socket,
+ net, 0);
+ break;
+ case GSM_BTS_TYPE_BS11:
+ if (enable)
+ return trau_recv_lchan(lchan, callref);
+ return trau_mux_unmap(NULL, callref);
+ break;
+ default:
+ DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
+ return -EINVAL;
+ }
- // todo IPACCESS
- return trau_send_lchan(trans->lchan,
- (struct decoded_trau_frame *)frame->data);
+ return 0;
}
-
static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
{
DEBUGP(DCC, "-> STATUS ENQ\n");
@@ -3262,11 +3292,30 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg)
case MNCC_BRIDGE:
return tch_bridge(net, arg);
case MNCC_FRAME_DROP:
- return tch_recv(net, arg, 0);
+ return tch_recv_mncc(net, data->callref, 0);
case MNCC_FRAME_RECV:
- return tch_recv(net, arg, 1);
- case GSM_TRAU_FRAME:
- return tch_frame(net, arg);
+ return tch_recv_mncc(net, data->callref, 1);
+ case GSM_TCHF_FRAME:
+ /* Find callref */
+ trans = trans_find_by_callref(net, data->callref);
+ if (!trans)
+ return -EIO;
+ if (!trans->lchan)
+ return 0;
+ if (trans->lchan->type != GSM_LCHAN_TCH_F)
+ return 0;
+ bts = trans->lchan->ts->trx->bts;
+ switch (bts->type) {
+ case GSM_BTS_TYPE_NANOBTS:
+ if (!trans->lchan->abis_ip.rtp_socket)
+ return 0;
+ return rtp_send_frame(trans->lchan->abis_ip.rtp_socket, arg);
+ case GSM_BTS_TYPE_BS11:
+ return trau_send_frame(trans->lchan, arg);
+ default:
+ DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
+ }
+ return -EINVAL;
}
memset(&rel, 0, sizeof(struct gsm_mncc));
diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c
index bfd494856..f9207d661 100644
--- a/openbsc/src/rtp_proxy.c
+++ b/openbsc/src/rtp_proxy.c
@@ -24,6 +24,10 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <sys/time.h> /* gettimeofday() */
+#include <unistd.h> /* get..() */
+#include <time.h> /* clock() */
+#include <sys/utsname.h> /* uname() */
#include <openbsc/talloc.h>
#include <openbsc/gsm_data.h>
@@ -57,6 +61,169 @@ struct rtcp_hdr {
#define RTCP_IE_CNAME 1
+/* according to RFC 3550 */
+struct rtp_hdr {
+ u_int8_t csrc_count:4,
+ extension:1,
+ padding:1,
+ version:2;
+ u_int8_t payload_type:7,
+ marker:1;
+ u_int16_t sequence;
+ u_int32_t timestamp;
+ u_int32_t ssrc;
+} __attribute__((packed));
+
+struct rtp_x_hdr {
+ u_int16_t by_profile;
+ u_int16_t length;
+} __attribute__((packed));
+
+#define RTP_VERSION 2
+
+#define RTP_PT_GSM_FULL 3
+
+/* decode an rtp frame and create a new buffer with payload */
+static int rtp_decode(struct msgb *msg, u_int32_t callref, struct msgb **data)
+{
+ struct msgb *new_msg;
+ struct gsm_data_frame *frame;
+ struct rtp_hdr *rtph = (struct rtp_hdr *)msg->data;
+ struct rtp_x_hdr *rtpxh;
+ u_int8_t *payload;
+ int payload_len;
+ int msg_type;
+ int x_len;
+
+ if (msg->len < 12) {
+ DEBUGPC(DMUX, "received RTP frame too short (len = %d)\n",
+ msg->len);
+ return -EINVAL;
+ }
+ if (rtph->version != RTP_VERSION) {
+ DEBUGPC(DMUX, "received RTP version %d not supported.\n",
+ rtph->version);
+ return -EINVAL;
+ }
+ payload = msg->data + sizeof(struct rtp_hdr) + (rtph->csrc_count << 2);
+ payload_len = msg->len - sizeof(struct rtp_hdr) - (rtph->csrc_count << 2);
+ if (payload_len < 0) {
+ DEBUGPC(DMUX, "received RTP frame too short (len = %d, "
+ "csrc count = %d)\n", msg->len, rtph->csrc_count);
+ return -EINVAL;
+ }
+ if (rtph->extension) {
+ if (payload_len < sizeof(struct rtp_x_hdr)) {
+ DEBUGPC(DMUX, "received RTP frame too short for "
+ "extension header\n");
+ return -EINVAL;
+ }
+ rtpxh = (struct rtp_x_hdr *)payload;
+ x_len = ntohs(rtpxh->length) * 4 + sizeof(struct rtp_x_hdr);
+ payload += x_len;
+ payload_len -= x_len;
+ if (payload_len < 0) {
+ DEBUGPC(DMUX, "received RTP frame too short, "
+ "extension header exceeds frame length\n");
+ return -EINVAL;
+ }
+ }
+ if (rtph->padding) {
+ if (payload_len < 0) {
+ DEBUGPC(DMUX, "received RTP frame too short for "
+ "padding length\n");
+ return -EINVAL;
+ }
+ payload_len -= payload[payload_len - 1];
+ if (payload_len < 0) {
+ DEBUGPC(DMUX, "received RTP frame with padding "
+ "greater than payload\n");
+ return -EINVAL;
+ }
+ }
+
+ switch (rtph->payload_type) {
+ case RTP_PT_GSM_FULL:
+ msg_type = GSM_TCHF_FRAME;
+ if (payload_len != 33) {
+ DEBUGPC(DMUX, "received RTP full rate frame with "
+ "payload length != 32 (len = %d)\n",
+ payload_len);
+ return -EINVAL;
+ }
+ break;
+ default:
+ DEBUGPC(DMUX, "received RTP frame with unknown payload "
+ "type %d\n", rtph->payload_type);
+ return -EINVAL;
+ }
+
+ new_msg = msgb_alloc(sizeof(struct gsm_data_frame) + payload_len,
+ "GSM-DATA");
+ if (!new_msg)
+ return -ENOMEM;
+ frame = (struct gsm_data_frame *)(new_msg->data);
+ frame->msg_type = msg_type;
+ frame->callref = callref;
+ memcpy(frame->data, payload, payload_len);
+ msgb_put(new_msg, sizeof(struct gsm_data_frame) + payload_len);
+
+ *data = new_msg;
+ return 0;
+}
+
+/* encode and send a rtp frame */
+int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame)
+{
+ struct rtp_sub_socket *rss = &rs->rtp;
+ struct msgb *msg;
+ struct rtp_hdr *rtph;
+ int payload_type;
+ int payload_len;
+ int duration; /* in samples */
+
+ if (rs->tx_action != RTP_SEND_DOWNSTREAM) {
+ /* initialize sequences */
+ rs->tx_action = RTP_SEND_DOWNSTREAM;
+ rs->transmit.ssrc = rand();
+ rs->transmit.sequence = random();
+ rs->transmit.timestamp = random();
+ }
+
+ switch (frame->msg_type) {
+ case GSM_TCHF_FRAME:
+ payload_type = RTP_PT_GSM_FULL;
+ payload_len = 33;
+ duration = 160;
+ break;
+ default:
+ DEBUGPC(DMUX, "unsupported message type %d\n",
+ frame->msg_type);
+ return -EINVAL;
+ }
+
+ msg = msgb_alloc(sizeof(struct rtp_hdr) + payload_len, "RTP-GSM-FULL");
+ if (!msg)
+ return -ENOMEM;
+ rtph = (struct rtp_hdr *)msg->data;
+ rtph->version = RTP_VERSION;
+ rtph->padding = 0;
+ rtph->extension = 0;
+ rtph->csrc_count = 0;
+ rtph->marker = 0;
+ rtph->payload_type = payload_type;
+ rtph->sequence = htons(rs->transmit.sequence++);
+ rtph->timestamp = htonl(rs->transmit.timestamp);
+ rs->transmit.timestamp += duration;
+ rtph->ssrc = htonl(rs->transmit.ssrc);
+ memcpy(msg->data + sizeof(struct rtp_hdr), frame->data, payload_len);
+ msgb_put(msg, sizeof(struct rtp_hdr) + payload_len);
+ msgb_enqueue(&rss->tx_queue, msg);
+ rss->bfd.when |= BSC_FD_WRITE;
+
+ return 0;
+}
+
/* iterate over all chunks in one RTCP message, look for CNAME IEs and
* replace all of those with 'new_cname' */
static int rtcp_sdes_cname_mangle(struct msgb *msg, struct rtcp_hdr *rh,
@@ -123,10 +290,16 @@ static int rtcp_mangle(struct msgb *msg, struct rtp_socket *rs)
if (!mangle_rtcp_cname)
return 0;
+ printf("RTCP\n");
/* iterate over list of RTCP messages */
rtph = (struct rtcp_hdr *)msg->data;
- while ((void *)rtph + sizeof(*rtph) < (void *)msg->data + msg->len) {
+ while ((void *)rtph + sizeof(*rtph) <= (void *)msg->data + msg->len) {
old_len = (ntohs(rtph->length) + 1) * 4;
+ if ((void *)rtph + old_len > (void *)msg->data + msg->len) {
+ DEBUGPC(DMUX, "received RTCP packet too short for "
+ "length element\n");
+ return -EINVAL;
+ }
if (rtph->type == RTCP_TYPE_SDES) {
char new_cname[255];
strncpy(new_cname, inet_ntoa(rss->sin_local.sin_addr),
@@ -148,6 +321,7 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
{
int rc;
struct msgb *msg = msgb_alloc(RTP_ALLOC_SIZE, "RTP/RTCP");
+ struct msgb *new_msg;
struct rtp_sub_socket *other_rss;
if (!msg)
@@ -184,13 +358,40 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
break;
case RTP_RECV_UPSTREAM:
- case RTP_NONE:
- /* FIXME: other cases */
- DEBUGP(DMUX, "unhandled action: %d\n", rs->rx_action);
+ if (!rs->receive.callref || !rs->receive.net) {
+ rc = -EIO;
+ goto out_free;
+ }
+ if (rss->bfd.priv_nr == RTP_PRIV_RTCP) {
+ if (!mangle_rtcp_cname) {
+ msgb_free(msg);
+ break;
+ }
+ /* modify RTCP SDES CNAME */
+ rc = rtcp_mangle(msg, rs);
+ if (rc < 0)
+ goto out_free;
+ msgb_enqueue(&rss->tx_queue, msg);
+ rss->bfd.when |= BSC_FD_WRITE;
+ break;
+ }
+ if (rss->bfd.priv_nr != RTP_PRIV_RTP) {
+ rc = -EINVAL;
+ goto out_free;
+ }
+ rc = rtp_decode(msg, rs->receive.callref, &new_msg);
+ if (rc < 0)
+ goto out_free;
+ msgb_free(msg);
+ msgb_enqueue(&rs->receive.net->upqueue, new_msg);
+ break;
+
+ case RTP_NONE: /* if socket exists, but disabled by app */
+ msgb_free(msg);
break;
}
- return rc;
+ return 0;
out_free:
msgb_free(msg);
@@ -420,6 +621,22 @@ int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other)
return 0;
}
+/* bind RTP/RTCP socket to application */
+int rtp_socket_upstream(struct rtp_socket *this, struct gsm_network *net, u_int32_t callref)
+{
+ DEBUGP(DMUX, "rtp_socket_proxy(this=%p, callref=%lu)\n",
+ this, callref);
+
+ if (callref) {
+ this->rx_action = RTP_RECV_UPSTREAM;
+ this->receive.net = net;
+ this->receive.callref = callref;
+ } else
+ this->rx_action = RTP_NONE;
+
+ return 0;
+}
+
static void free_tx_queue(struct rtp_sub_socket *rss)
{
struct msgb *msg;
diff --git a/openbsc/src/trau_mux.c b/openbsc/src/trau_mux.c
index 7ea65ce35..477ea21e5 100644
--- a/openbsc/src/trau_mux.c
+++ b/openbsc/src/trau_mux.c
@@ -32,6 +32,19 @@
#include <openbsc/debug.h>
#include <openbsc/talloc.h>
+u_int8_t gsm_fr_map[] = {
+ 6, 6, 5, 5, 4, 4, 3, 3,
+ 7, 2, 2, 6, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 7, 2, 2, 6, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 7, 2, 2, 6, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 7, 2, 2, 6, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3
+};
+
struct map_entry {
struct llist_head list;
struct gsm_e1_subslot src, dst;
@@ -144,6 +157,8 @@ lookup_trau_upqueue(const struct gsm_e1_subslot *src)
return NULL;
}
+static const u_int8_t c_bits_check[] = { 0, 0, 0, 1, 0 };
+
/* we get called by subchan_demux */
int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
const u_int8_t *trau_bits, int num_bits)
@@ -153,8 +168,6 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss);
struct subch_mux *mx;
struct upqueue_entry *ue;
- struct msgb *msg;
- struct gsm_trau_frame *frame;
int rc;
/* decode TRAU, change it to downlink, re-encode */
@@ -163,19 +176,44 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
return rc;
if (!dst_e1_ss) {
+ struct msgb *msg;
+ struct gsm_data_frame *frame;
+ unsigned char *data;
+ int i, j, k, l, o;
/* frame shall be sent to upqueue */
if (!(ue = lookup_trau_upqueue(src_e1_ss)))
return -EINVAL;
if (!ue->callref)
return -EINVAL;
- msg = msgb_alloc(sizeof(struct gsm_trau_frame) + sizeof(tf),
- "TRAU");
+ if (memcpy(tf.c_bits, c_bits_check, sizeof(c_bits_check)))
+ DEBUGPC(DMUX, "illegal trau (C1-C5) %s\n",
+ hexdump(tf.c_bits, sizeof(c_bits_check)));
+ msg = msgb_alloc(sizeof(struct gsm_data_frame) + 33,
+ "GSM-DATA");
if (!msg)
return -ENOMEM;
- frame = (struct gsm_trau_frame *)msg->data;
- frame->msg_type = GSM_TRAU_FRAME;
+
+ frame = (struct gsm_data_frame *)msg->data;
+ memset(frame, 0, sizeof(struct gsm_data_frame));
+ data = frame->data;
+ data[0] = 0xd << 4;
+ /* reassemble d-bits */
+ i = 0; /* counts bits */
+ j = 4; /* counts output bits */
+ k = gsm_fr_map[0]-1; /* current number bit in element */
+ l = 0; /* counts element bits */
+ o = 0; /* offset input bits */
+ while (i < 260) {
+ data[j/8] |= (tf.d_bits[k+o] << (7-(j%8)));
+ if (--k < 0) {
+ o += gsm_fr_map[l];
+ k = gsm_fr_map[++l]-1;
+ }
+ i++;
+ j++;
+ }
+ frame->msg_type = GSM_TCHF_FRAME;
frame->callref = ue->callref;
- memcpy(frame->data, &tf, sizeof(tf));
msgb_enqueue(&ue->net->upqueue, msg);
return 0;
@@ -221,17 +259,53 @@ int trau_recv_lchan(struct gsm_lchan *lchan, u_int32_t callref)
return 0;
}
-int trau_send_lchan(struct gsm_lchan *lchan, struct decoded_trau_frame *tf)
+int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
{
u_int8_t trau_bits_out[TRAU_FRAME_BITS];
struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
struct subch_mux *mx;
+ int i, j, k, l, o;
+ unsigned char *data = frame->data;
+ struct decoded_trau_frame tf;
mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
if (!mx)
return -EINVAL;
- encode_trau_frame(trau_bits_out, tf);
+ switch (frame->msg_type) {
+ case GSM_TCHF_FRAME:
+ /* set c-bits and t-bits */
+ tf.c_bits[0] = 1;
+ tf.c_bits[1] = 1;
+ tf.c_bits[2] = 1;
+ tf.c_bits[3] = 0;
+ tf.c_bits[4] = 0;
+ memset(&tf.c_bits[5], 0, 6);
+ memset(&tf.c_bits[11], 1, 10);
+ memset(&tf.t_bits[0], 1, 4);
+ /* reassemble d-bits */
+ i = 0; /* counts bits */
+ j = 4; /* counts input bits */
+ k = gsm_fr_map[0]-1; /* current number bit in element */
+ l = 0; /* counts element bits */
+ o = 0; /* offset output bits */
+ while (i < 260) {
+ tf.d_bits[k+o] = (data[j/8] >> (7-(j%8))) & 1;
+ if (--k < 0) {
+ o += gsm_fr_map[l];
+ k = gsm_fr_map[++l]-1;
+ }
+ i++;
+ j++;
+ }
+ break;
+ default:
+ DEBUGPC(DMUX, "unsupported message type %d\n",
+ frame->msg_type);
+ return -EINVAL;
+ }
+
+ encode_trau_frame(trau_bits_out, &tf);
/* and send it to the muxer */
return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,