FreeCalypso > hg > freecalypso-tools
comparison uptools/sms-pdu-decode/sms-pdu-decode.c @ 337:560af437a429
sms-pdu-decode main program written, compiles
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 04 Feb 2018 03:32:24 +0000 |
parents | |
children | 7f8f446db97e |
comparison
equal
deleted
inserted
replaced
336:ead4ee22ef62 | 337:560af437a429 |
---|---|
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 #include <unistd.h> | |
8 | |
9 char *infname; | |
10 FILE *inf; | |
11 int ascii_ext_mode, global_hexdump_mode; | |
12 | |
13 char input_line[1024]; | |
14 u_char pdu[176], first_octet; | |
15 unsigned pdu_length, pdu_ptr; | |
16 int dcs_distilled; | |
17 | |
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 handle_first_octet() | |
43 { | |
44 if (pdu_ptr >= pdu_length) { | |
45 printf("Decode-Error: end of PDU before FO\n"); | |
46 return(-1); | |
47 } | |
48 first_octet = pdu[pdu_ptr++]; | |
49 printf("First-Octet: 0x%02X\n", first_octet); | |
50 return(0); | |
51 } | |
52 | |
53 handle_mr() | |
54 { | |
55 if (pdu_ptr >= pdu_length) { | |
56 printf("Decode-Error: end of PDU before MR\n"); | |
57 return(-1); | |
58 } | |
59 printf("MR: 0x%02X\n", pdu[pdu_ptr++]); | |
60 return(0); | |
61 } | |
62 | |
63 handle_user_addr(direction) | |
64 char *direction; | |
65 { | |
66 unsigned addr_field_len, alpha_nsep; | |
67 char digits[21]; | |
68 u_char alpha_gsm7[11], alpha_decoded[23]; | |
69 | |
70 if (pdu_ptr >= pdu_length) { | |
71 printf("Decode-Error: end of PDU before %s address\n", | |
72 direction); | |
73 return(-1); | |
74 } | |
75 if (pdu[pdu_ptr] > 20) { | |
76 printf("Decode-Error: %s address > 20 digits\n", direction); | |
77 return(-1); | |
78 } | |
79 addr_field_len = ((pdu[pdu_ptr] + 1) >> 2) + 2; | |
80 if (pdu_ptr + addr_field_len > pdu_length) { | |
81 printf("Decode-Error: %s address goes past PDU end\n", | |
82 direction); | |
83 return(-1); | |
84 } | |
85 if (!pdu[pdu_ptr]) | |
86 printf("%s: empty-addr (type 0x%02X)\n", direction, | |
87 pdu[pdu_ptr+1]); | |
88 else if ((pdu[pdu_ptr+1] & 0x70) == 0x50 && | |
89 alpha_addr_valid(pdu[pdu_ptr], &alpha_nsep)) { | |
90 gsm7_unpack(pdu + pdu_ptr + 2, alpha_gsm7, alpha_nsep); | |
91 gsm7_to_ascii_or_ext(alpha_gsm7, alpha_nsep, alpha_decoded, 0, | |
92 ascii_ext_mode, 0, 0); | |
93 printf("%s: \"%s\" (type 0x%02X)\n", direction, alpha_decoded, | |
94 pdu[pdu_ptr+1]); | |
95 } else { | |
96 decode_address_digits(pdu + pdu_ptr + 2, digits, pdu[pdu_ptr]); | |
97 printf("%s: %s%s (type 0x%02X)\n", direction, | |
98 pdu[pdu_ptr+1] == 0x91 ? "+" : "", digits, | |
99 pdu[pdu_ptr+1]); | |
100 } | |
101 pdu_ptr += addr_field_len; | |
102 return(0); | |
103 } | |
104 | |
105 handle_pid() | |
106 { | |
107 if (pdu_ptr >= pdu_length) { | |
108 printf("Decode-Error: end of PDU before PID\n"); | |
109 return(-1); | |
110 } | |
111 printf("PID: 0x%02X\n", pdu[pdu_ptr++]); | |
112 return(0); | |
113 } | |
114 | |
115 handle_dcs() | |
116 { | |
117 u_char dcs; | |
118 char *strtype; | |
119 | |
120 if (pdu_ptr >= pdu_length) { | |
121 printf("Decode-Error: end of PDU before DCS\n"); | |
122 return(-1); | |
123 } | |
124 dcs = pdu[pdu_ptr++]; | |
125 dcs_distilled = sms_dcs_classify(dcs); | |
126 switch (dcs_distilled) { | |
127 case 7: | |
128 strtype = "7-bit"; | |
129 break; | |
130 case 8: | |
131 strtype = "raw octets"; | |
132 break; | |
133 case 9: | |
134 strtype = "compressed"; | |
135 break; | |
136 case 16: | |
137 strtype = "UCS-2"; | |
138 break; | |
139 } | |
140 printf("DCS: 0x%02X (%s)\n", dcs, strtype); | |
141 return(0); | |
142 } | |
143 | |
144 handle_scts() | |
145 { | |
146 char str[21]; | |
147 | |
148 if (pdu_ptr + 7 > pdu_length) { | |
149 printf("Decode-Error: end of PDU before SCTS\n"); | |
150 return(-1); | |
151 } | |
152 gsm_timestamp_decode(pdu + pdu_ptr, str); | |
153 printf("SC-Timestamp: %s\n", str); | |
154 pdu_ptr += 7; | |
155 return(0); | |
156 } | |
157 | |
158 handle_vp_abs() | |
159 { | |
160 char str[21]; | |
161 | |
162 if (pdu_ptr + 7 > pdu_length) { | |
163 printf("Decode-Error: end of PDU before VP-abs\n"); | |
164 return(-1); | |
165 } | |
166 gsm_timestamp_decode(pdu + pdu_ptr, str); | |
167 printf("VP-Absolute: %s\n", str); | |
168 pdu_ptr += 7; | |
169 return(0); | |
170 } | |
171 | |
172 handle_vp_rel() | |
173 { | |
174 unsigned vprel, hours, min; | |
175 | |
176 if (pdu_ptr >= pdu_length) { | |
177 printf("Decode-Error: end of PDU before VP-rel\n"); | |
178 return(-1); | |
179 } | |
180 vprel = pdu[pdu_ptr++]; | |
181 if (vprel <= 143) { | |
182 min = (vprel + 1) * 5; | |
183 goto hhmm; | |
184 } else if (vprel <= 167) { | |
185 min = (vprel - 143) * 30 + 12 * 60; | |
186 goto hhmm; | |
187 } else if (vprel <= 196) { | |
188 printf("VP-Relative: %u days\n", vprel - 166); | |
189 return(0); | |
190 } else { | |
191 printf("VP-Relative: %u weeks\n", vprel - 192); | |
192 return(0); | |
193 } | |
194 | |
195 hhmm: hours = min / 60; | |
196 min %= 60; | |
197 printf("VP-Relative: "); | |
198 if (hours) | |
199 printf(" %u hour%s", hours, hours != 1 ? "s" : ""); | |
200 if (min) | |
201 printf(" %u min", min); | |
202 putchar('\n'); | |
203 return(0); | |
204 } | |
205 | |
206 handle_vp_enh() | |
207 { | |
208 if (pdu_ptr + 7 > pdu_length) { | |
209 printf("Decode-Error: end of PDU before VP-enh\n"); | |
210 return(-1); | |
211 } | |
212 printf("VP-Enhanced: %02X %02X %02X %02X %02X %02X %02X\n", | |
213 pdu[pdu_ptr], pdu[pdu_ptr+1], pdu[pdu_ptr+2], pdu[pdu_ptr+3], | |
214 pdu[pdu_ptr+4], pdu[pdu_ptr+5], pdu[pdu_ptr+6]); | |
215 pdu_ptr += 7; | |
216 return(0); | |
217 } | |
218 | |
219 handle_vp() | |
220 { | |
221 int rc; | |
222 | |
223 switch (first_octet & 0x18) { | |
224 case 0x00: | |
225 rc = 0; | |
226 break; | |
227 case 0x08: | |
228 rc = handle_vp_enh(); | |
229 break; | |
230 case 0x10: | |
231 rc = handle_vp_rel(); | |
232 break; | |
233 case 0x18: | |
234 rc = handle_vp_abs(); | |
235 break; | |
236 } | |
237 return(rc); | |
238 } | |
239 | |
240 process_pdu() | |
241 { | |
242 unsigned udl, udl_octets; | |
243 unsigned udhl, udh_octets, udh_chars, ud_chars; | |
244 u_char ud7[160], decode_buf[321]; | |
245 int do_hexdump; | |
246 unsigned decoded_len, badchars; | |
247 | |
248 if (handle_sca() < 0) | |
249 return(-1); | |
250 if (handle_first_octet() < 0) | |
251 return(-1); | |
252 if (first_octet & 2) { | |
253 printf("Decode-Error: MTI not supported\n"); | |
254 return(-1); | |
255 } | |
256 if (first_octet & 1) { | |
257 if (handle_mr() < 0) | |
258 return(-1); | |
259 } | |
260 if (handle_user_addr(first_octet & 1 ? "To" : "From") < 0) | |
261 return(-1); | |
262 if (handle_pid() < 0) | |
263 return(-1); | |
264 if (handle_dcs() < 0) | |
265 return(-1); | |
266 if (first_octet & 1) { | |
267 if (handle_vp() < 0) | |
268 return(-1); | |
269 } else { | |
270 if (handle_scts() < 0) | |
271 return(-1); | |
272 } | |
273 if (pdu_ptr >= pdu_length) { | |
274 printf("Decode-Error: end of PDU before UDL\n"); | |
275 return(-1); | |
276 } | |
277 udl = pdu[pdu_ptr++]; | |
278 if (dcs_distilled == 7) { | |
279 if (udl > 160) { | |
280 printf("Decode-Error: UDL %u > 160\n", udl); | |
281 return(-1); | |
282 } | |
283 udl_octets = (udl * 7 + 7) / 8; | |
284 } else { | |
285 if (udl > 140) { | |
286 printf("Decode-Error: UDL %u > 140\n", udl); | |
287 return(-1); | |
288 } | |
289 udl_octets = udl; | |
290 } | |
291 if (pdu_length - pdu_ptr != udl_octets) { | |
292 printf("Decode-Error: UD length in PDU %u != expected %u\n", | |
293 pdu_length - pdu_ptr, udl_octets); | |
294 return(-1); | |
295 } | |
296 if (first_octet & 0x40) { | |
297 if (!udl) { | |
298 printf("Decode-Error: UDHI set with UDL=0\n"); | |
299 return(-1); | |
300 } | |
301 udhl = pdu[pdu_ptr]; | |
302 udh_octets = udhl + 1; | |
303 if (udh_octets > udl_octets) { | |
304 printf("Decode-Error: UDHL exceeds UDL\n"); | |
305 return(-1); | |
306 } | |
307 printf("UDH-Length: %u\n", udhl); | |
308 if (dcs_distilled == 7) | |
309 udh_chars = (udh_octets * 8 + 6) / 7; | |
310 else | |
311 udh_chars = udh_octets; | |
312 } else { | |
313 udhl = 0; | |
314 udh_octets = 0; | |
315 udh_chars = 0; | |
316 } | |
317 if (udh_chars >= udl) { | |
318 ud_chars = 0; | |
319 printf("Length: 0\n"); | |
320 } else { | |
321 ud_chars = udl - udh_chars; | |
322 if (dcs_distilled == 7) | |
323 gsm7_unpack(pdu + pdu_ptr, ud7, udl); | |
324 if (global_hexdump_mode) | |
325 do_hexdump = 1; | |
326 else switch (dcs_distilled) { | |
327 case 7: | |
328 do_hexdump = 0; | |
329 break; | |
330 case 8: | |
331 case 9: | |
332 do_hexdump = 1; | |
333 break; | |
334 case 16: | |
335 if (ud_chars & 1) | |
336 do_hexdump = 1; | |
337 else | |
338 do_hexdump = 0; | |
339 break; | |
340 } | |
341 if (do_hexdump) | |
342 printf("Length: %u (raw)\n", ud_chars); | |
343 else { | |
344 switch (dcs_distilled) { | |
345 case 7: | |
346 gsm7_to_ascii_or_ext(ud7 + udh_chars, ud_chars, | |
347 decode_buf, &decoded_len, | |
348 ascii_ext_mode, 1, | |
349 &badchars); | |
350 break; | |
351 case 16: | |
352 ucs2_to_ascii_or_ext(pdu + pdu_ptr + udh_chars, | |
353 ud_chars, | |
354 decode_buf, &decoded_len, | |
355 ascii_ext_mode, 1, | |
356 &badchars); | |
357 break; | |
358 } | |
359 printf("Length: %u", ud_chars); | |
360 if (decoded_len != ud_chars) | |
361 printf("->%u", decoded_len); | |
362 if (badchars) | |
363 printf(" (%u bad char%s)", badchars, | |
364 badchars != 1 ? "s" : ""); | |
365 putchar('\n'); | |
366 } | |
367 } | |
368 | |
369 if (udhl) { | |
370 printf("\nUDH:\n"); | |
371 msg_bits_hexdump(pdu + pdu_ptr + 1, udhl); | |
372 } | |
373 if (!ud_chars) | |
374 return(0); | |
375 putchar('\n'); | |
376 if (do_hexdump) { | |
377 if (dcs_distilled == 7) | |
378 msg_bits_hexdump(ud7 + udh_chars, ud_chars); | |
379 else | |
380 msg_bits_hexdump(pdu + pdu_ptr + udh_chars, ud_chars); | |
381 } else | |
382 puts(decode_buf); | |
383 return(0); | |
384 } | |
385 | |
386 process_cmdline(argc, argv) | |
387 char **argv; | |
388 { | |
389 int c; | |
390 extern int optind; | |
391 | |
392 while ((c = getopt(argc, argv, "ehu")) != EOF) | |
393 switch (c) { | |
394 case 'e': | |
395 ascii_ext_mode = 1; | |
396 continue; | |
397 case 'h': | |
398 global_hexdump_mode = 1; | |
399 continue; | |
400 case 'u': | |
401 ascii_ext_mode = 2; | |
402 continue; | |
403 default: | |
404 fprintf(stderr, "%s: invalid option\n", argv[0]); | |
405 exit(1); | |
406 } | |
407 if (argc > optind) | |
408 infname = argv[optind]; | |
409 } | |
410 | |
411 swallow_empty_line() | |
412 { | |
413 int c; | |
414 | |
415 c = getc(inf); | |
416 if (c != '\n') | |
417 ungetc(c, inf); | |
418 } | |
419 | |
420 main(argc, argv) | |
421 char **argv; | |
422 { | |
423 char *nl; | |
424 int lineno, cc; | |
425 | |
426 process_cmdline(argc, argv); | |
427 if (infname) { | |
428 inf = fopen(infname, "r"); | |
429 if (!inf) { | |
430 perror(infname); | |
431 exit(1); | |
432 } | |
433 } else { | |
434 inf = stdin; | |
435 infname = "stdin"; | |
436 } | |
437 for (lineno = 1; fgets(input_line, sizeof input_line, inf); lineno++) { | |
438 nl = index(input_line, '\n'); | |
439 if (!nl) { | |
440 fprintf(stderr, "%s line %d: no newline\n", | |
441 infname, lineno); | |
442 exit(1); | |
443 } | |
444 *nl = '\0'; | |
445 cc = decode_hex_line(input_line, pdu, sizeof pdu); | |
446 if (cc <= 0) { | |
447 puts(input_line); | |
448 continue; | |
449 } | |
450 pdu_length = cc; | |
451 cc = process_pdu(); | |
452 if (cc < 0) { | |
453 /* decode error, dump the raw PDU */ | |
454 printf("\n%s\n", input_line); | |
455 } | |
456 putchar('\n'); | |
457 swallow_empty_line(); | |
458 } | |
459 exit(0); | |
460 } |