FreeCalypso > hg > sms-coding-utils
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 } |