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