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 } |
