blob: 8d072a1fc0106d7a6e62ecd7faa87ee6766c9acf [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
Harald Welted38c8b82011-08-30 11:32:56 +020025/*! \mainpage libosmogsm Documentation
26 *
27 * \section sec_intro Introduction
28 * This library is a collection of common code used in various
29 * GSM related sub-projects inside the Osmocom family of projects. It
30 * includes A5/1 and A5/2 ciphers, COMP128v1, a LAPDm implementation,
31 * a GSM TLV parser, SMS utility routines as well as
32 * protocol definitions for a series of protocols:
33 * * Um L2 (04.06)
34 * * Um L3 (04.08)
35 * * A-bis RSL (08.58)
36 * * A-bis OML (08.59, 12.21)
37 * * A (08.08)
38 * \n\n
39 * Please note that C language projects inside Osmocom are typically
40 * single-threaded event-loop state machine designs. As such,
41 * routines in libosmogsm are not thread-safe. If you must use them in
42 * a multi-threaded context, you have to add your own locking.
43 *
44 * \section sec_copyright Copyright and License
45 * Copyright © 2008-2011 - Harald Welte, Holger Freyther and contributors\n
46 * All rights reserved. \n\n
47 * The source code of libosmogsm is licensed under the terms of the GNU
48 * General Public License as published by the Free Software Foundation;
49 * either version 2 of the License, or (at your option) any later
50 * version.\n
51 * See <http://www.gnu.org/licenses/> or COPYING included in the source
52 * code package istelf.\n
53 * The information detailed here is provided AS IS with NO WARRANTY OF
54 * ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND
55 * FITNESS FOR A PARTICULAR PURPOSE.
56 * \n\n
57 *
58 * \section sec_contact Contact and Support
59 * Community-based support is available at the OpenBSC mailing list
60 * <http://lists.osmocom.org/mailman/listinfo/openbsc>\n
61 * Commercial support options available upon request from
62 * <http://sysmocom.de/>
63 */
64
Harald Welteec8b4502010-02-20 20:34:29 +010065//#include <openbsc/gsm_data.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010066#include <osmocom/core/utils.h>
67#include <osmocom/gsm/gsm_utils.h>
Harald Welteec8b4502010-02-20 20:34:29 +010068
69#include <stdlib.h>
70#include <stdint.h>
71#include <string.h>
72#include <stdio.h>
73#include <errno.h>
Harald Welteaebe08c2010-03-04 10:39:17 +010074#include <ctype.h>
Harald Welteec8b4502010-02-20 20:34:29 +010075
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010076#include "../../config.h"
Harald Welteec8b4502010-02-20 20:34:29 +010077
Holger Hans Peter Freytherdd02a472010-07-23 16:35:00 +080078/* ETSI GSM 03.38 6.2.1 and 6.2.1.1 default alphabet
79 * Greek symbols at hex positions 0x10 and 0x12-0x1a
80 * left out as they can't be handled with a char and
81 * since most phones don't display or write these
82 * characters this would only needlessly make the code
83 * more complex
84*/
85static unsigned char gsm_7bit_alphabet[] = {
86 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0xff, 0xff, 0x0d, 0xff,
87 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
88 0xff, 0xff, 0x20, 0x21, 0x22, 0x23, 0x02, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
89 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
90 0x3c, 0x3d, 0x3e, 0x3f, 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
91 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
92 0x5a, 0x3c, 0x2f, 0x3e, 0x14, 0x11, 0xff, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
93 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
94 0x78, 0x79, 0x7a, 0x28, 0x40, 0x29, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
95 0xff, 0xff, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff,
96 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0xff, 0x01, 0xff,
97 0x03, 0xff, 0x7b, 0x7d, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff,
98 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5b, 0x7e, 0x5d, 0xff, 0x7c, 0xff, 0xff, 0xff,
99 0xff, 0x5b, 0x0e, 0x1c, 0x09, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5d,
100 0xff, 0xff, 0xff, 0xff, 0x5c, 0xff, 0x0b, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff, 0x1e, 0x7f,
101 0xff, 0xff, 0xff, 0x7b, 0x0f, 0x1d, 0xff, 0x04, 0x05, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff,
102 0xff, 0x7d, 0x08, 0xff, 0xff, 0xff, 0x7c, 0xff, 0x0c, 0x06, 0xff, 0xff, 0x7e, 0xff, 0xff
103};
104
Nico Golde28de0532010-07-09 17:19:12 +0200105/* GSM 03.38 6.2.1 Character lookup for decoding */
106static int gsm_septet_lookup(uint8_t ch)
107{
108 int i = 0;
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200109 for (; i < sizeof(gsm_7bit_alphabet); i++) {
110 if (gsm_7bit_alphabet[i] == ch)
Nico Golde28de0532010-07-09 17:19:12 +0200111 return i;
112 }
113 return -1;
114}
115
Dennis Wehrle291e6132011-07-24 20:14:13 +0200116/* Compute the number of octets from the number of septets, for instance: 47 septets needs 41,125 = 42 octets */
117uint8_t gsm_get_octet_len(const uint8_t sept_len){
118 int octet_len = (sept_len * 7) / 8;
119 if ((sept_len * 7) % 8 != 0)
120 octet_len++;
121
122 return octet_len;
123}
124
Nico Golde28de0532010-07-09 17:19:12 +0200125/* GSM 03.38 6.2.1 Character unpacking */
Dennis Wehrle291e6132011-07-24 20:14:13 +0200126int gsm_7bit_decode_hdr(char *text, const uint8_t *user_data, uint8_t septet_l, uint8_t ud_hdr_ind)
Harald Welteec8b4502010-02-20 20:34:29 +0100127{
128 int i = 0;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200129 int shift = 0;
130
Holger Hans Peter Freytherf8a342c2010-07-21 03:14:01 +0800131 uint8_t *rtext = calloc(septet_l, sizeof(uint8_t));
Nico Golde28de0532010-07-09 17:19:12 +0200132 uint8_t tmp;
Harald Welteec8b4502010-02-20 20:34:29 +0100133
Dennis Wehrle291e6132011-07-24 20:14:13 +0200134 /* skip the user data header */
135 if (ud_hdr_ind) {
136 /* get user data header length + 1 (for the 'user data header length'-field) */
137 shift = ((user_data[0] + 1) * 8) / 7;
138 if ((((user_data[0] + 1) * 8) % 7) != 0)
139 shift++;
140 septet_l = septet_l - shift;
141 }
142
143 for (i = 0; i < septet_l; i++) {
Nico Golde28de0532010-07-09 17:19:12 +0200144 rtext[i] =
Dennis Wehrle291e6132011-07-24 20:14:13 +0200145 ((user_data[((i + shift) * 7 + 7) >> 3] <<
146 (7 - (((i + shift) * 7 + 7) & 7))) |
147 (user_data[((i + shift) * 7) >> 3] >>
148 (((i + shift) * 7) & 7))) & 0x7f;
Nico Golde28de0532010-07-09 17:19:12 +0200149 }
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200150
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200151 for (i = 0; i < septet_l; i++) {
Nico Golde28de0532010-07-09 17:19:12 +0200152 /* this is an extension character */
Dennis Wehrle291e6132011-07-24 20:14:13 +0200153 if(rtext[i] == 0x1b && i + 1 < septet_l){
Nico Golde28de0532010-07-09 17:19:12 +0200154 tmp = rtext[i+1];
155 *(text++) = gsm_7bit_alphabet[0x7f + tmp];
Harald Welteec8b4502010-02-20 20:34:29 +0100156 i++;
Nico Golde28de0532010-07-09 17:19:12 +0200157 continue;
Harald Welteec8b4502010-02-20 20:34:29 +0100158 }
Nico Golde28de0532010-07-09 17:19:12 +0200159
160 *(text++) = gsm_septet_lookup(rtext[i]);
Harald Welteec8b4502010-02-20 20:34:29 +0100161 }
162
Dennis Wehrle291e6132011-07-24 20:14:13 +0200163 if (ud_hdr_ind)
164 i += shift;
Nico Golde28de0532010-07-09 17:19:12 +0200165 *text = '\0';
166 free(rtext);
167
168 return i;
169}
170
Dennis Wehrle291e6132011-07-24 20:14:13 +0200171int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t septet_l)
172{
173 return gsm_7bit_decode_hdr(text, user_data, septet_l, 0);
174}
175
Nico Golde28de0532010-07-09 17:19:12 +0200176/* GSM 03.38 6.2.1 Prepare character packing */
Dennis Wehrle291e6132011-07-24 20:14:13 +0200177int gsm_septet_encode(uint8_t *result, const char *data)
Nico Golde28de0532010-07-09 17:19:12 +0200178{
179 int i, y = 0;
180 uint8_t ch;
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200181 for (i = 0; i < strlen(data); i++) {
Nico Golde28de0532010-07-09 17:19:12 +0200182 ch = data[i];
183 switch(ch){
184 /* fall-through for extension characters */
185 case 0x0c:
186 case 0x5e:
187 case 0x7b:
188 case 0x7d:
189 case 0x5c:
190 case 0x5b:
191 case 0x7e:
192 case 0x5d:
193 case 0x7c:
194 result[y++] = 0x1b;
195 default:
196 result[y] = gsm_7bit_alphabet[ch];
197 break;
198 }
199 y++;
200 }
201
202 return y;
203}
204
Dennis Wehrle291e6132011-07-24 20:14:13 +0200205/* 7bit to octet packing */
206int gsm_septets2octets(uint8_t *result, uint8_t *rdata, uint8_t septet_len, uint8_t padding){
207 int i = 0, z = 0;
Nico Golde28de0532010-07-09 17:19:12 +0200208 uint8_t cb, nb;
209 int shift = 0;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200210 uint8_t *data = calloc(septet_len + 1, sizeof(uint8_t));
Nico Golde28de0532010-07-09 17:19:12 +0200211
Dennis Wehrle291e6132011-07-24 20:14:13 +0200212 if (padding) {
213 shift = 7 - padding;
214 /* the first zero is needed for padding */
215 memcpy(data + 1, rdata, septet_len);
216 septet_len++;
217 } else
218 memcpy(data, rdata, septet_len);
Nico Golde28de0532010-07-09 17:19:12 +0200219
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200220 for (i = 0; i < septet_len; i++) {
Dennis Wehrle291e6132011-07-24 20:14:13 +0200221 if (shift == 7) {
222 /*
223 * special end case with the. This is necessary if the
224 * last septet fits into the previous octet. E.g. 48
225 * non-extension characters:
226 * ....ag ( a = 1100001, g = 1100111)
227 * result[40] = 100001 XX, result[41] = 1100111 1 */
228 if (i + 1 < septet_len) {
229 shift = 0;
230 continue;
231 } else if (i + 1 == septet_len)
232 break;
Nico Golde28de0532010-07-09 17:19:12 +0200233 }
234
Dennis Wehrle291e6132011-07-24 20:14:13 +0200235 cb = (data[i] & 0x7f) >> shift;
236 if (i + 1 < septet_len) {
237 nb = (data[i + 1] & 0x7f) << (7 - shift);
Nico Golde28de0532010-07-09 17:19:12 +0200238 cb = cb | nb;
239 }
240
241 result[z++] = cb;
Nico Golde28de0532010-07-09 17:19:12 +0200242 shift++;
243 }
244
Dennis Wehrle291e6132011-07-24 20:14:13 +0200245 free(data);
246
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200247 return z;
Harald Welteec8b4502010-02-20 20:34:29 +0100248}
249
Dennis Wehrle291e6132011-07-24 20:14:13 +0200250/* GSM 03.38 6.2.1 Character packing */
251int gsm_7bit_encode(uint8_t *result, const char *data)
252{
253 int y = 0, z = 0;
254 /* prepare for the worst case, every character expanding to two bytes */
255 uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t));
256 y = gsm_septet_encode(rdata, data);
257 z = gsm_septets2octets(result, rdata, y, 0);
258
259 free(rdata);
260
261 /*
262 * We don't care about the number of octets (z), because they are not
263 * unique. E.g.:
264 * 1.) 46 non-extension characters + 1 extension character
265 * => (46 * 7 bit + (1 * (2 * 7 bit))) / 8 bit = 42 octets
266 * 2.) 47 non-extension characters
267 * => (47 * 7 bit) / 8 bit = 41,125 = 42 octets
268 * 3.) 48 non-extension characters
269 * => (48 * 7 bit) / 8 bit = 42 octects
270 */
271 return y;
272}
273
Andreas Eversberg2a68c7c2011-06-26 11:41:48 +0200274/* convert power class to dBm according to GSM TS 05.05 */
275unsigned int ms_class_gmsk_dbm(enum gsm_band band, int class)
276{
277 switch (band) {
278 case GSM_BAND_450:
279 case GSM_BAND_480:
280 case GSM_BAND_750:
281 case GSM_BAND_900:
282 case GSM_BAND_810:
283 case GSM_BAND_850:
284 if (class == 1)
285 return 43; /* 20W */
286 if (class == 2)
287 return 39; /* 8W */
288 if (class == 3)
289 return 37; /* 5W */
290 if (class == 4)
291 return 33; /* 2W */
292 if (class == 5)
293 return 29; /* 0.8W */
294 break;
295 case GSM_BAND_1800:
296 if (class == 1)
297 return 30; /* 1W */
298 if (class == 2)
299 return 24; /* 0.25W */
300 if (class == 3)
301 return 36; /* 4W */
302 break;
303 case GSM_BAND_1900:
304 if (class == 1)
305 return 30; /* 1W */
306 if (class == 2)
307 return 24; /* 0.25W */
308 if (class == 3)
309 return 33; /* 2W */
310 break;
311 }
312 return -EINVAL;
313}
314
Harald Welteec8b4502010-02-20 20:34:29 +0100315/* determine power control level for given dBm value, as indicated
316 * by the tables in chapter 4.1.1 of GSM TS 05.05 */
317int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
318{
319 switch (band) {
320 case GSM_BAND_450:
321 case GSM_BAND_480:
322 case GSM_BAND_750:
323 case GSM_BAND_900:
324 case GSM_BAND_810:
325 case GSM_BAND_850:
326 if (dbm >= 39)
327 return 0;
328 else if (dbm < 5)
329 return 19;
330 else {
331 /* we are guaranteed to have (5 <= dbm < 39) */
332 return 2 + ((39 - dbm) / 2);
333 }
334 break;
335 case GSM_BAND_1800:
336 if (dbm >= 36)
337 return 29;
338 else if (dbm >= 34)
339 return 30;
340 else if (dbm >= 32)
341 return 31;
342 else if (dbm == 31)
343 return 0;
344 else {
345 /* we are guaranteed to have (0 <= dbm < 31) */
346 return (30 - dbm) / 2;
347 }
348 break;
349 case GSM_BAND_1900:
350 if (dbm >= 33)
351 return 30;
352 else if (dbm >= 32)
353 return 31;
354 else if (dbm == 31)
355 return 0;
356 else {
357 /* we are guaranteed to have (0 <= dbm < 31) */
358 return (30 - dbm) / 2;
359 }
360 break;
361 }
362 return -EINVAL;
363}
364
365int ms_pwr_dbm(enum gsm_band band, uint8_t lvl)
366{
367 lvl &= 0x1f;
368
369 switch (band) {
370 case GSM_BAND_450:
371 case GSM_BAND_480:
372 case GSM_BAND_750:
373 case GSM_BAND_900:
374 case GSM_BAND_810:
375 case GSM_BAND_850:
376 if (lvl < 2)
377 return 39;
378 else if (lvl < 20)
379 return 39 - ((lvl - 2) * 2) ;
380 else
381 return 5;
382 break;
383 case GSM_BAND_1800:
384 if (lvl < 16)
385 return 30 - (lvl * 2);
386 else if (lvl < 29)
387 return 0;
388 else
389 return 36 - ((lvl - 29) * 2);
390 break;
391 case GSM_BAND_1900:
392 if (lvl < 16)
393 return 30 - (lvl * 2);
394 else if (lvl < 30)
395 return -EINVAL;
396 else
397 return 33 - (lvl - 30);
398 break;
399 }
400 return -EINVAL;
401}
402
403/* According to TS 08.05 Chapter 8.1.4 */
404int rxlev2dbm(uint8_t rxlev)
405{
406 if (rxlev > 63)
407 rxlev = 63;
408
409 return -110 + rxlev;
410}
411
412/* According to TS 08.05 Chapter 8.1.4 */
413uint8_t dbm2rxlev(int dbm)
414{
415 int rxlev = dbm + 110;
416
417 if (rxlev > 63)
418 rxlev = 63;
419 else if (rxlev < 0)
420 rxlev = 0;
421
422 return rxlev;
423}
424
Harald Weltecbc80622010-03-22 08:28:44 +0800425const char *gsm_band_name(enum gsm_band band)
Harald Welteaebe08c2010-03-04 10:39:17 +0100426{
427 switch (band) {
428 case GSM_BAND_450:
429 return "GSM450";
430 case GSM_BAND_480:
Sylvain Munaute10ae5b2010-07-04 11:41:36 +0200431 return "GSM480";
Harald Welteaebe08c2010-03-04 10:39:17 +0100432 case GSM_BAND_750:
433 return "GSM750";
434 case GSM_BAND_810:
435 return "GSM810";
436 case GSM_BAND_850:
437 return "GSM850";
438 case GSM_BAND_900:
439 return "GSM900";
440 case GSM_BAND_1800:
441 return "DCS1800";
442 case GSM_BAND_1900:
443 return "PCS1900";
444 }
445 return "invalid";
446}
447
448enum gsm_band gsm_band_parse(const char* mhz)
449{
450 while (*mhz && !isdigit(*mhz))
451 mhz++;
452
453 if (*mhz == '\0')
454 return -EINVAL;
455
Harald Welted3ff15f2010-03-07 18:23:47 +0100456 switch (strtol(mhz, NULL, 10)) {
Harald Welteaebe08c2010-03-04 10:39:17 +0100457 case 450:
458 return GSM_BAND_450;
459 case 480:
460 return GSM_BAND_480;
461 case 750:
462 return GSM_BAND_750;
463 case 810:
464 return GSM_BAND_810;
465 case 850:
466 return GSM_BAND_850;
467 case 900:
468 return GSM_BAND_900;
469 case 1800:
470 return GSM_BAND_1800;
471 case 1900:
472 return GSM_BAND_1900;
473 default:
474 return -EINVAL;
475 }
476}
477
Harald Welte622b7182010-03-07 17:50:21 +0100478enum gsm_band gsm_arfcn2band(uint16_t arfcn)
479{
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100480 int is_pcs = arfcn & ARFCN_PCS;
481
482 arfcn &= ~ARFCN_FLAG_MASK;
483
484 if (is_pcs)
Harald Welte622b7182010-03-07 17:50:21 +0100485 return GSM_BAND_1900;
486 else if (arfcn <= 124)
487 return GSM_BAND_900;
488 else if (arfcn >= 955 && arfcn <= 1023)
489 return GSM_BAND_900;
490 else if (arfcn >= 128 && arfcn <= 251)
491 return GSM_BAND_850;
492 else if (arfcn >= 512 && arfcn <= 885)
493 return GSM_BAND_1800;
494 else if (arfcn >= 259 && arfcn <= 293)
495 return GSM_BAND_450;
496 else if (arfcn >= 306 && arfcn <= 340)
497 return GSM_BAND_480;
498 else if (arfcn >= 350 && arfcn <= 425)
499 return GSM_BAND_810;
500 else if (arfcn >= 438 && arfcn <= 511)
501 return GSM_BAND_750;
502 else
503 return GSM_BAND_1800;
504}
505
506/* Convert an ARFCN to the frequency in MHz * 10 */
507uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink)
508{
509 uint16_t freq10_ul;
510 uint16_t freq10_dl;
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100511 int is_pcs = arfcn & ARFCN_PCS;
Harald Welte622b7182010-03-07 17:50:21 +0100512
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100513 arfcn &= ~ARFCN_FLAG_MASK;
514
515 if (is_pcs) {
Harald Welte622b7182010-03-07 17:50:21 +0100516 /* DCS 1900 */
517 arfcn &= ~ARFCN_PCS;
518 freq10_ul = 18502 + 2 * (arfcn-512);
519 freq10_dl = freq10_ul + 800;
520 } else if (arfcn <= 124) {
521 /* Primary GSM + ARFCN 0 of E-GSM */
522 freq10_ul = 8900 + 2 * arfcn;
523 freq10_dl = freq10_ul + 450;
524 } else if (arfcn >= 955 && arfcn <= 1023) {
525 /* E-GSM and R-GSM */
526 freq10_ul = 8900 + 2 * (arfcn - 1024);
527 freq10_dl = freq10_ul + 450;
528 } else if (arfcn >= 128 && arfcn <= 251) {
529 /* GSM 850 */
530 freq10_ul = 8242 + 2 * (arfcn - 128);
531 freq10_dl = freq10_ul + 450;
532 } else if (arfcn >= 512 && arfcn <= 885) {
533 /* DCS 1800 */
534 freq10_ul = 17102 + 2 * (arfcn - 512);
535 freq10_dl = freq10_ul + 950;
536 } else if (arfcn >= 259 && arfcn <= 293) {
537 /* GSM 450 */
538 freq10_ul = 4506 + 2 * (arfcn - 259);
539 freq10_dl = freq10_ul + 100;
540 } else if (arfcn >= 306 && arfcn <= 340) {
541 /* GSM 480 */
542 freq10_ul = 4790 + 2 * (arfcn - 306);
543 freq10_dl = freq10_ul + 100;
544 } else if (arfcn >= 350 && arfcn <= 425) {
545 /* GSM 810 */
546 freq10_ul = 8060 + 2 * (arfcn - 350);
547 freq10_dl = freq10_ul + 450;
548 } else if (arfcn >= 438 && arfcn <= 511) {
549 /* GSM 750 */
550 freq10_ul = 7472 + 2 * (arfcn - 438);
551 freq10_dl = freq10_ul + 300;
552 } else
553 return 0xffff;
554
555 if (uplink)
556 return freq10_ul;
557 else
558 return freq10_dl;
559}
560
561void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn)
562{
563 time->fn = fn;
564 time->t1 = time->fn / (26*51);
565 time->t2 = time->fn % 26;
566 time->t3 = time->fn % 51;
567 time->tc = (time->fn / 51) % 8;
568}
569
570uint32_t gsm_gsmtime2fn(struct gsm_time *time)
571{
572 /* TS 05.02 Chapter 4.3.3 TDMA frame number */
573 return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));
574}
Harald Weltea1c4f762010-05-01 11:59:42 +0200575
576/* TS 03.03 Chapter 2.6 */
577int gprs_tlli_type(uint32_t tlli)
578{
579 if ((tlli & 0xc0000000) == 0xc0000000)
580 return TLLI_LOCAL;
581 else if ((tlli & 0xc0000000) == 0x80000000)
582 return TLLI_FOREIGN;
583 else if ((tlli & 0xf8000000) == 0x78000000)
584 return TLLI_RANDOM;
585 else if ((tlli & 0xf8000000) == 0x70000000)
586 return TLLI_AUXILIARY;
587
588 return TLLI_RESERVED;
589}
Harald Weltec2263172010-06-01 10:47:07 +0200590
591uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type)
592{
593 uint32_t tlli;
594 switch (type) {
595 case TLLI_LOCAL:
596 tlli = p_tmsi | 0xc0000000;
597 break;
598 case TLLI_FOREIGN:
599 tlli = (p_tmsi & 0x3fffffff) | 0x80000000;
600 break;
601 default:
602 tlli = 0;
603 break;
604 }
605 return tlli;
606}