diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h
index 68d76ab..4b749e8 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
@@ -199,7 +199,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 e9fc157..a3e4596 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 961a649..6ffe254 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 90535ad..8deb708 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/Makefile.am b/openbsc/src/Makefile.am
index 919e075..726c712 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -13,7 +13,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \
 		talloc_ctx.c
 
 libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \
-		mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \
+		mncc.c rtp_proxy.c md5c.c gsm_04_08.c gsm_04_11.c transaction.c \
 		token_auth.c rrlp.c
 
 libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index bac920e..f960d17 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -1869,6 +1869,8 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
 	return 0;
 }
 
+static int tch_recv(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)
@@ -1876,6 +1878,8 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
 	struct gsm_lchan *lchan = signal_data;
 	struct gsm_bts_trx_ts *ts;
 	int rc;
+	struct gsm_network *net;
+	struct gsm_trans *trans;
 
 	if (subsys != SS_ABISIP)
 		return 0;
@@ -1904,6 +1908,14 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
 				   ts->abis_ip.bound_port);
 		if (rc < 0)
 			goto out_err;
+		/* receive if whish is pending */
+		net = ts->trx->bts->network;
+		llist_for_each_entry(trans, &net->trans_list, entry) {
+			if (trans->lchan == lchan && trans->tch_recv) {
+				DEBUGP(DCC, "is pending tch_recv whish\n");
+				tch_recv(net, trans->callref, 1);
+			}
+		}
 		break;
 	case S_ABISIP_DISC_IND:
 		/* the BTS tells us a RTP stream has been disconnected */
@@ -1952,7 +1964,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_900:
 	case GSM_BTS_TYPE_NANOBTS_1800:
@@ -1962,6 +1975,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->ts->abis_ip.rtp_socket,
@@ -1987,8 +2001,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;
@@ -2011,44 +2024,60 @@ static int tch_bridge(struct gsm_network *net, u_int32_t *refs)
 }
 
 /* enable receive of channels to upqueue */
-static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable)
+static int tch_recv(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_900:
+	case GSM_BTS_TYPE_NANOBTS_1800:
+		if (ipacc_rtp_direct) {
+			DEBUGP(DCC, "Error: RTP proxy is disabled\n");
+			return -EINVAL;
+		}
+		/* in case, we don't have a socket yet */
+		if (!lchan->ts->abis_ip.rtp_socket) {
+			trans->tch_recv = enable;
+			DEBUGP(DCC, "queue tch_recv whish (%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->ts->abis_ip.rtp_socket,
+				net, callref);
+		} else
+			rtp_socket_upstream(lchan->ts->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");
@@ -3287,11 +3316,31 @@ 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(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(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_900:
+		case GSM_BTS_TYPE_NANOBTS_1800:
+			if (!trans->lchan->ts->abis_ip.rtp_socket)
+				return 0;
+			return rtp_send_frame(trans->lchan->ts->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 59c0735..3933309 100644
--- a/openbsc/src/rtp_proxy.c
+++ b/openbsc/src/rtp_proxy.c
@@ -24,6 +24,11 @@
 #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/md5.h" /* from RFC 1321 */
 
 #include <openbsc/talloc.h>
 #include <openbsc/gsm_data.h>
@@ -57,6 +62,220 @@ 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
+
+/*
+ * Generate a random 32-bit quantity. (Appendix A. 6)
+ */
+
+#define MD_CTX MD5_CTX
+#define MDInit MD5Init
+#define MDUpdate MD5Update
+#define MDFinal MD5Final
+
+static u_int32_t md_32(unsigned char *string, int length)
+{
+	MD_CTX context;
+	union {
+		char      c[16];
+		u_int32_t x[4];
+	} digest;
+	u_int32_t r;
+	int i;
+
+	MDInit (&context);
+	MDUpdate (&context, string, length);
+	MDFinal ((unsigned char *)&digest, &context);
+	r = 0;
+	for (i = 0; i < 3; i++) {
+		r ^= digest.x[i];
+	}
+	return r;
+}
+
+/*
+ * Return random unsigned 32-bit quantity.  Use 'type' argument if
+ * you need to generate several different values in close succession.
+ */
+static u_int32_t random32(int type)
+{
+	struct {
+		int       type;
+		struct    timeval tv;
+		clock_t   cpu;
+		pid_t     pid;
+		u_int32_t hid;
+		uid_t     uid;
+		gid_t     gid;
+		struct    utsname name;
+	} s;
+
+	gettimeofday(&s.tv, 0);
+	uname(&s.name);
+	s.type = type;
+	s.cpu  = clock();
+	s.pid  = getpid();
+	s.hid  = gethostid();
+	s.uid  = getuid();
+	s.gid  = getgid();
+	/* also: system uptime */
+
+	return md_32((unsigned char *)&s, sizeof(s));
+}
+
+/* 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);
+		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 = random32(frame->callref);
+		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,
@@ -148,6 +367,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 +404,36 @@ 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) {
+			/* 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 +663,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 6a19f0c..b060657 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;
@@ -151,8 +164,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 */
@@ -161,19 +172,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 (tf.c_bits[0]!=0 || tf.c_bits[1]!=0 || tf.c_bits[2]!=0 || tf.c_bits[3]!=1 || tf.c_bits[4]!=0)
+			DEBUGPC(DMUX, "illegal trau (C1-C5) %d %d %d %d %d\n", tf.c_bits[0], tf.c_bits[1],
+				tf.c_bits[2], tf.c_bits[3], tf.c_bits[4]);
+		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;
@@ -219,17 +255,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,
diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c
index 032e16f..b9ec7e0 100644
--- a/openbsc/src/vty_interface_layer3.c
+++ b/openbsc/src/vty_interface_layer3.c
@@ -173,7 +173,7 @@ struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver, const char *text)
 		return NULL;
 	}
 
-	sms->receiver = subscr_get(receiver);
+	sms->receiver = receiver;
 	strncpy(sms->text, text, sizeof(sms->text)-1);
 
 	/* FIXME: don't use ID 1 static */
@@ -196,6 +196,10 @@ static int _send_sms_buffer(struct gsm_subscriber *receiver,
 	struct gsm_sms *sms;
 
 	sms = sms_from_text(receiver, buffer_getstr(b));
+	if (!sms) {
+		subscr_put(receiver);
+		return CMD_WARNING;
+	}
 
 	gsm411_send_sms_subscr(receiver, sms);
 
