FreeCalypso > hg > gsm-net-reveng
comparison trau-decode/parse-new16.c @ 107:c6ffb176eaed
trau-decode: new program trau-parse-n
| author | Mychaela Falconia <falcon@freecalypso.org> |
|---|---|
| date | Sun, 21 Dec 2025 20:05:22 +0000 |
| parents | trau-decode/parse-main.c@00fd38c7c8fe |
| children | f2009a354444 |
comparison
equal
deleted
inserted
replaced
| 106:028307356ba9 | 107:c6ffb176eaed |
|---|---|
| 1 /* | |
| 2 * This program reads a 64 kbit/s timeslot recording file, examines one | |
| 3 * of the four 16 kbit/s subslots (selected), looks for GSM 08.60 TRAU | |
| 4 * frames, and dumps whatever it finds. The present version is a new one, | |
| 5 * put together for the purpose of reverse-engineering Abis output from | |
| 6 * Nokia BTS, which exhibits more complex behaviour than what our original | |
| 7 * trau-parse program can analyze properly. | |
| 8 */ | |
| 9 | |
| 10 #include <sys/types.h> | |
| 11 #include <sys/file.h> | |
| 12 #include <sys/stat.h> | |
| 13 #include <stdio.h> | |
| 14 #include <stdint.h> | |
| 15 #include <stdlib.h> | |
| 16 #include <string.h> | |
| 17 #include <strings.h> | |
| 18 | |
| 19 static uint8_t *filebuf; | |
| 20 static unsigned total_size; | |
| 21 | |
| 22 static enum { | |
| 23 NOT_D144, | |
| 24 D144_SYNC, | |
| 25 D144_EDATA, | |
| 26 } d144_state; | |
| 27 | |
| 28 static void | |
| 29 read_ts_file(filename, subslot_arg) | |
| 30 char *filename, *subslot_arg; | |
| 31 { | |
| 32 FILE *inf; | |
| 33 struct stat st; | |
| 34 int subslot, right_shift; | |
| 35 unsigned n; | |
| 36 uint8_t *dp; | |
| 37 int b; | |
| 38 | |
| 39 inf = fopen(filename, "r"); | |
| 40 if (!inf) { | |
| 41 perror(filename); | |
| 42 exit(1); | |
| 43 } | |
| 44 fstat(fileno(inf), &st); | |
| 45 if (!S_ISREG(st.st_mode)) { | |
| 46 fprintf(stderr, "error: %s is not a regular file\n", filename); | |
| 47 exit(1); | |
| 48 } | |
| 49 total_size = st.st_size; | |
| 50 if (total_size < 160) { | |
| 51 fprintf(stderr, "error: %s is too short\n", filename); | |
| 52 exit(1); | |
| 53 } | |
| 54 filebuf = malloc(total_size); | |
| 55 if (!filebuf) { | |
| 56 perror("malloc of file size"); | |
| 57 exit(1); | |
| 58 } | |
| 59 subslot = atoi(subslot_arg); | |
| 60 if (subslot < 0 || subslot > 3) { | |
| 61 fprintf(stderr, "error: invalid subslot argument\n"); | |
| 62 exit(1); | |
| 63 } | |
| 64 right_shift = (3 - subslot) * 2; | |
| 65 dp = filebuf; | |
| 66 for (n = 0; n < total_size; n++) { | |
| 67 b = getc(inf); | |
| 68 if (b < 0) { | |
| 69 fprintf(stderr, | |
| 70 "error: getc() returned EOF contrary to st_size\n"); | |
| 71 exit(1); | |
| 72 } | |
| 73 *dp++ = (b >> right_shift) & 3; | |
| 74 } | |
| 75 fclose(inf); | |
| 76 } | |
| 77 | |
| 78 static int | |
| 79 check_sync(pos) | |
| 80 unsigned pos; | |
| 81 { | |
| 82 uint8_t *cand = filebuf + pos; | |
| 83 unsigned n; | |
| 84 | |
| 85 for (n = 0; n < 8; n++) { | |
| 86 if (cand[n]) | |
| 87 return 0; | |
| 88 } | |
| 89 if (!(cand[8] & 2)) | |
| 90 return 0; | |
| 91 if (cand[8] == 3 && cand[9] == 3 && cand[10] == 3 && | |
| 92 (d144_state == D144_SYNC || d144_state == D144_EDATA)) | |
| 93 return 1; | |
| 94 for (n = 2; n < 20; n++) { | |
| 95 if (!(cand[n * 8] & 2)) | |
| 96 return 0; | |
| 97 } | |
| 98 return 1; | |
| 99 } | |
| 100 | |
| 101 static void | |
| 102 unpack_dibits(in_frame_2bit, frame_bits) | |
| 103 uint8_t *in_frame_2bit, *frame_bits; | |
| 104 { | |
| 105 int i, inb; | |
| 106 uint8_t *op; | |
| 107 | |
| 108 op = frame_bits; | |
| 109 for (i = 0; i < 160; i++) { | |
| 110 inb = in_frame_2bit[i]; | |
| 111 if (inb & 2) | |
| 112 *op++ = 1; | |
| 113 else | |
| 114 *op++ = 0; | |
| 115 if (inb & 1) | |
| 116 *op++ = 1; | |
| 117 else | |
| 118 *op++ = 0; | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 static unsigned | |
| 123 bits_to_num(bits, nbits) | |
| 124 uint8_t *bits; | |
| 125 unsigned nbits; | |
| 126 { | |
| 127 unsigned accum; | |
| 128 unsigned n; | |
| 129 | |
| 130 accum = 0; | |
| 131 for (n = 0; n < nbits; n++) { | |
| 132 accum <<= 1; | |
| 133 if (*bits) | |
| 134 accum |= 1; | |
| 135 bits++; | |
| 136 } | |
| 137 return accum; | |
| 138 } | |
| 139 | |
| 140 static void | |
| 141 dump_raw_nibbles(dibits, num_dibits) | |
| 142 uint8_t *dibits; | |
| 143 unsigned num_dibits; | |
| 144 { | |
| 145 uint8_t *sp = dibits; | |
| 146 unsigned remain = num_dibits; | |
| 147 | |
| 148 if (remain >= 2) { | |
| 149 while (remain >= 2) { | |
| 150 printf("%x", (sp[0] << 2) | sp[1]); | |
| 151 sp += 2; | |
| 152 remain -= 2; | |
| 153 } | |
| 154 putchar('\n'); | |
| 155 } | |
| 156 if (remain) | |
| 157 printf("dribble %u%u\n", (*sp & 2) >> 1, (*sp & 1) >> 0); | |
| 158 } | |
| 159 | |
| 160 static int | |
| 161 process_frame(pos) | |
| 162 unsigned pos; | |
| 163 { | |
| 164 uint8_t *frame_2b = filebuf + pos; | |
| 165 uint8_t frame_bits[320]; | |
| 166 unsigned c1_5, c6_11; | |
| 167 | |
| 168 printf("Frame at 0x%x:\n", pos); | |
| 169 dump_raw_nibbles(frame_2b, 160); | |
| 170 unpack_dibits(frame_2b, frame_bits); | |
| 171 printf(" C1-C5: %u%u%u%u%u", frame_bits[17], frame_bits[18], | |
| 172 frame_bits[19], frame_bits[20], frame_bits[21]); | |
| 173 c1_5 = bits_to_num(frame_bits + 17, 5); | |
| 174 switch (c1_5) { | |
| 175 case 0x02: | |
| 176 fputs(" (FR UL)", stdout); | |
| 177 break; | |
| 178 case 0x1C: | |
| 179 fputs(" (FR DL)", stdout); | |
| 180 break; | |
| 181 case 0x1A: | |
| 182 fputs(" (EFR)", stdout); | |
| 183 break; | |
| 184 case 0x10: | |
| 185 fputs(" (idle UL)", stdout); | |
| 186 break; | |
| 187 case 0x0E: | |
| 188 fputs(" (idle DL)", stdout); | |
| 189 break; | |
| 190 case 0x08: | |
| 191 fputs(" (data UL)", stdout); | |
| 192 break; | |
| 193 case 0x16: | |
| 194 fputs(" (data DL)", stdout); | |
| 195 break; | |
| 196 case 0x09: | |
| 197 fputs(" (HR data UL)", stdout); | |
| 198 break; | |
| 199 case 0x17: | |
| 200 fputs(" (HR data DL)", stdout); | |
| 201 break; | |
| 202 case 0x14: | |
| 203 fputs(" (D144 sync)", stdout); | |
| 204 break; | |
| 205 case 0x1F: | |
| 206 fputs(" (E-TRAU)", stdout); | |
| 207 break; | |
| 208 case 0x06: | |
| 209 fputs(" (AMR)", stdout); | |
| 210 break; | |
| 211 } | |
| 212 putchar('\n'); | |
| 213 if (c1_5 == 0x14) | |
| 214 d144_state = D144_SYNC; | |
| 215 else if (c1_5 == 0x1F && | |
| 216 (d144_state == D144_SYNC || d144_state == D144_EDATA)) | |
| 217 d144_state = D144_EDATA; | |
| 218 else | |
| 219 d144_state = NOT_D144; | |
| 220 switch (c1_5) { | |
| 221 case 0x02: | |
| 222 case 0x1C: | |
| 223 case 0x1A: | |
| 224 case 0x10: | |
| 225 case 0x0E: | |
| 226 c6_11 = bits_to_num(frame_bits + 22, 6); | |
| 227 printf(" C6-C11: %u\n", c6_11); | |
| 228 printf(" C12=%u C13=%u C14=%u C15=%u\n", frame_bits[28], | |
| 229 frame_bits[29], frame_bits[30], frame_bits[31]); | |
| 230 print_fr_efr_frame(frame_bits, c1_5); | |
| 231 printf(" C16=%u C17=%u C18=%u C19=%u C20=%u C21=%u\n", | |
| 232 frame_bits[310], frame_bits[311], frame_bits[312], | |
| 233 frame_bits[313], frame_bits[314], frame_bits[315]); | |
| 234 printf(" T1=%u T2=%u T3=%u T4=%u\n", frame_bits[316], | |
| 235 frame_bits[317], frame_bits[318], frame_bits[319]); | |
| 236 return 1; | |
| 237 case 0x08: | |
| 238 case 0x09: | |
| 239 case 0x16: | |
| 240 case 0x17: | |
| 241 case 0x14: | |
| 242 print_data_frame(frame_bits); | |
| 243 return 0; | |
| 244 case 0x1F: | |
| 245 print_edata_frame(frame_bits); | |
| 246 return 0; | |
| 247 case 0x06: | |
| 248 print_amr_frame(frame_bits); | |
| 249 return 1; | |
| 250 default: | |
| 251 printf(" C6-C15: %u%u%u%u%u%u%u%u%u%u\n", frame_bits[22], | |
| 252 frame_bits[23], frame_bits[24], frame_bits[25], | |
| 253 frame_bits[26], frame_bits[27], frame_bits[28], | |
| 254 frame_bits[29], frame_bits[30], frame_bits[31]); | |
| 255 printf(" C16=%u C17=%u C18=%u C19=%u C20=%u C21=%u\n", | |
| 256 frame_bits[310], frame_bits[311], frame_bits[312], | |
| 257 frame_bits[313], frame_bits[314], frame_bits[315]); | |
| 258 printf(" T1=%u T2=%u T3=%u T4=%u\n", frame_bits[316], | |
| 259 frame_bits[317], frame_bits[318], frame_bits[319]); | |
| 260 return 0; | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 static void | |
| 265 process_filebuf() | |
| 266 { | |
| 267 unsigned p, nf_pos = 0, nf_accum = 0; | |
| 268 int match, have_t_bits; | |
| 269 | |
| 270 d144_state = NOT_D144; | |
| 271 for (p = 0; p < total_size; ) { | |
| 272 if ((total_size - p) >= 160) | |
| 273 match = check_sync(p); | |
| 274 else | |
| 275 match = 0; | |
| 276 if (match) { | |
| 277 if (nf_accum) { | |
| 278 printf("Non-frame at 0x%x:\n", nf_pos); | |
| 279 dump_raw_nibbles(filebuf + nf_pos, nf_accum); | |
| 280 } | |
| 281 have_t_bits = process_frame(p); | |
| 282 if (have_t_bits && !filebuf[p+158] && !filebuf[p+159]) { | |
| 283 puts("advance of 250 us"); | |
| 284 p += 158; | |
| 285 } else | |
| 286 p += 160; | |
| 287 nf_pos = p; | |
| 288 nf_accum = 0; | |
| 289 } else { | |
| 290 p++; | |
| 291 nf_accum++; | |
| 292 if (nf_accum >= 160) { | |
| 293 printf("Non-frame at 0x%x:\n", nf_pos); | |
| 294 dump_raw_nibbles(filebuf + nf_pos, nf_accum); | |
| 295 nf_pos = p; | |
| 296 nf_accum = 0; | |
| 297 } | |
| 298 d144_state = NOT_D144; | |
| 299 } | |
| 300 } | |
| 301 if (nf_accum) { | |
| 302 printf("Non-frame at 0x%x:\n", nf_pos); | |
| 303 dump_raw_nibbles(filebuf + nf_pos, nf_accum); | |
| 304 } | |
| 305 } | |
| 306 | |
| 307 main(argc, argv) | |
| 308 char **argv; | |
| 309 { | |
| 310 if (argc != 3) { | |
| 311 fprintf(stderr, "usage: %s r] binfile subslot\n", argv[0]); | |
| 312 exit(1); | |
| 313 } | |
| 314 read_ts_file(argv[1], argv[2]); | |
| 315 process_filebuf(); | |
| 316 exit(0); | |
| 317 } |
