blob: f2fa5c0234eed27df9677fb0e7c5eaaca62b8196 [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
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 */
21
22#include <errno.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26
27#include <openbsc/gsm_data.h>
28#include <openbsc/trau_frame.h>
29#include <openbsc/trau_mux.h>
30#include <openbsc/subchan_demux.h>
31#include <openbsc/e1_input.h>
Harald Welte41e16682009-02-18 03:34:55 +000032#include <openbsc/debug.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010033#include <osmocore/talloc.h>
Harald Welte1fa60c82009-02-09 18:13:26 +000034
Harald Welteda7ab742009-12-19 22:23:05 +010035u_int8_t gsm_fr_map[] = {
36 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;
57 u_int32_t callref;
58};
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 */
Harald Welte45b407a2009-05-23 15:51:12 +0000106int trau_mux_unmap(const struct gsm_e1_subslot *ss, u_int32_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
Harald Welteda7ab742009-12-19 22:23:05 +0100160static const u_int8_t c_bits_check[] = { 0, 0, 0, 1, 0 };
161
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,
164 const u_int8_t *trau_bits, int num_bits)
165{
166 struct decoded_trau_frame tf;
167 u_int8_t trau_bits_out[TRAU_FRAME_BITS];
168 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",
190 hexdump(tf.c_bits, sizeof(c_bits_check)));
191 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 Welte4bfdfe72009-06-10 23:11:52 +0800217 msgb_enqueue(&ue->net->upqueue, msg);
218
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 */
235int trau_recv_lchan(struct gsm_lchan *lchan, u_int32_t callref)
236{
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{
264 u_int8_t trau_bits_out[TRAU_FRAME_BITS];
265 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}