blob: 1a7ba0e4d94e65b56a973f27911259e818c8815c [file] [log] [blame]
Harald Welteec8b4502010-02-20 20:34:29 +01001/*
2 * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
3 * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
Harald Welte622b7182010-03-07 17:50:21 +01004 * (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
Nico Golde28de0532010-07-09 17:19:12 +02005 * (C) 2010 by Nico Golde <nico@ngolde.de>
Harald Welteec8b4502010-02-20 20:34:29 +01006 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25//#include <openbsc/gsm_data.h>
26#include <osmocore/utils.h>
27#include <osmocore/gsm_utils.h>
28
29#include <stdlib.h>
30#include <stdint.h>
31#include <string.h>
32#include <stdio.h>
33#include <errno.h>
Harald Welteaebe08c2010-03-04 10:39:17 +010034#include <ctype.h>
Harald Welteec8b4502010-02-20 20:34:29 +010035
36#include "../config.h"
37
Nico Golde28de0532010-07-09 17:19:12 +020038/* GSM 03.38 6.2.1 Character lookup for decoding */
39static int gsm_septet_lookup(uint8_t ch)
40{
41 int i = 0;
42 for(; i < sizeof(gsm_7bit_alphabet); i++){
43 if(gsm_7bit_alphabet[i] == ch)
44 return i;
45 }
46 return -1;
47}
48
49/* GSM 03.38 6.2.1 Character unpacking */
Harald Welteec8b4502010-02-20 20:34:29 +010050int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t length)
51{
52 int i = 0;
53 int l = 0;
Nico Goldec0ce9aa2010-07-20 15:43:58 +020054 int septet_l = (length * 8) / 7;
55 uint8_t *rtext = calloc(septet_l + 1, sizeof(uint8_t));
Nico Golde28de0532010-07-09 17:19:12 +020056 uint8_t tmp;
Harald Welteec8b4502010-02-20 20:34:29 +010057
Nico Golde28de0532010-07-09 17:19:12 +020058 /* FIXME: We need to account for user data headers here */
Harald Welteec8b4502010-02-20 20:34:29 +010059 i += l;
Nico Goldec0ce9aa2010-07-20 15:43:58 +020060 for (; i < septet_l; i++){
Nico Golde28de0532010-07-09 17:19:12 +020061 rtext[i] =
Harald Welteec8b4502010-02-20 20:34:29 +010062 ((user_data[(i * 7 + 7) >> 3] <<
63 (7 - ((i * 7 + 7) & 7))) |
64 (user_data[(i * 7) >> 3] >>
65 ((i * 7) & 7))) & 0x7f;
Nico Golde28de0532010-07-09 17:19:12 +020066 }
Nico Goldec0ce9aa2010-07-20 15:43:58 +020067
68 for(i = 0; i < septet_l; i++){
Nico Golde28de0532010-07-09 17:19:12 +020069 /* this is an extension character */
Holger Hans Peter Freyther446bf372010-07-20 02:54:54 +080070 if(rtext[i] == 0x1b && i + 1 < length){
Nico Golde28de0532010-07-09 17:19:12 +020071 tmp = rtext[i+1];
72 *(text++) = gsm_7bit_alphabet[0x7f + tmp];
Harald Welteec8b4502010-02-20 20:34:29 +010073 i++;
Nico Golde28de0532010-07-09 17:19:12 +020074 continue;
Harald Welteec8b4502010-02-20 20:34:29 +010075 }
Nico Golde28de0532010-07-09 17:19:12 +020076
77 *(text++) = gsm_septet_lookup(rtext[i]);
Harald Welteec8b4502010-02-20 20:34:29 +010078 }
79
Nico Golde28de0532010-07-09 17:19:12 +020080 *text = '\0';
81 free(rtext);
82
83 return i;
84}
85
86/* GSM 03.38 6.2.1 Prepare character packing */
87static int gsm_septet_encode(uint8_t *result, const char *data)
88{
89 int i, y = 0;
90 uint8_t ch;
91 for(i = 0; i < strlen(data); i++){
92 ch = data[i];
93 switch(ch){
94 /* fall-through for extension characters */
95 case 0x0c:
96 case 0x5e:
97 case 0x7b:
98 case 0x7d:
99 case 0x5c:
100 case 0x5b:
101 case 0x7e:
102 case 0x5d:
103 case 0x7c:
104 result[y++] = 0x1b;
105 default:
106 result[y] = gsm_7bit_alphabet[ch];
107 break;
108 }
109 y++;
110 }
111
112 return y;
113}
114
115/* GSM 03.38 6.2.1 Character packing */
116int gsm_7bit_encode(uint8_t *result, const char *data)
117{
118 int i,y,z = 0;
119 /* prepare for the worst case, every character expanding to two bytes */
120 uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t));
121 uint8_t cb, nb;
122 int shift = 0;
123
124 y = gsm_septet_encode(rdata, data);
125
126 for(i = 0; i < y; i++) {
127 if(shift == 7 && i + 1 < y){
128 shift = 0;
129 continue;
130 }
131
132 cb = (rdata[i] & 0x7f) >> shift;
133 if(i + 1 < y){
134 nb = (rdata[i + 1] & 0x7f) << (7 - shift);
135 cb = cb | nb;
136 }
137
138 result[z++] = cb;
139
140 shift++;
141 }
142
143 free(rdata);
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200144 return z;
Harald Welteec8b4502010-02-20 20:34:29 +0100145}
146
147/* determine power control level for given dBm value, as indicated
148 * by the tables in chapter 4.1.1 of GSM TS 05.05 */
149int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
150{
151 switch (band) {
152 case GSM_BAND_450:
153 case GSM_BAND_480:
154 case GSM_BAND_750:
155 case GSM_BAND_900:
156 case GSM_BAND_810:
157 case GSM_BAND_850:
158 if (dbm >= 39)
159 return 0;
160 else if (dbm < 5)
161 return 19;
162 else {
163 /* we are guaranteed to have (5 <= dbm < 39) */
164 return 2 + ((39 - dbm) / 2);
165 }
166 break;
167 case GSM_BAND_1800:
168 if (dbm >= 36)
169 return 29;
170 else if (dbm >= 34)
171 return 30;
172 else if (dbm >= 32)
173 return 31;
174 else if (dbm == 31)
175 return 0;
176 else {
177 /* we are guaranteed to have (0 <= dbm < 31) */
178 return (30 - dbm) / 2;
179 }
180 break;
181 case GSM_BAND_1900:
182 if (dbm >= 33)
183 return 30;
184 else if (dbm >= 32)
185 return 31;
186 else if (dbm == 31)
187 return 0;
188 else {
189 /* we are guaranteed to have (0 <= dbm < 31) */
190 return (30 - dbm) / 2;
191 }
192 break;
193 }
194 return -EINVAL;
195}
196
197int ms_pwr_dbm(enum gsm_band band, uint8_t lvl)
198{
199 lvl &= 0x1f;
200
201 switch (band) {
202 case GSM_BAND_450:
203 case GSM_BAND_480:
204 case GSM_BAND_750:
205 case GSM_BAND_900:
206 case GSM_BAND_810:
207 case GSM_BAND_850:
208 if (lvl < 2)
209 return 39;
210 else if (lvl < 20)
211 return 39 - ((lvl - 2) * 2) ;
212 else
213 return 5;
214 break;
215 case GSM_BAND_1800:
216 if (lvl < 16)
217 return 30 - (lvl * 2);
218 else if (lvl < 29)
219 return 0;
220 else
221 return 36 - ((lvl - 29) * 2);
222 break;
223 case GSM_BAND_1900:
224 if (lvl < 16)
225 return 30 - (lvl * 2);
226 else if (lvl < 30)
227 return -EINVAL;
228 else
229 return 33 - (lvl - 30);
230 break;
231 }
232 return -EINVAL;
233}
234
235/* According to TS 08.05 Chapter 8.1.4 */
236int rxlev2dbm(uint8_t rxlev)
237{
238 if (rxlev > 63)
239 rxlev = 63;
240
241 return -110 + rxlev;
242}
243
244/* According to TS 08.05 Chapter 8.1.4 */
245uint8_t dbm2rxlev(int dbm)
246{
247 int rxlev = dbm + 110;
248
249 if (rxlev > 63)
250 rxlev = 63;
251 else if (rxlev < 0)
252 rxlev = 0;
253
254 return rxlev;
255}
256
Harald Weltecbc80622010-03-22 08:28:44 +0800257const char *gsm_band_name(enum gsm_band band)
Harald Welteaebe08c2010-03-04 10:39:17 +0100258{
259 switch (band) {
260 case GSM_BAND_450:
261 return "GSM450";
262 case GSM_BAND_480:
Sylvain Munaute10ae5b2010-07-04 11:41:36 +0200263 return "GSM480";
Harald Welteaebe08c2010-03-04 10:39:17 +0100264 case GSM_BAND_750:
265 return "GSM750";
266 case GSM_BAND_810:
267 return "GSM810";
268 case GSM_BAND_850:
269 return "GSM850";
270 case GSM_BAND_900:
271 return "GSM900";
272 case GSM_BAND_1800:
273 return "DCS1800";
274 case GSM_BAND_1900:
275 return "PCS1900";
276 }
277 return "invalid";
278}
279
280enum gsm_band gsm_band_parse(const char* mhz)
281{
282 while (*mhz && !isdigit(*mhz))
283 mhz++;
284
285 if (*mhz == '\0')
286 return -EINVAL;
287
Harald Welted3ff15f2010-03-07 18:23:47 +0100288 switch (strtol(mhz, NULL, 10)) {
Harald Welteaebe08c2010-03-04 10:39:17 +0100289 case 450:
290 return GSM_BAND_450;
291 case 480:
292 return GSM_BAND_480;
293 case 750:
294 return GSM_BAND_750;
295 case 810:
296 return GSM_BAND_810;
297 case 850:
298 return GSM_BAND_850;
299 case 900:
300 return GSM_BAND_900;
301 case 1800:
302 return GSM_BAND_1800;
303 case 1900:
304 return GSM_BAND_1900;
305 default:
306 return -EINVAL;
307 }
308}
309
310
Harald Welteec8b4502010-02-20 20:34:29 +0100311#ifdef HAVE_EXECINFO_H
312#include <execinfo.h>
313void generate_backtrace()
314{
315 int i, nptrs;
316 void *buffer[100];
317 char **strings;
318
319 nptrs = backtrace(buffer, ARRAY_SIZE(buffer));
320 printf("backtrace() returned %d addresses\n", nptrs);
321
322 strings = backtrace_symbols(buffer, nptrs);
323 if (!strings)
324 return;
325
326 for (i = 1; i < nptrs; i++)
327 printf("%s\n", strings[i]);
328
329 free(strings);
330}
331#endif
Harald Welte622b7182010-03-07 17:50:21 +0100332
333enum gsm_band gsm_arfcn2band(uint16_t arfcn)
334{
335 if (arfcn & ARFCN_PCS)
336 return GSM_BAND_1900;
337 else if (arfcn <= 124)
338 return GSM_BAND_900;
339 else if (arfcn >= 955 && arfcn <= 1023)
340 return GSM_BAND_900;
341 else if (arfcn >= 128 && arfcn <= 251)
342 return GSM_BAND_850;
343 else if (arfcn >= 512 && arfcn <= 885)
344 return GSM_BAND_1800;
345 else if (arfcn >= 259 && arfcn <= 293)
346 return GSM_BAND_450;
347 else if (arfcn >= 306 && arfcn <= 340)
348 return GSM_BAND_480;
349 else if (arfcn >= 350 && arfcn <= 425)
350 return GSM_BAND_810;
351 else if (arfcn >= 438 && arfcn <= 511)
352 return GSM_BAND_750;
353 else
354 return GSM_BAND_1800;
355}
356
357/* Convert an ARFCN to the frequency in MHz * 10 */
358uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink)
359{
360 uint16_t freq10_ul;
361 uint16_t freq10_dl;
362
363 if (arfcn & ARFCN_PCS) {
364 /* DCS 1900 */
365 arfcn &= ~ARFCN_PCS;
366 freq10_ul = 18502 + 2 * (arfcn-512);
367 freq10_dl = freq10_ul + 800;
368 } else if (arfcn <= 124) {
369 /* Primary GSM + ARFCN 0 of E-GSM */
370 freq10_ul = 8900 + 2 * arfcn;
371 freq10_dl = freq10_ul + 450;
372 } else if (arfcn >= 955 && arfcn <= 1023) {
373 /* E-GSM and R-GSM */
374 freq10_ul = 8900 + 2 * (arfcn - 1024);
375 freq10_dl = freq10_ul + 450;
376 } else if (arfcn >= 128 && arfcn <= 251) {
377 /* GSM 850 */
378 freq10_ul = 8242 + 2 * (arfcn - 128);
379 freq10_dl = freq10_ul + 450;
380 } else if (arfcn >= 512 && arfcn <= 885) {
381 /* DCS 1800 */
382 freq10_ul = 17102 + 2 * (arfcn - 512);
383 freq10_dl = freq10_ul + 950;
384 } else if (arfcn >= 259 && arfcn <= 293) {
385 /* GSM 450 */
386 freq10_ul = 4506 + 2 * (arfcn - 259);
387 freq10_dl = freq10_ul + 100;
388 } else if (arfcn >= 306 && arfcn <= 340) {
389 /* GSM 480 */
390 freq10_ul = 4790 + 2 * (arfcn - 306);
391 freq10_dl = freq10_ul + 100;
392 } else if (arfcn >= 350 && arfcn <= 425) {
393 /* GSM 810 */
394 freq10_ul = 8060 + 2 * (arfcn - 350);
395 freq10_dl = freq10_ul + 450;
396 } else if (arfcn >= 438 && arfcn <= 511) {
397 /* GSM 750 */
398 freq10_ul = 7472 + 2 * (arfcn - 438);
399 freq10_dl = freq10_ul + 300;
400 } else
401 return 0xffff;
402
403 if (uplink)
404 return freq10_ul;
405 else
406 return freq10_dl;
407}
408
409void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn)
410{
411 time->fn = fn;
412 time->t1 = time->fn / (26*51);
413 time->t2 = time->fn % 26;
414 time->t3 = time->fn % 51;
415 time->tc = (time->fn / 51) % 8;
416}
417
418uint32_t gsm_gsmtime2fn(struct gsm_time *time)
419{
420 /* TS 05.02 Chapter 4.3.3 TDMA frame number */
421 return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));
422}
Harald Weltea1c4f762010-05-01 11:59:42 +0200423
424/* TS 03.03 Chapter 2.6 */
425int gprs_tlli_type(uint32_t tlli)
426{
427 if ((tlli & 0xc0000000) == 0xc0000000)
428 return TLLI_LOCAL;
429 else if ((tlli & 0xc0000000) == 0x80000000)
430 return TLLI_FOREIGN;
431 else if ((tlli & 0xf8000000) == 0x78000000)
432 return TLLI_RANDOM;
433 else if ((tlli & 0xf8000000) == 0x70000000)
434 return TLLI_AUXILIARY;
435
436 return TLLI_RESERVED;
437}
Harald Weltec2263172010-06-01 10:47:07 +0200438
439uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type)
440{
441 uint32_t tlli;
442 switch (type) {
443 case TLLI_LOCAL:
444 tlli = p_tmsi | 0xc0000000;
445 break;
446 case TLLI_FOREIGN:
447 tlli = (p_tmsi & 0x3fffffff) | 0x80000000;
448 break;
449 default:
450 tlli = 0;
451 break;
452 }
453 return tlli;
454}