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>
10 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include "dct3trace.h"
30 #include "file_wrappers.h"
36 #include <wsutil/strtoi.h>
39 Example downlink data:
43 <l1 direction="down" logicalchannel="96" physicalchannel="19" sequence="268116" error="0" timeshift="2992" bsic="22" data="31063F100DD0297A53E1020103C802398E0B2B2B2B2B2B" >
44 <l2 data="063F100DD0297A53E1020103" rest="C802398E0B2B2B2B2B2B" >
49 Example uplink data (no raw L1):
53 <l1 direction="up" logicalchannel="112" >
54 <l2 type="U" subtype="Unknown" p="0" data="061500400000000000000000000000000000" >
62 /* Magic text to check */
63 static const char dct3trace_magic_line1[] = "<?xml version=\"1.0\"?>";
64 static const char dct3trace_magic_line2[] = "<dump>";
65 static const char dct3trace_magic_record_start[] = "<l1 ";
66 static const char dct3trace_magic_record_end[] = "</l1>";
67 static const char dct3trace_magic_l2_start[] = "<l2 ";
68 #if 0 /* Not used ?? */
69 static const char dct3trace_magic_l2_end[] = "</l2>";
71 static const char dct3trace_magic_end[] = "</dump>";
73 #define MAX_PACKET_LEN 23
75 static gboolean dct3trace_read(wtap *wth, int *err, gchar **err_info,
77 static gboolean dct3trace_seek_read(wtap *wth, gint64 seek_off,
78 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
81 * Following 3 functions taken from gsmdecode-0.7bis, with permission - http://wiki.thc.org/gsm
85 hc2b(unsigned char hex)
87 hex = g_ascii_tolower(hex);
88 if ((hex >= '0') && (hex <= '9'))
90 if ((hex >= 'a') && (hex <= 'f'))
91 return hex - 'a' + 10;
96 hex2bin(guint8 *out, guint8 *out_end, char *in)
98 guint8 *out_start = out;
104 c = hc2b(*(unsigned char *)in);
127 return (int)(out - out_start);
131 xml_get_int(int *val, const char *str, const char *pattern, int *err, gchar **err_info)
133 const char *ptr, *endptr;
137 ptr = strstr(str, pattern);
139 *err = WTAP_ERR_BAD_FILE;
140 *err_info = g_strdup_printf("dct3trace: %s not found", pattern);
144 * XXX - should we just skip past the pattern and check for ="?
146 start = strchr(ptr, '"');
148 *err = WTAP_ERR_BAD_FILE;
149 *err_info = g_strdup_printf("dct3trace: opening quote for %s not found", pattern);
154 * XXX - should we just use ws_strtoi32() and check whether
155 * the character following the number is a "?
157 end = strchr(start, '"');
159 *err = WTAP_ERR_BAD_FILE;
160 *err_info = g_strdup_printf("dct3trace: closing quote for %s not found", pattern);
163 if (end - start > 31) {
164 *err = WTAP_ERR_BAD_FILE;
165 *err_info = g_strdup_printf("dct3trace: %s value is too long", pattern);
169 memcpy(buf, start, end - start);
170 buf[end - start] = '\0';
172 * XXX - should we allow negative numbers in all cases? Or are
173 * there cases where the number is unsigned?
175 if (!ws_strtoi32(buf, &endptr, val)) {
176 *err = WTAP_ERR_BAD_FILE;
177 if (errno == ERANGE) {
179 *err_info = g_strdup_printf("dct3trace: %s value is too small, minimum is %d", pattern, *val);
181 *err_info = g_strdup_printf("dct3trace: %s value is too large, maximum is %d", pattern, *val);
183 *err_info = g_strdup_printf("dct3trace: %s value \"%s\" not a number", pattern, buf);
186 if (*endptr != '\0') {
187 *err = WTAP_ERR_BAD_FILE;
188 *err_info = g_strdup_printf("dct3trace: %s value \"%s\" not a number", pattern, buf);
195 wtap_open_return_val dct3trace_open(wtap *wth, int *err, gchar **err_info)
197 char line1[64], line2[64];
199 /* Look for Gammu DCT3 trace header */
200 if (file_gets(line1, sizeof(line1), wth->fh) == NULL ||
201 file_gets(line2, sizeof(line2), wth->fh) == NULL)
203 *err = file_error(wth->fh, err_info);
204 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
205 return WTAP_OPEN_ERROR;
206 return WTAP_OPEN_NOT_MINE;
209 /* Don't compare line endings */
210 if( strncmp(dct3trace_magic_line1, line1, strlen(dct3trace_magic_line1)) != 0 ||
211 strncmp(dct3trace_magic_line2, line2, strlen(dct3trace_magic_line2)) != 0)
213 return WTAP_OPEN_NOT_MINE;
216 wth->file_encap = WTAP_ENCAP_GSM_UM;
217 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_DCT3TRACE;
218 wth->snapshot_length = 0; /* not known */
219 wth->subtype_read = dct3trace_read;
220 wth->subtype_seek_read = dct3trace_seek_read;
221 wth->file_tsprec = WTAP_TSPREC_SEC;
223 return WTAP_OPEN_MINE;
227 static gboolean dct3trace_get_packet(FILE_T fh, struct wtap_pkthdr *phdr,
228 Buffer *buf, int *err, gchar **err_info)
231 guint8 databuf[MAX_PACKET_LEN], *bufp;
232 gboolean have_data = FALSE;
236 while (file_gets(line, sizeof(line), fh) != NULL)
238 if( memcmp(dct3trace_magic_end, line, strlen(dct3trace_magic_end)) == 0 )
240 /* Return on end of file </dump> */
244 else if( memcmp(dct3trace_magic_record_end, line, strlen(dct3trace_magic_record_end)) == 0 )
246 /* Return on end of record </l1> */
249 /* We've got a full packet! */
250 phdr->rec_type = REC_TYPE_PACKET;
251 phdr->presence_flags = 0; /* no time stamp, no separate "on the wire" length */
259 /* Make sure we have enough room for the packet */
260 ws_buffer_assure_space(buf, phdr->caplen);
261 memcpy( ws_buffer_start_ptr(buf), databuf, phdr->caplen );
267 /* If not got any data return error */
268 *err = WTAP_ERR_BAD_FILE;
269 *err_info = g_strdup("dct3trace: record without data");
273 else if( memcmp(dct3trace_magic_record_start, line, strlen(dct3trace_magic_record_start)) == 0 )
275 /* Parse L1 header <l1 ...>*/
279 phdr->pseudo_header.gsm_um.uplink = !strstr(line, "direction=\"down\"");
280 if (!xml_get_int(&channel, line, "logicalchannel", err, err_info))
283 /* Parse downlink only fields */
284 if( !phdr->pseudo_header.gsm_um.uplink )
286 if (!xml_get_int(&tmp, line, "physicalchannel", err, err_info))
288 phdr->pseudo_header.gsm_um.arfcn = tmp;
289 if (!xml_get_int(&tmp, line, "sequence", err, err_info))
291 phdr->pseudo_header.gsm_um.tdma_frame = tmp;
292 if (!xml_get_int(&tmp, line, "bsic", err, err_info))
294 phdr->pseudo_header.gsm_um.bsic = tmp;
295 if (!xml_get_int(&tmp, line, "error", err, err_info))
297 phdr->pseudo_header.gsm_um.error = tmp;
298 if (!xml_get_int(&tmp, line, "timeshift", err, err_info))
300 phdr->pseudo_header.gsm_um.timeshift = tmp;
305 case 128: phdr->pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_SDCCH; break;
306 case 112: phdr->pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_SACCH; break;
307 case 176: phdr->pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_FACCH; break;
308 case 96: phdr->pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_CCCH; break;
309 case 80: phdr->pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_BCCH; break;
310 default: phdr->pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_UNKNOWN; break;
313 /* Read data (if have it) into databuf */
314 ptr = strstr(line, "data=\"");
317 have_data = TRUE; /* If has data... */
318 len = hex2bin(bufp, &databuf[MAX_PACKET_LEN], ptr+6);
321 *err = WTAP_ERR_BAD_FILE;
322 *err_info = g_strdup_printf("dct3trace: record length %d too long", phdr->caplen);
327 else if( !have_data && memcmp(dct3trace_magic_l2_start, line, strlen(dct3trace_magic_l2_start)) == 0 )
329 /* For uplink packets we might not get the raw L1, so have to recreate it from the L2 */
330 /* Parse L2 header if didn't get data from L1 <l2 ...> */
332 char *ptr = strstr(line, "data=\"");
342 * We know we have no data already, so we know
343 * we have enough room for the header.
345 if( phdr->pseudo_header.gsm_um.channel == GSM_UM_CHANNEL_SACCH || phdr->pseudo_header.gsm_um.channel == GSM_UM_CHANNEL_FACCH || phdr->pseudo_header.gsm_um.channel == GSM_UM_CHANNEL_SDCCH )
347 /* Add LAPDm B header */
348 memset(bufp, 0x1, 2);
353 /* Add LAPDm Bbis header */
358 data_len = hex2bin(bufp, &databuf[MAX_PACKET_LEN], ptr+6);
361 *err = WTAP_ERR_BAD_FILE;
362 *err_info = g_strdup_printf("dct3trace: record length %d too long", phdr->caplen);
367 /* Add LAPDm length byte */
368 *(bufp - 1) = data_len << 2 | 0x1;
372 *err = file_error(fh, err_info);
375 *err = WTAP_ERR_SHORT_READ;
381 /* Find the next packet and parse it; called from wtap_read(). */
382 static gboolean dct3trace_read(wtap *wth, int *err, gchar **err_info,
385 *data_offset = file_tell(wth->fh);
387 return dct3trace_get_packet(wth->fh, &wth->phdr, wth->frame_buffer,
392 /* Used to read packets in random-access fashion */
393 static gboolean dct3trace_seek_read(wtap *wth, gint64 seek_off,
394 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
396 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
401 return dct3trace_get_packet(wth->random_fh, phdr, buf, err, err_info);
405 * Editor modelines - http://www.wireshark.org/tools/modelines.html
410 * indent-tabs-mode: t
413 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
414 * :indentSize=8:tabSize=8:noTabs=false: