blob: 82813b3927a26a551c25c0185aa00948a3a499cf [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>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010032#include <osmocom/core/talloc.h>
Harald Welte1fa60c82009-02-09 18:13:26 +000033
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020034uint8_t gsm_fr_map[] = {
Harald Welteda7ab742009-12-19 22:23:05 +010035 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;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020056 uint32_t callref;
Harald Welte45b407a2009-05-23 15:51:12 +000057};
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 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200105int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_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
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200159static const uint8_t c_bits_check[] = { 0, 0, 0, 1, 0 };
Harald Welteda7ab742009-12-19 22:23:05 +0100160
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,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200163 const uint8_t *trau_bits, int num_bits)
Harald Welte1fa60c82009-02-09 18:13:26 +0000164{
165 struct decoded_trau_frame tf;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200166 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte1fa60c82009-02-09 18:13:26 +0000167 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 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200234int trau_recv_lchan(struct gsm_lchan *lchan, uint32_t callref)
Harald Welte45b407a2009-05-23 15:51:12 +0000235{
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{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200263 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte45b407a2009-05-23 15:51:12 +0000264 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}