blob: b2c630cc9591d034ed68b62c423f326eb431b809 [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>
26#include <openbsc/trau_frame.h>
27#include <openbsc/trau_mux.h>
28#include <openbsc/subchan_demux.h>
29#include <openbsc/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>
Harald Welte1fa60c82009-02-09 18:13:26 +000032
Harald Welte07b7bd72011-07-24 02:18:13 +020033/* this corresponds to teh bit-lengths of the individual codec
34 * parameters as indicated in Table 1.1 of TS 06.10 */
35static const uint8_t gsm_fr_map[] = {
Harald Welteda7ab742009-12-19 22:23:05 +010036 6, 6, 5, 5, 4, 4, 3, 3,
37 7, 2, 2, 6, 3, 3, 3, 3,
38 3, 3, 3, 3, 3, 3, 3, 3,
39 3, 7, 2, 2, 6, 3, 3, 3,
40 3, 3, 3, 3, 3, 3, 3, 3,
41 3, 3, 7, 2, 2, 6, 3, 3,
42 3, 3, 3, 3, 3, 3, 3, 3,
43 3, 3, 3, 7, 2, 2, 6, 3,
44 3, 3, 3, 3, 3, 3, 3, 3,
45 3, 3, 3, 3
46};
47
Harald Welte1fa60c82009-02-09 18:13:26 +000048struct map_entry {
49 struct llist_head list;
50 struct gsm_e1_subslot src, dst;
51};
52
Harald Welte45b407a2009-05-23 15:51:12 +000053struct upqueue_entry {
54 struct llist_head list;
55 struct gsm_network *net;
56 struct gsm_e1_subslot src;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020057 uint32_t callref;
Harald Welte45b407a2009-05-23 15:51:12 +000058};
59
Harald Welte1fa60c82009-02-09 18:13:26 +000060static LLIST_HEAD(ss_map);
Harald Welte45b407a2009-05-23 15:51:12 +000061static LLIST_HEAD(ss_upqueue);
Harald Welte1fa60c82009-02-09 18:13:26 +000062
Harald Welte (local)d19e58b2009-08-15 02:30:58 +020063void *tall_map_ctx, *tall_upq_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +020064
Harald Welte1fa60c82009-02-09 18:13:26 +000065/* map one particular subslot to another subslot */
66int trau_mux_map(const struct gsm_e1_subslot *src,
67 const struct gsm_e1_subslot *dst)
68{
Harald Welte2cf161b2009-06-20 22:36:41 +020069 struct map_entry *me;
70
Harald Welte2cf161b2009-06-20 22:36:41 +020071 me = talloc(tall_map_ctx, struct map_entry);
Harald Welteb1d4c8e2009-12-17 23:10:46 +010072 if (!me) {
73 LOGP(DMIB, LOGL_FATAL, "Out of memory\n");
Harald Welte1fa60c82009-02-09 18:13:26 +000074 return -ENOMEM;
Harald Welteb1d4c8e2009-12-17 23:10:46 +010075 }
Harald Welte1fa60c82009-02-09 18:13:26 +000076
Harald Weltedbd2ea82009-02-19 17:07:01 +000077 DEBUGP(DCC, "Setting up TRAU mux map between (e1=%u,ts=%u,ss=%u) "
78 "and (e1=%u,ts=%u,ss=%u)\n",
79 src->e1_nr, src->e1_ts, src->e1_ts_ss,
80 dst->e1_nr, dst->e1_ts, dst->e1_ts_ss);
81
Harald Welte26aa6a12009-02-19 15:14:23 +000082 /* make sure to get rid of any stale old mappings */
Harald Welte45b407a2009-05-23 15:51:12 +000083 trau_mux_unmap(src, 0);
84 trau_mux_unmap(dst, 0);
Harald Welte26aa6a12009-02-19 15:14:23 +000085
Harald Welte1fa60c82009-02-09 18:13:26 +000086 memcpy(&me->src, src, sizeof(me->src));
87 memcpy(&me->dst, dst, sizeof(me->dst));
88 llist_add(&me->list, &ss_map);
89
90 return 0;
91}
92
Harald Welte26aa6a12009-02-19 15:14:23 +000093int trau_mux_map_lchan(const struct gsm_lchan *src,
94 const struct gsm_lchan *dst)
95{
96 struct gsm_e1_subslot *src_ss, *dst_ss;
97
98 src_ss = &src->ts->e1_link;
99 dst_ss = &dst->ts->e1_link;
100
101 return trau_mux_map(src_ss, dst_ss);
102}
103
104
Harald Welte1fa60c82009-02-09 18:13:26 +0000105/* unmap one particular subslot from another subslot */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200106int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_t callref)
Harald Welte1fa60c82009-02-09 18:13:26 +0000107{
108 struct map_entry *me, *me2;
Harald Welte45b407a2009-05-23 15:51:12 +0000109 struct upqueue_entry *ue, *ue2;
Harald Welte1fa60c82009-02-09 18:13:26 +0000110
Harald Welte45b407a2009-05-23 15:51:12 +0000111 if (ss)
112 llist_for_each_entry_safe(me, me2, &ss_map, list) {
113 if (!memcmp(&me->src, ss, sizeof(*ss)) ||
114 !memcmp(&me->dst, ss, sizeof(*ss))) {
115 llist_del(&me->list);
116 return 0;
117 }
118 }
119 llist_for_each_entry_safe(ue, ue2, &ss_upqueue, list) {
120 if (ue->callref == callref) {
121 llist_del(&ue->list);
122 return 0;
123 }
124 if (ss && !memcmp(&ue->src, ss, sizeof(*ss))) {
125 llist_del(&ue->list);
Harald Welte1fa60c82009-02-09 18:13:26 +0000126 return 0;
127 }
128 }
129 return -ENOENT;
130}
131
132/* look-up an enty in the TRAU mux map */
133static struct gsm_e1_subslot *
134lookup_trau_mux_map(const struct gsm_e1_subslot *src)
135{
136 struct map_entry *me;
137
138 llist_for_each_entry(me, &ss_map, list) {
139 if (!memcmp(&me->src, src, sizeof(*src)))
140 return &me->dst;
141 if (!memcmp(&me->dst, src, sizeof(*src)))
142 return &me->src;
143 }
144 return NULL;
145}
146
Harald Welte45b407a2009-05-23 15:51:12 +0000147/* look-up an enty in the TRAU upqueue */
148struct upqueue_entry *
149lookup_trau_upqueue(const struct gsm_e1_subslot *src)
150{
151 struct upqueue_entry *ue;
152
153 llist_for_each_entry(ue, &ss_upqueue, list) {
154 if (!memcmp(&ue->src, src, sizeof(*src)))
155 return ue;
156 }
157 return NULL;
158}
159
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200160static const uint8_t c_bits_check[] = { 0, 0, 0, 1, 0 };
Harald Welteda7ab742009-12-19 22:23:05 +0100161
Harald Welte1fa60c82009-02-09 18:13:26 +0000162/* we get called by subchan_demux */
163int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200164 const uint8_t *trau_bits, int num_bits)
Harald Welte1fa60c82009-02-09 18:13:26 +0000165{
166 struct decoded_trau_frame tf;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200167 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte1fa60c82009-02-09 18:13:26 +0000168 struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss);
169 struct subch_mux *mx;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800170 struct upqueue_entry *ue;
Harald Welte41e16682009-02-18 03:34:55 +0000171 int rc;
Harald Welte1fa60c82009-02-09 18:13:26 +0000172
Harald Welte45b407a2009-05-23 15:51:12 +0000173 /* decode TRAU, change it to downlink, re-encode */
174 rc = decode_trau_frame(&tf, trau_bits);
175 if (rc)
176 return rc;
177
Harald Welte4bfdfe72009-06-10 23:11:52 +0800178 if (!dst_e1_ss) {
Harald Welteda7ab742009-12-19 22:23:05 +0100179 struct msgb *msg;
180 struct gsm_data_frame *frame;
181 unsigned char *data;
182 int i, j, k, l, o;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800183 /* frame shall be sent to upqueue */
184 if (!(ue = lookup_trau_upqueue(src_e1_ss)))
185 return -EINVAL;
186 if (!ue->callref)
187 return -EINVAL;
Andreas Eversberg56315f02009-12-21 01:18:44 +0100188 if (memcmp(tf.c_bits, c_bits_check, sizeof(c_bits_check)))
Harald Welteda7ab742009-12-19 22:23:05 +0100189 DEBUGPC(DMUX, "illegal trau (C1-C5) %s\n",
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200190 osmo_hexdump(tf.c_bits, sizeof(c_bits_check)));
Harald Welteda7ab742009-12-19 22:23:05 +0100191 msg = msgb_alloc(sizeof(struct gsm_data_frame) + 33,
192 "GSM-DATA");
Harald Welte4bfdfe72009-06-10 23:11:52 +0800193 if (!msg)
194 return -ENOMEM;
Harald Welteda7ab742009-12-19 22:23:05 +0100195
196 frame = (struct gsm_data_frame *)msg->data;
197 memset(frame, 0, sizeof(struct gsm_data_frame));
198 data = frame->data;
199 data[0] = 0xd << 4;
200 /* reassemble d-bits */
201 i = 0; /* counts bits */
202 j = 4; /* counts output bits */
203 k = gsm_fr_map[0]-1; /* current number bit in element */
204 l = 0; /* counts element bits */
205 o = 0; /* offset input bits */
206 while (i < 260) {
207 data[j/8] |= (tf.d_bits[k+o] << (7-(j%8)));
208 if (--k < 0) {
209 o += gsm_fr_map[l];
210 k = gsm_fr_map[++l]-1;
211 }
212 i++;
213 j++;
214 }
215 frame->msg_type = GSM_TCHF_FRAME;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800216 frame->callref = ue->callref;
Harald Welte31c00f72011-03-03 23:29:05 +0100217 trau_tx_to_mncc(ue->net, msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800218
219 return 0;
220 }
Harald Welte1fa60c82009-02-09 18:13:26 +0000221
222 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
223 if (!mx)
224 return -EINVAL;
225
Harald Welte1fa60c82009-02-09 18:13:26 +0000226 trau_frame_up2down(&tf);
227 encode_trau_frame(trau_bits_out, &tf);
228
229 /* and send it to the muxer */
230 return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
231 TRAU_FRAME_BITS);
232}
Harald Welte45b407a2009-05-23 15:51:12 +0000233
234/* add receiver instance for lchan and callref */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200235int trau_recv_lchan(struct gsm_lchan *lchan, uint32_t callref)
Harald Welte45b407a2009-05-23 15:51:12 +0000236{
237 struct gsm_e1_subslot *src_ss;
Harald Welte2cf161b2009-06-20 22:36:41 +0200238 struct upqueue_entry *ue;
Harald Welte45b407a2009-05-23 15:51:12 +0000239
Harald Welte2cf161b2009-06-20 22:36:41 +0200240 ue = talloc(tall_upq_ctx, struct upqueue_entry);
Harald Welte45b407a2009-05-23 15:51:12 +0000241 if (!ue)
242 return -ENOMEM;
243
244 src_ss = &lchan->ts->e1_link;
245
246 DEBUGP(DCC, "Setting up TRAU receiver (e1=%u,ts=%u,ss=%u) "
247 "and (callref 0x%x)\n",
248 src_ss->e1_nr, src_ss->e1_ts, src_ss->e1_ts_ss,
249 callref);
250
251 /* make sure to get rid of any stale old mappings */
252 trau_mux_unmap(src_ss, callref);
253
254 memcpy(&ue->src, src_ss, sizeof(ue->src));
255 ue->net = lchan->ts->trx->bts->network;
256 ue->callref = callref;
257 llist_add(&ue->list, &ss_upqueue);
258
259 return 0;
260}
261
Harald Welteda7ab742009-12-19 22:23:05 +0100262int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
Harald Welte45b407a2009-05-23 15:51:12 +0000263{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200264 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte45b407a2009-05-23 15:51:12 +0000265 struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
266 struct subch_mux *mx;
Harald Welteda7ab742009-12-19 22:23:05 +0100267 int i, j, k, l, o;
268 unsigned char *data = frame->data;
269 struct decoded_trau_frame tf;
Harald Welte45b407a2009-05-23 15:51:12 +0000270
271 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
272 if (!mx)
273 return -EINVAL;
274
Harald Welteda7ab742009-12-19 22:23:05 +0100275 switch (frame->msg_type) {
276 case GSM_TCHF_FRAME:
277 /* set c-bits and t-bits */
278 tf.c_bits[0] = 1;
279 tf.c_bits[1] = 1;
280 tf.c_bits[2] = 1;
281 tf.c_bits[3] = 0;
282 tf.c_bits[4] = 0;
283 memset(&tf.c_bits[5], 0, 6);
284 memset(&tf.c_bits[11], 1, 10);
285 memset(&tf.t_bits[0], 1, 4);
286 /* reassemble d-bits */
287 i = 0; /* counts bits */
288 j = 4; /* counts input bits */
289 k = gsm_fr_map[0]-1; /* current number bit in element */
290 l = 0; /* counts element bits */
291 o = 0; /* offset output bits */
292 while (i < 260) {
293 tf.d_bits[k+o] = (data[j/8] >> (7-(j%8))) & 1;
294 if (--k < 0) {
295 o += gsm_fr_map[l];
296 k = gsm_fr_map[++l]-1;
297 }
298 i++;
299 j++;
300 }
301 break;
302 default:
303 DEBUGPC(DMUX, "unsupported message type %d\n",
304 frame->msg_type);
305 return -EINVAL;
306 }
307
308 encode_trau_frame(trau_bits_out, &tf);
Harald Welte45b407a2009-05-23 15:51:12 +0000309
310 /* and send it to the muxer */
311 return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
312 TRAU_FRAME_BITS);
313}