aboutsummaryrefslogtreecommitdiffstats
path: root/library/Osmocom_Types.ttcn
blob: d034a74e1cce8780e7875acee2cdf01d7aef6d3e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
/* Osmocom utility type definitions in TTCN-3
 * (C) 2017-2019 Harald Welte <laforge@gnumonks.org>
 * All rights reserved.
 *
 * Released under the terms of GNU General Public License, Version 2 or
 * (at your option) any later version.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

module Osmocom_Types {

import from General_Types all;

type integer uint8_t (0..255) with { variant "unsigned 8 bit" };
type integer uint16_t (0..65535) with { variant "unsigned 16 bit" };
type integer uint24_t (0..16777215) with { variant "unsigned 24 bit" };
type integer uint32_t (0..4294967295) with { variant "unsigned 32 bit" };
type integer uint64_t (0..18446744073709551615) with { variant "unsigned 64 bit" };

type integer int8_t (-128..127) with { variant "8 bit" };
type integer int16_t (-32768..32767) with { variant "16 bit" };

type integer uint1_t (0..1) with { variant "unsigned 1 bit" };
type integer uint2_t (0..3) with { variant "unsigned 2 bit" };
type integer uint3_t (0..7) with { variant "unsigned 3 bit" };
type integer uint4_t (0..15) with { variant "unsigned 4 bit" };
type integer uint5_t (0..31) with { variant "unsigned 5 bit" };
type integer uint6_t (0..63) with { variant "unsigned 6 bit" };
type integer uint7_t (0..127) with { variant "unsigned 7 bit" };
type integer uint9_t (0..511) with { variant "unsigned 9 bit" };
type integer uint10_t (0..1023) with { variant "unsigned 10 bit" };
type integer uint11_t (0..2047) with { variant "unsigned 11 bit" };
type integer uint12_t (0..4095) with { variant "unsigned 12 bit" };
type integer uint13_t (0..8191) with { variant "unsigned 13 bit" };
type integer uint14_t (0..16383) with { variant "unsigned 14 bit" };
type integer uint15_t (0..32767) with { variant "unsigned 15 bit" };
type integer uint40_t (0..1099511627776) with { variant "unsigned 40 bit" };


const uint16_t c_UINT16_MAX := 65535;
const uint32_t c_UINT32_MAX := 4294967295;

/* CSN.1 L/H placeholders */
const BIT1 CSN1_L := '0'B;
const BIT1 CSN1_H := '1'B;

/* based on Linux */
type enumerated AddressFamily {
	AF_UNSPEC	('00'O),
	AF_INET		('02'O),
	AF_INET6	('0a'O)
}

/* like TTCN-3 int2str() but with padding of leading zeroes */
function f_int2str(integer i, integer total_digits) return charstring {
	var charstring istr := int2str(i);
	var charstring padstr := hex2str(int2hex(0, total_digits - lengthof(istr)));
	return padstr & istr;
}

/* return random integer 0 <= ret < max. According to ETSI ES 201 873 C.6.1, rnd() returns *less* than 1, so
	* the returned int will always be ret < max, or ret <= (max-1). */
function f_rnd_int(integer max) return integer {
	return float2int(rnd()*int2float(max));
}

/* return random integer 1 <= ret < max */
function f_rnd_int_nonzero(integer max) return integer {
	return float2int(1.0 + rnd()*int2float(max-1));
}

/* return hexstring composed of random digits */
function f_rnd_hexstring(in integer len, in integer max := 16) return hexstring {
	var integer i;
	var hexstring ret := ''H;
	for (i := 0; i < len; i := i + 1) {
		ret := ret & int2hex(f_rnd_int(max), 1);
	}
	return ret;
}

/* return octetstring composed of random bytes */
function f_rnd_octstring(in integer len) return octetstring {
	var integer i;
	var octetstring ret := ''O;
	for (i := 0; i < len; i := i + 1) {
		ret := ret & int2oct(f_rnd_int(256), 1);
	}
	return ret;
}

/* return ocetstring composed of random bytes, at least 1, maximum 'maxlen' bytes long */
function f_rnd_octstring_rnd_len(in integer maxlen) return octetstring {
	return f_rnd_octstring(f_rnd_int_nonzero(maxlen));
}

/* return bitstring composed of random bits */
function f_rnd_bitstring(in integer len) return bitstring {
	var octetstring oct := f_rnd_octstring(len / 8 + 1);
	return substr(oct2bit(oct), 0, len);
}

function f_rnd_imsi(in hexstring prefix) return hexstring {
	return prefix & f_rnd_hexstring(15 - lengthof(prefix), 10);
}

function f_rnd_imei(in hexstring prefix) return hexstring {
	return prefix & f_rnd_hexstring(14 - lengthof(prefix), 10);
}

function f_rnd_msisdn(in octetstring prefix, integer len := 6) return octetstring {
	return prefix & f_rnd_octstring(len - lengthof(prefix));
}

function f_sleep(float seconds) {
	timer T := seconds;
	T.start;
	T.timeout;
}

function bool2bit(boolean inp) return BIT1 {
	if (inp) {
		return '1'B;
	} else {
		return '0'B;
	}
}

function bool2bit_tmpl(template boolean inp) return template BIT1 {
	if (istemplatekind(inp, "omit")) {
		return omit;
	} else if (istemplatekind(inp, "*")) {
		return *;
	} else if (istemplatekind(inp, "?")) {
		return ?;
	} else {
		if (valueof(inp)) {
			return '1'B;
		} else {
			return '0'B;
		}
	}
}

type record of integer IntegerRecord;

function int2bool(integer int) return boolean {
	if (int != 0) {
		return true;
	} else {
		return false;
	}
}

function int2oct_tmpl(template integer inp, integer num_oct) return template octetstring
{
	if (istemplatekind(inp, "omit")) {
		return omit;
	} else if (istemplatekind(inp, "*")) {
		return *;
	} else if (istemplatekind(inp, "?")) {
		return ?;
	} else {
		return int2oct(valueof(inp), num_oct);
	}
}

function char2oct_tmpl(template charstring inp) return template octetstring
{
	if (istemplatekind(inp, "omit")) {
		return omit;
	} else if (istemplatekind(inp, "*")) {
		return *;
	} else if (istemplatekind(inp, "?")) {
		return ?;
	} else {
		return char2oct(valueof(inp));
	}
}

function hex2str_tmpl(template hexstring inp) return template charstring
{
	if (istemplatekind(inp, "omit")) {
		return omit;
	} else if (istemplatekind(inp, "*")) {
		return *;
	} else if (istemplatekind(inp, "?")) {
		return ?;
	} else {
		return hex2str(valueof(inp));
	}
}

function f_array_contains(IntegerRecord arr, integer key) return boolean {
	for (var integer i:= 0; i< sizeof(arr); i := i + 1) {
		if (arr[i] == key) {
		return true;
			}
	}
	return false;
}

/* re-start given timer in a warning-safe way: Stop (only if running) + start */
function f_timer_safe_restart(timer T) {
	if (T.running) {
		T.stop;
	}
	T.start;
}

/* divide two integers and return rounded-up result */
function f_div_round_up(integer dividend, integer divisor) return integer {
	var integer x := dividend / divisor;
	if (dividend rem divisor != 0) {
		x := x+1;
	}
	return x;
}

function imsi_hex2oct(hexstring imsi) return octetstring {
	var hexstring tmp := ''H;
	var octetstring ret;
	var integer i;

	/* swap nibbles and pad with F if insufficient input nibbles */
	for (i := 0; i < lengthof(imsi); i := i+1) {
		if (i+1 < lengthof(imsi)) {
			tmp := tmp & imsi[i+1];
		} else {
			tmp := tmp & 'F'H;
		}
		tmp := tmp & imsi[i];
		i := i+1;
	}
	ret := hex2oct(tmp);
	return ret;
}

function f_pad_oct(octetstring str, integer len, OCT1 pad) return octetstring {
	var integer strlen := lengthof(str);
	for (var integer i := 0; i < len-strlen; i := i+1) {
		str := str & pad;
	}
	return str;
}

function f_pad_bit(bitstring str, integer len, BIT1 pad) return bitstring {
	var integer strlen := lengthof(str);
	for (var integer i := 0; i < len-strlen; i := i+1) {
		str := str & pad;
	}
	return str;
}

function f_pad_bcd_number(hexstring number) return hexstring {
	if (lengthof(number) mod 2 != 0) {
		return number & 'F'H;
	} else {
		return number;
	}
}

function f_pad_bcd_number_tmpl(template hexstring inp) return template hexstring {
	if (istemplatekind(inp, "omit")) {
		return omit;
	} else if (istemplatekind(inp, "*")) {
		return *;
	} else if (istemplatekind(inp, "?")) {
		return ?;
	} else {
		return f_pad_bcd_number(valueof(inp));
	}
}

/* like L1SAP_IS_PACKET_RACH */
function ra_is_ps(OCT1 ra) return boolean {
	if ((ra and4b 'F0'O == '70'O) and (ra and4b '0F'O != '0F'O)) {
		return true;
	}
	return false;
}

function ra_is_emerg(OCT1 ra) return boolean {
	/* See also: 3GPP TS 04.08, Table 9.9, ra=101xxxxx */
	return (ra and4b 'E0'O == 'A0'O);
}

/* generate a random RACH for circuit-switched */
function f_rnd_ra_cs() return OCT1 {
	var OCT1 ra;
	do {
		ra := f_rnd_octstring(1);
	} while (ra_is_ps(ra) or ra_is_emerg(ra));
	return ra;
}

/* generate a random RACH for emergency */
function f_rnd_ra_emerg() return OCT1 {
	var OCT1 ra;
	do {
		ra := f_rnd_octstring(1);
	} while (not ra_is_emerg(ra));
	return ra;
}

/* generate a random RACH for packet-switched */
function f_rnd_ra_ps() return OCT1 {
	var OCT1 ra;
	do {
		ra := f_rnd_octstring(1);
	} while (not ra_is_ps(ra));
	return ra;
}

/* generate a random 11-bit RA (packet-switched only) */
function f_rnd_ra11_ps() return BIT11 {
	return f_rnd_bitstring(11);
}


private function f_concat_pad(integer tot_len, hexstring prefix, integer suffix) return hexstring {
	var integer suffix_len := tot_len - lengthof(prefix);
	var charstring suffix_ch := int2str(suffix);
	var integer pad_len := suffix_len - lengthof(suffix_ch);

	return prefix & int2hex(0, pad_len) & str2hex(suffix_ch);
}

function f_gen_imei(integer suffix) return hexstring {
	return f_concat_pad(14, '49999'H, suffix);
}

function f_gen_imsi(integer suffix) return hexstring {
	return f_concat_pad(15, '26242'H, suffix);
}

function f_gen_msisdn(integer suffix) return hexstring {
	return f_concat_pad(12, '49123'H, suffix);
}

function f_gen_tmsi(integer suffix, integer nri_v := 0, integer nri_bitlen := 10,
		    OCT4 base_tmsi := '42000023'O) return OCT4 {
	var integer tmsi_int := oct2int(base_tmsi) + suffix;
	var bitstring base_tmsi_bits := int2bit(tmsi_int, 32);
	var bitstring prefix_bits := substr(base_tmsi_bits, 0, 8);
	var bitstring suffix_bits := substr(base_tmsi_bits, 8 + nri_bitlen, 24 - nri_bitlen);
	var bitstring total_bits := prefix_bits & int2bit(nri_v, nri_bitlen) & suffix_bits;
	var OCT4 tmsi := bit2oct(total_bits);

	log("f_gen_tmsi(suffix:=", suffix, ", nri_v:=", nri_v, ", nri_bitlen:=", nri_bitlen,
	    ", base_tmsi:=", base_tmsi, ") -> prefix:=", prefix_bits, ", suffix:=", suffix_bits,
	    ", total_bits:=", total_bits, " == ", tmsi);

	return tmsi;
}

type record of integer ro_integer;

function ro_integer_contains(ro_integer r, integer x) return boolean {
	for (var integer j := 0; j < lengthof(r); j := j+1) {
		if (r[j] == x) {
			return true;
		}
	}
	return false;
}

function ro_integer_add_unique(inout ro_integer roi, integer new_entry)
{
	if (ro_integer_contains(roi, new_entry)) {
		return;
	}
	roi := roi & {new_entry};
}

function ro_integer_del(inout ro_integer roi, integer del_entry)
{
	var ro_integer tmp := {};
	for (var integer j := 0; j < lengthof(roi); j := j+1) {
		if (roi[j] != del_entry) {
			tmp := tmp & { roi[j] };
		}
	}
	roi := tmp;
}

type record of ro_integer roro_integer;

function f_bool2str(boolean val) return charstring {
	if (val) {
		return "true";
	} else {
		return "false";
	}
}

/* Return a reversed bitstring */
function f_bits_reversed(in bitstring bits) return bitstring {
	for (var integer i := 0; i < lengthof(bits) / 2; i := i + 1) {
		var integer reverse_i := lengthof(bits) - 1 - i;
		if (i >= reverse_i) {
			break;
		}
		var bitstring tmp;
		tmp[0] := bits[i];
		bits[i] := bits[reverse_i];
		bits[reverse_i] := tmp[0];
	}
	return bits;
}

} with { encode "RAW"; variant "FIELDORDER(msb)" }