blob: 4f159e4cb7c62a3faa6936fd602819d9bbfbb4b3 [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>
Andreas Eversberg02063672013-12-05 14:37:11 +010034#include <openbsc/transaction.h>
Harald Welte59b04682009-06-10 05:40:52 +080035
Holger Hans Peter Freyther16e59db2011-10-26 19:01:57 +020036/* this corresponds to the bit-lengths of the individual codec
Harald Welte9eb9b322011-07-24 02:18:13 +020037 * parameters as indicated in Table 1.1 of TS 06.10 */
38static const uint8_t gsm_fr_map[] = {
Harald Welte3971ad52009-12-19 22:23:05 +010039 6, 6, 5, 5, 4, 4, 3, 3,
40 7, 2, 2, 6, 3, 3, 3, 3,
41 3, 3, 3, 3, 3, 3, 3, 3,
42 3, 7, 2, 2, 6, 3, 3, 3,
43 3, 3, 3, 3, 3, 3, 3, 3,
44 3, 3, 7, 2, 2, 6, 3, 3,
45 3, 3, 3, 3, 3, 3, 3, 3,
46 3, 3, 3, 7, 2, 2, 6, 3,
47 3, 3, 3, 3, 3, 3, 3, 3,
48 3, 3, 3, 3
49};
50
Andreas Eversberg2c202cd2013-12-06 16:59:10 +010051
52/*
53 * EFR TRAU parity
54 *
55 * g(x) = x^3 + x^1 + 1
56 */
57static const struct osmo_crc8gen_code gsm0860_efr_crc3 = {
58 .bits = 3,
59 .poly = 0x3,
60 .init = 0x0,
61 .remainder = 0x7,
62};
63
64/* EFR parity bits */
65static inline void efr_parity_bits_1(ubit_t *check_bits, const ubit_t *d_bits)
66{
67 memcpy(check_bits + 0 , d_bits + 0, 22);
68 memcpy(check_bits + 22 , d_bits + 24, 3);
69 check_bits[25] = d_bits[28];
70}
71
72static inline void efr_parity_bits_2(ubit_t *check_bits, const ubit_t *d_bits)
73{
74 memcpy(check_bits + 0 , d_bits + 42, 10);
75 memcpy(check_bits + 10 , d_bits + 90, 2);
76}
77
78static inline void efr_parity_bits_3(ubit_t *check_bits, const ubit_t *d_bits)
79{
80 memcpy(check_bits + 0 , d_bits + 98, 5);
81 check_bits[5] = d_bits[104];
82 memcpy(check_bits + 6 , d_bits + 143, 2);
83}
84
85static inline void efr_parity_bits_4(ubit_t *check_bits, const ubit_t *d_bits)
86{
87 memcpy(check_bits + 0 , d_bits + 151, 10);
88 memcpy(check_bits + 10 , d_bits + 199, 2);
89}
90
91static inline void efr_parity_bits_5(ubit_t *check_bits, const ubit_t *d_bits)
92{
93 memcpy(check_bits + 0 , d_bits + 207, 5);
94 check_bits[5] = d_bits[213];
95 memcpy(check_bits + 6 , d_bits + 252, 2);
96}
97
Harald Welte59b04682009-06-10 05:40:52 +080098struct map_entry {
99 struct llist_head list;
100 struct gsm_e1_subslot src, dst;
101};
102
103struct upqueue_entry {
104 struct llist_head list;
105 struct gsm_network *net;
106 struct gsm_e1_subslot src;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200107 uint32_t callref;
Harald Welte59b04682009-06-10 05:40:52 +0800108};
109
110static LLIST_HEAD(ss_map);
111static LLIST_HEAD(ss_upqueue);
112
Harald Welte (local)8751ee92009-08-15 02:30:58 +0200113void *tall_map_ctx, *tall_upq_ctx;
Harald Weltea8379772009-06-20 22:36:41 +0200114
Harald Welte59b04682009-06-10 05:40:52 +0800115/* map one particular subslot to another subslot */
116int trau_mux_map(const struct gsm_e1_subslot *src,
117 const struct gsm_e1_subslot *dst)
118{
Harald Weltea8379772009-06-20 22:36:41 +0200119 struct map_entry *me;
120
Harald Weltea8379772009-06-20 22:36:41 +0200121 me = talloc(tall_map_ctx, struct map_entry);
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100122 if (!me) {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200123 LOGP(DLMIB, LOGL_FATAL, "Out of memory\n");
Harald Welte59b04682009-06-10 05:40:52 +0800124 return -ENOMEM;
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100125 }
Harald Welte59b04682009-06-10 05:40:52 +0800126
127 DEBUGP(DCC, "Setting up TRAU mux map between (e1=%u,ts=%u,ss=%u) "
128 "and (e1=%u,ts=%u,ss=%u)\n",
129 src->e1_nr, src->e1_ts, src->e1_ts_ss,
130 dst->e1_nr, dst->e1_ts, dst->e1_ts_ss);
131
132 /* make sure to get rid of any stale old mappings */
133 trau_mux_unmap(src, 0);
134 trau_mux_unmap(dst, 0);
135
136 memcpy(&me->src, src, sizeof(me->src));
137 memcpy(&me->dst, dst, sizeof(me->dst));
138 llist_add(&me->list, &ss_map);
139
140 return 0;
141}
142
143int trau_mux_map_lchan(const struct gsm_lchan *src,
144 const struct gsm_lchan *dst)
145{
146 struct gsm_e1_subslot *src_ss, *dst_ss;
147
148 src_ss = &src->ts->e1_link;
149 dst_ss = &dst->ts->e1_link;
150
151 return trau_mux_map(src_ss, dst_ss);
152}
153
154
155/* unmap one particular subslot from another subslot */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200156int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_t callref)
Harald Welte59b04682009-06-10 05:40:52 +0800157{
158 struct map_entry *me, *me2;
159 struct upqueue_entry *ue, *ue2;
160
161 if (ss)
162 llist_for_each_entry_safe(me, me2, &ss_map, list) {
163 if (!memcmp(&me->src, ss, sizeof(*ss)) ||
164 !memcmp(&me->dst, ss, sizeof(*ss))) {
165 llist_del(&me->list);
166 return 0;
167 }
168 }
169 llist_for_each_entry_safe(ue, ue2, &ss_upqueue, list) {
170 if (ue->callref == callref) {
171 llist_del(&ue->list);
172 return 0;
173 }
174 if (ss && !memcmp(&ue->src, ss, sizeof(*ss))) {
175 llist_del(&ue->list);
176 return 0;
177 }
178 }
179 return -ENOENT;
180}
181
182/* look-up an enty in the TRAU mux map */
183static struct gsm_e1_subslot *
184lookup_trau_mux_map(const struct gsm_e1_subslot *src)
185{
186 struct map_entry *me;
187
188 llist_for_each_entry(me, &ss_map, list) {
189 if (!memcmp(&me->src, src, sizeof(*src)))
190 return &me->dst;
191 if (!memcmp(&me->dst, src, sizeof(*src)))
192 return &me->src;
193 }
194 return NULL;
195}
196
197/* look-up an enty in the TRAU upqueue */
198struct upqueue_entry *
199lookup_trau_upqueue(const struct gsm_e1_subslot *src)
200{
201 struct upqueue_entry *ue;
202
203 llist_for_each_entry(ue, &ss_upqueue, list) {
204 if (!memcmp(&ue->src, src, sizeof(*src)))
205 return ue;
206 }
207 return NULL;
208}
209
Andreas Eversberg2c202cd2013-12-06 16:59:10 +0100210static const uint8_t c_bits_check_fr[] = { 0, 0, 0, 1, 0 };
211static const uint8_t c_bits_check_efr[] = { 1, 1, 0, 1, 0 };
212
213struct msgb *trau_decode_fr(uint32_t callref,
214 const struct decoded_trau_frame *tf)
215{
216 struct msgb *msg;
217 struct gsm_data_frame *frame;
218 unsigned char *data;
219 int i, j, k, l, o;
220
221 msg = msgb_alloc(sizeof(struct gsm_data_frame) + 33,
222 "GSM-DATA");
223 if (!msg)
224 return NULL;
225
226 frame = (struct gsm_data_frame *)msg->data;
227 memset(frame, 0, sizeof(struct gsm_data_frame));
228 data = frame->data;
229 data[0] = 0xd << 4;
230 /* reassemble d-bits */
231 i = 0; /* counts bits */
232 j = 4; /* counts output bits */
233 k = gsm_fr_map[0]-1; /* current number bit in element */
234 l = 0; /* counts element bits */
235 o = 0; /* offset input bits */
236 while (i < 260) {
237 data[j/8] |= (tf->d_bits[k+o] << (7-(j%8)));
238 if (--k < 0) {
239 o += gsm_fr_map[l];
240 k = gsm_fr_map[++l]-1;
241 }
242 i++;
243 j++;
244 }
245 frame->msg_type = GSM_TCHF_FRAME;
246 frame->callref = callref;
247 msgb_put(msg, sizeof(struct gsm_data_frame) + 33);
248
249 return msg;
250}
251
252struct msgb *trau_decode_efr(uint32_t callref,
253 const struct decoded_trau_frame *tf)
254{
255 struct msgb *msg;
256 struct gsm_data_frame *frame;
257 unsigned char *data;
258 int i, j, rc;
259 ubit_t check_bits[26];
260
261 msg = msgb_alloc(sizeof(struct gsm_data_frame) + 31,
262 "GSM-DATA");
263 if (!msg)
264 return NULL;
265
266 frame = (struct gsm_data_frame *)msg->data;
267 memset(frame, 0, sizeof(struct gsm_data_frame));
268 frame->msg_type = GSM_TCHF_FRAME_EFR;
269 frame->callref = callref;
270 msgb_put(msg, sizeof(struct gsm_data_frame) + 31);
271
272 if (tf->c_bits[11]) /* BFI */
273 goto bad_frame;
274
275 data = frame->data;
276 data[0] = 0xc << 4;
277 /* reassemble d-bits */
278 for (i = 1, j = 4; i < 39; i++, j++)
279 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
280 efr_parity_bits_1(check_bits, tf->d_bits);
281 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 26,
282 tf->d_bits + 39);
283 if (rc)
284 goto bad_frame;
285 for (i = 42, j = 42; i < 95; i++, j++)
286 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
287 efr_parity_bits_2(check_bits, tf->d_bits);
288 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12,
289 tf->d_bits + 95);
290 if (rc)
291 goto bad_frame;
292 for (i = 98, j = 95; i < 148; i++, j++)
293 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
294 efr_parity_bits_3(check_bits, tf->d_bits);
295 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8,
296 tf->d_bits + 148);
297 if (rc)
298 goto bad_frame;
299 for (i = 151, j = 145; i < 204; i++, j++)
300 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
301 efr_parity_bits_4(check_bits, tf->d_bits);
302 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12,
303 tf->d_bits + 204);
304 if (rc)
305 goto bad_frame;
306 for (i = 207, j = 198; i < 257; i++, j++)
307 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
308 efr_parity_bits_5(check_bits, tf->d_bits);
309 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8,
310 tf->d_bits + 257);
311 if (rc)
312 goto bad_frame;
313
314 return msg;
315
316bad_frame:
Andreas Eversbergeca41452014-01-31 09:02:01 +0100317 frame->msg_type = GSM_BAD_FRAME;
Andreas Eversberg2c202cd2013-12-06 16:59:10 +0100318
319 return msg;
320}
Harald Welte3971ad52009-12-19 22:23:05 +0100321
Harald Welte59b04682009-06-10 05:40:52 +0800322/* we get called by subchan_demux */
323int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200324 const uint8_t *trau_bits, int num_bits)
Harald Welte59b04682009-06-10 05:40:52 +0800325{
326 struct decoded_trau_frame tf;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200327 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte59b04682009-06-10 05:40:52 +0800328 struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss);
329 struct subch_mux *mx;
Harald Welte03740842009-06-10 23:11:52 +0800330 struct upqueue_entry *ue;
Harald Welte59b04682009-06-10 05:40:52 +0800331 int rc;
332
333 /* decode TRAU, change it to downlink, re-encode */
334 rc = decode_trau_frame(&tf, trau_bits);
335 if (rc)
336 return rc;
337
Harald Welte03740842009-06-10 23:11:52 +0800338 if (!dst_e1_ss) {
Andreas Eversberg2c202cd2013-12-06 16:59:10 +0100339 struct msgb *msg = NULL;
Harald Welte03740842009-06-10 23:11:52 +0800340 /* frame shall be sent to upqueue */
341 if (!(ue = lookup_trau_upqueue(src_e1_ss)))
342 return -EINVAL;
343 if (!ue->callref)
344 return -EINVAL;
Andreas Eversberg2c202cd2013-12-06 16:59:10 +0100345 if (!memcmp(tf.c_bits, c_bits_check_fr, 5))
346 msg = trau_decode_fr(ue->callref, &tf);
347 else if (!memcmp(tf.c_bits, c_bits_check_efr, 5))
348 msg = trau_decode_efr(ue->callref, &tf);
349 else {
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200350 DEBUGPC(DLMUX, "illegal trau (C1-C5) %s\n",
Andreas Eversberg2c202cd2013-12-06 16:59:10 +0100351 osmo_hexdump(tf.c_bits, 5));
352 DEBUGPC(DLMUX, "test trau (C1-C5) %s\n",
353 osmo_hexdump(c_bits_check_efr, 5));
354 return -EINVAL;
355 }
Harald Welte03740842009-06-10 23:11:52 +0800356 if (!msg)
357 return -ENOMEM;
Harald Welte4f272cc2011-03-03 23:29:05 +0100358 trau_tx_to_mncc(ue->net, msg);
Harald Welte03740842009-06-10 23:11:52 +0800359
360 return 0;
361 }
Harald Welte59b04682009-06-10 05:40:52 +0800362
363 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
364 if (!mx)
365 return -EINVAL;
366
367 trau_frame_up2down(&tf);
368 encode_trau_frame(trau_bits_out, &tf);
369
370 /* and send it to the muxer */
371 return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
372 TRAU_FRAME_BITS);
373}
374
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200375/* callback when a TRAU frame was received */
376int subch_cb(struct subch_demux *dmx, int ch, uint8_t *data, int len,
377 void *_priv)
378{
379 struct e1inp_ts *e1i_ts = _priv;
380 struct gsm_e1_subslot src_ss;
381
382 src_ss.e1_nr = e1i_ts->line->num;
383 src_ss.e1_ts = e1i_ts->num;
384 src_ss.e1_ts_ss = ch;
385
386 return trau_mux_input(&src_ss, data, len);
387}
388
Harald Welte59b04682009-06-10 05:40:52 +0800389/* add receiver instance for lchan and callref */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200390int trau_recv_lchan(struct gsm_lchan *lchan, uint32_t callref)
Harald Welte59b04682009-06-10 05:40:52 +0800391{
392 struct gsm_e1_subslot *src_ss;
Harald Weltea8379772009-06-20 22:36:41 +0200393 struct upqueue_entry *ue;
Harald Welte59b04682009-06-10 05:40:52 +0800394
Harald Weltea8379772009-06-20 22:36:41 +0200395 ue = talloc(tall_upq_ctx, struct upqueue_entry);
Harald Welte59b04682009-06-10 05:40:52 +0800396 if (!ue)
397 return -ENOMEM;
398
399 src_ss = &lchan->ts->e1_link;
400
401 DEBUGP(DCC, "Setting up TRAU receiver (e1=%u,ts=%u,ss=%u) "
402 "and (callref 0x%x)\n",
403 src_ss->e1_nr, src_ss->e1_ts, src_ss->e1_ts_ss,
404 callref);
405
406 /* make sure to get rid of any stale old mappings */
407 trau_mux_unmap(src_ss, callref);
408
409 memcpy(&ue->src, src_ss, sizeof(ue->src));
410 ue->net = lchan->ts->trx->bts->network;
411 ue->callref = callref;
412 llist_add(&ue->list, &ss_upqueue);
413
414 return 0;
415}
416
Andreas Eversberg2c202cd2013-12-06 16:59:10 +0100417void trau_encode_fr(struct decoded_trau_frame *tf,
418 const unsigned char *data)
419{
420 int i, j, k, l, o;
421
422 /* set c-bits and t-bits */
423 tf->c_bits[0] = 1;
424 tf->c_bits[1] = 1;
425 tf->c_bits[2] = 1;
426 tf->c_bits[3] = 0;
427 tf->c_bits[4] = 0;
428 memset(&tf->c_bits[5], 0, 6);
429 memset(&tf->c_bits[11], 1, 10);
430 memset(&tf->t_bits[0], 1, 4);
431 /* reassemble d-bits */
432 i = 0; /* counts bits */
433 j = 4; /* counts input bits */
434 k = gsm_fr_map[0]-1; /* current number bit in element */
435 l = 0; /* counts element bits */
436 o = 0; /* offset output bits */
437 while (i < 260) {
438 tf->d_bits[k+o] = (data[j/8] >> (7-(j%8))) & 1;
Harald Welteb0f19282014-06-23 09:48:07 +0200439 /* to avoid out-of-bounds access in gsm_fr_map[++l] */
440 if (i == 259)
441 break;
Andreas Eversberg2c202cd2013-12-06 16:59:10 +0100442 if (--k < 0) {
443 o += gsm_fr_map[l];
444 k = gsm_fr_map[++l]-1;
445 }
446 i++;
447 j++;
448 }
449}
450
451void trau_encode_efr(struct decoded_trau_frame *tf,
452 const unsigned char *data)
453{
454 int i, j;
455 ubit_t check_bits[26];
456
457 /* set c-bits and t-bits */
458 tf->c_bits[0] = 1;
459 tf->c_bits[1] = 1;
460 tf->c_bits[2] = 0;
461 tf->c_bits[3] = 1;
462 tf->c_bits[4] = 0;
463 memset(&tf->c_bits[5], 0, 6);
464 memset(&tf->c_bits[11], 1, 10);
465 memset(&tf->t_bits[0], 1, 4);
466 /* reassemble d-bits */
467 tf->d_bits[0] = 1;
468 for (i = 1, j = 4; i < 39; i++, j++)
469 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
470 efr_parity_bits_1(check_bits, tf->d_bits);
471 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 26,
472 tf->d_bits + 39);
473 for (i = 42, j = 42; i < 95; i++, j++)
474 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
475 efr_parity_bits_2(check_bits, tf->d_bits);
476 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 12,
477 tf->d_bits + 95);
478 for (i = 98, j = 95; i < 148; i++, j++)
479 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
480 efr_parity_bits_3(check_bits, tf->d_bits);
481 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 8,
482 tf->d_bits + 148);
483 for (i = 151, j = 145; i < 204; i++, j++)
484 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
485 efr_parity_bits_4(check_bits, tf->d_bits);
486 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 12,
487 tf->d_bits + 204);
488 for (i = 207, j = 198; i < 257; i++, j++)
489 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
490 efr_parity_bits_5(check_bits, tf->d_bits);
491 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 8,
492 tf->d_bits + 257);
493}
494
Harald Welte3971ad52009-12-19 22:23:05 +0100495int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
Harald Welte59b04682009-06-10 05:40:52 +0800496{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200497 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte59b04682009-06-10 05:40:52 +0800498 struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
499 struct subch_mux *mx;
Harald Welte3971ad52009-12-19 22:23:05 +0100500 struct decoded_trau_frame tf;
Harald Welte59b04682009-06-10 05:40:52 +0800501
502 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
503 if (!mx)
504 return -EINVAL;
505
Harald Welte3971ad52009-12-19 22:23:05 +0100506 switch (frame->msg_type) {
507 case GSM_TCHF_FRAME:
Andreas Eversberg2c202cd2013-12-06 16:59:10 +0100508 trau_encode_fr(&tf, frame->data);
509 break;
510 case GSM_TCHF_FRAME_EFR:
511 trau_encode_efr(&tf, frame->data);
Harald Welte3971ad52009-12-19 22:23:05 +0100512 break;
513 default:
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200514 DEBUGPC(DLMUX, "unsupported message type %d\n",
Harald Welte3971ad52009-12-19 22:23:05 +0100515 frame->msg_type);
516 return -EINVAL;
517 }
518
519 encode_trau_frame(trau_bits_out, &tf);
Harald Welte59b04682009-06-10 05:40:52 +0800520
521 /* and send it to the muxer */
522 return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
523 TRAU_FRAME_BITS);
524}
Andreas Eversberg02063672013-12-05 14:37:11 +0100525
526/* switch trau muxer to new lchan */
527int switch_trau_mux(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan)
528{
529 struct gsm_network *net = old_lchan->ts->trx->bts->network;
530 struct gsm_trans *trans;
531
532 /* look up transaction with TCH frame receive enabled */
533 llist_for_each_entry(trans, &net->trans_list, entry) {
534 if (trans->conn && trans->conn->lchan == old_lchan && trans->tch_recv) {
535 /* switch */
536 trau_recv_lchan(new_lchan, trans->callref);
537 }
538 }
539
540 return 0;
541}