blob: 3dd15375bf3d310bcaa0a814e679f2d6b92afe65 [file] [log] [blame]
Harald Welteec8b4502010-02-20 20:34:29 +01001/*
2 * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
Holger Hans Peter Freyther6bfa7442013-08-08 12:38:52 +02003 * (C) 2009,2013 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 Goldec56a56d2012-09-18 14:29:40 +02005 * (C) 2010-2012 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;
Nico Goldec56a56d2012-09-18 14:29:40 +0200130 uint8_t c;
131 uint8_t next_is_ext = 0;
Harald Welteec8b4502010-02-20 20:34:29 +0100132
Dennis Wehrle291e6132011-07-24 20:14:13 +0200133 /* skip the user data header */
134 if (ud_hdr_ind) {
135 /* get user data header length + 1 (for the 'user data header length'-field) */
136 shift = ((user_data[0] + 1) * 8) / 7;
137 if ((((user_data[0] + 1) * 8) % 7) != 0)
138 shift++;
139 septet_l = septet_l - shift;
140 }
141
142 for (i = 0; i < septet_l; i++) {
Nico Goldec56a56d2012-09-18 14:29:40 +0200143 c =
Dennis Wehrle291e6132011-07-24 20:14:13 +0200144 ((user_data[((i + shift) * 7 + 7) >> 3] <<
145 (7 - (((i + shift) * 7 + 7) & 7))) |
146 (user_data[((i + shift) * 7) >> 3] >>
147 (((i + shift) * 7) & 7))) & 0x7f;
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200148
Nico Goldec56a56d2012-09-18 14:29:40 +0200149 /* this is an extension character */
Harald Weltebe55a8b2012-09-20 10:00:25 +0200150 if (next_is_ext) {
Nico Goldec56a56d2012-09-18 14:29:40 +0200151 next_is_ext = 0;
152 *(text++) = gsm_7bit_alphabet[0x7f + c];
Nico Golde5b67a042012-09-20 16:56:23 +0200153 continue;
154 }
155
156 if (c == 0x1b && i + 1 < septet_l) {
157 next_is_ext = 1;
Nico Goldec56a56d2012-09-18 14:29:40 +0200158 } else {
159 *(text++) = gsm_septet_lookup(c);
160 }
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';
Nico Golde28de0532010-07-09 17:19:12 +0200166
167 return i;
168}
169
Dennis Wehrle291e6132011-07-24 20:14:13 +0200170int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t septet_l)
171{
172 return gsm_7bit_decode_hdr(text, user_data, septet_l, 0);
173}
174
Andreas Eversberg95975552013-08-08 12:38:53 +0200175int gsm_7bit_decode_ussd(char *text, const uint8_t *user_data, uint8_t length)
176{
177 int i;
178
179 gsm_7bit_decode_hdr(text, user_data, length, 0);
180 i = strlen(text);
181 /* remove last <CR>, if it fits up to the end of last octet */
182 if (i && (user_data[gsm_get_octet_len(length) - 1] >> 1) == '\r')
183 text[--i] = '\0';
184
185 return i;
186}
187
Nico Golde28de0532010-07-09 17:19:12 +0200188/* GSM 03.38 6.2.1 Prepare character packing */
Dennis Wehrle291e6132011-07-24 20:14:13 +0200189int gsm_septet_encode(uint8_t *result, const char *data)
Nico Golde28de0532010-07-09 17:19:12 +0200190{
191 int i, y = 0;
192 uint8_t ch;
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200193 for (i = 0; i < strlen(data); i++) {
Nico Golde28de0532010-07-09 17:19:12 +0200194 ch = data[i];
195 switch(ch){
196 /* fall-through for extension characters */
197 case 0x0c:
198 case 0x5e:
199 case 0x7b:
200 case 0x7d:
201 case 0x5c:
202 case 0x5b:
203 case 0x7e:
204 case 0x5d:
205 case 0x7c:
206 result[y++] = 0x1b;
207 default:
208 result[y] = gsm_7bit_alphabet[ch];
209 break;
210 }
211 y++;
212 }
213
214 return y;
215}
216
Dennis Wehrle291e6132011-07-24 20:14:13 +0200217/* 7bit to octet packing */
Harald Welteca693882013-03-13 15:10:55 +0100218int gsm_septets2octets(uint8_t *result, const uint8_t *rdata, uint8_t septet_len, uint8_t padding)
219{
Dennis Wehrle291e6132011-07-24 20:14:13 +0200220 int i = 0, z = 0;
Nico Golde28de0532010-07-09 17:19:12 +0200221 uint8_t cb, nb;
222 int shift = 0;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200223 uint8_t *data = calloc(septet_len + 1, sizeof(uint8_t));
Nico Golde28de0532010-07-09 17:19:12 +0200224
Dennis Wehrle291e6132011-07-24 20:14:13 +0200225 if (padding) {
226 shift = 7 - padding;
227 /* the first zero is needed for padding */
228 memcpy(data + 1, rdata, septet_len);
229 septet_len++;
230 } else
231 memcpy(data, rdata, septet_len);
Nico Golde28de0532010-07-09 17:19:12 +0200232
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200233 for (i = 0; i < septet_len; i++) {
Dennis Wehrle291e6132011-07-24 20:14:13 +0200234 if (shift == 7) {
235 /*
236 * special end case with the. This is necessary if the
237 * last septet fits into the previous octet. E.g. 48
238 * non-extension characters:
239 * ....ag ( a = 1100001, g = 1100111)
240 * result[40] = 100001 XX, result[41] = 1100111 1 */
241 if (i + 1 < septet_len) {
242 shift = 0;
243 continue;
244 } else if (i + 1 == septet_len)
245 break;
Nico Golde28de0532010-07-09 17:19:12 +0200246 }
247
Dennis Wehrle291e6132011-07-24 20:14:13 +0200248 cb = (data[i] & 0x7f) >> shift;
249 if (i + 1 < septet_len) {
250 nb = (data[i + 1] & 0x7f) << (7 - shift);
Nico Golde28de0532010-07-09 17:19:12 +0200251 cb = cb | nb;
252 }
253
254 result[z++] = cb;
Nico Golde28de0532010-07-09 17:19:12 +0200255 shift++;
256 }
257
Dennis Wehrle291e6132011-07-24 20:14:13 +0200258 free(data);
259
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200260 return z;
Harald Welteec8b4502010-02-20 20:34:29 +0100261}
262
Dennis Wehrle291e6132011-07-24 20:14:13 +0200263/* GSM 03.38 6.2.1 Character packing */
264int gsm_7bit_encode(uint8_t *result, const char *data)
265{
Holger Hans Peter Freyther6bfa7442013-08-08 12:38:52 +0200266 int out;
267 return gsm_7bit_encode_oct(result, data, &out);
268}
269
Andreas Eversberg95975552013-08-08 12:38:53 +0200270int gsm_7bit_encode_ussd(uint8_t *result, const char *data, int *octets)
271{
272 int y;
273
274 y = gsm_7bit_encode_oct(result, data, octets);
275 /* if last octet contains only one bit, add <CR> */
276 if (((y * 7) & 7) == 1)
277 result[(*octets) - 1] |= ('\r' << 1);
278 /* if last character is <CR> and completely fills last octet, add
279 * another <CR>. */
280 if (y && ((y * 7) & 7) == 0 && (result[(*octets) - 1] >> 1) == '\r') {
281 result[(*octets)++] = '\r';
282 y++;
283 }
284
285 return y;
286}
287
Holger Hans Peter Freyther6bfa7442013-08-08 12:38:52 +0200288int gsm_7bit_encode_oct(uint8_t *result, const char *data, int *octets)
289{
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200290 int y = 0;
291
Dennis Wehrle291e6132011-07-24 20:14:13 +0200292 /* prepare for the worst case, every character expanding to two bytes */
293 uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t));
294 y = gsm_septet_encode(rdata, data);
Holger Hans Peter Freyther6bfa7442013-08-08 12:38:52 +0200295 *octets = gsm_septets2octets(result, rdata, y, 0);
Dennis Wehrle291e6132011-07-24 20:14:13 +0200296
297 free(rdata);
298
299 /*
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200300 * We don't care about the number of octets, because they are not
Dennis Wehrle291e6132011-07-24 20:14:13 +0200301 * unique. E.g.:
302 * 1.) 46 non-extension characters + 1 extension character
303 * => (46 * 7 bit + (1 * (2 * 7 bit))) / 8 bit = 42 octets
304 * 2.) 47 non-extension characters
305 * => (47 * 7 bit) / 8 bit = 41,125 = 42 octets
306 * 3.) 48 non-extension characters
307 * => (48 * 7 bit) / 8 bit = 42 octects
308 */
309 return y;
310}
311
Andreas Eversberg2a68c7c2011-06-26 11:41:48 +0200312/* convert power class to dBm according to GSM TS 05.05 */
313unsigned int ms_class_gmsk_dbm(enum gsm_band band, int class)
314{
315 switch (band) {
316 case GSM_BAND_450:
317 case GSM_BAND_480:
318 case GSM_BAND_750:
319 case GSM_BAND_900:
320 case GSM_BAND_810:
321 case GSM_BAND_850:
322 if (class == 1)
323 return 43; /* 20W */
324 if (class == 2)
325 return 39; /* 8W */
326 if (class == 3)
327 return 37; /* 5W */
328 if (class == 4)
329 return 33; /* 2W */
330 if (class == 5)
331 return 29; /* 0.8W */
332 break;
333 case GSM_BAND_1800:
334 if (class == 1)
335 return 30; /* 1W */
336 if (class == 2)
337 return 24; /* 0.25W */
338 if (class == 3)
339 return 36; /* 4W */
340 break;
341 case GSM_BAND_1900:
342 if (class == 1)
343 return 30; /* 1W */
344 if (class == 2)
345 return 24; /* 0.25W */
346 if (class == 3)
347 return 33; /* 2W */
348 break;
349 }
350 return -EINVAL;
351}
352
Harald Welteec8b4502010-02-20 20:34:29 +0100353/* determine power control level for given dBm value, as indicated
354 * by the tables in chapter 4.1.1 of GSM TS 05.05 */
355int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
356{
357 switch (band) {
358 case GSM_BAND_450:
359 case GSM_BAND_480:
360 case GSM_BAND_750:
361 case GSM_BAND_900:
362 case GSM_BAND_810:
363 case GSM_BAND_850:
364 if (dbm >= 39)
365 return 0;
366 else if (dbm < 5)
367 return 19;
368 else {
369 /* we are guaranteed to have (5 <= dbm < 39) */
370 return 2 + ((39 - dbm) / 2);
371 }
372 break;
373 case GSM_BAND_1800:
374 if (dbm >= 36)
375 return 29;
376 else if (dbm >= 34)
377 return 30;
378 else if (dbm >= 32)
379 return 31;
380 else if (dbm == 31)
381 return 0;
382 else {
383 /* we are guaranteed to have (0 <= dbm < 31) */
384 return (30 - dbm) / 2;
385 }
386 break;
387 case GSM_BAND_1900:
388 if (dbm >= 33)
389 return 30;
390 else if (dbm >= 32)
391 return 31;
392 else if (dbm == 31)
393 return 0;
394 else {
395 /* we are guaranteed to have (0 <= dbm < 31) */
396 return (30 - dbm) / 2;
397 }
398 break;
399 }
400 return -EINVAL;
401}
402
403int ms_pwr_dbm(enum gsm_band band, uint8_t lvl)
404{
405 lvl &= 0x1f;
406
407 switch (band) {
408 case GSM_BAND_450:
409 case GSM_BAND_480:
410 case GSM_BAND_750:
411 case GSM_BAND_900:
412 case GSM_BAND_810:
413 case GSM_BAND_850:
414 if (lvl < 2)
415 return 39;
416 else if (lvl < 20)
417 return 39 - ((lvl - 2) * 2) ;
418 else
419 return 5;
420 break;
421 case GSM_BAND_1800:
422 if (lvl < 16)
423 return 30 - (lvl * 2);
424 else if (lvl < 29)
425 return 0;
426 else
427 return 36 - ((lvl - 29) * 2);
428 break;
429 case GSM_BAND_1900:
430 if (lvl < 16)
431 return 30 - (lvl * 2);
432 else if (lvl < 30)
433 return -EINVAL;
434 else
435 return 33 - (lvl - 30);
436 break;
437 }
438 return -EINVAL;
439}
440
Bhaskar6b30f922013-05-16 17:35:49 +0530441/* According to TS 05.08 Chapter 8.1.4 */
Harald Welteec8b4502010-02-20 20:34:29 +0100442int rxlev2dbm(uint8_t rxlev)
443{
444 if (rxlev > 63)
445 rxlev = 63;
446
447 return -110 + rxlev;
448}
449
Bhaskar6b30f922013-05-16 17:35:49 +0530450/* According to TS 05.08 Chapter 8.1.4 */
Harald Welteec8b4502010-02-20 20:34:29 +0100451uint8_t dbm2rxlev(int dbm)
452{
453 int rxlev = dbm + 110;
454
455 if (rxlev > 63)
456 rxlev = 63;
457 else if (rxlev < 0)
458 rxlev = 0;
459
460 return rxlev;
461}
462
Harald Weltecbc80622010-03-22 08:28:44 +0800463const char *gsm_band_name(enum gsm_band band)
Harald Welteaebe08c2010-03-04 10:39:17 +0100464{
465 switch (band) {
466 case GSM_BAND_450:
467 return "GSM450";
468 case GSM_BAND_480:
Sylvain Munaute10ae5b2010-07-04 11:41:36 +0200469 return "GSM480";
Harald Welteaebe08c2010-03-04 10:39:17 +0100470 case GSM_BAND_750:
471 return "GSM750";
472 case GSM_BAND_810:
473 return "GSM810";
474 case GSM_BAND_850:
475 return "GSM850";
476 case GSM_BAND_900:
477 return "GSM900";
478 case GSM_BAND_1800:
479 return "DCS1800";
480 case GSM_BAND_1900:
481 return "PCS1900";
482 }
483 return "invalid";
484}
485
486enum gsm_band gsm_band_parse(const char* mhz)
487{
488 while (*mhz && !isdigit(*mhz))
489 mhz++;
490
491 if (*mhz == '\0')
492 return -EINVAL;
493
Harald Welted3ff15f2010-03-07 18:23:47 +0100494 switch (strtol(mhz, NULL, 10)) {
Harald Welteaebe08c2010-03-04 10:39:17 +0100495 case 450:
496 return GSM_BAND_450;
497 case 480:
498 return GSM_BAND_480;
499 case 750:
500 return GSM_BAND_750;
501 case 810:
502 return GSM_BAND_810;
503 case 850:
504 return GSM_BAND_850;
505 case 900:
506 return GSM_BAND_900;
507 case 1800:
508 return GSM_BAND_1800;
509 case 1900:
510 return GSM_BAND_1900;
511 default:
512 return -EINVAL;
513 }
514}
515
Harald Welte622b7182010-03-07 17:50:21 +0100516enum gsm_band gsm_arfcn2band(uint16_t arfcn)
517{
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100518 int is_pcs = arfcn & ARFCN_PCS;
519
520 arfcn &= ~ARFCN_FLAG_MASK;
521
522 if (is_pcs)
Harald Welte622b7182010-03-07 17:50:21 +0100523 return GSM_BAND_1900;
524 else if (arfcn <= 124)
525 return GSM_BAND_900;
526 else if (arfcn >= 955 && arfcn <= 1023)
527 return GSM_BAND_900;
528 else if (arfcn >= 128 && arfcn <= 251)
529 return GSM_BAND_850;
530 else if (arfcn >= 512 && arfcn <= 885)
531 return GSM_BAND_1800;
532 else if (arfcn >= 259 && arfcn <= 293)
533 return GSM_BAND_450;
534 else if (arfcn >= 306 && arfcn <= 340)
535 return GSM_BAND_480;
536 else if (arfcn >= 350 && arfcn <= 425)
537 return GSM_BAND_810;
538 else if (arfcn >= 438 && arfcn <= 511)
539 return GSM_BAND_750;
540 else
541 return GSM_BAND_1800;
542}
543
Sylvain Munaut55720312012-12-11 23:44:41 +0100544struct gsm_freq_range {
545 uint16_t arfcn_first;
546 uint16_t arfcn_last;
547 uint16_t freq_ul_first;
548 uint16_t freq_dl_offset;
549 uint16_t flags;
550};
551
552static struct gsm_freq_range gsm_ranges[] = {
553 { 512, 810, 18502, 800, ARFCN_PCS }, /* PCS 1900 */
554 { 0, 124, 8900, 450, 0 }, /* P-GSM + E-GSM ARFCN 0 */
555 { 955, 1023, 8762, 450, 0 }, /* E-GSM + R-GSM */
556 { 128, 251, 8242, 450, 0 }, /* GSM 850 */
557 { 512, 885, 17102, 950, 0 }, /* DCS 1800 */
558 { 259, 293, 4506, 100, 0 }, /* GSM 450 */
559 { 306, 340, 4790, 100, 0 }, /* GSM 480 */
560 { 350, 425, 8060, 450, 0 }, /* GSM 810 */
561 { 438, 511, 7472, 300, 0 }, /* GSM 750 */
562 { /* Guard */ }
563};
564
Harald Welte622b7182010-03-07 17:50:21 +0100565/* Convert an ARFCN to the frequency in MHz * 10 */
566uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink)
567{
Sylvain Munaut55720312012-12-11 23:44:41 +0100568 struct gsm_freq_range *r;
569 uint16_t flags = arfcn & ARFCN_FLAG_MASK;
570 uint16_t freq10_ul = 0xffff;
571 uint16_t freq10_dl = 0xffff;
Harald Welte622b7182010-03-07 17:50:21 +0100572
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100573 arfcn &= ~ARFCN_FLAG_MASK;
574
Sylvain Munaut55720312012-12-11 23:44:41 +0100575 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
576 if ((flags == r->flags) &&
577 (arfcn >= r->arfcn_first) &&
578 (arfcn <= r->arfcn_last))
579 {
580 freq10_ul = r->freq_ul_first + 2 * (arfcn - r->arfcn_first);
581 freq10_dl = freq10_ul + r->freq_dl_offset;
582 break;
583 }
584 }
585
586 return uplink ? freq10_ul : freq10_dl;
587}
588
589/* Convert a Frequency in MHz * 10 to ARFCN */
590uint16_t gsm_freq102arfcn(uint16_t freq10, int uplink)
591{
592 struct gsm_freq_range *r;
593 uint16_t freq10_lo, freq10_hi;
594 uint16_t arfcn = 0xffff;
595
596 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
597 /* Generate frequency limits */
598 freq10_lo = r->freq_ul_first;
599 freq10_hi = freq10_lo + 2 * (r->arfcn_last - r->arfcn_first);
600 if (!uplink) {
601 freq10_lo += r->freq_dl_offset;
602 freq10_hi += r->freq_dl_offset;
603 }
604
605 /* Check if this fits */
606 if (freq10 >= freq10_lo && freq10 <= freq10_hi) {
607 arfcn = r->arfcn_first + ((freq10 - freq10_lo) >> 1);
608 arfcn |= r->flags;
609 break;
610 }
611 }
Harald Welte622b7182010-03-07 17:50:21 +0100612
613 if (uplink)
Sylvain Munaut55720312012-12-11 23:44:41 +0100614 arfcn |= ARFCN_UPLINK;
615
616 return arfcn;
Harald Welte622b7182010-03-07 17:50:21 +0100617}
618
619void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn)
620{
621 time->fn = fn;
622 time->t1 = time->fn / (26*51);
623 time->t2 = time->fn % 26;
624 time->t3 = time->fn % 51;
625 time->tc = (time->fn / 51) % 8;
626}
627
628uint32_t gsm_gsmtime2fn(struct gsm_time *time)
629{
630 /* TS 05.02 Chapter 4.3.3 TDMA frame number */
631 return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));
632}
Harald Weltea1c4f762010-05-01 11:59:42 +0200633
634/* TS 03.03 Chapter 2.6 */
635int gprs_tlli_type(uint32_t tlli)
636{
637 if ((tlli & 0xc0000000) == 0xc0000000)
638 return TLLI_LOCAL;
639 else if ((tlli & 0xc0000000) == 0x80000000)
640 return TLLI_FOREIGN;
641 else if ((tlli & 0xf8000000) == 0x78000000)
642 return TLLI_RANDOM;
643 else if ((tlli & 0xf8000000) == 0x70000000)
644 return TLLI_AUXILIARY;
645
646 return TLLI_RESERVED;
647}
Harald Weltec2263172010-06-01 10:47:07 +0200648
649uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type)
650{
651 uint32_t tlli;
652 switch (type) {
653 case TLLI_LOCAL:
654 tlli = p_tmsi | 0xc0000000;
655 break;
656 case TLLI_FOREIGN:
657 tlli = (p_tmsi & 0x3fffffff) | 0x80000000;
658 break;
659 default:
660 tlli = 0;
661 break;
662 }
663 return tlli;
664}