blob: 3831a80ad49d483eb7349fed8e7d6255c54efdc3 [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>
Andreas Eversbergdcf38e12013-12-05 14:37:11 +010034#include <openbsc/transaction.h>
Harald Welte1fa60c82009-02-09 18:13:26 +000035
Holger Hans Peter Freyther2a260ee2011-10-26 19:01:57 +020036/* this corresponds to the bit-lengths of the individual codec
Harald Welte07b7bd72011-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 Welteda7ab742009-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 Eversbergd074f8f2013-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 Welte1fa60c82009-02-09 18:13:26 +000098struct map_entry {
99 struct llist_head list;
100 struct gsm_e1_subslot src, dst;
101};
102
Harald Welte45b407a2009-05-23 15:51:12 +0000103struct upqueue_entry {
104 struct llist_head list;
105 struct gsm_network *net;
106 struct gsm_e1_subslot src;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200107 uint32_t callref;
Harald Welte45b407a2009-05-23 15:51:12 +0000108};
109
Harald Welte1fa60c82009-02-09 18:13:26 +0000110static LLIST_HEAD(ss_map);
Harald Welte45b407a2009-05-23 15:51:12 +0000111static LLIST_HEAD(ss_upqueue);
Harald Welte1fa60c82009-02-09 18:13:26 +0000112
Harald Welte (local)d19e58b2009-08-15 02:30:58 +0200113void *tall_map_ctx, *tall_upq_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +0200114
Harald Welte1fa60c82009-02-09 18:13:26 +0000115/* 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 Welte2cf161b2009-06-20 22:36:41 +0200119 struct map_entry *me;
120
Harald Welte2cf161b2009-06-20 22:36:41 +0200121 me = talloc(tall_map_ctx, struct map_entry);
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100122 if (!me) {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200123 LOGP(DLMIB, LOGL_FATAL, "Out of memory\n");
Harald Welte1fa60c82009-02-09 18:13:26 +0000124 return -ENOMEM;
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100125 }
Harald Welte1fa60c82009-02-09 18:13:26 +0000126
Harald Weltedbd2ea82009-02-19 17:07:01 +0000127 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
Harald Welte26aa6a12009-02-19 15:14:23 +0000132 /* make sure to get rid of any stale old mappings */
Harald Welte45b407a2009-05-23 15:51:12 +0000133 trau_mux_unmap(src, 0);
134 trau_mux_unmap(dst, 0);
Harald Welte26aa6a12009-02-19 15:14:23 +0000135
Harald Welte1fa60c82009-02-09 18:13:26 +0000136 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
Harald Welte26aa6a12009-02-19 15:14:23 +0000143int 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
Harald Welte1fa60c82009-02-09 18:13:26 +0000155/* unmap one particular subslot from another subslot */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200156int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_t callref)
Harald Welte1fa60c82009-02-09 18:13:26 +0000157{
158 struct map_entry *me, *me2;
Harald Welte45b407a2009-05-23 15:51:12 +0000159 struct upqueue_entry *ue, *ue2;
Harald Welte1fa60c82009-02-09 18:13:26 +0000160
Harald Welte45b407a2009-05-23 15:51:12 +0000161 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);
Harald Welte1fa60c82009-02-09 18:13:26 +0000176 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
Harald Welte45b407a2009-05-23 15:51:12 +0000197/* 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 Eversbergd074f8f2013-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)));
Holger Hans Peter Freyther24fc4352014-07-22 12:23:03 +0200238 /* to avoid out-of-bounds access in gsm_fr_map[++l] */
239 if (i == 259)
240 break;
Andreas Eversbergd074f8f2013-12-06 16:59:10 +0100241 if (--k < 0) {
242 o += gsm_fr_map[l];
243 k = gsm_fr_map[++l]-1;
244 }
245 i++;
246 j++;
247 }
248 frame->msg_type = GSM_TCHF_FRAME;
249 frame->callref = callref;
250 msgb_put(msg, sizeof(struct gsm_data_frame) + 33);
251
252 return msg;
253}
254
255struct msgb *trau_decode_efr(uint32_t callref,
256 const struct decoded_trau_frame *tf)
257{
258 struct msgb *msg;
259 struct gsm_data_frame *frame;
260 unsigned char *data;
261 int i, j, rc;
262 ubit_t check_bits[26];
263
264 msg = msgb_alloc(sizeof(struct gsm_data_frame) + 31,
265 "GSM-DATA");
266 if (!msg)
267 return NULL;
268
269 frame = (struct gsm_data_frame *)msg->data;
270 memset(frame, 0, sizeof(struct gsm_data_frame));
271 frame->msg_type = GSM_TCHF_FRAME_EFR;
272 frame->callref = callref;
273 msgb_put(msg, sizeof(struct gsm_data_frame) + 31);
274
275 if (tf->c_bits[11]) /* BFI */
276 goto bad_frame;
277
278 data = frame->data;
279 data[0] = 0xc << 4;
280 /* reassemble d-bits */
281 for (i = 1, j = 4; i < 39; i++, j++)
282 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
283 efr_parity_bits_1(check_bits, tf->d_bits);
284 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 26,
285 tf->d_bits + 39);
286 if (rc)
287 goto bad_frame;
288 for (i = 42, j = 42; i < 95; i++, j++)
289 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
290 efr_parity_bits_2(check_bits, tf->d_bits);
291 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12,
292 tf->d_bits + 95);
293 if (rc)
294 goto bad_frame;
295 for (i = 98, j = 95; i < 148; i++, j++)
296 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
297 efr_parity_bits_3(check_bits, tf->d_bits);
298 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8,
299 tf->d_bits + 148);
300 if (rc)
301 goto bad_frame;
302 for (i = 151, j = 145; i < 204; i++, j++)
303 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
304 efr_parity_bits_4(check_bits, tf->d_bits);
305 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12,
306 tf->d_bits + 204);
307 if (rc)
308 goto bad_frame;
309 for (i = 207, j = 198; i < 257; i++, j++)
310 data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
311 efr_parity_bits_5(check_bits, tf->d_bits);
312 rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8,
313 tf->d_bits + 257);
314 if (rc)
315 goto bad_frame;
316
317 return msg;
318
319bad_frame:
Andreas Eversbergf78fc4e2014-01-31 09:02:01 +0100320 frame->msg_type = GSM_BAD_FRAME;
Andreas Eversbergd074f8f2013-12-06 16:59:10 +0100321
322 return msg;
323}
Harald Welteda7ab742009-12-19 22:23:05 +0100324
Harald Welte1fa60c82009-02-09 18:13:26 +0000325/* we get called by subchan_demux */
326int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200327 const uint8_t *trau_bits, int num_bits)
Harald Welte1fa60c82009-02-09 18:13:26 +0000328{
329 struct decoded_trau_frame tf;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200330 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte1fa60c82009-02-09 18:13:26 +0000331 struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss);
332 struct subch_mux *mx;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800333 struct upqueue_entry *ue;
Harald Welte41e16682009-02-18 03:34:55 +0000334 int rc;
Harald Welte1fa60c82009-02-09 18:13:26 +0000335
Harald Welte45b407a2009-05-23 15:51:12 +0000336 /* decode TRAU, change it to downlink, re-encode */
337 rc = decode_trau_frame(&tf, trau_bits);
338 if (rc)
339 return rc;
340
Harald Welte4bfdfe72009-06-10 23:11:52 +0800341 if (!dst_e1_ss) {
Andreas Eversbergd074f8f2013-12-06 16:59:10 +0100342 struct msgb *msg = NULL;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800343 /* frame shall be sent to upqueue */
344 if (!(ue = lookup_trau_upqueue(src_e1_ss)))
345 return -EINVAL;
346 if (!ue->callref)
347 return -EINVAL;
Andreas Eversbergd074f8f2013-12-06 16:59:10 +0100348 if (!memcmp(tf.c_bits, c_bits_check_fr, 5))
349 msg = trau_decode_fr(ue->callref, &tf);
350 else if (!memcmp(tf.c_bits, c_bits_check_efr, 5))
351 msg = trau_decode_efr(ue->callref, &tf);
352 else {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200353 DEBUGPC(DLMUX, "illegal trau (C1-C5) %s\n",
Andreas Eversbergd074f8f2013-12-06 16:59:10 +0100354 osmo_hexdump(tf.c_bits, 5));
355 DEBUGPC(DLMUX, "test trau (C1-C5) %s\n",
356 osmo_hexdump(c_bits_check_efr, 5));
357 return -EINVAL;
358 }
Harald Welte4bfdfe72009-06-10 23:11:52 +0800359 if (!msg)
360 return -ENOMEM;
Harald Welte31c00f72011-03-03 23:29:05 +0100361 trau_tx_to_mncc(ue->net, msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800362
363 return 0;
364 }
Harald Welte1fa60c82009-02-09 18:13:26 +0000365
366 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
367 if (!mx)
368 return -EINVAL;
369
Harald Welte1fa60c82009-02-09 18:13:26 +0000370 trau_frame_up2down(&tf);
371 encode_trau_frame(trau_bits_out, &tf);
372
373 /* and send it to the muxer */
374 return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
375 TRAU_FRAME_BITS);
376}
Harald Welte45b407a2009-05-23 15:51:12 +0000377
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200378/* callback when a TRAU frame was received */
379int subch_cb(struct subch_demux *dmx, int ch, uint8_t *data, int len,
380 void *_priv)
381{
382 struct e1inp_ts *e1i_ts = _priv;
383 struct gsm_e1_subslot src_ss;
384
385 src_ss.e1_nr = e1i_ts->line->num;
386 src_ss.e1_ts = e1i_ts->num;
387 src_ss.e1_ts_ss = ch;
388
389 return trau_mux_input(&src_ss, data, len);
390}
391
Harald Welte45b407a2009-05-23 15:51:12 +0000392/* add receiver instance for lchan and callref */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200393int trau_recv_lchan(struct gsm_lchan *lchan, uint32_t callref)
Harald Welte45b407a2009-05-23 15:51:12 +0000394{
395 struct gsm_e1_subslot *src_ss;
Harald Welte2cf161b2009-06-20 22:36:41 +0200396 struct upqueue_entry *ue;
Harald Welte45b407a2009-05-23 15:51:12 +0000397
Harald Welte2cf161b2009-06-20 22:36:41 +0200398 ue = talloc(tall_upq_ctx, struct upqueue_entry);
Harald Welte45b407a2009-05-23 15:51:12 +0000399 if (!ue)
400 return -ENOMEM;
401
402 src_ss = &lchan->ts->e1_link;
403
404 DEBUGP(DCC, "Setting up TRAU receiver (e1=%u,ts=%u,ss=%u) "
405 "and (callref 0x%x)\n",
406 src_ss->e1_nr, src_ss->e1_ts, src_ss->e1_ts_ss,
407 callref);
408
409 /* make sure to get rid of any stale old mappings */
410 trau_mux_unmap(src_ss, callref);
411
412 memcpy(&ue->src, src_ss, sizeof(ue->src));
413 ue->net = lchan->ts->trx->bts->network;
414 ue->callref = callref;
415 llist_add(&ue->list, &ss_upqueue);
416
417 return 0;
418}
419
Andreas Eversbergd074f8f2013-12-06 16:59:10 +0100420void trau_encode_fr(struct decoded_trau_frame *tf,
421 const unsigned char *data)
422{
423 int i, j, k, l, o;
424
425 /* set c-bits and t-bits */
426 tf->c_bits[0] = 1;
427 tf->c_bits[1] = 1;
428 tf->c_bits[2] = 1;
429 tf->c_bits[3] = 0;
430 tf->c_bits[4] = 0;
431 memset(&tf->c_bits[5], 0, 6);
432 memset(&tf->c_bits[11], 1, 10);
433 memset(&tf->t_bits[0], 1, 4);
434 /* reassemble d-bits */
435 i = 0; /* counts bits */
436 j = 4; /* counts input bits */
437 k = gsm_fr_map[0]-1; /* current number bit in element */
438 l = 0; /* counts element bits */
439 o = 0; /* offset output bits */
440 while (i < 260) {
441 tf->d_bits[k+o] = (data[j/8] >> (7-(j%8))) & 1;
Harald Welte9f109df2014-06-23 09:48:07 +0200442 /* to avoid out-of-bounds access in gsm_fr_map[++l] */
443 if (i == 259)
444 break;
Andreas Eversbergd074f8f2013-12-06 16:59:10 +0100445 if (--k < 0) {
446 o += gsm_fr_map[l];
447 k = gsm_fr_map[++l]-1;
448 }
449 i++;
450 j++;
451 }
452}
453
454void trau_encode_efr(struct decoded_trau_frame *tf,
455 const unsigned char *data)
456{
457 int i, j;
458 ubit_t check_bits[26];
459
460 /* set c-bits and t-bits */
461 tf->c_bits[0] = 1;
462 tf->c_bits[1] = 1;
463 tf->c_bits[2] = 0;
464 tf->c_bits[3] = 1;
465 tf->c_bits[4] = 0;
466 memset(&tf->c_bits[5], 0, 6);
467 memset(&tf->c_bits[11], 1, 10);
468 memset(&tf->t_bits[0], 1, 4);
469 /* reassemble d-bits */
470 tf->d_bits[0] = 1;
471 for (i = 1, j = 4; i < 39; i++, j++)
472 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
473 efr_parity_bits_1(check_bits, tf->d_bits);
474 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 26,
475 tf->d_bits + 39);
476 for (i = 42, j = 42; i < 95; i++, j++)
477 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
478 efr_parity_bits_2(check_bits, tf->d_bits);
479 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 12,
480 tf->d_bits + 95);
481 for (i = 98, j = 95; i < 148; i++, j++)
482 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
483 efr_parity_bits_3(check_bits, tf->d_bits);
484 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 8,
485 tf->d_bits + 148);
486 for (i = 151, j = 145; i < 204; i++, j++)
487 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
488 efr_parity_bits_4(check_bits, tf->d_bits);
489 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 12,
490 tf->d_bits + 204);
491 for (i = 207, j = 198; i < 257; i++, j++)
492 tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
493 efr_parity_bits_5(check_bits, tf->d_bits);
494 osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 8,
495 tf->d_bits + 257);
496}
497
Harald Welteda7ab742009-12-19 22:23:05 +0100498int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
Harald Welte45b407a2009-05-23 15:51:12 +0000499{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200500 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte45b407a2009-05-23 15:51:12 +0000501 struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
502 struct subch_mux *mx;
Harald Welteda7ab742009-12-19 22:23:05 +0100503 struct decoded_trau_frame tf;
Harald Welte45b407a2009-05-23 15:51:12 +0000504
505 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
506 if (!mx)
507 return -EINVAL;
508
Harald Welteda7ab742009-12-19 22:23:05 +0100509 switch (frame->msg_type) {
510 case GSM_TCHF_FRAME:
Andreas Eversbergd074f8f2013-12-06 16:59:10 +0100511 trau_encode_fr(&tf, frame->data);
512 break;
513 case GSM_TCHF_FRAME_EFR:
514 trau_encode_efr(&tf, frame->data);
Harald Welteda7ab742009-12-19 22:23:05 +0100515 break;
516 default:
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200517 DEBUGPC(DLMUX, "unsupported message type %d\n",
Harald Welteda7ab742009-12-19 22:23:05 +0100518 frame->msg_type);
519 return -EINVAL;
520 }
521
522 encode_trau_frame(trau_bits_out, &tf);
Harald Welte45b407a2009-05-23 15:51:12 +0000523
524 /* and send it to the muxer */
525 return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
526 TRAU_FRAME_BITS);
527}
Andreas Eversbergdcf38e12013-12-05 14:37:11 +0100528
529/* switch trau muxer to new lchan */
530int switch_trau_mux(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan)
531{
532 struct gsm_network *net = old_lchan->ts->trx->bts->network;
533 struct gsm_trans *trans;
534
535 /* look up transaction with TCH frame receive enabled */
536 llist_for_each_entry(trans, &net->trans_list, entry) {
537 if (trans->conn && trans->conn->lchan == old_lchan && trans->tch_recv) {
538 /* switch */
539 trau_recv_lchan(new_lchan, trans->callref);
540 }
541 }
542
543 return 0;
544}