FreeCalypso > hg > freecalypso-tools
comparison uptools/sms-pdu-decode/sms-pdu-decode.c @ 598:9f7a263ad7f0
sms-pdu-decode split in preparation for pcm-sms-decode addition
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 08 Feb 2020 00:48:28 +0000 |
parents | 542c6d733772 |
children | 18bfc10ba20e |
comparison
equal
deleted
inserted
replaced
597:ca4433b714d2 | 598:9f7a263ad7f0 |
---|---|
4 #include <stdlib.h> | 4 #include <stdlib.h> |
5 #include <string.h> | 5 #include <string.h> |
6 #include <strings.h> | 6 #include <strings.h> |
7 #include <unistd.h> | 7 #include <unistd.h> |
8 | 8 |
9 char *infname; | 9 extern int ascii_ext_mode, global_hexdump_mode; |
10 FILE *inf; | 10 extern u_char pdu[176]; |
11 int ascii_ext_mode, global_hexdump_mode, keep_raw_pdu; | 11 extern unsigned pdu_length; |
12 | 12 |
13 char input_line[1024]; | 13 static char *infname; |
14 u_char pdu[176], first_octet; | 14 static FILE *inf; |
15 unsigned pdu_length, pdu_ptr; | 15 static int keep_raw_pdu; |
16 int dcs_distilled; | |
17 | 16 |
18 handle_sca() | 17 static char input_line[1024]; |
19 { | |
20 unsigned sca_len; | |
21 char digits[21]; | |
22 | 18 |
23 sca_len = pdu[0]; | 19 static |
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) >> 1) + 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, | |
92 (unsigned *) 0, ascii_ext_mode, 0, | |
93 (unsigned *) 0); | |
94 printf("%s: \"%s\" (type 0x%02X)\n", direction, alpha_decoded, | |
95 pdu[pdu_ptr+1]); | |
96 } else { | |
97 decode_address_digits(pdu + pdu_ptr + 2, digits, pdu[pdu_ptr]); | |
98 printf("%s: %s%s (type 0x%02X)\n", direction, | |
99 pdu[pdu_ptr+1] == 0x91 ? "+" : "", digits, | |
100 pdu[pdu_ptr+1]); | |
101 } | |
102 pdu_ptr += addr_field_len; | |
103 return(0); | |
104 } | |
105 | |
106 handle_pid() | |
107 { | |
108 if (pdu_ptr >= pdu_length) { | |
109 printf("Decode-Error: end of PDU before PID\n"); | |
110 return(-1); | |
111 } | |
112 printf("PID: 0x%02X\n", pdu[pdu_ptr++]); | |
113 return(0); | |
114 } | |
115 | |
116 handle_dcs() | |
117 { | |
118 u_char dcs; | |
119 char *strtype; | |
120 | |
121 if (pdu_ptr >= pdu_length) { | |
122 printf("Decode-Error: end of PDU before DCS\n"); | |
123 return(-1); | |
124 } | |
125 dcs = pdu[pdu_ptr++]; | |
126 dcs_distilled = sms_dcs_classify(dcs); | |
127 switch (dcs_distilled) { | |
128 case 7: | |
129 strtype = "7-bit"; | |
130 break; | |
131 case 8: | |
132 strtype = "raw octets"; | |
133 break; | |
134 case 9: | |
135 strtype = "compressed"; | |
136 break; | |
137 case 16: | |
138 strtype = "UCS-2"; | |
139 break; | |
140 } | |
141 printf("DCS: 0x%02X (%s)\n", dcs, strtype); | |
142 return(0); | |
143 } | |
144 | |
145 handle_scts() | |
146 { | |
147 char str[21]; | |
148 | |
149 if (pdu_ptr + 7 > pdu_length) { | |
150 printf("Decode-Error: end of PDU before SCTS\n"); | |
151 return(-1); | |
152 } | |
153 gsm_timestamp_decode(pdu + pdu_ptr, str); | |
154 printf("SC-Timestamp: %s\n", str); | |
155 pdu_ptr += 7; | |
156 return(0); | |
157 } | |
158 | |
159 handle_vp_abs() | |
160 { | |
161 char str[21]; | |
162 | |
163 if (pdu_ptr + 7 > pdu_length) { | |
164 printf("Decode-Error: end of PDU before VP-abs\n"); | |
165 return(-1); | |
166 } | |
167 gsm_timestamp_decode(pdu + pdu_ptr, str); | |
168 printf("VP-Absolute: %s\n", str); | |
169 pdu_ptr += 7; | |
170 return(0); | |
171 } | |
172 | |
173 handle_vp_rel() | |
174 { | |
175 unsigned vprel, hours, min; | |
176 | |
177 if (pdu_ptr >= pdu_length) { | |
178 printf("Decode-Error: end of PDU before VP-rel\n"); | |
179 return(-1); | |
180 } | |
181 vprel = pdu[pdu_ptr++]; | |
182 if (vprel <= 143) { | |
183 min = (vprel + 1) * 5; | |
184 goto hhmm; | |
185 } else if (vprel <= 167) { | |
186 min = (vprel - 143) * 30 + 12 * 60; | |
187 goto hhmm; | |
188 } else if (vprel <= 196) { | |
189 printf("VP-Relative: %u days\n", vprel - 166); | |
190 return(0); | |
191 } else { | |
192 printf("VP-Relative: %u weeks\n", vprel - 192); | |
193 return(0); | |
194 } | |
195 | |
196 hhmm: hours = min / 60; | |
197 min %= 60; | |
198 printf("VP-Relative: "); | |
199 if (hours) | |
200 printf(" %u hour%s", hours, hours != 1 ? "s" : ""); | |
201 if (min) | |
202 printf(" %u min", min); | |
203 putchar('\n'); | |
204 return(0); | |
205 } | |
206 | |
207 handle_vp_enh() | |
208 { | |
209 if (pdu_ptr + 7 > pdu_length) { | |
210 printf("Decode-Error: end of PDU before VP-enh\n"); | |
211 return(-1); | |
212 } | |
213 printf("VP-Enhanced: %02X %02X %02X %02X %02X %02X %02X\n", | |
214 pdu[pdu_ptr], pdu[pdu_ptr+1], pdu[pdu_ptr+2], pdu[pdu_ptr+3], | |
215 pdu[pdu_ptr+4], pdu[pdu_ptr+5], pdu[pdu_ptr+6]); | |
216 pdu_ptr += 7; | |
217 return(0); | |
218 } | |
219 | |
220 handle_vp() | |
221 { | |
222 int rc; | |
223 | |
224 switch (first_octet & 0x18) { | |
225 case 0x00: | |
226 rc = 0; | |
227 break; | |
228 case 0x08: | |
229 rc = handle_vp_enh(); | |
230 break; | |
231 case 0x10: | |
232 rc = handle_vp_rel(); | |
233 break; | |
234 case 0x18: | |
235 rc = handle_vp_abs(); | |
236 break; | |
237 } | |
238 return(rc); | |
239 } | |
240 | |
241 process_pdu() | |
242 { | |
243 unsigned udl, udl_octets; | |
244 unsigned udhl, udh_octets, udh_chars, ud_chars; | |
245 u_char ud7[160], decode_buf[321]; | |
246 int do_hexdump; | |
247 unsigned decoded_len, badchars; | |
248 | |
249 if (handle_sca() < 0) | |
250 return(-1); | |
251 if (handle_first_octet() < 0) | |
252 return(-1); | |
253 if (first_octet & 2) { | |
254 printf("Decode-Error: MTI not supported\n"); | |
255 return(-1); | |
256 } | |
257 if (first_octet & 1) { | |
258 if (handle_mr() < 0) | |
259 return(-1); | |
260 } | |
261 if (handle_user_addr(first_octet & 1 ? "To" : "From") < 0) | |
262 return(-1); | |
263 if (handle_pid() < 0) | |
264 return(-1); | |
265 if (handle_dcs() < 0) | |
266 return(-1); | |
267 if (first_octet & 1) { | |
268 if (handle_vp() < 0) | |
269 return(-1); | |
270 } else { | |
271 if (handle_scts() < 0) | |
272 return(-1); | |
273 } | |
274 if (pdu_ptr >= pdu_length) { | |
275 printf("Decode-Error: end of PDU before UDL\n"); | |
276 return(-1); | |
277 } | |
278 udl = pdu[pdu_ptr++]; | |
279 if (dcs_distilled == 7) { | |
280 if (udl > 160) { | |
281 printf("Decode-Error: UDL %u > 160\n", udl); | |
282 return(-1); | |
283 } | |
284 udl_octets = (udl * 7 + 7) / 8; | |
285 } else { | |
286 if (udl > 140) { | |
287 printf("Decode-Error: UDL %u > 140\n", udl); | |
288 return(-1); | |
289 } | |
290 udl_octets = udl; | |
291 } | |
292 if (pdu_length - pdu_ptr != udl_octets) { | |
293 printf("Decode-Error: UD length in PDU %u != expected %u\n", | |
294 pdu_length - pdu_ptr, udl_octets); | |
295 return(-1); | |
296 } | |
297 if (first_octet & 0x40) { | |
298 if (!udl) { | |
299 printf("Decode-Error: UDHI set with UDL=0\n"); | |
300 return(-1); | |
301 } | |
302 udhl = pdu[pdu_ptr]; | |
303 udh_octets = udhl + 1; | |
304 if (udh_octets > udl_octets) { | |
305 printf("Decode-Error: UDHL exceeds UDL\n"); | |
306 return(-1); | |
307 } | |
308 printf("UDH-Length: %u\n", udhl); | |
309 if (dcs_distilled == 7) | |
310 udh_chars = (udh_octets * 8 + 6) / 7; | |
311 else | |
312 udh_chars = udh_octets; | |
313 } else { | |
314 udhl = 0; | |
315 udh_octets = 0; | |
316 udh_chars = 0; | |
317 } | |
318 if (udh_chars >= udl) { | |
319 ud_chars = 0; | |
320 printf("Length: 0\n"); | |
321 } else { | |
322 ud_chars = udl - udh_chars; | |
323 if (dcs_distilled == 7) | |
324 gsm7_unpack(pdu + pdu_ptr, ud7, udl); | |
325 if (global_hexdump_mode) | |
326 do_hexdump = 1; | |
327 else switch (dcs_distilled) { | |
328 case 7: | |
329 do_hexdump = 0; | |
330 break; | |
331 case 8: | |
332 case 9: | |
333 do_hexdump = 1; | |
334 break; | |
335 case 16: | |
336 if (ud_chars & 1) | |
337 do_hexdump = 1; | |
338 else | |
339 do_hexdump = 0; | |
340 break; | |
341 } | |
342 if (do_hexdump) | |
343 printf("Length: %u (raw)\n", ud_chars); | |
344 else { | |
345 switch (dcs_distilled) { | |
346 case 7: | |
347 gsm7_to_ascii_or_ext(ud7 + udh_chars, ud_chars, | |
348 decode_buf, &decoded_len, | |
349 ascii_ext_mode, 1, | |
350 &badchars); | |
351 break; | |
352 case 16: | |
353 ucs2_to_ascii_or_ext(pdu + pdu_ptr + udh_chars, | |
354 ud_chars, | |
355 decode_buf, &decoded_len, | |
356 ascii_ext_mode, 1, | |
357 &badchars); | |
358 break; | |
359 } | |
360 printf("Length: %u", ud_chars); | |
361 if (decoded_len != ud_chars) | |
362 printf("->%u", decoded_len); | |
363 if (badchars) | |
364 printf(" (%u bad char%s)", badchars, | |
365 badchars != 1 ? "s" : ""); | |
366 putchar('\n'); | |
367 } | |
368 } | |
369 | |
370 if (udhl) { | |
371 printf("\nUDH:\n"); | |
372 msg_bits_hexdump(pdu + pdu_ptr + 1, udhl); | |
373 } | |
374 if (!ud_chars) | |
375 return(0); | |
376 putchar('\n'); | |
377 if (do_hexdump) { | |
378 if (dcs_distilled == 7) | |
379 msg_bits_hexdump(ud7 + udh_chars, ud_chars); | |
380 else | |
381 msg_bits_hexdump(pdu + pdu_ptr + udh_chars, ud_chars); | |
382 } else | |
383 puts(decode_buf); | |
384 return(0); | |
385 } | |
386 | |
387 process_cmdline(argc, argv) | 20 process_cmdline(argc, argv) |
388 char **argv; | 21 char **argv; |
389 { | 22 { |
390 int c; | 23 int c; |
391 extern int optind; | 24 extern int optind; |
410 } | 43 } |
411 if (argc > optind) | 44 if (argc > optind) |
412 infname = argv[optind]; | 45 infname = argv[optind]; |
413 } | 46 } |
414 | 47 |
48 static | |
415 swallow_empty_line() | 49 swallow_empty_line() |
416 { | 50 { |
417 int c; | 51 int c; |
418 | 52 |
419 c = getc(inf); | 53 c = getc(inf); |