blob: 712e22d85b032ac87f7ac958ff8c97213e508d2e [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>
24#include <sys/types.h>
25
26#include <openbsc/gsm_data.h>
27#include <openbsc/trau_frame.h>
28#include <openbsc/trau_mux.h>
29#include <openbsc/subchan_demux.h>
30#include <openbsc/e1_input.h>
Harald Welte41e16682009-02-18 03:34:55 +000031#include <openbsc/debug.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010032#include <osmocore/talloc.h>
Harald Welte1fa60c82009-02-09 18:13:26 +000033
Harald Welteda7ab742009-12-19 22:23:05 +010034u_int8_t gsm_fr_map[] = {
35 6, 6, 5, 5, 4, 4, 3, 3,
36 7, 2, 2, 6, 3, 3, 3, 3,
37 3, 3, 3, 3, 3, 3, 3, 3,
38 3, 7, 2, 2, 6, 3, 3, 3,
39 3, 3, 3, 3, 3, 3, 3, 3,
40 3, 3, 7, 2, 2, 6, 3, 3,
41 3, 3, 3, 3, 3, 3, 3, 3,
42 3, 3, 3, 7, 2, 2, 6, 3,
43 3, 3, 3, 3, 3, 3, 3, 3,
44 3, 3, 3, 3
45};
46
Harald Welte1fa60c82009-02-09 18:13:26 +000047struct map_entry {
48 struct llist_head list;
49 struct gsm_e1_subslot src, dst;
50};
51
Harald Welte45b407a2009-05-23 15:51:12 +000052struct upqueue_entry {
53 struct llist_head list;
54 struct gsm_network *net;
55 struct gsm_e1_subslot src;
56 u_int32_t callref;
57};
58
Harald Welte1fa60c82009-02-09 18:13:26 +000059static LLIST_HEAD(ss_map);
Harald Welte45b407a2009-05-23 15:51:12 +000060static LLIST_HEAD(ss_upqueue);
Harald Welte1fa60c82009-02-09 18:13:26 +000061
Harald Welte (local)d19e58b2009-08-15 02:30:58 +020062void *tall_map_ctx, *tall_upq_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +020063
Harald Welte1fa60c82009-02-09 18:13:26 +000064/* map one particular subslot to another subslot */
65int trau_mux_map(const struct gsm_e1_subslot *src,
66 const struct gsm_e1_subslot *dst)
67{
Harald Welte2cf161b2009-06-20 22:36:41 +020068 struct map_entry *me;
69
Harald Welte2cf161b2009-06-20 22:36:41 +020070 me = talloc(tall_map_ctx, struct map_entry);
Harald Welteb1d4c8e2009-12-17 23:10:46 +010071 if (!me) {
72 LOGP(DMIB, LOGL_FATAL, "Out of memory\n");
Harald Welte1fa60c82009-02-09 18:13:26 +000073 return -ENOMEM;
Harald Welteb1d4c8e2009-12-17 23:10:46 +010074 }
Harald Welte1fa60c82009-02-09 18:13:26 +000075
Harald Weltedbd2ea82009-02-19 17:07:01 +000076 DEBUGP(DCC, "Setting up TRAU mux map between (e1=%u,ts=%u,ss=%u) "
77 "and (e1=%u,ts=%u,ss=%u)\n",
78 src->e1_nr, src->e1_ts, src->e1_ts_ss,
79 dst->e1_nr, dst->e1_ts, dst->e1_ts_ss);
80
Harald Welte26aa6a12009-02-19 15:14:23 +000081 /* make sure to get rid of any stale old mappings */
Harald Welte45b407a2009-05-23 15:51:12 +000082 trau_mux_unmap(src, 0);
83 trau_mux_unmap(dst, 0);
Harald Welte26aa6a12009-02-19 15:14:23 +000084
Harald Welte1fa60c82009-02-09 18:13:26 +000085 memcpy(&me->src, src, sizeof(me->src));
86 memcpy(&me->dst, dst, sizeof(me->dst));
87 llist_add(&me->list, &ss_map);
88
89 return 0;
90}
91
Harald Welte26aa6a12009-02-19 15:14:23 +000092int trau_mux_map_lchan(const struct gsm_lchan *src,
93 const struct gsm_lchan *dst)
94{
95 struct gsm_e1_subslot *src_ss, *dst_ss;
96
97 src_ss = &src->ts->e1_link;
98 dst_ss = &dst->ts->e1_link;
99
100 return trau_mux_map(src_ss, dst_ss);
101}
102
103
Harald Welte1fa60c82009-02-09 18:13:26 +0000104/* unmap one particular subslot from another subslot */
Harald Welte45b407a2009-05-23 15:51:12 +0000105int trau_mux_unmap(const struct gsm_e1_subslot *ss, u_int32_t callref)
Harald Welte1fa60c82009-02-09 18:13:26 +0000106{
107 struct map_entry *me, *me2;
Harald Welte45b407a2009-05-23 15:51:12 +0000108 struct upqueue_entry *ue, *ue2;
Harald Welte1fa60c82009-02-09 18:13:26 +0000109
Harald Welte45b407a2009-05-23 15:51:12 +0000110 if (ss)
111 llist_for_each_entry_safe(me, me2, &ss_map, list) {
112 if (!memcmp(&me->src, ss, sizeof(*ss)) ||
113 !memcmp(&me->dst, ss, sizeof(*ss))) {
114 llist_del(&me->list);
115 return 0;
116 }
117 }
118 llist_for_each_entry_safe(ue, ue2, &ss_upqueue, list) {
119 if (ue->callref == callref) {
120 llist_del(&ue->list);
121 return 0;
122 }
123 if (ss && !memcmp(&ue->src, ss, sizeof(*ss))) {
124 llist_del(&ue->list);
Harald Welte1fa60c82009-02-09 18:13:26 +0000125 return 0;
126 }
127 }
128 return -ENOENT;
129}
130
131/* look-up an enty in the TRAU mux map */
132static struct gsm_e1_subslot *
133lookup_trau_mux_map(const struct gsm_e1_subslot *src)
134{
135 struct map_entry *me;
136
137 llist_for_each_entry(me, &ss_map, list) {
138 if (!memcmp(&me->src, src, sizeof(*src)))
139 return &me->dst;
140 if (!memcmp(&me->dst, src, sizeof(*src)))
141 return &me->src;
142 }
143 return NULL;
144}
145
Harald Welte45b407a2009-05-23 15:51:12 +0000146/* look-up an enty in the TRAU upqueue */
147struct upqueue_entry *
148lookup_trau_upqueue(const struct gsm_e1_subslot *src)
149{
150 struct upqueue_entry *ue;
151
152 llist_for_each_entry(ue, &ss_upqueue, list) {
153 if (!memcmp(&ue->src, src, sizeof(*src)))
154 return ue;
155 }
156 return NULL;
157}
158
Harald Welteda7ab742009-12-19 22:23:05 +0100159static const u_int8_t c_bits_check[] = { 0, 0, 0, 1, 0 };
160
Harald Welte1fa60c82009-02-09 18:13:26 +0000161/* we get called by subchan_demux */
162int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
163 const u_int8_t *trau_bits, int num_bits)
164{
165 struct decoded_trau_frame tf;
166 u_int8_t trau_bits_out[TRAU_FRAME_BITS];
167 struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss);
168 struct subch_mux *mx;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800169 struct upqueue_entry *ue;
Harald Welte41e16682009-02-18 03:34:55 +0000170 int rc;
Harald Welte1fa60c82009-02-09 18:13:26 +0000171
Harald Welte45b407a2009-05-23 15:51:12 +0000172 /* decode TRAU, change it to downlink, re-encode */
173 rc = decode_trau_frame(&tf, trau_bits);
174 if (rc)
175 return rc;
176
Harald Welte4bfdfe72009-06-10 23:11:52 +0800177 if (!dst_e1_ss) {
Harald Welteda7ab742009-12-19 22:23:05 +0100178 struct msgb *msg;
179 struct gsm_data_frame *frame;
180 unsigned char *data;
181 int i, j, k, l, o;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800182 /* frame shall be sent to upqueue */
183 if (!(ue = lookup_trau_upqueue(src_e1_ss)))
184 return -EINVAL;
185 if (!ue->callref)
186 return -EINVAL;
Andreas Eversberg56315f02009-12-21 01:18:44 +0100187 if (memcmp(tf.c_bits, c_bits_check, sizeof(c_bits_check)))
Harald Welteda7ab742009-12-19 22:23:05 +0100188 DEBUGPC(DMUX, "illegal trau (C1-C5) %s\n",
189 hexdump(tf.c_bits, sizeof(c_bits_check)));
190 msg = msgb_alloc(sizeof(struct gsm_data_frame) + 33,
191 "GSM-DATA");
Harald Welte4bfdfe72009-06-10 23:11:52 +0800192 if (!msg)
193 return -ENOMEM;
Harald Welteda7ab742009-12-19 22:23:05 +0100194
195 frame = (struct gsm_data_frame *)msg->data;
196 memset(frame, 0, sizeof(struct gsm_data_frame));
197 data = frame->data;
198 data[0] = 0xd << 4;
199 /* reassemble d-bits */
200 i = 0; /* counts bits */
201 j = 4; /* counts output bits */
202 k = gsm_fr_map[0]-1; /* current number bit in element */
203 l = 0; /* counts element bits */
204 o = 0; /* offset input bits */
205 while (i < 260) {
206 data[j/8] |= (tf.d_bits[k+o] << (7-(j%8)));
207 if (--k < 0) {
208 o += gsm_fr_map[l];
209 k = gsm_fr_map[++l]-1;
210 }
211 i++;
212 j++;
213 }
214 frame->msg_type = GSM_TCHF_FRAME;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800215 frame->callref = ue->callref;
Harald Welte31c00f72011-03-03 23:29:05 +0100216 trau_tx_to_mncc(ue->net, msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800217
218 return 0;
219 }
Harald Welte1fa60c82009-02-09 18:13:26 +0000220
221 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
222 if (!mx)
223 return -EINVAL;
224
Harald Welte1fa60c82009-02-09 18:13:26 +0000225 trau_frame_up2down(&tf);
226 encode_trau_frame(trau_bits_out, &tf);
227
228 /* and send it to the muxer */
229 return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
230 TRAU_FRAME_BITS);
231}
Harald Welte45b407a2009-05-23 15:51:12 +0000232
233/* add receiver instance for lchan and callref */
234int trau_recv_lchan(struct gsm_lchan *lchan, u_int32_t callref)
235{
236 struct gsm_e1_subslot *src_ss;
Harald Welte2cf161b2009-06-20 22:36:41 +0200237 struct upqueue_entry *ue;
Harald Welte45b407a2009-05-23 15:51:12 +0000238
Harald Welte2cf161b2009-06-20 22:36:41 +0200239 ue = talloc(tall_upq_ctx, struct upqueue_entry);
Harald Welte45b407a2009-05-23 15:51:12 +0000240 if (!ue)
241 return -ENOMEM;
242
243 src_ss = &lchan->ts->e1_link;
244
245 DEBUGP(DCC, "Setting up TRAU receiver (e1=%u,ts=%u,ss=%u) "
246 "and (callref 0x%x)\n",
247 src_ss->e1_nr, src_ss->e1_ts, src_ss->e1_ts_ss,
248 callref);
249
250 /* make sure to get rid of any stale old mappings */
251 trau_mux_unmap(src_ss, callref);
252
253 memcpy(&ue->src, src_ss, sizeof(ue->src));
254 ue->net = lchan->ts->trx->bts->network;
255 ue->callref = callref;
256 llist_add(&ue->list, &ss_upqueue);
257
258 return 0;
259}
260
Harald Welteda7ab742009-12-19 22:23:05 +0100261int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
Harald Welte45b407a2009-05-23 15:51:12 +0000262{
263 u_int8_t trau_bits_out[TRAU_FRAME_BITS];
264 struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
265 struct subch_mux *mx;
Harald Welteda7ab742009-12-19 22:23:05 +0100266 int i, j, k, l, o;
267 unsigned char *data = frame->data;
268 struct decoded_trau_frame tf;
Harald Welte45b407a2009-05-23 15:51:12 +0000269
270 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
271 if (!mx)
272 return -EINVAL;
273
Harald Welteda7ab742009-12-19 22:23:05 +0100274 switch (frame->msg_type) {
275 case GSM_TCHF_FRAME:
276 /* set c-bits and t-bits */
277 tf.c_bits[0] = 1;
278 tf.c_bits[1] = 1;
279 tf.c_bits[2] = 1;
280 tf.c_bits[3] = 0;
281 tf.c_bits[4] = 0;
282 memset(&tf.c_bits[5], 0, 6);
283 memset(&tf.c_bits[11], 1, 10);
284 memset(&tf.t_bits[0], 1, 4);
285 /* reassemble d-bits */
286 i = 0; /* counts bits */
287 j = 4; /* counts input bits */
288 k = gsm_fr_map[0]-1; /* current number bit in element */
289 l = 0; /* counts element bits */
290 o = 0; /* offset output bits */
291 while (i < 260) {
292 tf.d_bits[k+o] = (data[j/8] >> (7-(j%8))) & 1;
293 if (--k < 0) {
294 o += gsm_fr_map[l];
295 k = gsm_fr_map[++l]-1;
296 }
297 i++;
298 j++;
299 }
300 break;
301 default:
302 DEBUGPC(DMUX, "unsupported message type %d\n",
303 frame->msg_type);
304 return -EINVAL;
305 }
306
307 encode_trau_frame(trau_bits_out, &tf);
Harald Welte45b407a2009-05-23 15:51:12 +0000308
309 /* and send it to the muxer */
310 return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
311 TRAU_FRAME_BITS);
312}