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 }