blob: 71910c6e0120a366729cb08cc2f48903b3e88abe [file] [log] [blame]
Harald Welte1e908662010-03-07 23:39:54 +01001/* GSM Mobile Radio Interface Layer 3 messages
2 * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
3
4/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
Harald Welteb1ac2b92010-04-09 07:50:18 +02005 * (C) 2009-2010 by Andreas Eversberg
Harald Welte1e908662010-03-07 23:39:54 +01006 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25
26#include <stdint.h>
27#include <string.h>
28#include <errno.h>
29
30#include <osmocore/utils.h>
31#include <osmocore/msgb.h>
32#include <osmocore/tlv.h>
33#include <osmocore/mncc.h>
34#include <osmocore/protocol/gsm_04_08.h>
Harald Welte1523d702010-08-04 11:46:44 +020035#include <osmocore/gsm48_ie.h>
Harald Welte1e908662010-03-07 23:39:54 +010036
37static const char bcd_num_digits[] = {
38 '0', '1', '2', '3', '4', '5', '6', '7',
39 '8', '9', '*', '#', 'a', 'b', 'c', '\0'
40};
41
42/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */
43int gsm48_decode_bcd_number(char *output, int output_len,
44 const uint8_t *bcd_lv, int h_len)
45{
46 uint8_t in_len = bcd_lv[0];
47 int i;
48
49 for (i = 1 + h_len; i <= in_len; i++) {
50 /* lower nibble */
51 output_len--;
52 if (output_len <= 1)
53 break;
54 *output++ = bcd_num_digits[bcd_lv[i] & 0xf];
55
56 /* higher nibble */
57 output_len--;
58 if (output_len <= 1)
59 break;
60 *output++ = bcd_num_digits[bcd_lv[i] >> 4];
61 }
62 if (output_len >= 1)
63 *output++ = '\0';
64
65 return 0;
66}
67
68/* convert a single ASCII character to call-control BCD */
69static int asc_to_bcd(const char asc)
70{
71 int i;
72
73 for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) {
74 if (bcd_num_digits[i] == asc)
75 return i;
76 }
77 return -EINVAL;
78}
79
80/* convert a ASCII phone number to 'called/calling/connect party BCD number' */
81int gsm48_encode_bcd_number(uint8_t *bcd_lv, uint8_t max_len,
82 int h_len, const char *input)
83{
84 int in_len = strlen(input);
85 int i;
86 uint8_t *bcd_cur = bcd_lv + 1 + h_len;
87
88 /* two digits per byte, plus type byte */
89 bcd_lv[0] = in_len/2 + h_len;
90 if (in_len % 2)
91 bcd_lv[0]++;
92
93 if (bcd_lv[0] > max_len)
94 return -EIO;
95
96 for (i = 0; i < in_len; i++) {
97 int rc = asc_to_bcd(input[i]);
98 if (rc < 0)
99 return rc;
100 if (i % 2 == 0)
101 *bcd_cur = rc;
102 else
103 *bcd_cur++ |= (rc << 4);
104 }
105 /* append padding nibble in case of odd length */
106 if (i % 2)
107 *bcd_cur++ |= 0xf0;
108
109 /* return how many bytes we used */
110 return (bcd_cur - bcd_lv);
111}
112
113/* decode 'bearer capability' */
114int gsm48_decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
115 const uint8_t *lv)
116{
117 uint8_t in_len = lv[0];
118 int i, s;
119
120 if (in_len < 1)
121 return -EINVAL;
122
123 bcap->speech_ver[0] = -1; /* end of list, of maximum 7 values */
124
125 /* octet 3 */
126 bcap->transfer = lv[1] & 0x07;
127 bcap->mode = (lv[1] & 0x08) >> 3;
128 bcap->coding = (lv[1] & 0x10) >> 4;
129 bcap->radio = (lv[1] & 0x60) >> 5;
130
131 if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) {
132 i = 1;
133 s = 0;
134 while(!(lv[i] & 0x80)) {
135 i++; /* octet 3a etc */
136 if (in_len < i)
137 return 0;
138 bcap->speech_ver[s++] = lv[i] & 0x0f;
139 bcap->speech_ver[s] = -1; /* end of list */
140 if (i == 2) /* octet 3a */
141 bcap->speech_ctm = (lv[i] & 0x20) >> 5;
142 if (s == 7) /* maximum speech versions + end of list */
143 return 0;
144 }
145 } else {
146 i = 1;
147 while (!(lv[i] & 0x80)) {
148 i++; /* octet 3a etc */
149 if (in_len < i)
150 return 0;
151 /* ignore them */
152 }
153 /* FIXME: implement OCTET 4+ parsing */
154 }
155
156 return 0;
157}
158
159/* encode 'bearer capability' */
160int gsm48_encode_bearer_cap(struct msgb *msg, int lv_only,
161 const struct gsm_mncc_bearer_cap *bcap)
162{
163 uint8_t lv[32 + 1];
164 int i = 1, s;
165
166 lv[1] = bcap->transfer;
167 lv[1] |= bcap->mode << 3;
168 lv[1] |= bcap->coding << 4;
169 lv[1] |= bcap->radio << 5;
170
171 if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) {
172 for (s = 0; bcap->speech_ver[s] >= 0; s++) {
173 i++; /* octet 3a etc */
174 lv[i] = bcap->speech_ver[s];
175 if (i == 2) /* octet 3a */
176 lv[i] |= bcap->speech_ctm << 5;
177 }
178 lv[i] |= 0x80; /* last IE of octet 3 etc */
179 } else {
180 /* FIXME: implement OCTET 4+ encoding */
181 }
182
183 lv[0] = i;
184 if (lv_only)
185 msgb_lv_put(msg, lv[0], lv+1);
186 else
187 msgb_tlv_put(msg, GSM48_IE_BEARER_CAP, lv[0], lv+1);
188
189 return 0;
190}
191
192/* decode 'call control cap' */
193int gsm48_decode_cccap(struct gsm_mncc_cccap *ccap, const uint8_t *lv)
194{
195 uint8_t in_len = lv[0];
196
197 if (in_len < 1)
198 return -EINVAL;
199
200 /* octet 3 */
201 ccap->dtmf = lv[1] & 0x01;
202 ccap->pcp = (lv[1] & 0x02) >> 1;
203
204 return 0;
205}
206
207/* encode 'call control cap' */
208int gsm48_encode_cccap(struct msgb *msg,
209 const struct gsm_mncc_cccap *ccap)
210{
211 uint8_t lv[2];
212
213 lv[0] = 1;
214 lv[1] = 0;
215 if (ccap->dtmf)
216 lv [1] |= 0x01;
217 if (ccap->pcp)
218 lv [1] |= 0x02;
219
220 msgb_tlv_put(msg, GSM48_IE_CC_CAP, lv[0], lv+1);
221
222 return 0;
223}
224
225/* decode 'called party BCD number' */
226int gsm48_decode_called(struct gsm_mncc_number *called,
227 const uint8_t *lv)
228{
229 uint8_t in_len = lv[0];
230
231 if (in_len < 1)
232 return -EINVAL;
233
234 /* octet 3 */
235 called->plan = lv[1] & 0x0f;
236 called->type = (lv[1] & 0x70) >> 4;
237
238 /* octet 4..N */
239 gsm48_decode_bcd_number(called->number, sizeof(called->number), lv, 1);
240
241 return 0;
242}
243
244/* encode 'called party BCD number' */
245int gsm48_encode_called(struct msgb *msg,
246 const struct gsm_mncc_number *called)
247{
248 uint8_t lv[18];
249 int ret;
250
251 /* octet 3 */
252 lv[1] = called->plan;
253 lv[1] |= called->type << 4;
254
255 /* octet 4..N, octet 2 */
256 ret = gsm48_encode_bcd_number(lv, sizeof(lv), 1, called->number);
257 if (ret < 0)
258 return ret;
259
260 msgb_tlv_put(msg, GSM48_IE_CALLED_BCD, lv[0], lv+1);
261
262 return 0;
263}
264
265/* decode callerid of various IEs */
266int gsm48_decode_callerid(struct gsm_mncc_number *callerid,
267 const uint8_t *lv)
268{
269 uint8_t in_len = lv[0];
270 int i = 1;
271
272 if (in_len < 1)
273 return -EINVAL;
274
275 /* octet 3 */
276 callerid->plan = lv[1] & 0x0f;
277 callerid->type = (lv[1] & 0x70) >> 4;
278
279 /* octet 3a */
280 if (!(lv[1] & 0x80)) {
281 callerid->screen = lv[2] & 0x03;
282 callerid->present = (lv[2] & 0x60) >> 5;
283 i = 2;
284 }
285
286 /* octet 4..N */
287 gsm48_decode_bcd_number(callerid->number, sizeof(callerid->number), lv, i);
288
289 return 0;
290}
291
292/* encode callerid of various IEs */
293int gsm48_encode_callerid(struct msgb *msg, int ie, int max_len,
294 const struct gsm_mncc_number *callerid)
295{
296 uint8_t lv[max_len - 1];
297 int h_len = 1;
298 int ret;
299
300 /* octet 3 */
301 lv[1] = callerid->plan;
302 lv[1] |= callerid->type << 4;
303
304 if (callerid->present || callerid->screen) {
305 /* octet 3a */
306 lv[2] = callerid->screen;
307 lv[2] |= callerid->present << 5;
308 lv[2] |= 0x80;
309 h_len++;
310 } else
311 lv[1] |= 0x80;
312
313 /* octet 4..N, octet 2 */
314 ret = gsm48_encode_bcd_number(lv, sizeof(lv), h_len, callerid->number);
315 if (ret < 0)
316 return ret;
317
318 msgb_tlv_put(msg, ie, lv[0], lv+1);
319
320 return 0;
321}
322
323/* decode 'cause' */
324int gsm48_decode_cause(struct gsm_mncc_cause *cause,
325 const uint8_t *lv)
326{
327 uint8_t in_len = lv[0];
328 int i;
329
330 if (in_len < 2)
331 return -EINVAL;
332
333 cause->diag_len = 0;
334
335 /* octet 3 */
336 cause->location = lv[1] & 0x0f;
337 cause->coding = (lv[1] & 0x60) >> 5;
338
339 i = 1;
340 if (!(lv[i] & 0x80)) {
341 i++; /* octet 3a */
342 if (in_len < i+1)
343 return 0;
344 cause->rec = 1;
345 cause->rec_val = lv[i] & 0x7f;
346 }
347 i++;
348
349 /* octet 4 */
350 cause->value = lv[i] & 0x7f;
351 i++;
352
353 if (in_len < i) /* no diag */
354 return 0;
355
356 if (in_len - (i-1) > 32) /* maximum 32 octets */
357 return 0;
358
359 /* octet 5-N */
360 memcpy(cause->diag, lv + i, in_len - (i-1));
361 cause->diag_len = in_len - (i-1);
362
363 return 0;
364}
365
366/* encode 'cause' */
367int gsm48_encode_cause(struct msgb *msg, int lv_only,
368 const struct gsm_mncc_cause *cause)
369{
370 uint8_t lv[32+4];
371 int i;
372
373 if (cause->diag_len > 32)
374 return -EINVAL;
375
376 /* octet 3 */
377 lv[1] = cause->location;
378 lv[1] |= cause->coding << 5;
379
380 i = 1;
381 if (cause->rec) {
382 i++; /* octet 3a */
383 lv[i] = cause->rec_val;
384 }
385 lv[i] |= 0x80; /* end of octet 3 */
386
387 /* octet 4 */
388 i++;
389 lv[i] = 0x80 | cause->value;
390
391 /* octet 5-N */
392 if (cause->diag_len) {
393 memcpy(lv + i, cause->diag, cause->diag_len);
394 i += cause->diag_len;
395 }
396
397 lv[0] = i;
398 if (lv_only)
399 msgb_lv_put(msg, lv[0], lv+1);
400 else
401 msgb_tlv_put(msg, GSM48_IE_CAUSE, lv[0], lv+1);
402
403 return 0;
404}
405
406/* decode 'calling number' */
407int gsm48_decode_calling(struct gsm_mncc_number *calling,
408 const uint8_t *lv)
409{
410 return gsm48_decode_callerid(calling, lv);
411}
412
413/* encode 'calling number' */
414int gsm48_encode_calling(struct msgb *msg,
415 const struct gsm_mncc_number *calling)
416{
417 return gsm48_encode_callerid(msg, GSM48_IE_CALLING_BCD, 14, calling);
418}
419
420/* decode 'connected number' */
421int gsm48_decode_connected(struct gsm_mncc_number *connected,
422 const uint8_t *lv)
423{
424 return gsm48_decode_callerid(connected, lv);
425}
426
427/* encode 'connected number' */
428int gsm48_encode_connected(struct msgb *msg,
429 const struct gsm_mncc_number *connected)
430{
431 return gsm48_encode_callerid(msg, GSM48_IE_CONN_BCD, 14, connected);
432}
433
434/* decode 'redirecting number' */
435int gsm48_decode_redirecting(struct gsm_mncc_number *redirecting,
436 const uint8_t *lv)
437{
438 return gsm48_decode_callerid(redirecting, lv);
439}
440
441/* encode 'redirecting number' */
442int gsm48_encode_redirecting(struct msgb *msg,
443 const struct gsm_mncc_number *redirecting)
444{
445 return gsm48_encode_callerid(msg, GSM48_IE_REDIR_BCD, 19, redirecting);
446}
447
448/* decode 'facility' */
449int gsm48_decode_facility(struct gsm_mncc_facility *facility,
450 const uint8_t *lv)
451{
452 uint8_t in_len = lv[0];
453
454 if (in_len < 1)
455 return -EINVAL;
456
457 if (in_len > sizeof(facility->info))
458 return -EINVAL;
459
460 memcpy(facility->info, lv+1, in_len);
461 facility->len = in_len;
462
463 return 0;
464}
465
466/* encode 'facility' */
467int gsm48_encode_facility(struct msgb *msg, int lv_only,
468 const struct gsm_mncc_facility *facility)
469{
470 uint8_t lv[GSM_MAX_FACILITY + 1];
471
472 if (facility->len < 1 || facility->len > GSM_MAX_FACILITY)
473 return -EINVAL;
474
475 memcpy(lv+1, facility->info, facility->len);
476 lv[0] = facility->len;
477 if (lv_only)
478 msgb_lv_put(msg, lv[0], lv+1);
479 else
480 msgb_tlv_put(msg, GSM48_IE_FACILITY, lv[0], lv+1);
481
482 return 0;
483}
484
485/* decode 'notify' */
486int gsm48_decode_notify(int *notify, const uint8_t *v)
487{
488 *notify = v[0] & 0x7f;
489
490 return 0;
491}
492
493/* encode 'notify' */
494int gsm48_encode_notify(struct msgb *msg, int notify)
495{
496 msgb_v_put(msg, notify | 0x80);
497
498 return 0;
499}
500
501/* decode 'signal' */
502int gsm48_decode_signal(int *signal, const uint8_t *v)
503{
504 *signal = v[0];
505
506 return 0;
507}
508
509/* encode 'signal' */
510int gsm48_encode_signal(struct msgb *msg, int signal)
511{
512 msgb_tv_put(msg, GSM48_IE_SIGNAL, signal);
513
514 return 0;
515}
516
517/* decode 'keypad' */
518int gsm48_decode_keypad(int *keypad, const uint8_t *lv)
519{
520 uint8_t in_len = lv[0];
521
522 if (in_len < 1)
523 return -EINVAL;
524
525 *keypad = lv[1] & 0x7f;
526
527 return 0;
528}
529
530/* encode 'keypad' */
531int gsm48_encode_keypad(struct msgb *msg, int keypad)
532{
533 msgb_tv_put(msg, GSM48_IE_KPD_FACILITY, keypad);
534
535 return 0;
536}
537
538/* decode 'progress' */
539int gsm48_decode_progress(struct gsm_mncc_progress *progress,
540 const uint8_t *lv)
541{
542 uint8_t in_len = lv[0];
543
544 if (in_len < 2)
545 return -EINVAL;
546
547 progress->coding = (lv[1] & 0x60) >> 5;
548 progress->location = lv[1] & 0x0f;
549 progress->descr = lv[2] & 0x7f;
550
551 return 0;
552}
553
554/* encode 'progress' */
555int gsm48_encode_progress(struct msgb *msg, int lv_only,
556 const struct gsm_mncc_progress *p)
557{
558 uint8_t lv[3];
559
560 lv[0] = 2;
561 lv[1] = 0x80 | ((p->coding & 0x3) << 5) | (p->location & 0xf);
562 lv[2] = 0x80 | (p->descr & 0x7f);
563 if (lv_only)
564 msgb_lv_put(msg, lv[0], lv+1);
565 else
566 msgb_tlv_put(msg, GSM48_IE_PROGR_IND, lv[0], lv+1);
567
568 return 0;
569}
570
571/* decode 'user-user' */
572int gsm48_decode_useruser(struct gsm_mncc_useruser *uu,
573 const uint8_t *lv)
574{
575 uint8_t in_len = lv[0];
576 char *info = uu->info;
577 int info_len = sizeof(uu->info);
578 int i;
579
580 if (in_len < 1)
581 return -EINVAL;
582
583 uu->proto = lv[1];
584
585 for (i = 2; i <= in_len; i++) {
586 info_len--;
587 if (info_len <= 1)
588 break;
589 *info++ = lv[i];
590 }
591 if (info_len >= 1)
592 *info++ = '\0';
593
594 return 0;
595}
596
597/* encode 'useruser' */
598int gsm48_encode_useruser(struct msgb *msg, int lv_only,
599 const struct gsm_mncc_useruser *uu)
600{
601 uint8_t lv[GSM_MAX_USERUSER + 2];
602
603 if (strlen(uu->info) > GSM_MAX_USERUSER)
604 return -EINVAL;
605
606 lv[0] = 1 + strlen(uu->info);
607 lv[1] = uu->proto;
608 memcpy(lv + 2, uu->info, strlen(uu->info));
609 if (lv_only)
610 msgb_lv_put(msg, lv[0], lv+1);
611 else
612 msgb_tlv_put(msg, GSM48_IE_USER_USER, lv[0], lv+1);
613
614 return 0;
615}
616
617/* decode 'ss version' */
618int gsm48_decode_ssversion(struct gsm_mncc_ssversion *ssv,
619 const uint8_t *lv)
620{
621 uint8_t in_len = lv[0];
622
623 if (in_len < 1 || in_len < sizeof(ssv->info))
624 return -EINVAL;
625
626 memcpy(ssv->info, lv + 1, in_len);
627 ssv->len = in_len;
628
629 return 0;
630}
631
632/* encode 'ss version' */
633int gsm48_encode_ssversion(struct msgb *msg,
634 const struct gsm_mncc_ssversion *ssv)
635{
636 uint8_t lv[GSM_MAX_SSVERSION + 1];
637
638 if (ssv->len > GSM_MAX_SSVERSION)
639 return -EINVAL;
640
641 lv[0] = ssv->len;
642 memcpy(lv + 1, ssv->info, ssv->len);
643 msgb_tlv_put(msg, GSM48_IE_SS_VERS, lv[0], lv+1);
644
645 return 0;
646}
647
648/* decode 'more data' does not require a function, because it has no value */
649
650/* encode 'more data' */
651int gsm48_encode_more(struct msgb *msg)
652{
653 uint8_t *ie;
654
655 ie = msgb_put(msg, 1);
656 ie[0] = GSM48_IE_MORE_DATA;
657
658 return 0;
659}
660
Harald Welte1523d702010-08-04 11:46:44 +0200661/* decode "Cell Channel Description" (10.5.2.1b) and other frequency lists */
662int gsm48_decode_freq_list(struct gsm_sysinfo_freq *f, uint8_t *cd,
663 uint8_t len, uint8_t mask, uint8_t frqt)
664{
665 int i;
666
667 /* NOTES:
668 *
669 * The Range format uses "SMOD" computation.
670 * e.g. "n SMOD m" equals "((n - 1) % m) + 1"
671 * A cascade of multiple SMOD computations is simpified:
672 * "(n SMOD m) SMOD o" equals "(((n - 1) % m) % o) + 1"
673 *
674 * The Range format uses 16 octets of data in SYSTEM INFORMATION.
675 * When used in dedicated messages, the length can be less.
676 * In this case the ranges are decoded for all frequencies that
677 * fit in the block of given length.
678 */
679
680 /* tabula rasa */
681 for (i = 0; i < 1024; i++)
682 f[i].mask &= ~frqt;
683
684 /* 00..XXX. */
685 if ((cd[0] & 0xc0 & mask) == 0x00) {
686 /* Bit map 0 format */
687 if (len < 16)
688 return -EINVAL;
689 for (i = 1; i <= 124; i++)
690 if ((cd[15 - ((i-1) >> 3)] & (1 << ((i-1) & 7))))
691 f[i].mask |= frqt;
692
693 return 0;
694 }
695
696 /* 10..0XX. */
697 if ((cd[0] & 0xc8 & mask) == 0x80) {
698 /* Range 1024 format */
699 uint16_t w[17]; /* 1..16 */
700 struct gsm48_range_1024 *r = (struct gsm48_range_1024 *)cd;
701
702 if (len < 2)
703 return -EINVAL;
704 memset(w, 0, sizeof(w));
705 if (r->f0)
706 f[0].mask |= frqt;
707 w[1] = (r->w1_hi << 8) | r->w1_lo;
708 if (len >= 4)
709 w[2] = (r->w2_hi << 1) | r->w2_lo;
710 if (len >= 5)
711 w[3] = (r->w3_hi << 2) | r->w3_lo;
712 if (len >= 6)
713 w[4] = (r->w4_hi << 2) | r->w4_lo;
714 if (len >= 7)
715 w[5] = (r->w5_hi << 2) | r->w5_lo;
716 if (len >= 8)
717 w[6] = (r->w6_hi << 2) | r->w6_lo;
718 if (len >= 9)
719 w[7] = (r->w7_hi << 2) | r->w7_lo;
720 if (len >= 10)
721 w[8] = (r->w8_hi << 1) | r->w8_lo;
722 if (len >= 10)
723 w[9] = r->w9;
724 if (len >= 11)
725 w[10] = r->w10;
726 if (len >= 12)
727 w[11] = (r->w11_hi << 6) | r->w11_lo;
728 if (len >= 13)
729 w[12] = (r->w12_hi << 5) | r->w12_lo;
730 if (len >= 14)
731 w[13] = (r->w13_hi << 4) | r->w13_lo;
732 if (len >= 15)
733 w[14] = (r->w14_hi << 3) | r->w14_lo;
734 if (len >= 16)
735 w[15] = (r->w15_hi << 2) | r->w15_lo;
736 if (len >= 16)
737 w[16] = r->w16;
738 if (w[1])
739 f[w[1]].mask |= frqt;
740 if (w[2])
741 f[((w[1] - 512 + w[2] - 1) % 1023) + 1].mask |= frqt;
742 if (w[3])
743 f[((w[1] + w[3] - 1) % 1023) + 1].mask |= frqt;
744 if (w[4])
745 f[((w[1] - 512 + ((w[2] - 256 + w[4] - 1) % 511)) % 1023) + 1].mask |= frqt;
746 if (w[5])
747 f[((w[1] + ((w[3] - 256 - w[5] - 1) % 511)) % 1023) + 1].mask |= frqt;
748 if (w[6])
749 f[((w[1] - 512 + ((w[2] + w[6] - 1) % 511)) % 1023) + 1].mask |= frqt;
750 if (w[7])
751 f[((w[1] + ((w[3] + w[7] - 1) % 511)) % 1023) + 1].mask |= frqt;
752 if (w[8])
753 f[((w[1] - 512 + ((w[2] - 256 + ((w[4] - 128 + w[8] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
754 if (w[9])
755 f[((w[1] + ((w[3] - 256 + ((w[5] - 128 + w[9] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
756 if (w[10])
757 f[((w[1] - 512 + ((w[2] + ((w[6] - 128 + w[10] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
758 if (w[11])
759 f[((w[1] + ((w[3] + ((w[7] - 128 + w[11] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
760 if (w[12])
761 f[((w[1] - 512 + ((w[2] - 256 + ((w[4] + w[12] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
762 if (w[13])
763 f[((w[1] + ((w[3] - 256 + ((w[5] + w[13] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
764 if (w[14])
765 f[((w[1] - 512 + ((w[2] + ((w[6] + w[14] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
766 if (w[15])
767 f[((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
768 if (w[16])
769 f[((w[1] - 512 + ((w[2] - 256 + ((w[4] - 128 + ((w[8] - 64 + w[16] - 1) % 127)) % 255)) % 511)) % 1023) + 1].mask |= frqt;
770
771 return 0;
772 }
773 /* 10..100. */
774 if ((cd[0] & 0xce & mask) == 0x88) {
775 /* Range 512 format */
776 uint16_t w[18]; /* 1..17 */
777 struct gsm48_range_512 *r = (struct gsm48_range_512 *)cd;
778
779 if (len < 4)
780 return -EINVAL;
781 memset(w, 0, sizeof(w));
782 w[0] = (r->orig_arfcn_hi << 9) | (r->orig_arfcn_mid << 1) | r->orig_arfcn_lo;
783 w[1] = (r->w1_hi << 2) | r->w1_lo;
784 if (len >= 5)
785 w[2] = (r->w2_hi << 2) | r->w2_lo;
786 if (len >= 6)
787 w[3] = (r->w3_hi << 2) | r->w3_lo;
788 if (len >= 7)
789 w[4] = (r->w4_hi << 1) | r->w4_lo;
790 if (len >= 7)
791 w[5] = r->w5;
792 if (len >= 8)
793 w[6] = r->w6;
794 if (len >= 9)
795 w[7] = (r->w7_hi << 6) | r->w7_lo;
796 if (len >= 10)
797 w[8] = (r->w8_hi << 4) | r->w8_lo;
798 if (len >= 11)
799 w[9] = (r->w9_hi << 2) | r->w9_lo;
800 if (len >= 11)
801 w[10] = r->w10;
802 if (len >= 12)
803 w[11] = r->w11;
804 if (len >= 13)
805 w[12] = (r->w12_hi << 4) | r->w12_lo;
806 if (len >= 14)
807 w[13] = (r->w13_hi << 2) | r->w13_lo;
808 if (len >= 14)
809 w[14] = r->w14;
810 if (len >= 15)
811 w[15] = r->w15;
812 if (len >= 16)
813 w[16] = (r->w16_hi << 3) | r->w16_lo;
814 if (len >= 16)
815 w[17] = r->w17;
816 f[w[0]].mask |= frqt;
817 if (w[1])
818 f[(w[0] + w[1]) % 1024].mask |= frqt;
819 if (w[2])
820 f[(w[0] + ((w[1] - 256 + w[2] - 1) % 511) + 1) % 1024].mask |= frqt;
821 if (w[3])
822 f[(w[0] + ((w[1] + w[3] - 1) % 511) + 1) % 1024].mask |= frqt;
823 if (w[4])
824 f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + w[4] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt;
825 if (w[5])
826 f[(w[0] + ((w[1] + ((w[3] - 128 + w[5] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt;
827 if (w[6])
828 f[(w[0] + ((w[1] - 256 + ((w[2] + w[6] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt;
829 if (w[7])
830 f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt;
831 if (w[8])
832 f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + ((w[4] - 64 + w[8] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
833 if (w[9])
834 f[(w[0] + ((w[1] + ((w[3] - 128 + ((w[5] - 64 + w[9] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
835 if (w[10])
836 f[(w[0] + ((w[1] - 256 + ((w[2] + ((w[6] - 64 + w[10] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
837 if (w[11])
838 f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 64 + w[11] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
839 if (w[12])
840 f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + ((w[4] + w[12] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
841 if (w[13])
842 f[(w[0] + ((w[1] + ((w[3] - 128 + ((w[5] + w[13] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
843 if (w[14])
844 f[(w[0] + ((w[1] - 256 + ((w[2] + ((w[6] + w[14] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
845 if (w[15])
846 f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
847 if (w[16])
848 f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + ((w[4] - 64 + ((w[8] - 32 + w[16] - 1) % 63)) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
849 if (w[17])
850 f[(w[0] + ((w[1] + ((w[3] - 128 + ((w[5] - 64 + ((w[9] - 32 + w[17] - 1) % 63)) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
851
852 return 0;
853 }
854 /* 10..101. */
855 if ((cd[0] & 0xce & mask) == 0x8a) {
856 /* Range 256 format */
857 uint16_t w[22]; /* 1..21 */
858 struct gsm48_range_256 *r = (struct gsm48_range_256 *)cd;
859
860 if (len < 4)
861 return -EINVAL;
862 memset(w, 0, sizeof(w));
863 w[0] = (r->orig_arfcn_hi << 9) | (r->orig_arfcn_mid << 1) | r->orig_arfcn_lo;
864 w[1] = (r->w1_hi << 1) | r->w1_lo;
865 if (len >= 4)
866 w[2] = r->w2;
867 if (len >= 5)
868 w[3] = r->w3;
869 if (len >= 6)
870 w[4] = (r->w4_hi << 5) | r->w4_lo;
871 if (len >= 7)
872 w[5] = (r->w5_hi << 3) | r->w5_lo;
873 if (len >= 8)
874 w[6] = (r->w6_hi << 1) | r->w6_lo;
875 if (len >= 8)
876 w[7] = r->w7;
877 if (len >= 9)
878 w[8] = (r->w8_hi << 4) | r->w8_lo;
879 if (len >= 10)
880 w[9] = (r->w9_hi << 1) | r->w9_lo;
881 if (len >= 10)
882 w[10] = r->w10;
883 if (len >= 11)
884 w[11] = (r->w11_hi << 3) | r->w11_lo;
885 if (len >= 11)
886 w[12] = r->w12;
887 if (len >= 12)
888 w[13] = r->w13;
889 if (len >= 13)
890 w[14] = r->w15;
891 if (len >= 13)
892 w[15] = (r->w14_hi << 2) | r->w14_lo;
893 if (len >= 14)
894 w[16] = (r->w16_hi << 3) | r->w16_lo;
895 if (len >= 14)
896 w[17] = r->w17;
897 if (len >= 15)
898 w[18] = r->w19;
899 if (len >= 15)
900 w[19] = (r->w18_hi << 3) | r->w18_lo;
901 if (len >= 16)
902 w[20] = (r->w20_hi << 3) | r->w20_lo;
903 if (len >= 16)
904 w[21] = r->w21;
905 f[w[0]].mask |= frqt;
906 if (w[1])
907 f[(w[0] + w[1]) % 1024].mask |= frqt;
908 if (w[2])
909 f[(w[0] + ((w[1] - 128 + w[2] - 1) % 255) + 1) % 1024].mask |= frqt;
910 if (w[3])
911 f[(w[0] + ((w[1] + w[3] - 1) % 255) + 1) % 1024].mask |= frqt;
912 if (w[4])
913 f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + w[4] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt;
914 if (w[5])
915 f[(w[0] + ((w[1] + ((w[3] - 64 + w[5] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt;
916 if (w[6])
917 f[(w[0] + ((w[1] - 128 + ((w[2] + w[6] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt;
918 if (w[7])
919 f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt;
920 if (w[8])
921 f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] - 32 + w[8] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
922 if (w[9])
923 f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] - 32 + w[9] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
924 if (w[10])
925 f[(w[0] + ((w[1] - 128 + ((w[2] + ((w[6] - 32 + w[10] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
926 if (w[11])
927 f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 32 + w[11] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
928 if (w[12])
929 f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] + w[12] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
930 if (w[13])
931 f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] + w[13] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
932 if (w[14])
933 f[(w[0] + ((w[1] - 128 + ((w[2] + ((w[6] + w[14] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
934 if (w[15])
935 f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
936 if (w[16])
937 f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] - 32 + ((w[8] - 16 + w[16] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
938 if (w[17])
939 f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] - 32 + ((w[9] - 16 + w[17] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
940 if (w[18])
941 f[(w[0] + ((w[1] - 128 + ((w[2] + ((w[6] - 32 + ((w[10] - 16 + w[18] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
942 if (w[19])
943 f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 32 + ((w[11] - 16 + w[19] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
944 if (w[20])
945 f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] + ((w[12] - 16 + w[20] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
946 if (w[21])
947 f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] + ((w[13] - 16 + w[21] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
948
949 return 0;
950 }
951 /* 10..110. */
952 if ((cd[0] & 0xce & mask) == 0x8c) {
953 /* Range 128 format */
954 uint16_t w[29]; /* 1..28 */
955 struct gsm48_range_128 *r = (struct gsm48_range_128 *)cd;
956
957 if (len < 3)
958 return -EINVAL;
959 memset(w, 0, sizeof(w));
960 w[0] = (r->orig_arfcn_hi << 9) | (r->orig_arfcn_mid << 1) | r->orig_arfcn_lo;
961 w[1] = r->w1;
962 if (len >= 4)
963 w[2] = r->w2;
964 if (len >= 5)
965 w[3] = (r->w3_hi << 4) | r->w3_lo;
966 if (len >= 6)
967 w[4] = (r->w4_hi << 1) | r->w4_lo;
968 if (len >= 6)
969 w[5] = r->w5;
970 if (len >= 7)
971 w[6] = (r->w6_hi << 3) | r->w6_lo;
972 if (len >= 7)
973 w[7] = r->w7;
974 if (len >= 8)
975 w[8] = r->w8;
976 if (len >= 8)
977 w[9] = r->w9;
978 if (len >= 9)
979 w[10] = r->w10;
980 if (len >= 9)
981 w[11] = r->w11;
982 if (len >= 10)
983 w[12] = r->w12;
984 if (len >= 10)
985 w[13] = r->w13;
986 if (len >= 11)
987 w[14] = r->w14;
988 if (len >= 11)
989 w[15] = r->w15;
990 if (len >= 12)
991 w[16] = r->w16;
992 if (len >= 12)
993 w[17] = r->w17;
994 if (len >= 13)
995 w[18] = (r->w18_hi << 1) | r->w18_lo;
996 if (len >= 13)
997 w[19] = r->w19;
998 if (len >= 13)
999 w[20] = r->w20;
1000 if (len >= 14)
1001 w[21] = (r->w21_hi << 2) | r->w21_lo;
1002 if (len >= 14)
1003 w[22] = r->w22;
1004 if (len >= 14)
1005 w[23] = r->w23;
1006 if (len >= 15)
1007 w[24] = r->w24;
1008 if (len >= 15)
1009 w[25] = r->w25;
1010 if (len >= 16)
1011 w[26] = (r->w26_hi << 1) | r->w26_lo;
1012 if (len >= 16)
1013 w[27] = r->w27;
1014 if (len >= 16)
1015 w[28] = r->w28;
1016 f[w[0]].mask |= frqt;
1017 if (w[1])
1018 f[(w[0] + w[1]) % 1024].mask |= frqt;
1019 if (w[2])
1020 f[(w[0] + ((w[1] - 64 + w[2] - 1) % 127) + 1) % 1024].mask |= frqt;
1021 if (w[3])
1022 f[(w[0] + ((w[1] + w[3] - 1) % 127) + 1) % 1024].mask |= frqt;
1023 if (w[4])
1024 f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + w[4] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt;
1025 if (w[5])
1026 f[(w[0] + ((w[1] + ((w[3] - 32 + w[5] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt;
1027 if (w[6])
1028 f[(w[0] + ((w[1] - 64 + ((w[2] + w[6] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt;
1029 if (w[7])
1030 f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt;
1031 if (w[8])
1032 f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] - 16 + w[8] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1033 if (w[9])
1034 f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] - 16 + w[9] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1035 if (w[10])
1036 f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] - 16 + w[10] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1037 if (w[11])
1038 f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 16 + w[11] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1039 if (w[12])
1040 f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] + w[12] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1041 if (w[13])
1042 f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] + w[13] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1043 if (w[14])
1044 f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] + w[14] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1045 if (w[15])
1046 f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1047 if (w[16])
1048 f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] - 16 + ((w[8] - 8 + w[16] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1049 if (w[17])
1050 f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] - 16 + ((w[9] - 8 + w[17] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1051 if (w[18])
1052 f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] - 16 + ((w[10] - 8 + w[18] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1053 if (w[19])
1054 f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 16 + ((w[11] - 8 + w[19] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1055 if (w[20])
1056 f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] + ((w[12] - 8 + w[20] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1057 if (w[21])
1058 f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] + ((w[13] - 8 + w[21] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1059 if (w[22])
1060 f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] + ((w[14] - 8 + w[22] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1061 if (w[23])
1062 f[(w[0] + ((w[1] + ((w[3] + ((w[7] + ((w[15] - 8 + w[23] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1063 if (w[24])
1064 f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] - 16 + ((w[8] + w[24] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1065 if (w[25])
1066 f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] - 16 + ((w[9] + w[25] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1067 if (w[26])
1068 f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] - 16 + ((w[10] + w[26] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1069 if (w[27])
1070 f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 16 + ((w[11] + w[27] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1071 if (w[28])
1072 f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] + ((w[12] + w[28] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
1073
1074 return 0;
1075 }
1076 /* 10..111. */
1077 if ((cd[0] & 0xce & mask) == 0x8e) {
1078 /* Variable bitmap format (can be any length >= 3) */
1079 uint16_t orig = 0;
1080 struct gsm48_var_bit *r = (struct gsm48_var_bit *)cd;
1081
1082 if (len < 3)
1083 return -EINVAL;
1084 orig = (r->orig_arfcn_hi << 9) | (r->orig_arfcn_mid << 1) | r->orig_arfcn_lo;
1085 f[orig].mask |= frqt;
1086 for (i = 1; 2 + (i >> 3) < len; i++)
1087 if ((cd[2 + (i >> 3)] & (0x80 >> (i & 7))))
1088 f[(orig + i) % 1024].mask |= frqt;
1089
1090 return 0;
1091 }
1092
1093 return 0;
1094}