With this patch, the TRAU muxing code supports not just bridging only. 

A new function trau_recv_lchan() is used to link a channel to a call reference
of a transaction. (Transactions are used in later patches.) TRAU frames will
then be forwarded to the application with the given call reference (in later
patches). Also the application can send TRAU frames by using trau_send_lchan().

A new list is introduced in trau_mux.c. (upqueue_entry) All subslots
that must be sent to application are listed here.

Received TRAU frames are written in the upqueue of application
interface, if a call reference is found in the upqueue-list. If an entry
is found the ss_entry list, the TRAU frames are bridged as before. The
frames have a message type (msg_type), a call reference (callref) and a
trau frame (data). The length of trau frame is defined by the content of
the c-bits inside the frame.

There is no support for ip.access yet, as they don't use the traditional
TRAU frame format. Harald must add this in order to use application interface
with ip-access. The bridging with ip-access works as before.
(Andreas Eversberg)

diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h
index 0e3a380..071b1c6 100644
--- a/include/openbsc/gsm_data.h
+++ b/include/openbsc/gsm_data.h
@@ -138,8 +138,10 @@
 	struct gsm_bts_trx_ts *ts;
 	/* The logical subslot number in the TS */
 	u_int8_t nr;
-	/* The lotical channel type */
+	/* The logical channel type */
 	enum gsm_chan_t type;
+	/* If TCH, traffic channel mode */
+	enum gsm_chan_t tch_mode;
 	/* Power levels for MS and BTS */
 	u_int8_t bs_power;
 	u_int8_t ms_power;
diff --git a/include/openbsc/trau_mux.h b/include/openbsc/trau_mux.h
index f3d519f..90535ad 100644
--- a/include/openbsc/trau_mux.h
+++ b/include/openbsc/trau_mux.h
@@ -36,8 +36,14 @@
 			const struct gsm_lchan *dst);
 
 /* unmap a TRAU mux map entry */
-int trau_mux_unmap(const struct gsm_e1_subslot *ss);
+int trau_mux_unmap(const struct gsm_e1_subslot *ss, u_int32_t callref);
 
 /* 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);
+
+/* add a trau receiver */
+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);
diff --git a/src/abis_rsl.c b/src/abis_rsl.c
index 753a666..d9a39b8 100644
--- a/src/abis_rsl.c
+++ b/src/abis_rsl.c
@@ -476,10 +476,21 @@
 	/* FIXME: what to do with data calls ? */
 	cm.dtx_dtu = 0x00;
 	switch (lchan->type) {
+	/* todo more modes */
 	case GSM_LCHAN_TCH_F:
 		cm.spd_ind = RSL_CMOD_SPD_SPEECH;
 		cm.chan_rt = RSL_CMOD_CRT_TCH_Bm;
-		cm.chan_rate = RSL_CMOD_SP_GSM2;
+		switch(lchan->tch_mode) {
+		case GSM48_CMODE_SPEECH_V1:
+			cm.chan_rate = RSL_CMOD_SP_GSM1;
+			break;
+		case GSM48_CMODE_SPEECH_EFR:
+			cm.chan_rate = RSL_CMOD_SP_GSM2;
+			break;
+		default:
+			DEBUGP(DRSL, "Unimplemented channel modification\n");
+			return -1;
+		}
 		break;
 	default:
 		DEBUGP(DRSL, "Unimplemented channel modification\n");
diff --git a/src/e1_config.c b/src/e1_config.c
index ffc7e46..fc23b55 100644
--- a/src/e1_config.c
+++ b/src/e1_config.c
@@ -5,6 +5,7 @@
 
 #include <openbsc/gsm_data.h>
 #include <openbsc/e1_input.h>
+#include <openbsc/trau_frame.h>
 #include <openbsc/trau_mux.h>
 #include <openbsc/misdn.h>
 
diff --git a/src/e1_input.c b/src/e1_input.c
index 7fbf179..c3c7c75 100644
--- a/src/e1_input.c
+++ b/src/e1_input.c
@@ -49,6 +49,7 @@
 #include <openbsc/abis_rsl.h>
 #include <openbsc/linuxlist.h>
 #include <openbsc/subchan_demux.h>
+#include <openbsc/trau_frame.h>
 #include <openbsc/trau_mux.h>
 
 #define NUM_E1_TS	32
diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c
index 849ef48..07e7a46 100644
--- a/src/gsm_04_08.c
+++ b/src/gsm_04_08.c
@@ -42,6 +42,7 @@
 #include <openbsc/chan_alloc.h>
 #include <openbsc/paging.h>
 #include <openbsc/signal.h>
+#include <openbsc/trau_frame.h>
 #include <openbsc/trau_mux.h>
 
 #define GSM48_ALLOC_SIZE	1024
@@ -635,6 +636,7 @@
 
 	DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode);
 
+	lchan->tch_mode = mode;
 	msg->lchan = lchan;
 	gh->proto_discr = GSM48_PDISC_RR;
 	gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF;
diff --git a/src/trau_mux.c b/src/trau_mux.c
index 2616785..96f8589 100644
--- a/src/trau_mux.c
+++ b/src/trau_mux.c
@@ -36,7 +36,15 @@
 	struct gsm_e1_subslot src, dst;
 };
 
+struct upqueue_entry {
+	struct llist_head list;
+	struct gsm_network *net;
+	struct gsm_e1_subslot src;
+	u_int32_t callref;
+};
+
 static LLIST_HEAD(ss_map);
+static LLIST_HEAD(ss_upqueue);
 
 /* map one particular subslot to another subslot */
 int trau_mux_map(const struct gsm_e1_subslot *src,
@@ -52,8 +60,8 @@
 		dst->e1_nr, dst->e1_ts, dst->e1_ts_ss);
 
 	/* make sure to get rid of any stale old mappings */
-	trau_mux_unmap(src);
-	trau_mux_unmap(dst);
+	trau_mux_unmap(src, 0);
+	trau_mux_unmap(dst, 0);
 
 	memcpy(&me->src, src, sizeof(me->src));
 	memcpy(&me->dst, dst, sizeof(me->dst));
@@ -75,14 +83,26 @@
 
 
 /* unmap one particular subslot from another subslot */
-int trau_mux_unmap(const struct gsm_e1_subslot *ss)
+int trau_mux_unmap(const struct gsm_e1_subslot *ss, u_int32_t callref)
 {
 	struct map_entry *me, *me2;
+	struct upqueue_entry *ue, *ue2;
 
-	llist_for_each_entry_safe(me, me2, &ss_map, list) {
-		if (!memcmp(&me->src, ss, sizeof(*ss)) ||
-		    !memcmp(&me->dst, ss, sizeof(*ss))) {
-			llist_del(&me->list);
+	if (ss)
+		llist_for_each_entry_safe(me, me2, &ss_map, list) {
+			if (!memcmp(&me->src, ss, sizeof(*ss)) ||
+			    !memcmp(&me->dst, ss, sizeof(*ss))) {
+				llist_del(&me->list);
+				return 0;
+			}
+		}
+	llist_for_each_entry_safe(ue, ue2, &ss_upqueue, list) {
+		if (ue->callref == callref) {
+			llist_del(&ue->list);
+			return 0;
+		}
+		if (ss && !memcmp(&ue->src, ss, sizeof(*ss))) {
+			llist_del(&ue->list);
 			return 0;
 		}
 	}
@@ -104,6 +124,19 @@
 	return NULL;
 }
 
+/* look-up an enty in the TRAU upqueue */
+struct upqueue_entry *
+lookup_trau_upqueue(const struct gsm_e1_subslot *src)
+{
+	struct upqueue_entry *ue;
+
+	llist_for_each_entry(ue, &ss_upqueue, list) {
+		if (!memcmp(&ue->src, src, sizeof(*src)))
+			return ue;
+	}
+	return NULL;
+}
+
 /* 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)
@@ -114,6 +147,11 @@
 	struct subch_mux *mx;
 	int rc;
 
+	/* decode TRAU, change it to downlink, re-encode */
+	rc = decode_trau_frame(&tf, trau_bits);
+	if (rc)
+		return rc;
+
 	if (!dst_e1_ss)
 		return -EINVAL;
 
@@ -121,11 +159,6 @@
 	if (!mx)
 		return -EINVAL;
 
-	/* decode TRAU, change it to downlink, re-encode */
-	rc = decode_trau_frame(&tf, trau_bits);
-	if (rc)
-		return rc;
-
 	trau_frame_up2down(&tf);
 	encode_trau_frame(trau_bits_out, &tf);
 
@@ -133,3 +166,47 @@
 	return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
 				   TRAU_FRAME_BITS);
 }
+
+/* add receiver instance for lchan and callref */
+int trau_recv_lchan(struct gsm_lchan *lchan, u_int32_t callref)
+{
+	struct gsm_e1_subslot *src_ss;
+	struct upqueue_entry *ue = malloc(sizeof(*ue));
+
+	if (!ue)
+		return -ENOMEM;
+
+	src_ss = &lchan->ts->e1_link;
+
+	DEBUGP(DCC, "Setting up TRAU receiver (e1=%u,ts=%u,ss=%u) "
+		"and (callref 0x%x)\n",
+		src_ss->e1_nr, src_ss->e1_ts, src_ss->e1_ts_ss,
+		callref);
+
+	/* make sure to get rid of any stale old mappings */
+	trau_mux_unmap(src_ss, callref);
+
+	memcpy(&ue->src, src_ss, sizeof(ue->src));
+	ue->net = lchan->ts->trx->bts->network;
+	ue->callref = callref;
+	llist_add(&ue->list, &ss_upqueue);
+
+	return 0;
+}
+
+int trau_send_lchan(struct gsm_lchan *lchan, struct decoded_trau_frame *tf)
+{
+	u_int8_t trau_bits_out[TRAU_FRAME_BITS];
+	struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
+	struct subch_mux *mx;
+
+	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);
+
+	/* and send it to the muxer */
+	return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
+				   TRAU_FRAME_BITS);
+}