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>
12 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #include "dct3trace.h"
33 #include "file_wrappers.h"
42 Example downlink data:
46 <l1 direction="down" logicalchannel="96" physicalchannel="19" sequence="268116" error="0" timeshift="2992" bsic="22" data="31063F100DD0297A53E1020103C802398E0B2B2B2B2B2B" >
47 <l2 data="063F100DD0297A53E1020103" rest="C802398E0B2B2B2B2B2B" >
52 Example uplink data (no raw L1):
56 <l1 direction="up" logicalchannel="112" >
57 <l2 type="U" subtype="Unknown" p="0" data="061500400000000000000000000000000000" >
65 /* Magic text to check */
66 static const char dct3trace_magic_line1
[] = "<?xml version=\"1.0\"?>";
67 static const char dct3trace_magic_line2
[] = "<dump>";
68 static const char dct3trace_magic_record_start
[] = "<l1 ";
69 static const char dct3trace_magic_record_end
[] = "</l1>";
70 static const char dct3trace_magic_l2_start
[] = "<l2 ";
71 #if 0 /* Not used ?? */
72 static const char dct3trace_magic_l2_end
[] = "</l2>";
74 static const char dct3trace_magic_end
[] = "</dump>";
76 #define MAX_PACKET_LEN 23
78 static gboolean
dct3trace_read(wtap
*wth
, int *err
, gchar
**err_info
,
80 static gboolean
dct3trace_seek_read(wtap
*wth
, gint64 seek_off
,
81 struct wtap_pkthdr
*phdr
, Buffer
*buf
, int len
,
82 int *err
, gchar
**err_info
);
85 * Following 3 functions taken from gsmdecode-0.7bis, with permission - http://wiki.thc.org/gsm
89 hc2b(unsigned char hex
)
92 if ((hex
>= '0') && (hex
<= '9'))
94 if ((hex
>= 'a') && (hex
<= 'f'))
95 return hex
- 'a' + 10;
100 hex2bin(guint8
*out
, guint8
*out_end
, char *in
)
102 guint8
*out_start
= out
;
108 c
= hc2b(*(unsigned char *)in
);
131 return (int)(out
- out_start
);
135 xml_get_int(int *val
, const char *str
, const char *pattern
)
141 ptr
= strstr(str
, pattern
);
144 start
= strchr(ptr
, '"');
148 end
= strchr(start
, '"');
151 if (end
- start
> 31)
154 memcpy(buf
, start
, end
- start
);
155 buf
[end
- start
] = '\0';
161 int dct3trace_open(wtap
*wth
, int *err
, gchar
**err_info
)
163 char line1
[64], line2
[64];
165 /* Look for Gammu DCT3 trace header */
166 if (file_gets(line1
, sizeof(line1
), wth
->fh
) == NULL
||
167 file_gets(line2
, sizeof(line2
), wth
->fh
) == NULL
)
169 *err
= file_error(wth
->fh
, err_info
);
170 if (*err
!= 0 && *err
!= WTAP_ERR_SHORT_READ
)
175 /* Don't compare line endings */
176 if( strncmp(dct3trace_magic_line1
, line1
, strlen(dct3trace_magic_line1
)) != 0 ||
177 strncmp(dct3trace_magic_line2
, line2
, strlen(dct3trace_magic_line2
)) != 0)
182 wth
->file_encap
= WTAP_ENCAP_GSM_UM
;
183 wth
->file_type_subtype
= WTAP_FILE_TYPE_SUBTYPE_DCT3TRACE
;
184 wth
->snapshot_length
= 0; /* not known */
185 wth
->subtype_read
= dct3trace_read
;
186 wth
->subtype_seek_read
= dct3trace_seek_read
;
187 wth
->tsprecision
= WTAP_FILE_TSPREC_SEC
;
193 static gboolean
dct3trace_get_packet(FILE_T fh
, struct wtap_pkthdr
*phdr
,
194 Buffer
*buf
, int *err
, gchar
**err_info
)
197 guint8 databuf
[MAX_PACKET_LEN
], *bufp
;
198 gboolean have_data
= FALSE
;
202 while (file_gets(line
, sizeof(line
), fh
) != NULL
)
204 if( memcmp(dct3trace_magic_end
, line
, strlen(dct3trace_magic_end
)) == 0 )
206 /* Return on end of file </dump> */
210 else if( memcmp(dct3trace_magic_record_end
, line
, strlen(dct3trace_magic_record_end
)) == 0 )
212 /* Return on end of record </l1> */
215 /* We've got a full packet! */
216 phdr
->presence_flags
= 0; /* no time stamp, no separate "on the wire" length */
224 /* Make sure we have enough room for the packet */
225 buffer_assure_space(buf
, phdr
->caplen
);
226 memcpy( buffer_start_ptr(buf
), databuf
, phdr
->caplen
);
232 /* If not got any data return error */
233 *err
= WTAP_ERR_BAD_FILE
;
234 *err_info
= g_strdup_printf("dct3trace: record without data");
238 else if( memcmp(dct3trace_magic_record_start
, line
, strlen(dct3trace_magic_record_start
)) == 0 )
240 /* Parse L1 header <l1 ...>*/
244 phdr
->pseudo_header
.gsm_um
.uplink
= !strstr(line
, "direction=\"down\"");
245 if (xml_get_int(&channel
, line
, "logicalchannel") != 0)
248 /* Parse downlink only fields */
249 if( !phdr
->pseudo_header
.gsm_um
.uplink
)
251 if (xml_get_int(&tmp
, line
, "physicalchannel") != 0)
253 phdr
->pseudo_header
.gsm_um
.arfcn
= tmp
;
254 if (xml_get_int(&tmp
, line
, "sequence") != 0)
256 phdr
->pseudo_header
.gsm_um
.tdma_frame
= tmp
;
257 if (xml_get_int(&tmp
, line
, "bsic") != 0)
259 phdr
->pseudo_header
.gsm_um
.bsic
= tmp
;
260 if (xml_get_int(&tmp
, line
, "error") != 0)
262 phdr
->pseudo_header
.gsm_um
.error
= tmp
;
263 if (xml_get_int(&tmp
, line
, "timeshift") != 0)
265 phdr
->pseudo_header
.gsm_um
.timeshift
= tmp
;
270 case 128: phdr
->pseudo_header
.gsm_um
.channel
= GSM_UM_CHANNEL_SDCCH
; break;
271 case 112: phdr
->pseudo_header
.gsm_um
.channel
= GSM_UM_CHANNEL_SACCH
; break;
272 case 176: phdr
->pseudo_header
.gsm_um
.channel
= GSM_UM_CHANNEL_FACCH
; break;
273 case 96: phdr
->pseudo_header
.gsm_um
.channel
= GSM_UM_CHANNEL_CCCH
; break;
274 case 80: phdr
->pseudo_header
.gsm_um
.channel
= GSM_UM_CHANNEL_BCCH
; break;
275 default: phdr
->pseudo_header
.gsm_um
.channel
= GSM_UM_CHANNEL_UNKNOWN
; break;
278 /* Read data (if have it) into databuf */
279 ptr
= strstr(line
, "data=\"");
282 have_data
= TRUE
; /* If has data... */
283 len
= hex2bin(bufp
, &databuf
[MAX_PACKET_LEN
], ptr
+6);
286 *err
= WTAP_ERR_BAD_FILE
;
287 *err_info
= g_strdup_printf("dct3trace: record length %d too long", phdr
->caplen
);
292 else if( !have_data
&& memcmp(dct3trace_magic_l2_start
, line
, strlen(dct3trace_magic_l2_start
)) == 0 )
294 /* For uplink packets we might not get the raw L1, so have to recreate it from the L2 */
295 /* Parse L2 header if didn't get data from L1 <l2 ...> */
297 char *ptr
= strstr(line
, "data=\"");
307 * We know we have no data already, so we know
308 * we have enough room for the header.
310 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
)
312 /* Add LAPDm B header */
313 memset(bufp
, 0x1, 2);
318 /* Add LAPDm Bbis header */
323 data_len
= hex2bin(bufp
, &databuf
[MAX_PACKET_LEN
], ptr
+6);
326 *err
= WTAP_ERR_BAD_FILE
;
327 *err_info
= g_strdup_printf("dct3trace: record length %d too long", phdr
->caplen
);
332 /* Add LAPDm length byte */
333 *(bufp
- 1) = data_len
<< 2 | 0x1;
337 *err
= file_error(fh
, err_info
);
340 *err
= WTAP_ERR_SHORT_READ
;
345 *err
= WTAP_ERR_BAD_FILE
;
346 *err_info
= g_strdup_printf("dct3trace: record missing mandatory attributes");
351 /* Find the next packet and parse it; called from wtap_read(). */
352 static gboolean
dct3trace_read(wtap
*wth
, int *err
, gchar
**err_info
,
355 *data_offset
= file_tell(wth
->fh
);
357 return dct3trace_get_packet(wth
->fh
, &wth
->phdr
, wth
->frame_buffer
,
362 /* Used to read packets in random-access fashion */
363 static gboolean
dct3trace_seek_read(wtap
*wth
, gint64 seek_off
,
364 struct wtap_pkthdr
*phdr
, Buffer
*buf
, int len _U_
,
365 int *err
, gchar
**err_info
)
367 if (file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
) == -1)
372 return dct3trace_get_packet(wth
->random_fh
, phdr
, buf
, err
, err_info
);