blob: b8b90bd02cccdfef2cbe84a21e33b8778c0f4bde [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
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020033uint8_t gsm_fr_map[] = {
Harald Welteda7ab742009-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 Welte1fa60c82009-02-09 18:13:26 +000046struct map_entry {
47 struct llist_head list;
48 struct gsm_e1_subslot src, dst;
49};
50
Harald Welte45b407a2009-05-23 15:51:12 +000051struct upqueue_entry {
52 struct llist_head list;
53 struct gsm_network *net;
54 struct gsm_e1_subslot src;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020055 uint32_t callref;
Harald Welte45b407a2009-05-23 15:51:12 +000056};
57
Harald Welte1fa60c82009-02-09 18:13:26 +000058static LLIST_HEAD(ss_map);
Harald Welte45b407a2009-05-23 15:51:12 +000059static LLIST_HEAD(ss_upqueue);
Harald Welte1fa60c82009-02-09 18:13:26 +000060
Harald Welte (local)d19e58b2009-08-15 02:30:58 +020061void *tall_map_ctx, *tall_upq_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +020062
Harald Welte1fa60c82009-02-09 18:13:26 +000063/* 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 Welte2cf161b2009-06-20 22:36:41 +020067 struct map_entry *me;
68
Harald Welte2cf161b2009-06-20 22:36:41 +020069 me = talloc(tall_map_ctx, struct map_entry);
Harald Welteb1d4c8e2009-12-17 23:10:46 +010070 if (!me) {
71 LOGP(DMIB, LOGL_FATAL, "Out of memory\n");
Harald Welte1fa60c82009-02-09 18:13:26 +000072 return -ENOMEM;
Harald Welteb1d4c8e2009-12-17 23:10:46 +010073 }
Harald Welte1fa60c82009-02-09 18:13:26 +000074
Harald Weltedbd2ea82009-02-19 17:07:01 +000075 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
Harald Welte26aa6a12009-02-19 15:14:23 +000080 /* make sure to get rid of any stale old mappings */
Harald Welte45b407a2009-05-23 15:51:12 +000081 trau_mux_unmap(src, 0);
82 trau_mux_unmap(dst, 0);
Harald Welte26aa6a12009-02-19 15:14:23 +000083
Harald Welte1fa60c82009-02-09 18:13:26 +000084 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
Harald Welte26aa6a12009-02-19 15:14:23 +000091int 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
Harald Welte1fa60c82009-02-09 18:13:26 +0000103/* unmap one particular subslot from another subslot */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200104int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_t callref)
Harald Welte1fa60c82009-02-09 18:13:26 +0000105{
106 struct map_entry *me, *me2;
Harald Welte45b407a2009-05-23 15:51:12 +0000107 struct upqueue_entry *ue, *ue2;
Harald Welte1fa60c82009-02-09 18:13:26 +0000108
Harald Welte45b407a2009-05-23 15:51:12 +0000109 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);
Harald Welte1fa60c82009-02-09 18:13:26 +0000124 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
Harald Welte45b407a2009-05-23 15:51:12 +0000145/* 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 Freytherc42ad8b2011-04-18 17:04:00 +0200158static const uint8_t c_bits_check[] = { 0, 0, 0, 1, 0 };
Harald Welteda7ab742009-12-19 22:23:05 +0100159
Harald Welte1fa60c82009-02-09 18:13:26 +0000160/* we get called by subchan_demux */
161int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200162 const uint8_t *trau_bits, int num_bits)
Harald Welte1fa60c82009-02-09 18:13:26 +0000163{
164 struct decoded_trau_frame tf;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200165 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte1fa60c82009-02-09 18:13:26 +0000166 struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss);
167 struct subch_mux *mx;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800168 struct upqueue_entry *ue;
Harald Welte41e16682009-02-18 03:34:55 +0000169 int rc;
Harald Welte1fa60c82009-02-09 18:13:26 +0000170
Harald Welte45b407a2009-05-23 15:51:12 +0000171 /* decode TRAU, change it to downlink, re-encode */
172 rc = decode_trau_frame(&tf, trau_bits);
173 if (rc)
174 return rc;
175
Harald Welte4bfdfe72009-06-10 23:11:52 +0800176 if (!dst_e1_ss) {
Harald Welteda7ab742009-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 Welte4bfdfe72009-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 Eversberg56315f02009-12-21 01:18:44 +0100186 if (memcmp(tf.c_bits, c_bits_check, sizeof(c_bits_check)))
Harald Welteda7ab742009-12-19 22:23:05 +0100187 DEBUGPC(DMUX, "illegal trau (C1-C5) %s\n",
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200188 osmo_hexdump(tf.c_bits, sizeof(c_bits_check)));
Harald Welteda7ab742009-12-19 22:23:05 +0100189 msg = msgb_alloc(sizeof(struct gsm_data_frame) + 33,
190 "GSM-DATA");
Harald Welte4bfdfe72009-06-10 23:11:52 +0800191 if (!msg)
192 return -ENOMEM;
Harald Welteda7ab742009-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 Welte4bfdfe72009-06-10 23:11:52 +0800214 frame->callref = ue->callref;
Harald Welte31c00f72011-03-03 23:29:05 +0100215 trau_tx_to_mncc(ue->net, msg);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800216
217 return 0;
218 }
Harald Welte1fa60c82009-02-09 18:13:26 +0000219
220 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
221 if (!mx)
222 return -EINVAL;
223
Harald Welte1fa60c82009-02-09 18:13:26 +0000224 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}
Harald Welte45b407a2009-05-23 15:51:12 +0000231
232/* add receiver instance for lchan and callref */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200233int trau_recv_lchan(struct gsm_lchan *lchan, uint32_t callref)
Harald Welte45b407a2009-05-23 15:51:12 +0000234{
235 struct gsm_e1_subslot *src_ss;
Harald Welte2cf161b2009-06-20 22:36:41 +0200236 struct upqueue_entry *ue;
Harald Welte45b407a2009-05-23 15:51:12 +0000237
Harald Welte2cf161b2009-06-20 22:36:41 +0200238 ue = talloc(tall_upq_ctx, struct upqueue_entry);
Harald Welte45b407a2009-05-23 15:51:12 +0000239 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 Welteda7ab742009-12-19 22:23:05 +0100260int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
Harald Welte45b407a2009-05-23 15:51:12 +0000261{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200262 uint8_t trau_bits_out[TRAU_FRAME_BITS];
Harald Welte45b407a2009-05-23 15:51:12 +0000263 struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
264 struct subch_mux *mx;
Harald Welteda7ab742009-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 Welte45b407a2009-05-23 15:51:12 +0000268
269 mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
270 if (!mx)
271 return -EINVAL;
272
Harald Welteda7ab742009-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 Welte45b407a2009-05-23 15:51:12 +0000307
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}