blob: c9d77cf7803f902f3da42f98259dd71a895df3e8 [file] [log] [blame]
Harald Welte1fa60c82009-02-09 18:13:26 +00001/* 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 Welte9af6ddf2011-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 Welte1fa60c82009-02-09 18:13:26 +00009 * (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 Welte9af6ddf2011-01-01 15:25:50 +010014 * GNU Affero General Public License for more details.
Harald Welte1fa60c82009-02-09 18:13:26 +000015 *
Harald Welte9af6ddf2011-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 Welte1fa60c82009-02-09 18:13:26 +000018 *
19 */
20
21#include <errno.h>
22#include <stdlib.h>
23#include <string.h>
Harald Welte1fa60c82009-02-09 18:13:26 +000024
25#include <openbsc/gsm_data.h>
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020026#include <osmocom/abis/trau_frame.h>
Harald Welte1fa60c82009-02-09 18:13:26 +000027#include <openbsc/trau_mux.h>
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020028#include <osmocom/abis/subchan_demux.h>
29#include <osmocom/abis/e1_input.h>
Harald Welte41e16682009-02-18 03:34:55 +000030#include <openbsc/debug.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010031#include <osmocom/core/talloc.h>
Alexander Huemer0a654612011-09-06 00:09:49 +020032#include <openbsc/trau_upqueue.h>
Andreas Eversbergd074f8f2013-12-06 16:59:10 +010033#include <osmocom/core/crcgen.h>
Harald Welte1fa60c82009-02-09 18:13:26 +000034
Holger Hans Peter Freyther2a260ee2011-10-26 19:01:57 +020035/* this corresponds to the bit-lengths of the individual codec
Harald Welte07b7bd72011-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 Welteda7ab742009-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 Eversbergd074f8f2013-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 Welte1fa60c82009-02-09 18:13:26 +000097struct map_entry {
98 struct llist_head list;
99 struct gsm_e1_subslot src, dst;
100};
101
Harald Welte45b407a2009-05-23 15:51:12 +0000102struct upqueue_entry {
103 struct llist_head list;
104 struct gsm_network *net;
105 struct gsm_e1_subslot src;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200106 uint32_t callref;
Harald Welte45b407a2009-05-23 15:51:12 +0000107};
108
Harald Welte1fa60c82009-02-09 18:13:26 +0000109static LLIST_HEAD(ss_map);
Harald Welte45b407a2009-05-23 15:51:12 +0000110static LLIST_HEAD(ss_upqueue);
Harald Welte1fa60c82009-02-09 18:13:26 +0000111
Harald Welte (local)d19e58b2009-08-15 02:30:58 +0200112void *tall_map_ctx, *tall_upq_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +0200113
Harald Welte1fa60c82009-02-09 18:13:26 +0000114/* 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 Welte2cf161b2009-06-20 22:36:41 +0200118 struct map_entry *me;
119
Harald Welte2cf161b2009-06-20 22:36:41 +0200120 me = talloc(tall_map_ctx, struct map_entry);
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100121 if (!me) {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200122 LOGP(DLMIB, LOGL_FATAL, "Out of memory\n");
Harald Welte1fa60c82009-02-09 18:13:26 +0000123 return -ENOMEM;
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100124 }
Harald Welte1fa60c82009-02-09 18:13:26 +0000125
Harald Weltedbd2ea82009-02-19 17:07:01 +0000126 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
Harald Welte26aa6a12009-02-19 15:14:23 +0000131 /* make sure to get rid of any stale old mappings */
Harald Welte45b407a2009-05-23 15:51:12 +0000132 trau_mux_unmap(src, 0);
133 trau_mux_unmap(dst, 0);
Harald Welte26aa6a12009-02-19 15:14:23 +0000134
Harald Welte1fa60c82009-02-09 18:13:26 +0000135 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
Harald Welte26aa6a12009-02-19 15:14:23 +0000142int 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
Harald Welte1fa60c82009-02-09 18:13:26 +0000154/* unmap one particular subslot from another subslot */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200155int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_t callref)
Harald Welte1fa60c82009-02-09 18:13:26 +0000156{
157 struct map_entry *me, *me2;
Harald Welte45b407a2009-05-23 15:51:12 +0000158 struct upqueue_entry *ue, *ue2;
Harald Welte1fa60c82009-02-09 18:13:26 +0000159
Harald Welte45b407a2009-05-23 15:51:12 +0000160 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);
Harald Welte1fa60c82009-02-09 18:13:26 +0000175 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
Harald Welte45b407a2009-05-23 15:51:12 +0000196/* 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 Eversbergd074f8f2013-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 Welteda7ab742009-12-19 22:23:05 +0100320
Harald Welte1fa60c82009-02-09 18:13:26 +0000321/* we get called by subchan_demux */
322int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200323 const uint8_t *trau_bits, int num_bits)
Harald Welte1fa60c82009-02-09 18:13:26 +0000324{
325 struct decoded_trau_frame tf;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200326 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte1fa60c82009-02-09 18:13:26 +0000327 struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss);
328 struct subch_mux *mx;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800329 struct upqueue_entry *ue;
Harald Welte41e16682009-02-18 03:34:55 +0000330 int rc;
Harald Welte1fa60c82009-02-09 18:13:26 +0000331
Harald Welte45b407a2009-05-23 15:51:12 +0000332 /* decode TRAU, change it to downlink, re-encode */
333 rc = decode_trau_frame(&tf, trau_bits);
334 if (rc)
335 return rc;
336
Harald Welte4bfdfe72009-06-10 23:11:52 +0800337 if (!dst_e1_ss) {
Andreas Eversbergd074f8f2013-12-06 16:59:10 +0100338 struct msgb *msg = NULL;
Harald Welte4bfdfe72009-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 Eversbergd074f8f2013-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 Ayusoed5cacb2011-08-17 22:44:07 +0200349 DEBUGPC(DLMUX, "illegal trau (C1-C5) %s\n",
Andreas Eversbergd074f8f2013-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 Welte4bfdfe72009-06-10 23:11:52 +0800355 if (!msg)
356 return -ENOMEM;
Harald Welte31c00f72011-03-03 23:29:05 +0100357 trau_tx_to_mncc(ue->net, msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800358
359 return 0;
360 }
Harald Welte1fa60c82009-02-09 18:13:26 +0000361
362 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
363 if (!mx)
364 return -EINVAL;
365
Harald Welte1fa60c82009-02-09 18:13:26 +0000366 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}
Harald Welte45b407a2009-05-23 15:51:12 +0000373
Pablo Neira Ayusoed5cacb2011-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 Welte45b407a2009-05-23 15:51:12 +0000388/* add receiver instance for lchan and callref */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200389int trau_recv_lchan(struct gsm_lchan *lchan, uint32_t callref)
Harald Welte45b407a2009-05-23 15:51:12 +0000390{
391 struct gsm_e1_subslot *src_ss;
Harald Welte2cf161b2009-06-20 22:36:41 +0200392 struct upqueue_entry *ue;
Harald Welte45b407a2009-05-23 15:51:12 +0000393
Harald Welte2cf161b2009-06-20 22:36:41 +0200394 ue = talloc(tall_upq_ctx, struct upqueue_entry);
Harald Welte45b407a2009-05-23 15:51:12 +0000395 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 Eversbergd074f8f2013-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 Welteda7ab742009-12-19 22:23:05 +0100491int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
Harald Welte45b407a2009-05-23 15:51:12 +0000492{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200493 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte45b407a2009-05-23 15:51:12 +0000494 struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
495 struct subch_mux *mx;
Harald Welteda7ab742009-12-19 22:23:05 +0100496 struct decoded_trau_frame tf;
Harald Welte45b407a2009-05-23 15:51:12 +0000497
498 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
499 if (!mx)
500 return -EINVAL;
501
Harald Welteda7ab742009-12-19 22:23:05 +0100502 switch (frame->msg_type) {
503 case GSM_TCHF_FRAME:
Andreas Eversbergd074f8f2013-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 Welteda7ab742009-12-19 22:23:05 +0100508 break;
509 default:
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200510 DEBUGPC(DLMUX, "unsupported message type %d\n",
Harald Welteda7ab742009-12-19 22:23:05 +0100511 frame->msg_type);
512 return -EINVAL;
513 }
514
515 encode_trau_frame(trau_bits_out, &tf);
Harald Welte45b407a2009-05-23 15:51:12 +0000516
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}