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 }