blob: c9d77cf7803f902f3da42f98259dd71a895df3e8 [file] [log] [blame]
Harald Welte59b04682009-06-10 05:40:52 +08001/* Simple TRAU frame reflector to route voice calls */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
Harald Welte0e3e88e2011-01-01 15:25:50 +01007 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
Harald Welte59b04682009-06-10 05:40:52 +08009 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte0e3e88e2011-01-01 15:25:50 +010014 * GNU Affero General Public License for more details.
Harald Welte59b04682009-06-10 05:40:52 +080015 *
Harald Welte0e3e88e2011-01-01 15:25:50 +010016 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte59b04682009-06-10 05:40:52 +080018 *
19 */
20
21#include <errno.h>
22#include <stdlib.h>
23#include <string.h>
Harald Welte59b04682009-06-10 05:40:52 +080024
25#include <openbsc/gsm_data.h>
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +020026#include <osmocom/abis/trau_frame.h>
Harald Welte59b04682009-06-10 05:40:52 +080027#include <openbsc/trau_mux.h>
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +020028#include <osmocom/abis/subchan_demux.h>
29#include <osmocom/abis/e1_input.h>
Harald Welte59b04682009-06-10 05:40:52 +080030#include <openbsc/debug.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010031#include <osmocom/core/talloc.h>
Alexander Huemer45a00142011-09-06 00:09:49 +020032#include <openbsc/trau_upqueue.h>
Andreas Eversberg2c202cd2013-12-06 16:59:10 +010033#include <osmocom/core/crcgen.h>
Harald Welte59b04682009-06-10 05:40:52 +080034
Holger Hans Peter Freyther16e59db2011-10-26 19:01:57 +020035/* this corresponds to the bit-lengths of the individual codec
Harald Welte9eb9b322011-07-24 02:18:13 +020036 * parameters as indicated in Table 1.1 of TS 06.10 */
37static const uint8_t gsm_fr_map[] = {
Harald Welte3971ad52009-12-19 22:23:05 +010038 6, 6, 5, 5, 4, 4, 3, 3,
39 7, 2, 2, 6, 3, 3, 3, 3,
40 3, 3, 3, 3, 3, 3, 3, 3,
41 3, 7, 2, 2, 6, 3, 3, 3,
42 3, 3, 3, 3, 3, 3, 3, 3,
43 3, 3, 7, 2, 2, 6, 3, 3,
44 3, 3, 3, 3, 3, 3, 3, 3,
45 3, 3, 3, 7, 2, 2, 6, 3,
46 3, 3, 3, 3, 3, 3, 3, 3,
47 3, 3, 3, 3
48};
49
Andreas Eversberg2c202cd2013-12-06 16:59:10 +010050
51/*
52 * EFR TRAU parity
53 *
54 * g(x) = x^3 + x^1 + 1
55 */
56static const struct osmo_crc8gen_code gsm0860_efr_crc3 = {
57 .bits = 3,
58 .poly = 0x3,
59 .init = 0x0,
60 .remainder = 0x7,
61};
62
63/* EFR parity bits */
64static inline void efr_parity_bits_1(ubit_t *check_bits, const ubit_t *d_bits)
65{
66 memcpy(check_bits + 0 , d_bits + 0, 22);
67 memcpy(check_bits + 22 , d_bits + 24, 3);
68 check_bits[25] = d_bits[28];
69}
70
71static inline void efr_parity_bits_2(ubit_t *check_bits, const ubit_t *d_bits)
72{
73 memcpy(check_bits + 0 , d_bits + 42, 10);
74 memcpy(check_bits + 10 , d_bits + 90, 2);
75}
76
77static inline void efr_parity_bits_3(ubit_t *check_bits, const ubit_t *d_bits)
78{
79 memcpy(check_bits + 0 , d_bits + 98, 5);
80 check_bits[5] = d_bits[104];
81 memcpy(check_bits + 6 , d_bits + 143, 2);
82}
83
84static inline void efr_parity_bits_4(ubit_t *check_bits, const ubit_t *d_bits)
85{
86 memcpy(check_bits + 0 , d_bits + 151, 10);
87 memcpy(check_bits + 10 , d_bits + 199, 2);
88}
89
90static inline void efr_parity_bits_5(ubit_t *check_bits, const ubit_t *d_bits)
91{
92 memcpy(check_bits + 0 , d_bits + 207, 5);
93 check_bits[5] = d_bits[213];
94 memcpy(check_bits + 6 , d_bits + 252, 2);
95}
96
Harald Welte59b04682009-06-10 05:40:52 +080097struct map_entry {
98 struct llist_head list;
99 struct gsm_e1_subslot src, dst;
100};
101
102struct upqueue_entry {
103 struct llist_head list;
104 struct gsm_network *net;
105 struct gsm_e1_subslot src;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200106 uint32_t callref;
Harald Welte59b04682009-06-10 05:40:52 +0800107};
108
109static LLIST_HEAD(ss_map);
110static LLIST_HEAD(ss_upqueue);
111
Harald Welte (local)8751ee92009-08-15 02:30:58 +0200112void *tall_map_ctx, *tall_upq_ctx;
Harald Weltea8379772009-06-20 22:36:41 +0200113
Harald Welte59b04682009-06-10 05:40:52 +0800114/* map one particular subslot to another subslot */
115int trau_mux_map(const struct gsm_e1_subslot *src,
116 const struct gsm_e1_subslot *dst)
117{
Harald Weltea8379772009-06-20 22:36:41 +0200118 struct map_entry *me;
119
Harald Weltea8379772009-06-20 22:36:41 +0200120 me = talloc(tall_map_ctx, struct map_entry);
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100121 if (!me) {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200122 LOGP(DLMIB, LOGL_FATAL, "Out of memory\n");
Harald Welte59b04682009-06-10 05:40:52 +0800123 return -ENOMEM;
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100124 }
Harald Welte59b04682009-06-10 05:40:52 +0800125
126 DEBUGP(DCC, "Setting up TRAU mux map between (e1=%u,ts=%u,ss=%u) "
127 "and (e1=%u,ts=%u,ss=%u)\n",
128 src->e1_nr, src->e1_ts, src->e1_ts_ss,
129 dst->e1_nr, dst->e1_ts, dst->e1_ts_ss);
130
131 /* make sure to get rid of any stale old mappings */
132 trau_mux_unmap(src, 0);
133 trau_mux_unmap(dst, 0);
134
135 memcpy(&me->src, src, sizeof(me->src));
136 memcpy(&me->dst, dst, sizeof(me->dst));
137 llist_add(&me->list, &ss_map);
138
139 return 0;
140}
141
142int trau_mux_map_lchan(const struct gsm_lchan *src,
143 const struct gsm_lchan *dst)
144{
145 struct gsm_e1_subslot *src_ss, *dst_ss;
146
147 src_ss = &src->ts->e1_link;
148 dst_ss = &dst->ts->e1_link;
149
150 return trau_mux_map(src_ss, dst_ss);
151}
152
153
154/* unmap one particular subslot from another subslot */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200155int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_t callref)
Harald Welte59b04682009-06-10 05:40:52 +0800156{
157 struct map_entry *me, *me2;
158 struct upqueue_entry *ue, *ue2;
159
160 if (ss)
161 llist_for_each_entry_safe(me, me2, &ss_map, list) {
162 if (!memcmp(&me->src, ss, sizeof(*ss)) ||
163 !memcmp(&me->dst, ss, sizeof(*ss))) {
164 llist_del(&me->list);
165 return 0;
166 }
167 }
168 llist_for_each_entry_safe(ue, ue2, &ss_upqueue, list) {
169 if (ue->callref == callref) {
170 llist_del(&ue->list);
171 return 0;
172 }
173 if (ss && !memcmp(&ue->src, ss, sizeof(*ss))) {
174 llist_del(&ue->list);
175 return 0;
176 }
177 }
178 return -ENOENT;
179}
180
181/* look-up an enty in the TRAU mux map */
182static struct gsm_e1_subslot *
183lookup_trau_mux_map(const struct gsm_e1_subslot *src)
184{
185 struct map_entry *me;
186
187 llist_for_each_entry(me, &ss_map, list) {
188 if (!memcmp(&me->src, src, sizeof(*src)))
189 return &me->dst;
190 if (!memcmp(&me->dst, src, sizeof(*src)))
191 return &me->src;
192 }
193 return NULL;
194}
195
196/* look-up an enty in the TRAU upqueue */
197struct upqueue_entry *
198lookup_trau_upqueue(const struct gsm_e1_subslot *src)
199{
200 struct upqueue_entry *ue;
201
202 llist_for_each_entry(ue, &ss_upqueue, list) {
203 if (!memcmp(&ue->src, src, sizeof(*src)))
204 return ue;
205 }
206 return NULL;
207}
208
Andreas Eversberg2c202cd2013-12-06 16:59:10 +0100209static const uint8_t c_bits_check_fr[] = { 0, 0, 0, 1, 0 };
210static const uint8_t c_bits_check_efr[] = { 1, 1, 0, 1, 0 };
211
212struct msgb *trau_decode_fr(uint32_t callref,
213 const struct decoded_trau_frame *tf)
214{
215 struct msgb *msg;
216 struct gsm_data_frame *frame;
217 unsigned char *data;
218 int i, j, k, l, o;
219
220 msg = msgb_alloc(sizeof(struct gsm_data_frame) + 33,
221 "GSM-DATA");
222 if (!msg)
223 return NULL;
224
225 frame = (struct gsm_data_frame *)msg->data;
226 memset(frame, 0, sizeof(struct gsm_data_frame));
227 data = frame->data;
228 data[0] = 0xd << 4;
229 /* reassemble d-bits */
230 i = 0; /* counts bits */
231 j = 4; /* counts output bits */
232 k = gsm_fr_map[0]-1; /* current number bit in element */
233 l = 0; /* counts element bits */
234 o = 0; /* offset input bits */
235 while (i < 260) {
236 data[j/8] |= (tf->d_bits[k+o] << (7-(j%8)));
237 if (--k < 0) {
238 o += gsm_fr_map[l];
239 k = gsm_fr_map[++l]-1;
240 }
241 i++;
242 j++;
243 }
244 frame->msg_type = GSM_TCHF_FRAME;
245 frame->callref = callref;
246 msgb_put(msg, sizeof(struct gsm_data_frame) + 33);
247
248 return msg;
249}
250
251struct msgb *trau_decode_efr(uint32_t callref,
252 const struct decoded_trau_frame *tf)
253{
254 struct msgb *msg;
255 struct gsm_data_frame *frame;
256 unsigned char *data;
257 int i, j, rc;
258 ubit_t check_bits[26];
259
260 msg = msgb_alloc(sizeof(struct gsm_data_frame) + 31,
261 "GSM-DATA");
262 if (!msg)
263 return NULL;
264
265 frame = (struct gsm_data_frame *)msg->data;
266 memset(frame, 0, sizeof(struct gsm_data_frame));
267 frame->msg_type = GSM_TCHF_FRAME_EFR;
268 frame->callref = callref;
269 msgb_put(msg, sizeof(struct gsm_data_frame) + 31);
270
271 if (tf->c_bits[11]) /* BFI */
272 goto bad_frame;
273
274 data = frame->data;
275 data[0] = 0xc << 4;
276 /* reassemble d-bits */
277 for (i = 1, j = 4; i < 39; i++, j++)
278 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
279 efr_parity_bits_1(check_bits, tf->d_bits);
280 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 26,
281 tf->d_bits + 39);
282 if (rc)
283 goto bad_frame;
284 for (i = 42, j = 42; i < 95; i++, j++)
285 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
286 efr_parity_bits_2(check_bits, tf->d_bits);
287 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12,
288 tf->d_bits + 95);
289 if (rc)
290 goto bad_frame;
291 for (i = 98, j = 95; i < 148; i++, j++)
292 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
293 efr_parity_bits_3(check_bits, tf->d_bits);
294 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8,
295 tf->d_bits + 148);
296 if (rc)
297 goto bad_frame;
298 for (i = 151, j = 145; i < 204; i++, j++)
299 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
300 efr_parity_bits_4(check_bits, tf->d_bits);
301 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12,
302 tf->d_bits + 204);
303 if (rc)
304 goto bad_frame;
305 for (i = 207, j = 198; i < 257; i++, j++)
306 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
307 efr_parity_bits_5(check_bits, tf->d_bits);
308 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8,
309 tf->d_bits + 257);
310 if (rc)
311 goto bad_frame;
312
313 return msg;
314
315bad_frame:
316 frame->msg_type = GSM_TCHF_BAD_FRAME;
317
318 return msg;
319}
Harald Welte3971ad52009-12-19 22:23:05 +0100320
Harald Welte59b04682009-06-10 05:40:52 +0800321/* we get called by subchan_demux */
322int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200323 const uint8_t *trau_bits, int num_bits)
Harald Welte59b04682009-06-10 05:40:52 +0800324{
325 struct decoded_trau_frame tf;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200326 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte59b04682009-06-10 05:40:52 +0800327 struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss);
328 struct subch_mux *mx;
Harald Welte03740842009-06-10 23:11:52 +0800329 struct upqueue_entry *ue;
Harald Welte59b04682009-06-10 05:40:52 +0800330 int rc;
331
332 /* decode TRAU, change it to downlink, re-encode */
333 rc = decode_trau_frame(&tf, trau_bits);
334 if (rc)
335 return rc;
336
Harald Welte03740842009-06-10 23:11:52 +0800337 if (!dst_e1_ss) {
Andreas Eversberg2c202cd2013-12-06 16:59:10 +0100338 struct msgb *msg = NULL;
Harald Welte03740842009-06-10 23:11:52 +0800339 /* frame shall be sent to upqueue */
340 if (!(ue = lookup_trau_upqueue(src_e1_ss)))
341 return -EINVAL;
342 if (!ue->callref)
343 return -EINVAL;
Andreas Eversberg2c202cd2013-12-06 16:59:10 +0100344 if (!memcmp(tf.c_bits, c_bits_check_fr, 5))
345 msg = trau_decode_fr(ue->callref, &tf);
346 else if (!memcmp(tf.c_bits, c_bits_check_efr, 5))
347 msg = trau_decode_efr(ue->callref, &tf);
348 else {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200349 DEBUGPC(DLMUX, "illegal trau (C1-C5) %s\n",
Andreas Eversberg2c202cd2013-12-06 16:59:10 +0100350 osmo_hexdump(tf.c_bits, 5));
351 DEBUGPC(DLMUX, "test trau (C1-C5) %s\n",
352 osmo_hexdump(c_bits_check_efr, 5));
353 return -EINVAL;
354 }
Harald Welte03740842009-06-10 23:11:52 +0800355 if (!msg)
356 return -ENOMEM;
Harald Welte4f272cc2011-03-03 23:29:05 +0100357 trau_tx_to_mncc(ue->net, msg);
Harald Welte03740842009-06-10 23:11:52 +0800358
359 return 0;
360 }
Harald Welte59b04682009-06-10 05:40:52 +0800361
362 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
363 if (!mx)
364 return -EINVAL;
365
366 trau_frame_up2down(&tf);
367 encode_trau_frame(trau_bits_out, &tf);
368
369 /* and send it to the muxer */
370 return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
371 TRAU_FRAME_BITS);
372}
373
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200374/* callback when a TRAU frame was received */
375int subch_cb(struct subch_demux *dmx, int ch, uint8_t *data, int len,
376 void *_priv)
377{
378 struct e1inp_ts *e1i_ts = _priv;
379 struct gsm_e1_subslot src_ss;
380
381 src_ss.e1_nr = e1i_ts->line->num;
382 src_ss.e1_ts = e1i_ts->num;
383 src_ss.e1_ts_ss = ch;
384
385 return trau_mux_input(&src_ss, data, len);
386}
387
Harald Welte59b04682009-06-10 05:40:52 +0800388/* add receiver instance for lchan and callref */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200389int trau_recv_lchan(struct gsm_lchan *lchan, uint32_t callref)
Harald Welte59b04682009-06-10 05:40:52 +0800390{
391 struct gsm_e1_subslot *src_ss;
Harald Weltea8379772009-06-20 22:36:41 +0200392 struct upqueue_entry *ue;
Harald Welte59b04682009-06-10 05:40:52 +0800393
Harald Weltea8379772009-06-20 22:36:41 +0200394 ue = talloc(tall_upq_ctx, struct upqueue_entry);
Harald Welte59b04682009-06-10 05:40:52 +0800395 if (!ue)
396 return -ENOMEM;
397
398 src_ss = &lchan->ts->e1_link;
399
400 DEBUGP(DCC, "Setting up TRAU receiver (e1=%u,ts=%u,ss=%u) "
401 "and (callref 0x%x)\n",
402 src_ss->e1_nr, src_ss->e1_ts, src_ss->e1_ts_ss,
403 callref);
404
405 /* make sure to get rid of any stale old mappings */
406 trau_mux_unmap(src_ss, callref);
407
408 memcpy(&ue->src, src_ss, sizeof(ue->src));
409 ue->net = lchan->ts->trx->bts->network;
410 ue->callref = callref;
411 llist_add(&ue->list, &ss_upqueue);
412
413 return 0;
414}
415
Andreas Eversberg2c202cd2013-12-06 16:59:10 +0100416void trau_encode_fr(struct decoded_trau_frame *tf,
417 const unsigned char *data)
418{
419 int i, j, k, l, o;
420
421 /* set c-bits and t-bits */
422 tf->c_bits[0] = 1;
423 tf->c_bits[1] = 1;
424 tf->c_bits[2] = 1;
425 tf->c_bits[3] = 0;
426 tf->c_bits[4] = 0;
427 memset(&tf->c_bits[5], 0, 6);
428 memset(&tf->c_bits[11], 1, 10);
429 memset(&tf->t_bits[0], 1, 4);
430 /* reassemble d-bits */
431 i = 0; /* counts bits */
432 j = 4; /* counts input bits */
433 k = gsm_fr_map[0]-1; /* current number bit in element */
434 l = 0; /* counts element bits */
435 o = 0; /* offset output bits */
436 while (i < 260) {
437 tf->d_bits[k+o] = (data[j/8] >> (7-(j%8))) & 1;
438 if (--k < 0) {
439 o += gsm_fr_map[l];
440 k = gsm_fr_map[++l]-1;
441 }
442 i++;
443 j++;
444 }
445}
446
447void trau_encode_efr(struct decoded_trau_frame *tf,
448 const unsigned char *data)
449{
450 int i, j;
451 ubit_t check_bits[26];
452
453 /* set c-bits and t-bits */
454 tf->c_bits[0] = 1;
455 tf->c_bits[1] = 1;
456 tf->c_bits[2] = 0;
457 tf->c_bits[3] = 1;
458 tf->c_bits[4] = 0;
459 memset(&tf->c_bits[5], 0, 6);
460 memset(&tf->c_bits[11], 1, 10);
461 memset(&tf->t_bits[0], 1, 4);
462 /* reassemble d-bits */
463 tf->d_bits[0] = 1;
464 for (i = 1, j = 4; i < 39; i++, j++)
465 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
466 efr_parity_bits_1(check_bits, tf->d_bits);
467 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 26,
468 tf->d_bits + 39);
469 for (i = 42, j = 42; i < 95; i++, j++)
470 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
471 efr_parity_bits_2(check_bits, tf->d_bits);
472 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 12,
473 tf->d_bits + 95);
474 for (i = 98, j = 95; i < 148; i++, j++)
475 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
476 efr_parity_bits_3(check_bits, tf->d_bits);
477 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 8,
478 tf->d_bits + 148);
479 for (i = 151, j = 145; i < 204; i++, j++)
480 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
481 efr_parity_bits_4(check_bits, tf->d_bits);
482 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 12,
483 tf->d_bits + 204);
484 for (i = 207, j = 198; i < 257; i++, j++)
485 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
486 efr_parity_bits_5(check_bits, tf->d_bits);
487 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 8,
488 tf->d_bits + 257);
489}
490
Harald Welte3971ad52009-12-19 22:23:05 +0100491int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
Harald Welte59b04682009-06-10 05:40:52 +0800492{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200493 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte59b04682009-06-10 05:40:52 +0800494 struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
495 struct subch_mux *mx;
Harald Welte3971ad52009-12-19 22:23:05 +0100496 struct decoded_trau_frame tf;
Harald Welte59b04682009-06-10 05:40:52 +0800497
498 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
499 if (!mx)
500 return -EINVAL;
501
Harald Welte3971ad52009-12-19 22:23:05 +0100502 switch (frame->msg_type) {
503 case GSM_TCHF_FRAME:
Andreas Eversberg2c202cd2013-12-06 16:59:10 +0100504 trau_encode_fr(&tf, frame->data);
505 break;
506 case GSM_TCHF_FRAME_EFR:
507 trau_encode_efr(&tf, frame->data);
Harald Welte3971ad52009-12-19 22:23:05 +0100508 break;
509 default:
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200510 DEBUGPC(DLMUX, "unsupported message type %d\n",
Harald Welte3971ad52009-12-19 22:23:05 +0100511 frame->msg_type);
512 return -EINVAL;
513 }
514
515 encode_trau_frame(trau_bits_out, &tf);
Harald Welte59b04682009-06-10 05:40:52 +0800516
517 /* and send it to the muxer */
518 return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
519 TRAU_FRAME_BITS);
520}