dcerpc-netlogon: improve NetrLogonGetCapabilities dissection
[wireshark-sm.git] / wiretap / dct3trace.c
blob6d41b7cfc7e0343e1d9b56b9ad96a043b2a72d55
1 /* dct3trace.c
2 * Routines for reading signalling traces generated by Gammu (www.gammu.org)
3 * from Nokia DCT3 phones in Netmonitor mode.
5 * gammu --nokiadebug nhm5_587.txt v18-19
7 * Duncan Salerno <duncan.salerno@googlemail.com>
9 * Wiretap Library
10 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
12 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include "config.h"
16 #include "dct3trace.h"
17 #include "wtap-int.h"
18 #include "file_wrappers.h"
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
24 #include <wsutil/strtoi.h>
27 Example downlink data:
29 <?xml version="1.0"?>
30 <dump>
31 <l1 direction="down" logicalchannel="96" physicalchannel="19" sequence="268116" error="0" timeshift="2992" bsic="22" data="31063F100DD0297A53E1020103C802398E0B2B2B2B2B2B" >
32 <l2 data="063F100DD0297A53E1020103" rest="C802398E0B2B2B2B2B2B" >
33 </l2>
34 </l1>
35 </dump>
37 Example uplink data (no raw L1):
39 <?xml version="1.0"?>
40 <dump>
41 <l1 direction="up" logicalchannel="112" >
42 <l2 type="U" subtype="Unknown" p="0" data="061500400000000000000000000000000000" >
43 </l2>
44 </l1>
45 </dump>
50 /* Magic text to check */
51 static const char dct3trace_magic_line1[] = "<?xml version=\"1.0\"?>";
52 static const char dct3trace_magic_line2[] = "<dump>";
53 static const char dct3trace_magic_record_start[] = "<l1 ";
54 static const char dct3trace_magic_record_end[] = "</l1>";
55 static const char dct3trace_magic_l2_start[] = "<l2 ";
56 #if 0 /* Not used ?? */
57 static const char dct3trace_magic_l2_end[] = "</l2>";
58 #endif
59 static const char dct3trace_magic_end[] = "</dump>";
61 #define MAX_PACKET_LEN 23
63 static bool dct3trace_read(wtap *wth, wtap_rec *rec,
64 Buffer *buf, int *err, char **err_info, int64_t *data_offset);
65 static bool dct3trace_seek_read(wtap *wth, int64_t seek_off,
66 wtap_rec *rec, Buffer *buf, int *err, char **err_info);
68 static int dct3trace_file_type_subtype = -1;
70 void register_dct3trace(void);
73 * Following 3 functions taken from gsmdecode-0.7bis, with permission:
75 * https://web.archive.org/web/20091218112927/http://wiki.thc.org/gsm
78 static int
79 hc2b(unsigned char hex)
81 hex = g_ascii_tolower(hex);
82 if ((hex >= '0') && (hex <= '9'))
83 return hex - '0';
84 if ((hex >= 'a') && (hex <= 'f'))
85 return hex - 'a' + 10;
86 return -1;
89 static int
90 hex2bin(uint8_t *out, uint8_t *out_end, char *in)
92 uint8_t *out_start = out;
93 int is_low = 0;
94 int c;
96 while (*in != '\0')
98 c = hc2b(*(unsigned char *)in);
99 if (c < 0)
101 in++;
102 continue;
104 if (out == out_end)
106 /* Too much data */
107 return -1;
109 if (is_low == 0)
111 *out = c << 4;
112 is_low = 1;
113 } else {
114 *out |= (c & 0x0f);
115 is_low = 0;
116 out++;
118 in++;
121 return (int)(out - out_start);
124 static bool
125 xml_get_int(int *val, const char *str, const char *pattern, int *err, char **err_info)
127 const char *ptr, *endptr;
128 char *start, *end;
129 char buf[32];
131 ptr = strstr(str, pattern);
132 if (ptr == NULL) {
133 *err = WTAP_ERR_BAD_FILE;
134 *err_info = ws_strdup_printf("dct3trace: %s not found", pattern);
135 return false;
138 * XXX - should we just skip past the pattern and check for ="?
140 start = strchr(ptr, '"');
141 if (start == NULL) {
142 *err = WTAP_ERR_BAD_FILE;
143 *err_info = ws_strdup_printf("dct3trace: opening quote for %s not found", pattern);
144 return false;
146 start++;
148 * XXX - should we just use ws_strtoi32() and check whether
149 * the character following the number is a "?
151 end = strchr(start, '"');
152 if (end == NULL) {
153 *err = WTAP_ERR_BAD_FILE;
154 *err_info = ws_strdup_printf("dct3trace: closing quote for %s not found", pattern);
155 return false;
157 if (end - start > 31) {
158 *err = WTAP_ERR_BAD_FILE;
159 *err_info = ws_strdup_printf("dct3trace: %s value is too long", pattern);
160 return false;
163 memcpy(buf, start, end - start);
164 buf[end - start] = '\0';
166 * XXX - should we allow negative numbers in all cases? Or are
167 * there cases where the number is unsigned?
169 if (!ws_strtoi32(buf, &endptr, val)) {
170 *err = WTAP_ERR_BAD_FILE;
171 if (errno == ERANGE) {
172 if (*val < 0)
173 *err_info = ws_strdup_printf("dct3trace: %s value is too small, minimum is %d", pattern, *val);
174 else
175 *err_info = ws_strdup_printf("dct3trace: %s value is too large, maximum is %d", pattern, *val);
176 } else
177 *err_info = ws_strdup_printf("dct3trace: %s value \"%s\" not a number", pattern, buf);
178 return false;
180 if (*endptr != '\0') {
181 *err = WTAP_ERR_BAD_FILE;
182 *err_info = ws_strdup_printf("dct3trace: %s value \"%s\" not a number", pattern, buf);
183 return false;
185 return true;
189 wtap_open_return_val dct3trace_open(wtap *wth, int *err, char **err_info)
191 char line1[64], line2[64];
193 /* Look for Gammu DCT3 trace header */
194 if (file_gets(line1, sizeof(line1), wth->fh) == NULL ||
195 file_gets(line2, sizeof(line2), wth->fh) == NULL)
197 *err = file_error(wth->fh, err_info);
198 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
199 return WTAP_OPEN_ERROR;
200 return WTAP_OPEN_NOT_MINE;
203 /* Don't compare line endings */
204 if( strncmp(dct3trace_magic_line1, line1, strlen(dct3trace_magic_line1)) != 0 ||
205 strncmp(dct3trace_magic_line2, line2, strlen(dct3trace_magic_line2)) != 0)
207 return WTAP_OPEN_NOT_MINE;
210 wth->file_encap = WTAP_ENCAP_GSM_UM;
211 wth->file_type_subtype = dct3trace_file_type_subtype;
212 wth->snapshot_length = 0; /* not known */
213 wth->subtype_read = dct3trace_read;
214 wth->subtype_seek_read = dct3trace_seek_read;
215 wth->file_tsprec = WTAP_TSPREC_SEC;
218 * Add an IDB; we don't know how many interfaces were
219 * involved, so we just say one interface, about which
220 * we only know the link-layer type, snapshot length,
221 * and time stamp resolution.
223 wtap_add_generated_idb(wth);
225 return WTAP_OPEN_MINE;
229 static bool dct3trace_get_packet(FILE_T fh, wtap_rec *rec,
230 Buffer *buf, int *err, char **err_info)
232 char line[1024];
233 uint8_t databuf[MAX_PACKET_LEN], *bufp;
234 bool have_data = false;
235 int len = 0;
237 bufp = &databuf[0];
238 while (file_gets(line, sizeof(line), fh) != NULL)
240 if( memcmp(dct3trace_magic_end, line, strlen(dct3trace_magic_end)) == 0 )
242 /* Return on end of file </dump> */
243 *err = 0;
244 return false;
246 else if( memcmp(dct3trace_magic_record_end, line, strlen(dct3trace_magic_record_end)) == 0 )
248 /* Return on end of record </l1> */
249 if( have_data )
251 /* We've got a full packet! */
252 rec->rec_type = REC_TYPE_PACKET;
253 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
254 rec->presence_flags = 0; /* no time stamp, no separate "on the wire" length */
255 rec->ts.secs = 0;
256 rec->ts.nsecs = 0;
257 rec->rec_header.packet_header.caplen = len;
258 rec->rec_header.packet_header.len = len;
260 *err = 0;
262 /* Make sure we have enough room for the packet */
263 ws_buffer_assure_space(buf, rec->rec_header.packet_header.caplen);
264 memcpy( ws_buffer_start_ptr(buf), databuf, rec->rec_header.packet_header.caplen );
266 return true;
268 else
270 /* If not got any data return error */
271 *err = WTAP_ERR_BAD_FILE;
272 *err_info = g_strdup("dct3trace: record without data");
273 return false;
276 else if( memcmp(dct3trace_magic_record_start, line, strlen(dct3trace_magic_record_start)) == 0 )
278 /* Parse L1 header <l1 ...>*/
279 int channel, tmp;
280 char *ptr;
282 rec->rec_header.packet_header.pseudo_header.gsm_um.uplink = !strstr(line, "direction=\"down\"");
283 if (!xml_get_int(&channel, line, "logicalchannel", err, err_info))
284 return false;
286 /* Parse downlink only fields */
287 if( !rec->rec_header.packet_header.pseudo_header.gsm_um.uplink )
289 if (!xml_get_int(&tmp, line, "physicalchannel", err, err_info))
290 return false;
291 rec->rec_header.packet_header.pseudo_header.gsm_um.arfcn = tmp;
292 if (!xml_get_int(&tmp, line, "sequence", err, err_info))
293 return false;
294 rec->rec_header.packet_header.pseudo_header.gsm_um.tdma_frame = tmp;
295 if (!xml_get_int(&tmp, line, "bsic", err, err_info))
296 return false;
297 rec->rec_header.packet_header.pseudo_header.gsm_um.bsic = tmp;
298 if (!xml_get_int(&tmp, line, "error", err, err_info))
299 return false;
300 rec->rec_header.packet_header.pseudo_header.gsm_um.error = tmp;
301 if (!xml_get_int(&tmp, line, "timeshift", err, err_info))
302 return false;
303 rec->rec_header.packet_header.pseudo_header.gsm_um.timeshift = tmp;
306 switch( channel )
308 case 128: rec->rec_header.packet_header.pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_SDCCH; break;
309 case 112: rec->rec_header.packet_header.pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_SACCH; break;
310 case 176: rec->rec_header.packet_header.pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_FACCH; break;
311 case 96: rec->rec_header.packet_header.pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_CCCH; break;
312 case 80: rec->rec_header.packet_header.pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_BCCH; break;
313 default: rec->rec_header.packet_header.pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_UNKNOWN; break;
316 /* Read data (if have it) into databuf */
317 ptr = strstr(line, "data=\"");
318 if( ptr )
320 have_data = true; /* If has data... */
321 len = hex2bin(bufp, &databuf[MAX_PACKET_LEN], ptr+6);
322 if (len == -1)
324 *err = WTAP_ERR_BAD_FILE;
325 *err_info = ws_strdup_printf("dct3trace: record length %d too long", rec->rec_header.packet_header.caplen);
326 return false;
330 else if( !have_data && memcmp(dct3trace_magic_l2_start, line, strlen(dct3trace_magic_l2_start)) == 0 )
332 /* For uplink packets we might not get the raw L1, so have to recreate it from the L2 */
333 /* Parse L2 header if didn't get data from L1 <l2 ...> */
334 int data_len;
335 char *ptr = strstr(line, "data=\"");
337 if( !ptr )
339 continue;
342 have_data = true;
345 * We know we have no data already, so we know
346 * we have enough room for the header.
348 if( rec->rec_header.packet_header.pseudo_header.gsm_um.channel == GSM_UM_CHANNEL_SACCH || rec->rec_header.packet_header.pseudo_header.gsm_um.channel == GSM_UM_CHANNEL_FACCH || rec->rec_header.packet_header.pseudo_header.gsm_um.channel == GSM_UM_CHANNEL_SDCCH )
350 /* Add LAPDm B header */
351 memset(bufp, 0x1, 2);
352 len = 3;
354 else
356 /* Add LAPDm Bbis header */
357 len = 1;
359 bufp += len;
361 data_len = hex2bin(bufp, &databuf[MAX_PACKET_LEN], ptr+6);
362 if (data_len == -1)
364 *err = WTAP_ERR_BAD_FILE;
365 *err_info = ws_strdup_printf("dct3trace: record length %d too long", rec->rec_header.packet_header.caplen);
366 return false;
368 len += data_len;
370 /* Add LAPDm length byte */
371 *(bufp - 1) = data_len << 2 | 0x1;
375 *err = file_error(fh, err_info);
376 if (*err == 0)
378 *err = WTAP_ERR_SHORT_READ;
380 return false;
384 /* Find the next packet and parse it; called from wtap_read(). */
385 static bool dct3trace_read(wtap *wth, wtap_rec *rec, Buffer *buf,
386 int *err, char **err_info, int64_t *data_offset)
388 *data_offset = file_tell(wth->fh);
390 return dct3trace_get_packet(wth->fh, rec, buf, err, err_info);
394 /* Used to read packets in random-access fashion */
395 static bool dct3trace_seek_read(wtap *wth, int64_t seek_off,
396 wtap_rec *rec, Buffer *buf, int *err, char **err_info)
398 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
400 return false;
403 return dct3trace_get_packet(wth->random_fh, rec, buf, err, err_info);
406 static const struct supported_block_type dct3trace_blocks_supported[] = {
408 * We support packet blocks, with no comments or other options.
410 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
413 static const struct file_type_subtype_info dct3trace_info = {
414 "Gammu DCT3 trace", "dct3trace", "xml", NULL,
415 false, BLOCKS_SUPPORTED(dct3trace_blocks_supported),
416 NULL, NULL, NULL
419 void register_dct3trace(void)
421 dct3trace_file_type_subtype = wtap_register_file_type_subtype(&dct3trace_info);
424 * Register name for backwards compatibility with the
425 * wtap_filetypes table in Lua.
427 wtap_register_backwards_compatibility_lua_name("DCT3TRACE",
428 dct3trace_file_type_subtype);
432 * Editor modelines - https://www.wireshark.org/tools/modelines.html
434 * Local variables:
435 * c-basic-offset: 8
436 * tab-width: 8
437 * indent-tabs-mode: t
438 * End:
440 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
441 * :indentSize=8:tabSize=8:noTabs=false: