comparison decode/pdu-common.c @ 29:aae078d9eaa6

immigrate sms-pdu-decode and pcm-sms-decode here
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 13 Jun 2024 02:39:21 +0000
parents
children
comparison
equal deleted inserted replaced
28:6e925aa54727 29:aae078d9eaa6
1 #include <sys/types.h>
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <strings.h>
7
8 int ascii_ext_mode, global_hexdump_mode;
9
10 u_char pdu[176];
11 unsigned pdu_length;
12
13 static u_char first_octet;
14 static unsigned pdu_ptr;
15 static int dcs_distilled;
16
17 static
18 handle_sca()
19 {
20 unsigned sca_len;
21 char digits[21];
22
23 sca_len = pdu[0];
24 pdu_ptr = 1;
25 if (!sca_len)
26 return(0);
27 if (sca_len < 2 || sca_len > 11) {
28 printf("Decode-Error: invalid SCA length\n");
29 return(-1);
30 }
31 if (pdu_ptr + sca_len > pdu_length) {
32 printf("Decode-Error: SCA goes past PDU end\n");
33 return(-1);
34 }
35 pdu_ptr += sca_len;
36 decode_address_digits(pdu + 2, digits, sc_addr_ndigits(pdu));
37 printf("SCA: %s%s (type 0x%02X)\n", pdu[1] == 0x91 ? "+" : "", digits,
38 pdu[1]);
39 return(0);
40 }
41
42 static
43 handle_first_octet()
44 {
45 if (pdu_ptr >= pdu_length) {
46 printf("Decode-Error: end of PDU before FO\n");
47 return(-1);
48 }
49 first_octet = pdu[pdu_ptr++];
50 printf("First-Octet: 0x%02X\n", first_octet);
51 return(0);
52 }
53
54 static
55 handle_mr()
56 {
57 if (pdu_ptr >= pdu_length) {
58 printf("Decode-Error: end of PDU before MR\n");
59 return(-1);
60 }
61 printf("MR: 0x%02X\n", pdu[pdu_ptr++]);
62 return(0);
63 }
64
65 static
66 handle_user_addr(direction)
67 char *direction;
68 {
69 unsigned addr_field_len, alpha_nsep;
70 char digits[21];
71 u_char alpha_gsm7[11];
72
73 if (pdu_ptr >= pdu_length) {
74 printf("Decode-Error: end of PDU before %s address\n",
75 direction);
76 return(-1);
77 }
78 if (pdu[pdu_ptr] > 20) {
79 printf("Decode-Error: %s address > 20 digits\n", direction);
80 return(-1);
81 }
82 addr_field_len = ((pdu[pdu_ptr] + 1) >> 1) + 2;
83 if (pdu_ptr + addr_field_len > pdu_length) {
84 printf("Decode-Error: %s address goes past PDU end\n",
85 direction);
86 return(-1);
87 }
88 if (!pdu[pdu_ptr])
89 printf("%s: empty-addr (type 0x%02X)\n", direction,
90 pdu[pdu_ptr+1]);
91 else if ((pdu[pdu_ptr+1] & 0x70) == 0x50 &&
92 alpha_addr_valid(pdu[pdu_ptr], &alpha_nsep)) {
93 gsm7_unpack(pdu + pdu_ptr + 2, alpha_gsm7, alpha_nsep);
94 printf("%s: ", direction);
95 print_gsm7_string_to_file(alpha_gsm7, alpha_nsep, stdout);
96 printf(" (type 0x%02X)\n", pdu[pdu_ptr+1]);
97 } else {
98 decode_address_digits(pdu + pdu_ptr + 2, digits, pdu[pdu_ptr]);
99 printf("%s: %s%s (type 0x%02X)\n", direction,
100 pdu[pdu_ptr+1] == 0x91 ? "+" : "", digits,
101 pdu[pdu_ptr+1]);
102 }
103 pdu_ptr += addr_field_len;
104 return(0);
105 }
106
107 static
108 handle_pid()
109 {
110 if (pdu_ptr >= pdu_length) {
111 printf("Decode-Error: end of PDU before PID\n");
112 return(-1);
113 }
114 printf("PID: 0x%02X\n", pdu[pdu_ptr++]);
115 return(0);
116 }
117
118 static
119 handle_dcs()
120 {
121 u_char dcs;
122 char *strtype;
123
124 if (pdu_ptr >= pdu_length) {
125 printf("Decode-Error: end of PDU before DCS\n");
126 return(-1);
127 }
128 dcs = pdu[pdu_ptr++];
129 dcs_distilled = sms_dcs_classify(dcs);
130 switch (dcs_distilled) {
131 case 7:
132 strtype = "7-bit";
133 break;
134 case 8:
135 strtype = "raw octets";
136 break;
137 case 9:
138 strtype = "compressed";
139 break;
140 case 16:
141 strtype = "UCS-2";
142 break;
143 }
144 printf("DCS: 0x%02X (%s)\n", dcs, strtype);
145 return(0);
146 }
147
148 static
149 handle_scts()
150 {
151 char str[21];
152
153 if (pdu_ptr + 7 > pdu_length) {
154 printf("Decode-Error: end of PDU before SCTS\n");
155 return(-1);
156 }
157 gsm_timestamp_decode(pdu + pdu_ptr, str);
158 printf("SC-Timestamp: %s\n", str);
159 pdu_ptr += 7;
160 return(0);
161 }
162
163 static
164 handle_vp_abs()
165 {
166 char str[21];
167
168 if (pdu_ptr + 7 > pdu_length) {
169 printf("Decode-Error: end of PDU before VP-abs\n");
170 return(-1);
171 }
172 gsm_timestamp_decode(pdu + pdu_ptr, str);
173 printf("VP-Absolute: %s\n", str);
174 pdu_ptr += 7;
175 return(0);
176 }
177
178 static
179 handle_vp_rel()
180 {
181 unsigned vprel, hours, min;
182
183 if (pdu_ptr >= pdu_length) {
184 printf("Decode-Error: end of PDU before VP-rel\n");
185 return(-1);
186 }
187 vprel = pdu[pdu_ptr++];
188 if (vprel <= 143) {
189 min = (vprel + 1) * 5;
190 goto hhmm;
191 } else if (vprel <= 167) {
192 min = (vprel - 143) * 30 + 12 * 60;
193 goto hhmm;
194 } else if (vprel <= 196) {
195 printf("VP-Relative: %u days\n", vprel - 166);
196 return(0);
197 } else {
198 printf("VP-Relative: %u weeks\n", vprel - 192);
199 return(0);
200 }
201
202 hhmm: hours = min / 60;
203 min %= 60;
204 printf("VP-Relative:");
205 if (hours)
206 printf(" %u hour%s", hours, hours != 1 ? "s" : "");
207 if (min)
208 printf(" %u min", min);
209 putchar('\n');
210 return(0);
211 }
212
213 static
214 handle_vp_enh()
215 {
216 if (pdu_ptr + 7 > pdu_length) {
217 printf("Decode-Error: end of PDU before VP-enh\n");
218 return(-1);
219 }
220 printf("VP-Enhanced: %02X %02X %02X %02X %02X %02X %02X\n",
221 pdu[pdu_ptr], pdu[pdu_ptr+1], pdu[pdu_ptr+2], pdu[pdu_ptr+3],
222 pdu[pdu_ptr+4], pdu[pdu_ptr+5], pdu[pdu_ptr+6]);
223 pdu_ptr += 7;
224 return(0);
225 }
226
227 static
228 handle_vp()
229 {
230 int rc;
231
232 switch (first_octet & 0x18) {
233 case 0x00:
234 rc = 0;
235 break;
236 case 0x08:
237 rc = handle_vp_enh();
238 break;
239 case 0x10:
240 rc = handle_vp_rel();
241 break;
242 case 0x18:
243 rc = handle_vp_abs();
244 break;
245 }
246 return(rc);
247 }
248
249 process_pdu(require_exact_length, expect_sca)
250 {
251 unsigned udl, udl_octets;
252 unsigned udhl, udh_octets, udh_chars, ud_chars;
253 u_char ud7[160], decode_buf[481];
254 int do_hexdump;
255 unsigned decoded_len;
256
257 if (expect_sca) {
258 if (handle_sca() < 0)
259 return(-1);
260 } else
261 pdu_ptr = 0;
262 if (handle_first_octet() < 0)
263 return(-1);
264 if (first_octet & 2) {
265 printf("Decode-Error: MTI not supported\n");
266 return(-1);
267 }
268 if (first_octet & 1) {
269 if (handle_mr() < 0)
270 return(-1);
271 }
272 if (handle_user_addr(first_octet & 1 ? "To" : "From") < 0)
273 return(-1);
274 if (handle_pid() < 0)
275 return(-1);
276 if (handle_dcs() < 0)
277 return(-1);
278 if (first_octet & 1) {
279 if (handle_vp() < 0)
280 return(-1);
281 } else {
282 if (handle_scts() < 0)
283 return(-1);
284 }
285 if (pdu_ptr >= pdu_length) {
286 printf("Decode-Error: end of PDU before UDL\n");
287 return(-1);
288 }
289 udl = pdu[pdu_ptr++];
290 if (dcs_distilled == 7) {
291 if (udl > 160) {
292 printf("Decode-Error: UDL %u > 160\n", udl);
293 return(-1);
294 }
295 udl_octets = (udl * 7 + 7) / 8;
296 } else {
297 if (udl > 140) {
298 printf("Decode-Error: UDL %u > 140\n", udl);
299 return(-1);
300 }
301 udl_octets = udl;
302 }
303 if (require_exact_length && pdu_length - pdu_ptr != udl_octets) {
304 printf("Decode-Error: UD length in PDU %u != expected %u\n",
305 pdu_length - pdu_ptr, udl_octets);
306 return(-1);
307 }
308 if (first_octet & 0x40) {
309 if (!udl) {
310 printf("Decode-Error: UDHI set with UDL=0\n");
311 return(-1);
312 }
313 udhl = pdu[pdu_ptr];
314 udh_octets = udhl + 1;
315 if (udh_octets > udl_octets) {
316 printf("Decode-Error: UDHL exceeds UDL\n");
317 return(-1);
318 }
319 printf("UDH-Length: %u\n", udhl);
320 if (dcs_distilled == 7)
321 udh_chars = (udh_octets * 8 + 6) / 7;
322 else
323 udh_chars = udh_octets;
324 } else {
325 udhl = 0;
326 udh_octets = 0;
327 udh_chars = 0;
328 }
329 if (udh_chars >= udl) {
330 ud_chars = 0;
331 printf("Length: 0\n");
332 } else {
333 ud_chars = udl - udh_chars;
334 if (dcs_distilled == 7)
335 gsm7_unpack(pdu + pdu_ptr, ud7, udl);
336 if (global_hexdump_mode)
337 do_hexdump = 1;
338 else switch (dcs_distilled) {
339 case 7:
340 do_hexdump = 0;
341 break;
342 case 8:
343 case 9:
344 do_hexdump = 1;
345 break;
346 case 16:
347 if (ud_chars & 1)
348 do_hexdump = 1;
349 else
350 do_hexdump = 0;
351 break;
352 }
353 if (do_hexdump)
354 printf("Length: %u (raw)\n", ud_chars);
355 else {
356 switch (dcs_distilled) {
357 case 7:
358 gsm7_to_ascii_or_ext(ud7 + udh_chars, ud_chars,
359 decode_buf, &decoded_len,
360 ascii_ext_mode, 1);
361 break;
362 case 16:
363 ucs2_to_ascii_or_ext(pdu + pdu_ptr + udh_chars,
364 ud_chars,
365 decode_buf, &decoded_len,
366 ascii_ext_mode, 1);
367 break;
368 }
369 printf("Length: %u", ud_chars);
370 if (decoded_len != ud_chars)
371 printf("->%u", decoded_len);
372 putchar('\n');
373 }
374 }
375
376 if (udhl) {
377 printf("\nUDH:\n");
378 msg_bits_hexdump(pdu + pdu_ptr + 1, udhl);
379 }
380 if (!ud_chars)
381 return(0);
382 putchar('\n');
383 if (do_hexdump) {
384 if (dcs_distilled == 7)
385 msg_bits_hexdump(ud7 + udh_chars, ud_chars);
386 else
387 msg_bits_hexdump(pdu + pdu_ptr + udh_chars, ud_chars);
388 } else
389 puts(decode_buf);
390 return(0);
391 }