blob: b8b90bd02cccdfef2cbe84a21e33b8778c0f4bde [file] [log] [blame]
Harald Welte59b04682009-06-10 05:40:52 +08001/* 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 Welte0e3e88e2011-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 Welte59b04682009-06-10 05:40:52 +08009 * (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 Welte0e3e88e2011-01-01 15:25:50 +010014 * GNU Affero General Public License for more details.
Harald Welte59b04682009-06-10 05:40:52 +080015 *
Harald Welte0e3e88e2011-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 Welte59b04682009-06-10 05:40:52 +080018 *
19 */
20
21#include <errno.h>
22#include <stdlib.h>
23#include <string.h>
Harald Welte59b04682009-06-10 05:40:52 +080024
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>
30#include <openbsc/debug.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010031#include <osmocom/core/talloc.h>
Harald Welte59b04682009-06-10 05:40:52 +080032
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020033uint8_t gsm_fr_map[] = {
Harald Welte3971ad52009-12-19 22:23:05 +010034 6, 6, 5, 5, 4, 4, 3, 3,
35 7, 2, 2, 6, 3, 3, 3, 3,
36 3, 3, 3, 3, 3, 3, 3, 3,
37 3, 7, 2, 2, 6, 3, 3, 3,
38 3, 3, 3, 3, 3, 3, 3, 3,
39 3, 3, 7, 2, 2, 6, 3, 3,
40 3, 3, 3, 3, 3, 3, 3, 3,
41 3, 3, 3, 7, 2, 2, 6, 3,
42 3, 3, 3, 3, 3, 3, 3, 3,
43 3, 3, 3, 3
44};
45
Harald Welte59b04682009-06-10 05:40:52 +080046struct map_entry {
47 struct llist_head list;
48 struct gsm_e1_subslot src, dst;
49};
50
51struct upqueue_entry {
52 struct llist_head list;
53 struct gsm_network *net;
54 struct gsm_e1_subslot src;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020055 uint32_t callref;
Harald Welte59b04682009-06-10 05:40:52 +080056};
57
58static LLIST_HEAD(ss_map);
59static LLIST_HEAD(ss_upqueue);
60
Harald Welte (local)8751ee92009-08-15 02:30:58 +020061void *tall_map_ctx, *tall_upq_ctx;
Harald Weltea8379772009-06-20 22:36:41 +020062
Harald Welte59b04682009-06-10 05:40:52 +080063/* map one particular subslot to another subslot */
64int trau_mux_map(const struct gsm_e1_subslot *src,
65 const struct gsm_e1_subslot *dst)
66{
Harald Weltea8379772009-06-20 22:36:41 +020067 struct map_entry *me;
68
Harald Weltea8379772009-06-20 22:36:41 +020069 me = talloc(tall_map_ctx, struct map_entry);
Harald Weltecf2ec4a2009-12-17 23:10:46 +010070 if (!me) {
71 LOGP(DMIB, LOGL_FATAL, "Out of memory\n");
Harald Welte59b04682009-06-10 05:40:52 +080072 return -ENOMEM;
Harald Weltecf2ec4a2009-12-17 23:10:46 +010073 }
Harald Welte59b04682009-06-10 05:40:52 +080074
75 DEBUGP(DCC, "Setting up TRAU mux map between (e1=%u,ts=%u,ss=%u) "
76 "and (e1=%u,ts=%u,ss=%u)\n",
77 src->e1_nr, src->e1_ts, src->e1_ts_ss,
78 dst->e1_nr, dst->e1_ts, dst->e1_ts_ss);
79
80 /* make sure to get rid of any stale old mappings */
81 trau_mux_unmap(src, 0);
82 trau_mux_unmap(dst, 0);
83
84 memcpy(&me->src, src, sizeof(me->src));
85 memcpy(&me->dst, dst, sizeof(me->dst));
86 llist_add(&me->list, &ss_map);
87
88 return 0;
89}
90
91int trau_mux_map_lchan(const struct gsm_lchan *src,
92 const struct gsm_lchan *dst)
93{
94 struct gsm_e1_subslot *src_ss, *dst_ss;
95
96 src_ss = &src->ts->e1_link;
97 dst_ss = &dst->ts->e1_link;
98
99 return trau_mux_map(src_ss, dst_ss);
100}
101
102
103/* unmap one particular subslot from another subslot */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200104int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_t callref)
Harald Welte59b04682009-06-10 05:40:52 +0800105{
106 struct map_entry *me, *me2;
107 struct upqueue_entry *ue, *ue2;
108
109 if (ss)
110 llist_for_each_entry_safe(me, me2, &ss_map, list) {
111 if (!memcmp(&me->src, ss, sizeof(*ss)) ||
112 !memcmp(&me->dst, ss, sizeof(*ss))) {
113 llist_del(&me->list);
114 return 0;
115 }
116 }
117 llist_for_each_entry_safe(ue, ue2, &ss_upqueue, list) {
118 if (ue->callref == callref) {
119 llist_del(&ue->list);
120 return 0;
121 }
122 if (ss && !memcmp(&ue->src, ss, sizeof(*ss))) {
123 llist_del(&ue->list);
124 return 0;
125 }
126 }
127 return -ENOENT;
128}
129
130/* look-up an enty in the TRAU mux map */
131static struct gsm_e1_subslot *
132lookup_trau_mux_map(const struct gsm_e1_subslot *src)
133{
134 struct map_entry *me;
135
136 llist_for_each_entry(me, &ss_map, list) {
137 if (!memcmp(&me->src, src, sizeof(*src)))
138 return &me->dst;
139 if (!memcmp(&me->dst, src, sizeof(*src)))
140 return &me->src;
141 }
142 return NULL;
143}
144
145/* look-up an enty in the TRAU upqueue */
146struct upqueue_entry *
147lookup_trau_upqueue(const struct gsm_e1_subslot *src)
148{
149 struct upqueue_entry *ue;
150
151 llist_for_each_entry(ue, &ss_upqueue, list) {
152 if (!memcmp(&ue->src, src, sizeof(*src)))
153 return ue;
154 }
155 return NULL;
156}
157
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200158static const uint8_t c_bits_check[] = { 0, 0, 0, 1, 0 };
Harald Welte3971ad52009-12-19 22:23:05 +0100159
Harald Welte59b04682009-06-10 05:40:52 +0800160/* we get called by subchan_demux */
161int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200162 const uint8_t *trau_bits, int num_bits)
Harald Welte59b04682009-06-10 05:40:52 +0800163{
164 struct decoded_trau_frame tf;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200165 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte59b04682009-06-10 05:40:52 +0800166 struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss);
167 struct subch_mux *mx;
Harald Welte03740842009-06-10 23:11:52 +0800168 struct upqueue_entry *ue;
Harald Welte59b04682009-06-10 05:40:52 +0800169 int rc;
170
171 /* decode TRAU, change it to downlink, re-encode */
172 rc = decode_trau_frame(&tf, trau_bits);
173 if (rc)
174 return rc;
175
Harald Welte03740842009-06-10 23:11:52 +0800176 if (!dst_e1_ss) {
Harald Welte3971ad52009-12-19 22:23:05 +0100177 struct msgb *msg;
178 struct gsm_data_frame *frame;
179 unsigned char *data;
180 int i, j, k, l, o;
Harald Welte03740842009-06-10 23:11:52 +0800181 /* frame shall be sent to upqueue */
182 if (!(ue = lookup_trau_upqueue(src_e1_ss)))
183 return -EINVAL;
184 if (!ue->callref)
185 return -EINVAL;
Andreas Eversbergbd107a42009-12-21 01:18:44 +0100186 if (memcmp(tf.c_bits, c_bits_check, sizeof(c_bits_check)))
Harald Welte3971ad52009-12-19 22:23:05 +0100187 DEBUGPC(DMUX, "illegal trau (C1-C5) %s\n",
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200188 osmo_hexdump(tf.c_bits, sizeof(c_bits_check)));
Harald Welte3971ad52009-12-19 22:23:05 +0100189 msg = msgb_alloc(sizeof(struct gsm_data_frame) + 33,
190 "GSM-DATA");
Harald Welte03740842009-06-10 23:11:52 +0800191 if (!msg)
192 return -ENOMEM;
Harald Welte3971ad52009-12-19 22:23:05 +0100193
194 frame = (struct gsm_data_frame *)msg->data;
195 memset(frame, 0, sizeof(struct gsm_data_frame));
196 data = frame->data;
197 data[0] = 0xd << 4;
198 /* reassemble d-bits */
199 i = 0; /* counts bits */
200 j = 4; /* counts output bits */
201 k = gsm_fr_map[0]-1; /* current number bit in element */
202 l = 0; /* counts element bits */
203 o = 0; /* offset input bits */
204 while (i < 260) {
205 data[j/8] |= (tf.d_bits[k+o] << (7-(j%8)));
206 if (--k < 0) {
207 o += gsm_fr_map[l];
208 k = gsm_fr_map[++l]-1;
209 }
210 i++;
211 j++;
212 }
213 frame->msg_type = GSM_TCHF_FRAME;
Harald Welte03740842009-06-10 23:11:52 +0800214 frame->callref = ue->callref;
Harald Welte4f272cc2011-03-03 23:29:05 +0100215 trau_tx_to_mncc(ue->net, msg);
Harald Welte03740842009-06-10 23:11:52 +0800216
217 return 0;
218 }
Harald Welte59b04682009-06-10 05:40:52 +0800219
220 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
221 if (!mx)
222 return -EINVAL;
223
224 trau_frame_up2down(&tf);
225 encode_trau_frame(trau_bits_out, &tf);
226
227 /* and send it to the muxer */
228 return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
229 TRAU_FRAME_BITS);
230}
231
232/* add receiver instance for lchan and callref */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200233int trau_recv_lchan(struct gsm_lchan *lchan, uint32_t callref)
Harald Welte59b04682009-06-10 05:40:52 +0800234{
235 struct gsm_e1_subslot *src_ss;
Harald Weltea8379772009-06-20 22:36:41 +0200236 struct upqueue_entry *ue;
Harald Welte59b04682009-06-10 05:40:52 +0800237
Harald Weltea8379772009-06-20 22:36:41 +0200238 ue = talloc(tall_upq_ctx, struct upqueue_entry);
Harald Welte59b04682009-06-10 05:40:52 +0800239 if (!ue)
240 return -ENOMEM;
241
242 src_ss = &lchan->ts->e1_link;
243
244 DEBUGP(DCC, "Setting up TRAU receiver (e1=%u,ts=%u,ss=%u) "
245 "and (callref 0x%x)\n",
246 src_ss->e1_nr, src_ss->e1_ts, src_ss->e1_ts_ss,
247 callref);
248
249 /* make sure to get rid of any stale old mappings */
250 trau_mux_unmap(src_ss, callref);
251
252 memcpy(&ue->src, src_ss, sizeof(ue->src));
253 ue->net = lchan->ts->trx->bts->network;
254 ue->callref = callref;
255 llist_add(&ue->list, &ss_upqueue);
256
257 return 0;
258}
259
Harald Welte3971ad52009-12-19 22:23:05 +0100260int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
Harald Welte59b04682009-06-10 05:40:52 +0800261{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200262 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte59b04682009-06-10 05:40:52 +0800263 struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
264 struct subch_mux *mx;
Harald Welte3971ad52009-12-19 22:23:05 +0100265 int i, j, k, l, o;
266 unsigned char *data = frame->data;
267 struct decoded_trau_frame tf;
Harald Welte59b04682009-06-10 05:40:52 +0800268
269 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
270 if (!mx)
271 return -EINVAL;
272
Harald Welte3971ad52009-12-19 22:23:05 +0100273 switch (frame->msg_type) {
274 case GSM_TCHF_FRAME:
275 /* set c-bits and t-bits */
276 tf.c_bits[0] = 1;
277 tf.c_bits[1] = 1;
278 tf.c_bits[2] = 1;
279 tf.c_bits[3] = 0;
280 tf.c_bits[4] = 0;
281 memset(&tf.c_bits[5], 0, 6);
282 memset(&tf.c_bits[11], 1, 10);
283 memset(&tf.t_bits[0], 1, 4);
284 /* reassemble d-bits */
285 i = 0; /* counts bits */
286 j = 4; /* counts input bits */
287 k = gsm_fr_map[0]-1; /* current number bit in element */
288 l = 0; /* counts element bits */
289 o = 0; /* offset output bits */
290 while (i < 260) {
291 tf.d_bits[k+o] = (data[j/8] >> (7-(j%8))) & 1;
292 if (--k < 0) {
293 o += gsm_fr_map[l];
294 k = gsm_fr_map[++l]-1;
295 }
296 i++;
297 j++;
298 }
299 break;
300 default:
301 DEBUGPC(DMUX, "unsupported message type %d\n",
302 frame->msg_type);
303 return -EINVAL;
304 }
305
306 encode_trau_frame(trau_bits_out, &tf);
Harald Welte59b04682009-06-10 05:40:52 +0800307
308 /* and send it to the muxer */
309 return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
310 TRAU_FRAME_BITS);
311}