blob: 6070e5ccd1458bd648a59cc76f80035f20341fe8 [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file gsm48_ie.c
2 * GSM Mobile Radio Interface Layer 3 messages.
3 * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0. */
4/*
5 * (C) 2008 by Harald Welte <laforge@gnumonks.org>
Harald Welteb1ac2b92010-04-09 07:50:18 +02006 * (C) 2009-2010 by Andreas Eversberg
Harald Welte1e908662010-03-07 23:39:54 +01007 *
8 * All Rights Reserved
9 *
Harald Weltee08da972017-11-13 01:00:26 +090010 * SPDX-License-Identifier: GPL-2.0+
11 *
Harald Welte1e908662010-03-07 23:39:54 +010012 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 *
26 */
27
28
29#include <stdint.h>
30#include <string.h>
31#include <errno.h>
32
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010033#include <osmocom/core/utils.h>
34#include <osmocom/core/msgb.h>
35#include <osmocom/gsm/tlv.h>
36#include <osmocom/gsm/mncc.h>
Philipp Maiere36be562020-11-12 11:33:54 +010037#include <osmocom/core/bitvec.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010038#include <osmocom/gsm/protocol/gsm_04_08.h>
39#include <osmocom/gsm/gsm48_ie.h>
Harald Welte1e908662010-03-07 23:39:54 +010040
Harald Welte96e2a002017-06-12 21:44:18 +020041/*! \addtogroup gsm0408
42 * @{
43 */
44
Harald Welte1e908662010-03-07 23:39:54 +010045static const char bcd_num_digits[] = {
46 '0', '1', '2', '3', '4', '5', '6', '7',
47 '8', '9', '*', '#', 'a', 'b', 'c', '\0'
48};
49
Neels Hofmeyr8212fc62019-04-01 14:34:37 +020050/*! Like gsm48_decode_bcd_number2() but with less airtight bounds checking.
Harald Welte96e2a002017-06-12 21:44:18 +020051 * \param[out] Caller-provided output buffer
52 * \param[in] bcd_lv Length-Value portion of to-be-decoded IE
53 * \param[in] h_len Length of an optional heder between L and V portion
54 * \returns - in case of success; negative on error */
Harald Welte1e908662010-03-07 23:39:54 +010055int gsm48_decode_bcd_number(char *output, int output_len,
56 const uint8_t *bcd_lv, int h_len)
57{
58 uint8_t in_len = bcd_lv[0];
Neels Hofmeyr83d45312019-04-29 19:15:11 +020059 /* Just assume the input buffer is big enough for the length byte and the following data, so pass in_len + 1 for
60 * the input buffer size. */
61 return gsm48_decode_bcd_number2(output, output_len, bcd_lv, in_len + 1, h_len);
62}
63
64/*! Decode a 'called/calling/connect party BCD number' as in 10.5.4.7.
65 * \param[out] output Caller-provided output buffer.
66 * \param[in] output_len sizeof(output).
67 * \param[in] bcd_lv Length-Value part of to-be-decoded IE.
68 * \param[in] input_len Size of the bcd_lv buffer for bounds checking.
69 * \param[in] h_len Length of an optional header between L and V parts.
Vadim Yanitskiy71940872019-05-26 00:49:57 +070070 * \return 0 in case of success, negative on error.
71 *
72 * Errors checked:
73 * - no or too little input data (-EIO),
Vadim Yanitskiye4799f52019-05-26 00:55:20 +070074 * - IE length exceeds input data size (-EINVAL),
Vadim Yanitskiy71940872019-05-26 00:49:57 +070075 * - no or too little output buffer size (-ENOSPC),
76 * - decoded number exceeds size of the output buffer (-ENOSPC).
77 *
78 * The output is guaranteed to be nul terminated iff output_len > 0.
Neels Hofmeyr83d45312019-04-29 19:15:11 +020079 */
80int gsm48_decode_bcd_number2(char *output, size_t output_len,
81 const uint8_t *bcd_lv, size_t input_len,
82 size_t h_len)
83{
84 uint8_t in_len;
Harald Welte1e908662010-03-07 23:39:54 +010085 int i;
Oliver Smith186f8782019-06-06 16:11:32 +020086 bool truncated = false;
Neels Hofmeyr83d45312019-04-29 19:15:11 +020087 if (output_len < 1)
88 return -ENOSPC;
89 *output = '\0';
90 if (input_len < 1)
91 return -EIO;
92 in_len = bcd_lv[0];
93 /* len + 1: the BCD length plus the length byte itself must fit in the input buffer. */
94 if (input_len < in_len + 1)
Vadim Yanitskiye4799f52019-05-26 00:55:20 +070095 return -EINVAL;
Harald Welte1e908662010-03-07 23:39:54 +010096
97 for (i = 1 + h_len; i <= in_len; i++) {
98 /* lower nibble */
Oliver Smith186f8782019-06-06 16:11:32 +020099 if (output_len <= 1) {
100 truncated = true;
Harald Welte1e908662010-03-07 23:39:54 +0100101 break;
Oliver Smith186f8782019-06-06 16:11:32 +0200102 }
Harald Welte1e908662010-03-07 23:39:54 +0100103 *output++ = bcd_num_digits[bcd_lv[i] & 0xf];
Vadim Yanitskiy2cd1dda2019-05-26 00:14:16 +0700104 output_len--;
Harald Welte1e908662010-03-07 23:39:54 +0100105
106 /* higher nibble */
Oliver Smith186f8782019-06-06 16:11:32 +0200107 if (output_len <= 1) {
108 /* not truncated if there is exactly one 0xf ('\0') higher nibble remaining */
109 if (i == in_len && (bcd_lv[i] & 0xf0) == 0xf0) {
110 break;
111 }
112
113 truncated = true;
Harald Welte1e908662010-03-07 23:39:54 +0100114 break;
Oliver Smith186f8782019-06-06 16:11:32 +0200115 }
Harald Welte1e908662010-03-07 23:39:54 +0100116 *output++ = bcd_num_digits[bcd_lv[i] >> 4];
Vadim Yanitskiy2cd1dda2019-05-26 00:14:16 +0700117 output_len--;
Harald Welte1e908662010-03-07 23:39:54 +0100118 }
119 if (output_len >= 1)
120 *output++ = '\0';
121
Vadim Yanitskiy71940872019-05-26 00:49:57 +0700122 /* Indicate whether the output was truncated */
Oliver Smith186f8782019-06-06 16:11:32 +0200123 if (truncated)
Vadim Yanitskiy71940872019-05-26 00:49:57 +0700124 return -ENOSPC;
125
Harald Welte1e908662010-03-07 23:39:54 +0100126 return 0;
127}
128
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200129/*! convert a single ASCII character to call-control BCD */
Harald Welte1e908662010-03-07 23:39:54 +0100130static int asc_to_bcd(const char asc)
131{
132 int i;
133
134 for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) {
135 if (bcd_num_digits[i] == asc)
136 return i;
137 }
138 return -EINVAL;
139}
140
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200141/*! convert a ASCII phone number to 'called/calling/connect party BCD number'
Harald Welte96e2a002017-06-12 21:44:18 +0200142 * \param[out] bcd_lv Caller-provided output buffer
143 * \param[in] max_len Maximum Length of \a bcd_lv
144 * \param[in] h_len Length of an optional heder between L and V portion
145 * \param[in] input phone number as 0-terminated ASCII
Vadim Yanitskiy1dc82642019-05-27 00:53:54 +0700146 * \returns number of bytes used in \a bcd_lv
147 *
148 * Depending on a context (e.g. called or calling party BCD number), the
149 * optional header between L and V parts can contain TON (Type Of Number),
150 * NPI (Numbering Plan Indication), presentation or screening indicator.
151 * NOTE: it is up to the caller to initialize this header!
152 */
Harald Welte1e908662010-03-07 23:39:54 +0100153int gsm48_encode_bcd_number(uint8_t *bcd_lv, uint8_t max_len,
154 int h_len, const char *input)
155{
156 int in_len = strlen(input);
157 int i;
158 uint8_t *bcd_cur = bcd_lv + 1 + h_len;
159
160 /* two digits per byte, plus type byte */
161 bcd_lv[0] = in_len/2 + h_len;
162 if (in_len % 2)
163 bcd_lv[0]++;
164
165 if (bcd_lv[0] > max_len)
166 return -EIO;
167
168 for (i = 0; i < in_len; i++) {
169 int rc = asc_to_bcd(input[i]);
170 if (rc < 0)
171 return rc;
172 if (i % 2 == 0)
173 *bcd_cur = rc;
174 else
175 *bcd_cur++ |= (rc << 4);
176 }
177 /* append padding nibble in case of odd length */
178 if (i % 2)
179 *bcd_cur++ |= 0xf0;
180
181 /* return how many bytes we used */
182 return (bcd_cur - bcd_lv);
183}
184
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200185/*! Decode TS 04.08 Bearer Capability IE (10.5.4.5)
Harald Welte96e2a002017-06-12 21:44:18 +0200186 * \param[out] Caller-provided memory for decoded output
187 * \[aram[in] LV portion of TS 04.08 Bearer Capability
188 * \returns 0 on success; negative on error */
Harald Welte1e908662010-03-07 23:39:54 +0100189int gsm48_decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
190 const uint8_t *lv)
191{
192 uint8_t in_len = lv[0];
193 int i, s;
194
195 if (in_len < 1)
196 return -EINVAL;
197
198 bcap->speech_ver[0] = -1; /* end of list, of maximum 7 values */
199
200 /* octet 3 */
201 bcap->transfer = lv[1] & 0x07;
202 bcap->mode = (lv[1] & 0x08) >> 3;
203 bcap->coding = (lv[1] & 0x10) >> 4;
204 bcap->radio = (lv[1] & 0x60) >> 5;
205
Harald Weltec8a0b932012-08-24 21:27:26 +0200206 switch (bcap->transfer) {
207 case GSM_MNCC_BCAP_SPEECH:
Harald Welte1e908662010-03-07 23:39:54 +0100208 i = 1;
209 s = 0;
210 while(!(lv[i] & 0x80)) {
211 i++; /* octet 3a etc */
212 if (in_len < i)
213 return 0;
214 bcap->speech_ver[s++] = lv[i] & 0x0f;
215 bcap->speech_ver[s] = -1; /* end of list */
216 if (i == 2) /* octet 3a */
217 bcap->speech_ctm = (lv[i] & 0x20) >> 5;
218 if (s == 7) /* maximum speech versions + end of list */
219 return 0;
220 }
Harald Weltec8a0b932012-08-24 21:27:26 +0200221 break;
222 case GSM_MNCC_BCAP_UNR_DIG:
223 case GSM_MNCC_BCAP_FAX_G3:
224 i = 1;
225 while(!(lv[i] & 0x80)) {
226 i++; /* octet 3a etc */
227 if (in_len < i)
228 return 0;
229 /* ignore them */
230 }
231 /* octet 4: skip */
232 i++;
233 /* octet 5 */
234 i++;
235 if (in_len < i)
236 return 0;
237 bcap->data.rate_adaption = (lv[i] >> 3) & 3;
238 bcap->data.sig_access = lv[i] & 7;
239 while(!(lv[i] & 0x80)) {
240 i++; /* octet 5a etc */
241 if (in_len < i)
242 return 0;
243 /* ignore them */
244 }
245 /* octet 6 */
246 i++;
247 if (in_len < i)
248 return 0;
249 bcap->data.async = lv[i] & 1;
250 if (!(lv[i] & 0x80)) {
251 i++;
252 if (in_len < i)
253 return 0;
254 /* octet 6a */
255 bcap->data.nr_stop_bits = ((lv[i] >> 7) & 1) + 1;
256 if (lv[i] & 0x10)
257 bcap->data.nr_data_bits = 8;
258 else
259 bcap->data.nr_data_bits = 7;
260 bcap->data.user_rate = lv[i] & 0xf;
261
262 if (!(lv[i] & 0x80)) {
263 i++;
264 if (in_len < i)
265 return 0;
266 /* octet 6b */
267 bcap->data.parity = lv[i] & 7;
268 bcap->data.interm_rate = (lv[i] >> 5) & 3;
269
270 /* octet 6c */
271 if (!(lv[i] & 0x80)) {
272 i++;
273 if (in_len < i)
274 return 0;
275 bcap->data.transp = (lv[i] >> 5) & 3;
276 bcap->data.modem_type = lv[i] & 0x1F;
277 }
278 }
279
280 }
281 break;
282 default:
Harald Welte1e908662010-03-07 23:39:54 +0100283 i = 1;
284 while (!(lv[i] & 0x80)) {
285 i++; /* octet 3a etc */
286 if (in_len < i)
287 return 0;
288 /* ignore them */
289 }
290 /* FIXME: implement OCTET 4+ parsing */
Harald Weltec8a0b932012-08-24 21:27:26 +0200291 break;
Harald Welte1e908662010-03-07 23:39:54 +0100292 }
293
294 return 0;
295}
296
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200297/*! Encode TS 04.08 Bearer Capability IE (10.5.4.5)
Harald Welte96e2a002017-06-12 21:44:18 +0200298 * \param[out] msg Message Buffer to which IE is to be appended
299 * \param[in] lv_only Write only LV portion (1) or TLV (0)
300 * \param[in] bcap Decoded Bearer Capability to be encoded
301 * \returns 0 on success; negative on error */
Harald Welte1e908662010-03-07 23:39:54 +0100302int gsm48_encode_bearer_cap(struct msgb *msg, int lv_only,
303 const struct gsm_mncc_bearer_cap *bcap)
304{
305 uint8_t lv[32 + 1];
306 int i = 1, s;
307
308 lv[1] = bcap->transfer;
309 lv[1] |= bcap->mode << 3;
310 lv[1] |= bcap->coding << 4;
311 lv[1] |= bcap->radio << 5;
312
Harald Weltec8a0b932012-08-24 21:27:26 +0200313 switch (bcap->transfer) {
314 case GSM_MNCC_BCAP_SPEECH:
Harald Welte1e908662010-03-07 23:39:54 +0100315 for (s = 0; bcap->speech_ver[s] >= 0; s++) {
316 i++; /* octet 3a etc */
317 lv[i] = bcap->speech_ver[s];
318 if (i == 2) /* octet 3a */
319 lv[i] |= bcap->speech_ctm << 5;
320 }
321 lv[i] |= 0x80; /* last IE of octet 3 etc */
Harald Weltec8a0b932012-08-24 21:27:26 +0200322 break;
323 case GSM48_BCAP_ITCAP_UNR_DIG_INF:
324 case GSM48_BCAP_ITCAP_FAX_G3:
325 lv[i++] |= 0x80; /* last IE of octet 3 etc */
326 /* octet 4 */
327 lv[i++] = 0xb8;
328 /* octet 5 */
329 lv[i++] = 0x80 | ((bcap->data.rate_adaption & 3) << 3)
330 | (bcap->data.sig_access & 7);
331 /* octet 6 */
332 lv[i++] = 0x20 | (bcap->data.async & 1);
333 /* octet 6a */
334 lv[i++] = (bcap->data.user_rate & 0xf) |
335 (bcap->data.nr_data_bits == 8 ? 0x10 : 0x00) |
336 (bcap->data.nr_stop_bits == 2 ? 0x40 : 0x00);
337 /* octet 6b */
338 lv[i++] = (bcap->data.parity & 7) |
339 ((bcap->data.interm_rate & 3) << 5);
340 /* octet 6c */
341 lv[i] = 0x80 | (bcap->data.modem_type & 0x1f);
342 break;
343 default:
344 return -EINVAL;
Harald Welte1e908662010-03-07 23:39:54 +0100345 }
346
347 lv[0] = i;
348 if (lv_only)
349 msgb_lv_put(msg, lv[0], lv+1);
350 else
351 msgb_tlv_put(msg, GSM48_IE_BEARER_CAP, lv[0], lv+1);
352
353 return 0;
354}
355
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200356/*! Decode TS 04.08 Call Control Capabilities IE (10.5.4.5a)
Harald Welte96e2a002017-06-12 21:44:18 +0200357 * \param[out] Caller-provided memory for decoded CC capabilities
358 * \param[in] lv Length-Value of IE
359 * \retursns 0 on success; negative on error */
Harald Welte1e908662010-03-07 23:39:54 +0100360int gsm48_decode_cccap(struct gsm_mncc_cccap *ccap, const uint8_t *lv)
361{
362 uint8_t in_len = lv[0];
363
364 if (in_len < 1)
365 return -EINVAL;
366
367 /* octet 3 */
368 ccap->dtmf = lv[1] & 0x01;
369 ccap->pcp = (lv[1] & 0x02) >> 1;
370
371 return 0;
372}
373
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200374/*! Encodoe TS 04.08 Call Control Capabilities (10.5.4.5a)
Harald Welte96e2a002017-06-12 21:44:18 +0200375 * \param[out] msg Message Buffer to which to append IE (as TLV)
376 * \param[in] ccap Decoded CC Capabilities to be encoded
377 * \returns 0 on success; negative on error */
Harald Welte1e908662010-03-07 23:39:54 +0100378int gsm48_encode_cccap(struct msgb *msg,
379 const struct gsm_mncc_cccap *ccap)
380{
381 uint8_t lv[2];
382
383 lv[0] = 1;
384 lv[1] = 0;
385 if (ccap->dtmf)
386 lv [1] |= 0x01;
387 if (ccap->pcp)
388 lv [1] |= 0x02;
389
390 msgb_tlv_put(msg, GSM48_IE_CC_CAP, lv[0], lv+1);
391
392 return 0;
393}
394
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200395/*! Decode TS 04.08 Called Party BCD Number IE (10.5.4.7)
Harald Welte96e2a002017-06-12 21:44:18 +0200396 * \param[out] called Caller-provided memory for decoded number
397 * \param[in] lv Length-Value portion of IE
398 * \returns 0 on success; negative on error */
Harald Welte1e908662010-03-07 23:39:54 +0100399int gsm48_decode_called(struct gsm_mncc_number *called,
400 const uint8_t *lv)
401{
402 uint8_t in_len = lv[0];
403
404 if (in_len < 1)
405 return -EINVAL;
406
407 /* octet 3 */
408 called->plan = lv[1] & 0x0f;
409 called->type = (lv[1] & 0x70) >> 4;
410
411 /* octet 4..N */
412 gsm48_decode_bcd_number(called->number, sizeof(called->number), lv, 1);
413
414 return 0;
415}
416
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200417/*! Encode TS 04.08 Called Party IE (10.5.4.7)
Harald Welte96e2a002017-06-12 21:44:18 +0200418 * \param[out] msg Mesage Buffer to which to append IE (as TLV)
419 * \param[in] called MNCC Number to encode/append
420 * \returns 0 on success; negative on error */
Harald Welte1e908662010-03-07 23:39:54 +0100421int gsm48_encode_called(struct msgb *msg,
422 const struct gsm_mncc_number *called)
423{
424 uint8_t lv[18];
425 int ret;
426
427 /* octet 3 */
Sylvain Munaut47ee6932010-09-20 20:59:23 +0200428 lv[1] = 0x80; /* no extension */
429 lv[1] |= called->plan;
Harald Welte1e908662010-03-07 23:39:54 +0100430 lv[1] |= called->type << 4;
431
432 /* octet 4..N, octet 2 */
433 ret = gsm48_encode_bcd_number(lv, sizeof(lv), 1, called->number);
434 if (ret < 0)
435 return ret;
436
437 msgb_tlv_put(msg, GSM48_IE_CALLED_BCD, lv[0], lv+1);
438
439 return 0;
440}
441
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200442/*! Decode TS 04.08 Caller ID
Harald Welte96e2a002017-06-12 21:44:18 +0200443 * \param[out] called Caller-provided memory for decoded number
444 * \param[in] lv Length-Value portion of IE
445 * \returns 0 on success; negative on error */
Harald Welte1e908662010-03-07 23:39:54 +0100446int gsm48_decode_callerid(struct gsm_mncc_number *callerid,
447 const uint8_t *lv)
448{
449 uint8_t in_len = lv[0];
450 int i = 1;
451
452 if (in_len < 1)
453 return -EINVAL;
454
455 /* octet 3 */
456 callerid->plan = lv[1] & 0x0f;
457 callerid->type = (lv[1] & 0x70) >> 4;
458
459 /* octet 3a */
460 if (!(lv[1] & 0x80)) {
461 callerid->screen = lv[2] & 0x03;
462 callerid->present = (lv[2] & 0x60) >> 5;
463 i = 2;
464 }
465
466 /* octet 4..N */
467 gsm48_decode_bcd_number(callerid->number, sizeof(callerid->number), lv, i);
468
469 return 0;
470}
471
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200472/*! Encode TS 04.08 Caller ID IE
Harald Welte96e2a002017-06-12 21:44:18 +0200473 * \param[out] msg Mesage Buffer to which to append IE (as TLV)
474 * \param[in] ie IE Identifier (tag)
475 * \param[in] max_len maximum generated output in bytes
476 * \param[in] callerid MNCC Number to encode/append
477 * \returns 0 on success; negative on error */
Harald Welte1e908662010-03-07 23:39:54 +0100478int gsm48_encode_callerid(struct msgb *msg, int ie, int max_len,
479 const struct gsm_mncc_number *callerid)
480{
481 uint8_t lv[max_len - 1];
482 int h_len = 1;
483 int ret;
484
485 /* octet 3 */
486 lv[1] = callerid->plan;
487 lv[1] |= callerid->type << 4;
488
489 if (callerid->present || callerid->screen) {
490 /* octet 3a */
491 lv[2] = callerid->screen;
492 lv[2] |= callerid->present << 5;
493 lv[2] |= 0x80;
494 h_len++;
495 } else
496 lv[1] |= 0x80;
497
498 /* octet 4..N, octet 2 */
499 ret = gsm48_encode_bcd_number(lv, sizeof(lv), h_len, callerid->number);
500 if (ret < 0)
501 return ret;
502
503 msgb_tlv_put(msg, ie, lv[0], lv+1);
504
505 return 0;
506}
507
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200508/*! Decode TS 04.08 Cause IE (10.5.4.11)
Harald Welte96e2a002017-06-12 21:44:18 +0200509 * \param[out] cause Caller-provided memory for output
510 * \param[in] lv LV portion of Cause IE
511 * \returns 0 on success; negative on error */
Harald Welte1e908662010-03-07 23:39:54 +0100512int gsm48_decode_cause(struct gsm_mncc_cause *cause,
513 const uint8_t *lv)
514{
515 uint8_t in_len = lv[0];
516 int i;
517
518 if (in_len < 2)
519 return -EINVAL;
520
521 cause->diag_len = 0;
522
523 /* octet 3 */
524 cause->location = lv[1] & 0x0f;
525 cause->coding = (lv[1] & 0x60) >> 5;
526
527 i = 1;
528 if (!(lv[i] & 0x80)) {
529 i++; /* octet 3a */
530 if (in_len < i+1)
531 return 0;
532 cause->rec = 1;
533 cause->rec_val = lv[i] & 0x7f;
534 }
535 i++;
536
537 /* octet 4 */
538 cause->value = lv[i] & 0x7f;
539 i++;
540
541 if (in_len < i) /* no diag */
542 return 0;
543
544 if (in_len - (i-1) > 32) /* maximum 32 octets */
545 return 0;
546
547 /* octet 5-N */
548 memcpy(cause->diag, lv + i, in_len - (i-1));
549 cause->diag_len = in_len - (i-1);
550
551 return 0;
552}
553
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200554/*! Encode TS 04.08 Cause IE (10.5.4.11)
Harald Welte96e2a002017-06-12 21:44:18 +0200555 * \param[out] msg Message Buffer to which to append IE
556 * \param[in] lv_only Encode as LV (1) or TLV (0)
557 * \param[in] cause Cause value to be encoded
558 * \returns 0 on success; negative on error */
Harald Welte1e908662010-03-07 23:39:54 +0100559int gsm48_encode_cause(struct msgb *msg, int lv_only,
560 const struct gsm_mncc_cause *cause)
561{
562 uint8_t lv[32+4];
563 int i;
564
565 if (cause->diag_len > 32)
566 return -EINVAL;
567
568 /* octet 3 */
569 lv[1] = cause->location;
570 lv[1] |= cause->coding << 5;
571
572 i = 1;
573 if (cause->rec) {
574 i++; /* octet 3a */
575 lv[i] = cause->rec_val;
576 }
577 lv[i] |= 0x80; /* end of octet 3 */
578
579 /* octet 4 */
580 i++;
581 lv[i] = 0x80 | cause->value;
582
583 /* octet 5-N */
584 if (cause->diag_len) {
585 memcpy(lv + i, cause->diag, cause->diag_len);
586 i += cause->diag_len;
587 }
588
589 lv[0] = i;
590 if (lv_only)
591 msgb_lv_put(msg, lv[0], lv+1);
592 else
593 msgb_tlv_put(msg, GSM48_IE_CAUSE, lv[0], lv+1);
594
595 return 0;
596}
597
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200598/*! Decode TS 04.08 Calling Number IE (10.5.4.9) */
Harald Welte1e908662010-03-07 23:39:54 +0100599int gsm48_decode_calling(struct gsm_mncc_number *calling,
600 const uint8_t *lv)
601{
602 return gsm48_decode_callerid(calling, lv);
603}
604
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200605/*! Encode TS 04.08 Calling Number IE (10.5.4.9) */
Harald Welte1e908662010-03-07 23:39:54 +0100606int gsm48_encode_calling(struct msgb *msg,
607 const struct gsm_mncc_number *calling)
608{
609 return gsm48_encode_callerid(msg, GSM48_IE_CALLING_BCD, 14, calling);
610}
611
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200612/*! Decode TS 04.08 Connected Number IE (10.5.4.13) */
Harald Welte1e908662010-03-07 23:39:54 +0100613int gsm48_decode_connected(struct gsm_mncc_number *connected,
614 const uint8_t *lv)
615{
616 return gsm48_decode_callerid(connected, lv);
617}
618
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200619/*! Encode TS 04.08 Connected Number IE (10.5.4.13) */
Harald Welte1e908662010-03-07 23:39:54 +0100620int gsm48_encode_connected(struct msgb *msg,
621 const struct gsm_mncc_number *connected)
622{
623 return gsm48_encode_callerid(msg, GSM48_IE_CONN_BCD, 14, connected);
624}
625
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200626/*! Decode TS 04.08 Redirecting Number IE (10.5.4.21b) */
Harald Welte1e908662010-03-07 23:39:54 +0100627int gsm48_decode_redirecting(struct gsm_mncc_number *redirecting,
628 const uint8_t *lv)
629{
630 return gsm48_decode_callerid(redirecting, lv);
631}
632
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200633/*! Encode TS 04.08 Redirecting Number IE (10.5.4.21b) */
Harald Welte1e908662010-03-07 23:39:54 +0100634int gsm48_encode_redirecting(struct msgb *msg,
635 const struct gsm_mncc_number *redirecting)
636{
637 return gsm48_encode_callerid(msg, GSM48_IE_REDIR_BCD, 19, redirecting);
638}
639
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200640/*! Decode TS 04.08 Facility IE (10.5.4.15) */
Harald Welte1e908662010-03-07 23:39:54 +0100641int gsm48_decode_facility(struct gsm_mncc_facility *facility,
642 const uint8_t *lv)
643{
644 uint8_t in_len = lv[0];
645
646 if (in_len < 1)
647 return -EINVAL;
648
649 if (in_len > sizeof(facility->info))
650 return -EINVAL;
651
652 memcpy(facility->info, lv+1, in_len);
653 facility->len = in_len;
654
655 return 0;
656}
657
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200658/*! Encode TS 04.08 Facility IE (10.5.4.15) */
Harald Welte1e908662010-03-07 23:39:54 +0100659int gsm48_encode_facility(struct msgb *msg, int lv_only,
660 const struct gsm_mncc_facility *facility)
661{
662 uint8_t lv[GSM_MAX_FACILITY + 1];
663
664 if (facility->len < 1 || facility->len > GSM_MAX_FACILITY)
665 return -EINVAL;
666
667 memcpy(lv+1, facility->info, facility->len);
668 lv[0] = facility->len;
669 if (lv_only)
670 msgb_lv_put(msg, lv[0], lv+1);
671 else
672 msgb_tlv_put(msg, GSM48_IE_FACILITY, lv[0], lv+1);
673
674 return 0;
675}
676
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200677/*! Decode TS 04.08 Notify IE (10.5.4.20) */
Harald Welte1e908662010-03-07 23:39:54 +0100678int gsm48_decode_notify(int *notify, const uint8_t *v)
679{
680 *notify = v[0] & 0x7f;
681
682 return 0;
683}
684
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200685/*! Encode TS 04.08 Notify IE (10.5.4.20) */
Harald Welte1e908662010-03-07 23:39:54 +0100686int gsm48_encode_notify(struct msgb *msg, int notify)
687{
688 msgb_v_put(msg, notify | 0x80);
689
690 return 0;
691}
692
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200693/*! Decode TS 04.08 Signal IE (10.5.4.23) */
Harald Welte1e908662010-03-07 23:39:54 +0100694int gsm48_decode_signal(int *signal, const uint8_t *v)
695{
696 *signal = v[0];
697
698 return 0;
699}
700
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200701/*! Encode TS 04.08 Signal IE (10.5.4.23) */
Harald Welte1e908662010-03-07 23:39:54 +0100702int gsm48_encode_signal(struct msgb *msg, int signal)
703{
704 msgb_tv_put(msg, GSM48_IE_SIGNAL, signal);
705
706 return 0;
707}
708
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200709/*! Decode TS 04.08 Keypad IE (10.5.4.17) */
Harald Welte1e908662010-03-07 23:39:54 +0100710int gsm48_decode_keypad(int *keypad, const uint8_t *lv)
711{
712 uint8_t in_len = lv[0];
713
714 if (in_len < 1)
715 return -EINVAL;
716
717 *keypad = lv[1] & 0x7f;
718
719 return 0;
720}
721
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200722/*! Encode TS 04.08 Keypad IE (10.5.4.17) */
Harald Welte1e908662010-03-07 23:39:54 +0100723int gsm48_encode_keypad(struct msgb *msg, int keypad)
724{
725 msgb_tv_put(msg, GSM48_IE_KPD_FACILITY, keypad);
726
727 return 0;
728}
729
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200730/*! Decode TS 04.08 Progress IE (10.5.4.21) */
Harald Welte1e908662010-03-07 23:39:54 +0100731int gsm48_decode_progress(struct gsm_mncc_progress *progress,
732 const uint8_t *lv)
733{
734 uint8_t in_len = lv[0];
735
736 if (in_len < 2)
737 return -EINVAL;
738
739 progress->coding = (lv[1] & 0x60) >> 5;
740 progress->location = lv[1] & 0x0f;
741 progress->descr = lv[2] & 0x7f;
742
743 return 0;
744}
745
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200746/*! Encode TS 04.08 Progress IE (10.5.4.21) */
Harald Welte1e908662010-03-07 23:39:54 +0100747int gsm48_encode_progress(struct msgb *msg, int lv_only,
748 const struct gsm_mncc_progress *p)
749{
750 uint8_t lv[3];
751
752 lv[0] = 2;
753 lv[1] = 0x80 | ((p->coding & 0x3) << 5) | (p->location & 0xf);
754 lv[2] = 0x80 | (p->descr & 0x7f);
755 if (lv_only)
756 msgb_lv_put(msg, lv[0], lv+1);
757 else
758 msgb_tlv_put(msg, GSM48_IE_PROGR_IND, lv[0], lv+1);
759
760 return 0;
761}
762
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200763/*! Decode TS 04.08 User-User IE (10.5.4.25) */
Harald Welte1e908662010-03-07 23:39:54 +0100764int gsm48_decode_useruser(struct gsm_mncc_useruser *uu,
765 const uint8_t *lv)
766{
767 uint8_t in_len = lv[0];
768 char *info = uu->info;
769 int info_len = sizeof(uu->info);
770 int i;
771
772 if (in_len < 1)
773 return -EINVAL;
774
775 uu->proto = lv[1];
776
777 for (i = 2; i <= in_len; i++) {
778 info_len--;
779 if (info_len <= 1)
780 break;
781 *info++ = lv[i];
782 }
783 if (info_len >= 1)
784 *info++ = '\0';
785
786 return 0;
787}
788
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200789/*! Encode TS 04.08 User-User IE (10.5.4.25) */
Harald Welte1e908662010-03-07 23:39:54 +0100790int gsm48_encode_useruser(struct msgb *msg, int lv_only,
791 const struct gsm_mncc_useruser *uu)
792{
793 uint8_t lv[GSM_MAX_USERUSER + 2];
794
795 if (strlen(uu->info) > GSM_MAX_USERUSER)
796 return -EINVAL;
797
798 lv[0] = 1 + strlen(uu->info);
799 lv[1] = uu->proto;
800 memcpy(lv + 2, uu->info, strlen(uu->info));
801 if (lv_only)
802 msgb_lv_put(msg, lv[0], lv+1);
803 else
804 msgb_tlv_put(msg, GSM48_IE_USER_USER, lv[0], lv+1);
805
806 return 0;
807}
808
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200809/*! Decode TS 04.08 SS Version IE (10.5.4.24) */
Harald Welte1e908662010-03-07 23:39:54 +0100810int gsm48_decode_ssversion(struct gsm_mncc_ssversion *ssv,
811 const uint8_t *lv)
812{
813 uint8_t in_len = lv[0];
814
815 if (in_len < 1 || in_len < sizeof(ssv->info))
816 return -EINVAL;
817
818 memcpy(ssv->info, lv + 1, in_len);
819 ssv->len = in_len;
820
821 return 0;
822}
823
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200824/*! Encode TS 04.08 SS Version IE (10.5.4.24) */
Harald Welte1e908662010-03-07 23:39:54 +0100825int gsm48_encode_ssversion(struct msgb *msg,
826 const struct gsm_mncc_ssversion *ssv)
827{
828 uint8_t lv[GSM_MAX_SSVERSION + 1];
829
830 if (ssv->len > GSM_MAX_SSVERSION)
831 return -EINVAL;
832
833 lv[0] = ssv->len;
834 memcpy(lv + 1, ssv->info, ssv->len);
835 msgb_tlv_put(msg, GSM48_IE_SS_VERS, lv[0], lv+1);
836
837 return 0;
838}
839
840/* decode 'more data' does not require a function, because it has no value */
841
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200842/*! Encode TS 04.08 More Data IE (10.5.4.19) */
Harald Welte1e908662010-03-07 23:39:54 +0100843int gsm48_encode_more(struct msgb *msg)
844{
845 uint8_t *ie;
846
847 ie = msgb_put(msg, 1);
848 ie[0] = GSM48_IE_MORE_DATA;
849
850 return 0;
851}
852
Sylvain Munaut71fd42f2011-09-01 22:05:29 +0200853static int32_t smod(int32_t n, int32_t m)
854{
855 int32_t res;
856
857 res = n % m;
858
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200859 if (res <= 0)
Sylvain Munaut71fd42f2011-09-01 22:05:29 +0200860 res += m;
861
Sylvain Munaut71fd42f2011-09-01 22:05:29 +0200862 return res;
863}
864
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200865/*! Decode TS 04.08 Cell Channel Description IE (10.5.2.1b) and other frequency lists
Pau Espin Pedrold8d0c3e2018-11-15 18:26:01 +0100866 * \param[out] f Caller-provided output memory, an array of 1024 elements
Harald Welte96e2a002017-06-12 21:44:18 +0200867 * \param[in] cd Cell Channel Description IE
868 * \param[in] len Length of \a cd in bytes
869 * \returns 0 on success; negative on error */
Harald Welte1523d702010-08-04 11:46:44 +0200870int gsm48_decode_freq_list(struct gsm_sysinfo_freq *f, uint8_t *cd,
871 uint8_t len, uint8_t mask, uint8_t frqt)
872{
873 int i;
874
875 /* NOTES:
876 *
877 * The Range format uses "SMOD" computation.
878 * e.g. "n SMOD m" equals "((n - 1) % m) + 1"
879 * A cascade of multiple SMOD computations is simpified:
880 * "(n SMOD m) SMOD o" equals "(((n - 1) % m) % o) + 1"
881 *
882 * The Range format uses 16 octets of data in SYSTEM INFORMATION.
883 * When used in dedicated messages, the length can be less.
884 * In this case the ranges are decoded for all frequencies that
885 * fit in the block of given length.
886 */
887
888 /* tabula rasa */
889 for (i = 0; i < 1024; i++)
890 f[i].mask &= ~frqt;
891
892 /* 00..XXX. */
893 if ((cd[0] & 0xc0 & mask) == 0x00) {
894 /* Bit map 0 format */
895 if (len < 16)
896 return -EINVAL;
897 for (i = 1; i <= 124; i++)
898 if ((cd[15 - ((i-1) >> 3)] & (1 << ((i-1) & 7))))
899 f[i].mask |= frqt;
900
901 return 0;
902 }
903
904 /* 10..0XX. */
905 if ((cd[0] & 0xc8 & mask) == 0x80) {
906 /* Range 1024 format */
907 uint16_t w[17]; /* 1..16 */
908 struct gsm48_range_1024 *r = (struct gsm48_range_1024 *)cd;
909
910 if (len < 2)
911 return -EINVAL;
912 memset(w, 0, sizeof(w));
913 if (r->f0)
914 f[0].mask |= frqt;
915 w[1] = (r->w1_hi << 8) | r->w1_lo;
916 if (len >= 4)
917 w[2] = (r->w2_hi << 1) | r->w2_lo;
918 if (len >= 5)
919 w[3] = (r->w3_hi << 2) | r->w3_lo;
920 if (len >= 6)
921 w[4] = (r->w4_hi << 2) | r->w4_lo;
922 if (len >= 7)
923 w[5] = (r->w5_hi << 2) | r->w5_lo;
924 if (len >= 8)
925 w[6] = (r->w6_hi << 2) | r->w6_lo;
926 if (len >= 9)
927 w[7] = (r->w7_hi << 2) | r->w7_lo;
928 if (len >= 10)
929 w[8] = (r->w8_hi << 1) | r->w8_lo;
930 if (len >= 10)
931 w[9] = r->w9;
932 if (len >= 11)
933 w[10] = r->w10;
934 if (len >= 12)
935 w[11] = (r->w11_hi << 6) | r->w11_lo;
936 if (len >= 13)
937 w[12] = (r->w12_hi << 5) | r->w12_lo;
938 if (len >= 14)
939 w[13] = (r->w13_hi << 4) | r->w13_lo;
940 if (len >= 15)
941 w[14] = (r->w14_hi << 3) | r->w14_lo;
942 if (len >= 16)
943 w[15] = (r->w15_hi << 2) | r->w15_lo;
944 if (len >= 16)
945 w[16] = r->w16;
946 if (w[1])
947 f[w[1]].mask |= frqt;
948 if (w[2])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200949 f[smod(w[1] - 512 + w[2], 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200950 if (w[3])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200951 f[smod(w[1] + w[3], 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200952 if (w[4])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200953 f[smod(w[1] - 512 + smod(w[2] - 256 + w[4], 511), 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200954 if (w[5])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200955 f[smod(w[1] + smod(w[3] - 256 + w[5], 511), 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200956 if (w[6])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200957 f[smod(w[1] - 512 + smod(w[2] + w[6], 511), 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200958 if (w[7])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200959 f[smod(w[1] + smod(w[3] + w[7], 511), 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200960 if (w[8])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200961 f[smod(w[1] - 512 + smod(w[2] - 256 + smod(w[4] - 128 + w[8] , 255), 511), 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200962 if (w[9])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200963 f[smod(w[1] + smod(w[3] - 256 + smod(w[5] - 128 + w[9] , 255), 511), 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200964 if (w[10])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200965 f[smod(w[1] - 512 + smod(w[2] + smod(w[6] - 128 + w[10], 255), 511), 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200966 if (w[11])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200967 f[smod(w[1] + smod(w[3] + smod(w[7] - 128 + w[11], 255), 511), 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200968 if (w[12])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200969 f[smod(w[1] - 512 + smod(w[2] - 256 + smod(w[4] + w[12], 255), 511), 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200970 if (w[13])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200971 f[smod(w[1] + smod(w[3] - 256 + smod(w[5] + w[13], 255), 511), 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200972 if (w[14])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200973 f[smod(w[1] - 512 + smod(w[2] + smod(w[6] + w[14], 255), 511), 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200974 if (w[15])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200975 f[smod(w[1] + smod(w[3] + smod(w[7] + w[15], 255), 511), 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200976 if (w[16])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +0200977 f[smod(w[1] - 512 + smod(w[2] - 256 + smod(w[4] - 128 + smod(w[8] - 64 + w[16], 127), 255), 511), 1023)].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +0200978
979 return 0;
980 }
981 /* 10..100. */
982 if ((cd[0] & 0xce & mask) == 0x88) {
983 /* Range 512 format */
984 uint16_t w[18]; /* 1..17 */
985 struct gsm48_range_512 *r = (struct gsm48_range_512 *)cd;
986
987 if (len < 4)
988 return -EINVAL;
989 memset(w, 0, sizeof(w));
990 w[0] = (r->orig_arfcn_hi << 9) | (r->orig_arfcn_mid << 1) | r->orig_arfcn_lo;
991 w[1] = (r->w1_hi << 2) | r->w1_lo;
992 if (len >= 5)
993 w[2] = (r->w2_hi << 2) | r->w2_lo;
994 if (len >= 6)
995 w[3] = (r->w3_hi << 2) | r->w3_lo;
996 if (len >= 7)
997 w[4] = (r->w4_hi << 1) | r->w4_lo;
998 if (len >= 7)
999 w[5] = r->w5;
1000 if (len >= 8)
1001 w[6] = r->w6;
1002 if (len >= 9)
1003 w[7] = (r->w7_hi << 6) | r->w7_lo;
1004 if (len >= 10)
1005 w[8] = (r->w8_hi << 4) | r->w8_lo;
1006 if (len >= 11)
1007 w[9] = (r->w9_hi << 2) | r->w9_lo;
1008 if (len >= 11)
1009 w[10] = r->w10;
1010 if (len >= 12)
1011 w[11] = r->w11;
1012 if (len >= 13)
1013 w[12] = (r->w12_hi << 4) | r->w12_lo;
1014 if (len >= 14)
1015 w[13] = (r->w13_hi << 2) | r->w13_lo;
1016 if (len >= 14)
1017 w[14] = r->w14;
1018 if (len >= 15)
1019 w[15] = r->w15;
1020 if (len >= 16)
1021 w[16] = (r->w16_hi << 3) | r->w16_lo;
1022 if (len >= 16)
1023 w[17] = r->w17;
1024 f[w[0]].mask |= frqt;
1025 if (w[1])
1026 f[(w[0] + w[1]) % 1024].mask |= frqt;
1027 if (w[2])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001028 f[(w[0] + smod(w[1] - 256 + w[2], 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001029 if (w[3])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001030 f[(w[0] + smod(w[1] + w[3], 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001031 if (w[4])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001032 f[(w[0] + smod(w[1] - 256 + smod(w[2] - 128 + w[4], 255), 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001033 if (w[5])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001034 f[(w[0] + smod(w[1] + smod(w[3] - 128 + w[5], 255), 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001035 if (w[6])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001036 f[(w[0] + smod(w[1] - 256 + smod(w[2] + w[6], 255), 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001037 if (w[7])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001038 f[(w[0] + smod(w[1] + smod(w[3] + w[7], 255), 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001039 if (w[8])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001040 f[(w[0] + smod(w[1] - 256 + smod(w[2] - 128 + smod(w[4] - 64 + w[8] , 127), 255), 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001041 if (w[9])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001042 f[(w[0] + smod(w[1] + smod(w[3] - 128 + smod(w[5] - 64 + w[9] , 127), 255), 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001043 if (w[10])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001044 f[(w[0] + smod(w[1] - 256 + smod(w[2] + smod(w[6] - 64 + w[10], 127), 255), 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001045 if (w[11])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001046 f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 64 + w[11], 127), 255), 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001047 if (w[12])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001048 f[(w[0] + smod(w[1] - 256 + smod(w[2] - 128 + smod(w[4] + w[12], 127), 255), 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001049 if (w[13])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001050 f[(w[0] + smod(w[1] + smod(w[3] - 128 + smod(w[5] + w[13], 127), 255), 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001051 if (w[14])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001052 f[(w[0] + smod(w[1] - 256 + smod(w[2] + smod(w[6] + w[14], 127), 255), 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001053 if (w[15])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001054 f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] + w[15], 127), 255), 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001055 if (w[16])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001056 f[(w[0] + smod(w[1] - 256 + smod(w[2] - 128 + smod(w[4] - 64 + smod(w[8] - 32 + w[16], 63), 127), 255), 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001057 if (w[17])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001058 f[(w[0] + smod(w[1] + smod(w[3] - 128 + smod(w[5] - 64 + smod(w[9] - 32 + w[17], 63), 127), 255), 511)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001059
1060 return 0;
1061 }
1062 /* 10..101. */
1063 if ((cd[0] & 0xce & mask) == 0x8a) {
1064 /* Range 256 format */
1065 uint16_t w[22]; /* 1..21 */
1066 struct gsm48_range_256 *r = (struct gsm48_range_256 *)cd;
1067
1068 if (len < 4)
1069 return -EINVAL;
1070 memset(w, 0, sizeof(w));
1071 w[0] = (r->orig_arfcn_hi << 9) | (r->orig_arfcn_mid << 1) | r->orig_arfcn_lo;
1072 w[1] = (r->w1_hi << 1) | r->w1_lo;
1073 if (len >= 4)
1074 w[2] = r->w2;
1075 if (len >= 5)
1076 w[3] = r->w3;
1077 if (len >= 6)
1078 w[4] = (r->w4_hi << 5) | r->w4_lo;
1079 if (len >= 7)
1080 w[5] = (r->w5_hi << 3) | r->w5_lo;
1081 if (len >= 8)
1082 w[6] = (r->w6_hi << 1) | r->w6_lo;
1083 if (len >= 8)
1084 w[7] = r->w7;
1085 if (len >= 9)
1086 w[8] = (r->w8_hi << 4) | r->w8_lo;
1087 if (len >= 10)
1088 w[9] = (r->w9_hi << 1) | r->w9_lo;
1089 if (len >= 10)
1090 w[10] = r->w10;
1091 if (len >= 11)
1092 w[11] = (r->w11_hi << 3) | r->w11_lo;
1093 if (len >= 11)
1094 w[12] = r->w12;
1095 if (len >= 12)
1096 w[13] = r->w13;
1097 if (len >= 13)
Jacob Erlbeck85bc5492014-01-13 14:21:23 +01001098 w[14] = (r->w14_hi << 2) | r->w14_lo;
Harald Welte1523d702010-08-04 11:46:44 +02001099 if (len >= 13)
Jacob Erlbeck85bc5492014-01-13 14:21:23 +01001100 w[15] = r->w15;
Harald Welte1523d702010-08-04 11:46:44 +02001101 if (len >= 14)
1102 w[16] = (r->w16_hi << 3) | r->w16_lo;
1103 if (len >= 14)
1104 w[17] = r->w17;
1105 if (len >= 15)
Jacob Erlbeck85bc5492014-01-13 14:21:23 +01001106 w[18] = (r->w18_hi << 3) | r->w18_lo;
Harald Welte1523d702010-08-04 11:46:44 +02001107 if (len >= 15)
Jacob Erlbeck85bc5492014-01-13 14:21:23 +01001108 w[19] = r->w19;
Harald Welte1523d702010-08-04 11:46:44 +02001109 if (len >= 16)
1110 w[20] = (r->w20_hi << 3) | r->w20_lo;
1111 if (len >= 16)
1112 w[21] = r->w21;
1113 f[w[0]].mask |= frqt;
1114 if (w[1])
1115 f[(w[0] + w[1]) % 1024].mask |= frqt;
1116 if (w[2])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001117 f[(w[0] + smod(w[1] - 128 + w[2], 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001118 if (w[3])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001119 f[(w[0] + smod(w[1] + w[3], 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001120 if (w[4])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001121 f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + w[4], 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001122 if (w[5])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001123 f[(w[0] + smod(w[1] + smod(w[3] - 64 + w[5], 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001124 if (w[6])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001125 f[(w[0] + smod(w[1] - 128 + smod(w[2] + w[6], 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001126 if (w[7])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001127 f[(w[0] + smod(w[1] + smod(w[3] + w[7], 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001128 if (w[8])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001129 f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + smod(w[4] - 32 + w[8] , 63), 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001130 if (w[9])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001131 f[(w[0] + smod(w[1] + smod(w[3] - 64 + smod(w[5] - 32 + w[9] , 63), 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001132 if (w[10])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001133 f[(w[0] + smod(w[1] - 128 + smod(w[2] + smod(w[6] - 32 + w[10], 63), 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001134 if (w[11])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001135 f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 32 + w[11], 63), 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001136 if (w[12])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001137 f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + smod(w[4] + w[12], 63), 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001138 if (w[13])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001139 f[(w[0] + smod(w[1] + smod(w[3] - 64 + smod(w[5] + w[13], 63), 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001140 if (w[14])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001141 f[(w[0] + smod(w[1] - 128 + smod(w[2] + smod(w[6] + w[14], 63), 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001142 if (w[15])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001143 f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] + w[15], 63), 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001144 if (w[16])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001145 f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + smod(w[4] - 32 + smod(w[8] - 16 + w[16], 31), 63), 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001146 if (w[17])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001147 f[(w[0] + smod(w[1] + smod(w[3] - 64 + smod(w[5] - 32 + smod(w[9] - 16 + w[17], 31), 63), 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001148 if (w[18])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001149 f[(w[0] + smod(w[1] - 128 + smod(w[2] + smod(w[6] - 32 + smod(w[10] - 16 + w[18], 31), 63), 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001150 if (w[19])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001151 f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 32 + smod(w[11] - 16 + w[19], 31), 63), 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001152 if (w[20])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001153 f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + smod(w[4] + smod(w[12] - 16 + w[20], 31), 63), 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001154 if (w[21])
Sylvain Munaut71fd42f2011-09-01 22:05:29 +02001155 f[(w[0] + smod(w[1] + smod(w[3] - 64 + smod(w[5] + smod(w[13] - 16 + w[21], 31), 63), 127), 255)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001156
1157 return 0;
1158 }
1159 /* 10..110. */
1160 if ((cd[0] & 0xce & mask) == 0x8c) {
1161 /* Range 128 format */
1162 uint16_t w[29]; /* 1..28 */
1163 struct gsm48_range_128 *r = (struct gsm48_range_128 *)cd;
1164
1165 if (len < 3)
1166 return -EINVAL;
1167 memset(w, 0, sizeof(w));
1168 w[0] = (r->orig_arfcn_hi << 9) | (r->orig_arfcn_mid << 1) | r->orig_arfcn_lo;
1169 w[1] = r->w1;
1170 if (len >= 4)
1171 w[2] = r->w2;
1172 if (len >= 5)
1173 w[3] = (r->w3_hi << 4) | r->w3_lo;
1174 if (len >= 6)
1175 w[4] = (r->w4_hi << 1) | r->w4_lo;
1176 if (len >= 6)
1177 w[5] = r->w5;
1178 if (len >= 7)
1179 w[6] = (r->w6_hi << 3) | r->w6_lo;
1180 if (len >= 7)
1181 w[7] = r->w7;
1182 if (len >= 8)
1183 w[8] = r->w8;
1184 if (len >= 8)
1185 w[9] = r->w9;
1186 if (len >= 9)
1187 w[10] = r->w10;
1188 if (len >= 9)
1189 w[11] = r->w11;
1190 if (len >= 10)
1191 w[12] = r->w12;
1192 if (len >= 10)
1193 w[13] = r->w13;
1194 if (len >= 11)
1195 w[14] = r->w14;
1196 if (len >= 11)
1197 w[15] = r->w15;
1198 if (len >= 12)
1199 w[16] = r->w16;
1200 if (len >= 12)
1201 w[17] = r->w17;
1202 if (len >= 13)
1203 w[18] = (r->w18_hi << 1) | r->w18_lo;
1204 if (len >= 13)
1205 w[19] = r->w19;
1206 if (len >= 13)
1207 w[20] = r->w20;
1208 if (len >= 14)
1209 w[21] = (r->w21_hi << 2) | r->w21_lo;
1210 if (len >= 14)
1211 w[22] = r->w22;
1212 if (len >= 14)
1213 w[23] = r->w23;
1214 if (len >= 15)
1215 w[24] = r->w24;
1216 if (len >= 15)
1217 w[25] = r->w25;
1218 if (len >= 16)
1219 w[26] = (r->w26_hi << 1) | r->w26_lo;
1220 if (len >= 16)
1221 w[27] = r->w27;
1222 if (len >= 16)
1223 w[28] = r->w28;
1224 f[w[0]].mask |= frqt;
1225 if (w[1])
1226 f[(w[0] + w[1]) % 1024].mask |= frqt;
1227 if (w[2])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001228 f[(w[0] + smod(w[1] - 64 + w[2], 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001229 if (w[3])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001230 f[(w[0] + smod(w[1] + w[3], 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001231 if (w[4])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001232 f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + w[4], 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001233 if (w[5])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001234 f[(w[0] + smod(w[1] + smod(w[3] - 32 + w[5], 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001235 if (w[6])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001236 f[(w[0] + smod(w[1] - 64 + smod(w[2] + w[6], 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001237 if (w[7])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001238 f[(w[0] + smod(w[1] + smod(w[3] + w[7], 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001239 if (w[8])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001240 f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] - 16 + w[8] , 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001241 if (w[9])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001242 f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] - 16 + w[9] , 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001243 if (w[10])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001244 f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] - 16 + w[10], 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001245 if (w[11])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001246 f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 16 + w[11], 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001247 if (w[12])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001248 f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] + w[12], 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001249 if (w[13])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001250 f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] + w[13], 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001251 if (w[14])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001252 f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] + w[14], 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001253 if (w[15])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001254 f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] + w[15], 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001255 if (w[16])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001256 f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] - 16 + smod(w[8] - 8 + w[16], 15), 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001257 if (w[17])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001258 f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] - 16 + smod(w[9] - 8 + w[17], 15), 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001259 if (w[18])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001260 f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] - 16 + smod(w[10] - 8 + w[18], 15), 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001261 if (w[19])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001262 f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 16 + smod(w[11] - 8 + w[19], 15), 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001263 if (w[20])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001264 f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] + smod(w[12] - 8 + w[20], 15), 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001265 if (w[21])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001266 f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] + smod(w[13] - 8 + w[21], 15), 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001267 if (w[22])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001268 f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] + smod(w[14] - 8 + w[22], 15), 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001269 if (w[23])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001270 f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] + smod(w[15] - 8 + w[23], 15), 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001271 if (w[24])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001272 f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] - 16 + smod(w[8] + w[24], 15), 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001273 if (w[25])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001274 f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] - 16 + smod(w[9] + w[25], 15), 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001275 if (w[26])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001276 f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] - 16 + smod(w[10] + w[26], 15), 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001277 if (w[27])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001278 f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 16 + smod(w[11] + w[27], 15), 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001279 if (w[28])
Andreas.Eversbergeaac0cf2011-09-02 20:12:19 +02001280 f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] + smod(w[12] + w[28], 15), 31), 63), 127)) % 1024].mask |= frqt;
Harald Welte1523d702010-08-04 11:46:44 +02001281
1282 return 0;
1283 }
1284 /* 10..111. */
1285 if ((cd[0] & 0xce & mask) == 0x8e) {
1286 /* Variable bitmap format (can be any length >= 3) */
1287 uint16_t orig = 0;
1288 struct gsm48_var_bit *r = (struct gsm48_var_bit *)cd;
1289
1290 if (len < 3)
1291 return -EINVAL;
1292 orig = (r->orig_arfcn_hi << 9) | (r->orig_arfcn_mid << 1) | r->orig_arfcn_lo;
1293 f[orig].mask |= frqt;
1294 for (i = 1; 2 + (i >> 3) < len; i++)
1295 if ((cd[2 + (i >> 3)] & (0x80 >> (i & 7))))
1296 f[(orig + i) % 1024].mask |= frqt;
1297
1298 return 0;
1299 }
1300
1301 return 0;
1302}
Philipp Maiere36be562020-11-12 11:33:54 +01001303
1304/*! Decode 3GPP TS 24.008 Mobile Station Classmark 3 (10.5.1.7).
1305 * \param[out] classmark3_out user provided memory to store decoded classmark3.
1306 * \param[in] classmark3 pointer to memory that contains the raw classmark bits.
1307 * \param[in] classmark3_len length in bytes of the memory where classmark3 points to.
1308 * \returns 0 on success; negative on error. */
1309int gsm48_decode_classmark3(struct gsm48_classmark3 *classmark3_out,
1310 const uint8_t *classmark3, size_t classmark3_len)
1311{
1312 struct bitvec bv;
1313 uint8_t data[255];
1314 struct gsm48_classmark3 *cm3 = classmark3_out;
1315
1316 /* if cm3 gets extended by spec, it will be truncated, but 255 bytes
1317 * should be more than enough. */
1318 if (classmark3_len > sizeof(data))
1319 classmark3_len = sizeof(data);
1320
1321 memset(&bv, 0, sizeof(bv));
1322 memset(data, 0, sizeof(data));
1323 memset(classmark3_out, 0, sizeof(*classmark3_out));
1324
1325 memcpy(data, classmark3, classmark3_len);
1326 bv.data = (uint8_t*) data;
1327 bv.data_len = sizeof(data);
1328
1329 /* Parse bit vector, see also: 3GPP TS 24.008, section 10.5.1.7 */
1330 bitvec_get_uint(&bv, 1);
1331 cm3->mult_band_supp = bitvec_get_uint(&bv, 3);
1332 switch (cm3->mult_band_supp) {
1333 case 0x00:
1334 cm3->a5_bits = bitvec_get_uint(&bv, 4);
1335 break;
1336 case 0x05:
1337 case 0x06:
1338 cm3->a5_bits = bitvec_get_uint(&bv, 4);
1339 cm3->assoc_radio_cap_2 = bitvec_get_uint(&bv, 4);
1340 cm3->assoc_radio_cap_1 = bitvec_get_uint(&bv, 4);
1341 break;
1342 case 0x01:
1343 case 0x02:
1344 case 0x04:
1345 cm3->a5_bits = bitvec_get_uint(&bv, 4);
1346 bitvec_get_uint(&bv, 4);
1347 cm3->assoc_radio_cap_1 = bitvec_get_uint(&bv, 4);
1348 break;
1349 default:
1350 return -1;
1351 }
1352
1353 cm3->r_support.present = bitvec_get_uint(&bv, 1);
1354 if (cm3->r_support.present)
1355 cm3->r_support.r_gsm_assoc_radio_cap = bitvec_get_uint(&bv, 3);
1356
1357 cm3->hscsd_mult_slot_cap.present = bitvec_get_uint(&bv, 1);
1358 if (cm3->hscsd_mult_slot_cap.present)
1359 cm3->hscsd_mult_slot_cap.mslot_class = bitvec_get_uint(&bv, 5);
1360
1361 cm3->ucs2_treatment = bitvec_get_uint(&bv, 1);
1362 cm3->extended_meas_cap = bitvec_get_uint(&bv, 1);
1363
1364 cm3->ms_meas_cap.present = bitvec_get_uint(&bv, 1);
1365 if (cm3->ms_meas_cap.present) {
1366 cm3->ms_meas_cap.sms_value = bitvec_get_uint(&bv, 4);
1367 cm3->ms_meas_cap.sm_value = bitvec_get_uint(&bv, 4);
1368 }
1369
1370 cm3->ms_pos_method_cap.present = bitvec_get_uint(&bv, 1);
1371 if (cm3->ms_pos_method_cap.present)
1372 cm3->ms_pos_method_cap.method = bitvec_get_uint(&bv, 5);
1373
1374 cm3->ecsd_multislot_cap.present = bitvec_get_uint(&bv, 1);
1375 if (cm3->ecsd_multislot_cap.present)
1376 cm3->ecsd_multislot_cap.mslot_class = bitvec_get_uint(&bv, 5);
1377
1378 cm3->psk8_struct.present = bitvec_get_uint(&bv, 1);
1379 if (cm3->psk8_struct.present) {
1380 cm3->psk8_struct.mod_cap = bitvec_get_uint(&bv, 1);
1381
1382 cm3->psk8_struct.rf_pwr_cap_1.present = bitvec_get_uint(&bv, 1);
1383 if (cm3->psk8_struct.rf_pwr_cap_1.present) {
1384 cm3->psk8_struct.rf_pwr_cap_1.value =
1385 bitvec_get_uint(&bv, 2);
1386 }
1387
1388 cm3->psk8_struct.rf_pwr_cap_2.present = bitvec_get_uint(&bv, 1);
1389 if (cm3->psk8_struct.rf_pwr_cap_2.present) {
1390 cm3->psk8_struct.rf_pwr_cap_2.value =
1391 bitvec_get_uint(&bv, 2);
1392 }
1393 }
1394
1395 cm3->gsm_400_bands_supp.present = bitvec_get_uint(&bv, 1);
1396 if (cm3->gsm_400_bands_supp.present) {
1397 cm3->gsm_400_bands_supp.value = bitvec_get_uint(&bv, 2);
1398 if (cm3->gsm_400_bands_supp.value == 0x00)
1399 return -1;
1400 cm3->gsm_400_bands_supp.assoc_radio_cap =
1401 bitvec_get_uint(&bv, 4);
1402 }
1403
1404 cm3->gsm_850_assoc_radio_cap.present = bitvec_get_uint(&bv, 1);
1405 if (cm3->gsm_850_assoc_radio_cap.present)
1406 cm3->gsm_850_assoc_radio_cap.value = bitvec_get_uint(&bv, 4);
1407
1408 cm3->gsm_1900_assoc_radio_cap.present = bitvec_get_uint(&bv, 1);
1409 if (cm3->gsm_1900_assoc_radio_cap.present)
1410 cm3->gsm_1900_assoc_radio_cap.value = bitvec_get_uint(&bv, 4);
1411
1412 cm3->umts_fdd_rat_cap = bitvec_get_uint(&bv, 1);
1413 cm3->umts_tdd_rat_cap = bitvec_get_uint(&bv, 1);
1414 cm3->cdma200_rat_cap = bitvec_get_uint(&bv, 1);
1415
1416 cm3->dtm_gprs_multislot_cap.present = bitvec_get_uint(&bv, 1);
1417 if (cm3->dtm_gprs_multislot_cap.present) {
1418 cm3->dtm_gprs_multislot_cap.mslot_class = bitvec_get_uint(&bv, 2);
1419 cm3->dtm_gprs_multislot_cap.single_slot_dtm =
1420 bitvec_get_uint(&bv, 1);
1421 cm3->dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.present =
1422 bitvec_get_uint(&bv, 1);
1423 if (cm3->dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.present)
1424 cm3->dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.
1425 mslot_class = bitvec_get_uint(&bv, 2);
1426 }
1427
1428 /* Release 4 starts here. */
1429 cm3->single_band_supp.present = bitvec_get_uint(&bv, 1);
1430 if (cm3->single_band_supp.present)
1431 cm3->single_band_supp.value = bitvec_get_uint(&bv, 4);
1432
1433 cm3->gsm_750_assoc_radio_cap.present = bitvec_get_uint(&bv, 1);
1434 if (cm3->gsm_750_assoc_radio_cap.present)
1435 cm3->gsm_750_assoc_radio_cap.value = bitvec_get_uint(&bv, 4);
1436
1437 cm3->umts_1_28_mcps_tdd_rat_cap = bitvec_get_uint(&bv, 1);
1438 cm3->geran_feature_package = bitvec_get_uint(&bv, 1);
1439
1440 cm3->extended_dtm_gprs_multislot_cap.present = bitvec_get_uint(&bv, 1);
1441 if (cm3->extended_dtm_gprs_multislot_cap.present) {
1442 cm3->extended_dtm_gprs_multislot_cap.mslot_class =
1443 bitvec_get_uint(&bv, 2);
1444 cm3->extended_dtm_gprs_multislot_cap.
1445 extended_dtm_egprs_multislot_cap.present =
1446 bitvec_get_uint(&bv, 1);
1447 if (cm3->extended_dtm_gprs_multislot_cap.
1448 extended_dtm_egprs_multislot_cap.present)
1449 cm3->extended_dtm_gprs_multislot_cap.
1450 extended_dtm_egprs_multislot_cap.mslot_class =
1451 bitvec_get_uint(&bv, 2);
1452 }
1453
1454 /* Release 5 starts here */
1455 cm3->high_multislot_cap.present = bitvec_get_uint(&bv, 1);
1456 if (cm3->high_multislot_cap.present)
1457 cm3->high_multislot_cap.value = bitvec_get_uint(&bv, 2);
1458
1459 /* This used to be the GERAN Iu mode support bit, but the newer spec
1460 * releases say that it should not be used (always zero), however
1461 * we will just ignore tha state of this bit. */
1462 bitvec_get_uint(&bv, 1);
1463
1464 cm3->geran_feature_package_2 = bitvec_get_uint(&bv, 1);
1465 cm3->gmsk_multislot_power_prof = bitvec_get_uint(&bv, 2);
1466 cm3->psk8_multislot_power_prof = bitvec_get_uint(&bv, 2);
1467
1468 /* Release 6 starts here */
1469 cm3->t_gsm_400_bands_supp.present = bitvec_get_uint(&bv, 1);
1470 if (cm3->t_gsm_400_bands_supp.present) {
1471 cm3->t_gsm_400_bands_supp.value = bitvec_get_uint(&bv, 2);
1472 cm3->t_gsm_400_bands_supp.assoc_radio_cap =
1473 bitvec_get_uint(&bv, 4);
1474 }
1475
1476 /* This used to be T-GSM 900 associated radio capability, but the
1477 * newer spec releases say that this bit should not be used, but if
1478 * it is used by some MS anyway we must assume that there is data
1479 * we have to override. */
1480 if (bitvec_get_uint(&bv, 1))
1481 bitvec_get_uint(&bv, 4);
1482
1483 cm3->dl_advanced_rx_perf = bitvec_get_uint(&bv, 2);
1484 cm3->dtm_enhancements_cap = bitvec_get_uint(&bv, 1);
1485
1486 cm3->dtm_gprs_high_multislot_cap.present = bitvec_get_uint(&bv, 1);
1487 if (cm3->dtm_gprs_high_multislot_cap.present) {
1488 cm3->dtm_gprs_high_multislot_cap.mslot_class =
1489 bitvec_get_uint(&bv, 3);
1490 cm3->dtm_gprs_high_multislot_cap.offset_required =
1491 bitvec_get_uint(&bv, 1);
1492 cm3->dtm_gprs_high_multislot_cap.dtm_egprs_high_multislot_cap.
1493 present = bitvec_get_uint(&bv, 1);
1494 if (cm3->dtm_gprs_high_multislot_cap.
1495 dtm_egprs_high_multislot_cap.present)
1496 cm3->dtm_gprs_high_multislot_cap.
1497 dtm_egprs_high_multislot_cap.mslot_class =
1498 bitvec_get_uint(&bv, 3);
1499 }
1500
1501 cm3->repeated_acch_capability = bitvec_get_uint(&bv, 1);
1502
1503 /* Release 7 starts here */
1504 cm3->gsm_710_assoc_radio_cap.present = bitvec_get_uint(&bv, 1);
1505 if (cm3->gsm_710_assoc_radio_cap.present)
1506 cm3->gsm_710_assoc_radio_cap.value = bitvec_get_uint(&bv, 4);
1507
1508 cm3->t_gsm_810_assoc_radio_cap.present = bitvec_get_uint(&bv, 1);
1509 if (cm3->t_gsm_810_assoc_radio_cap.present)
1510 cm3->t_gsm_810_assoc_radio_cap.value = bitvec_get_uint(&bv, 4);
1511
1512 cm3->ciphering_mode_setting_cap = bitvec_get_uint(&bv, 1);
1513 cm3->add_pos_cap = bitvec_get_uint(&bv, 1);
1514
1515 /* Release 8 starts here */
1516 cm3->e_utra_fdd_supp = bitvec_get_uint(&bv, 1);
1517 cm3->e_utra_tdd_supp = bitvec_get_uint(&bv, 1);
1518 cm3->e_utra_meas_rep_supp = bitvec_get_uint(&bv, 1);
1519 cm3->prio_resel_supp = bitvec_get_uint(&bv, 1);
1520
1521 /* Release 9 starts here */
1522 cm3->utra_csg_cells_rep = bitvec_get_uint(&bv, 1);
1523
1524 cm3->vamos_level = bitvec_get_uint(&bv, 2);
1525
1526 /* Release 10 starts here */
1527 cm3->tighter_capability = bitvec_get_uint(&bv, 2);
1528 cm3->sel_ciph_dl_sacch = bitvec_get_uint(&bv, 1);
1529
1530 /* Release 11 starts here */
1531 cm3->cs_ps_srvcc_geran_utra = bitvec_get_uint(&bv, 2);
1532 cm3->cs_ps_srvcc_geran_eutra = bitvec_get_uint(&bv, 2);
1533
1534 cm3->geran_net_sharing = bitvec_get_uint(&bv, 1);
1535 cm3->e_utra_wb_rsrq_meas_supp = bitvec_get_uint(&bv, 1);
1536
1537 /* Release 12 starts here */
1538 cm3->er_band_support = bitvec_get_uint(&bv, 1);
1539 cm3->utra_mult_band_ind_supp = bitvec_get_uint(&bv, 1);
1540 cm3->e_utra_mult_band_ind_supp = bitvec_get_uint(&bv, 1);
1541 cm3->extended_tsc_set_cap_supp = bitvec_get_uint(&bv, 1);
1542
1543 /* Late addition of a release 11 feature */
1544 cm3->extended_earfcn_val_range = bitvec_get_uint(&bv, 1);
1545
1546 return 0;
1547}
Harald Welte96e2a002017-06-12 21:44:18 +02001548/*! @} */