3 * File format support for Rabbit Labs CAM Inspector files
4 * Copyright (c) 2013 by Martin Kaiser <martin@kaiser.cx>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (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 along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 /* CAM Inspector is a commercial log tool for DVB-CI
29 it stores recorded packets between a CI module and a DVB receiver,
30 using a proprietary file format
32 a CAM Inspector file consists of 16bit blocks
33 the first byte contains payload data,
34 the second byte contains a "transaction type"
36 we currently support the following transaction types
38 0x20 == data transfer from CI module to host
39 0x22 == host reads the lower byte of the size register
40 0x23 == host reads the higher byte of the size register
41 0x2A == host writes the lower byte of the size register
42 0x2B == host writes the higher byte of the size register
43 0x28 == data transfer from host to CI module
45 using these transaction types, we can identify and assemble data transfers
46 from the host to the CAM and vice versa
48 a host->module data transfer will use the following transactions
49 one 0x2A and one 0x2B transaction to write the 16bit size
50 <size> 0x28 transactions to transfer one byte at a time
51 this will be assembled into one packet
53 the module->host transfer is similar
56 when we run into an error while assembling a data transfer, the
57 primary goal is to recover so that we can handle the next transfer
58 correctly (all files I used for testing contained errors where
59 apparently the logging hardware missed some bytes)
68 #include <file_wrappers.h>
74 #define TRANS_CAM_HOST 0x20
75 #define TRANS_READ_SIZE_LOW 0x22
76 #define TRANS_READ_SIZE_HIGH 0x23
77 #define TRANS_HOST_CAM 0x28
78 #define TRANS_WRITE_SIZE_LOW 0x2A
79 #define TRANS_WRITE_SIZE_HIGH 0x2B
81 #define IS_TRANS_SIZE(x) \
82 ((x)==TRANS_WRITE_SIZE_LOW || (x)==TRANS_WRITE_SIZE_HIGH || \
83 (x)==TRANS_READ_SIZE_LOW || (x)==TRANS_READ_SIZE_HIGH)
92 #define RESET_STAT_VALS \
94 *dat_trans_type = 0x00; \
96 size_stat = SIZE_HAVE_NONE; \
99 #define SIZE_ADD_LOW \
100 { size_stat = (size_stat==SIZE_HAVE_HIGH ? SIZE_HAVE_ALL : SIZE_HAVE_LOW); }
102 #define SIZE_ADD_HIGH \
103 { size_stat = (size_stat==SIZE_HAVE_LOW ? SIZE_HAVE_ALL : SIZE_HAVE_HIGH); }
105 /* PCAP DVB-CI pseudo-header, see http://www.kaiser.cx/pcap-dvbci.html */
106 #define DVB_CI_PSEUDO_HDR_VER 0
107 #define DVB_CI_PSEUDO_HDR_LEN 4
108 #define DVB_CI_PSEUDO_HDR_CAM_TO_HOST 0xFF
109 #define DVB_CI_PSEUDO_HDR_HOST_TO_CAM 0xFE
112 /* read a block of data from the camins file and handle the errors */
114 read_block(FILE_T fh
, guint8
*buf
, guint16 buf_len
, int *err
, gchar
**err_info
)
118 bytes_read
= file_read((void *)buf
, buf_len
, fh
);
119 if (bytes_read
!= buf_len
) {
120 *err
= file_error(fh
, err_info
);
121 /* bytes_read==0 is end of file */
122 if (bytes_read
>0 && *err
== 0) {
123 *err
= WTAP_ERR_SHORT_READ
;
132 /* find the transaction type for the data bytes of the next packet
133 and the number of data bytes in that packet
134 the fd is moved such that it can be used in a subsequent call
135 to retrieve the data */
137 find_next_pkt_dat_type_len(FILE_T fh
,
138 guint8
*dat_trans_type
, /* transaction type used for the data bytes */
139 guint16
*dat_len
, /* the number of data bytes in the packet */
140 int *err
, gchar
**err_info
)
143 size_read_t size_stat
;
145 if (!dat_trans_type
|| !dat_len
)
151 if (read_block(fh
, block
, sizeof(block
), err
, err_info
) == FALSE
) {
156 /* our strategy is to continue reading until we have a high and a
157 low size byte for the same direction, duplicates or spurious data
161 case TRANS_READ_SIZE_LOW
:
162 if (*dat_trans_type
!= TRANS_CAM_HOST
)
164 *dat_trans_type
= TRANS_CAM_HOST
;
165 *dat_len
|= block
[0];
168 case TRANS_READ_SIZE_HIGH
:
169 if (*dat_trans_type
!= TRANS_CAM_HOST
)
171 *dat_trans_type
= TRANS_CAM_HOST
;
172 *dat_len
|= (block
[0] << 8);
175 case TRANS_WRITE_SIZE_LOW
:
176 if (*dat_trans_type
!= TRANS_HOST_CAM
)
178 *dat_trans_type
= TRANS_HOST_CAM
;
179 *dat_len
|= block
[0];
182 case TRANS_WRITE_SIZE_HIGH
:
183 if (*dat_trans_type
!= TRANS_HOST_CAM
)
185 *dat_trans_type
= TRANS_HOST_CAM
;
186 *dat_len
|= (block
[0] << 8);
192 } while (size_stat
!= SIZE_HAVE_ALL
);
198 /* buffer allocated by the caller, must be long enough to hold
199 dat_len bytes, ... */
201 read_packet_data(FILE_T fh
, guint8 dat_trans_type
, guint8
*buf
, guint16 dat_len
,
202 int *err
, gchar
**err_info
)
206 guint16 bytes_count
= 0;
211 /* we're not checking for end-of-file here, we read as many bytes as
212 we can get (up to dat_len) and return those
213 end-of-file will be detected when we search for the next packet */
216 while (bytes_count
< dat_len
) {
217 if (read_block(fh
, block
, sizeof(block
), err
, err_info
) == FALSE
)
220 if (block
[1] == dat_trans_type
) {
224 else if (IS_TRANS_SIZE(block
[1])) {
225 /* go back before the size transaction block
226 the next packet should be able to pick up this block */
227 if (-1 == file_seek(fh
, -(gint64
)sizeof(block
), SEEK_CUR
, err
))
237 /* create a DVB-CI pseudo header
238 return its length or -1 for error */
240 create_pseudo_hdr(guint8
*buf
, guint8 dat_trans_type
, guint16 dat_len
)
245 buf
[0] = DVB_CI_PSEUDO_HDR_VER
;
247 if (dat_trans_type
==TRANS_CAM_HOST
)
248 buf
[1] = DVB_CI_PSEUDO_HDR_CAM_TO_HOST
;
249 else if (dat_trans_type
==TRANS_HOST_CAM
)
250 buf
[1] = DVB_CI_PSEUDO_HDR_HOST_TO_CAM
;
254 buf
[2] = (dat_len
>>8) & 0xFF;
255 buf
[3] = dat_len
& 0xFF;
257 return DVB_CI_PSEUDO_HDR_LEN
;
262 camins_read_packet(FILE_T fh
, struct wtap_pkthdr
*phdr
, Buffer
*buf
,
263 int *err
, gchar
**err_info
)
265 guint8 dat_trans_type
;
268 gint offset
, bytes_read
;
270 if (!find_next_pkt_dat_type_len(fh
, &dat_trans_type
, &dat_len
, err
, err_info
))
273 buffer_assure_space(buf
, DVB_CI_PSEUDO_HDR_LEN
+dat_len
);
274 p
= buffer_start_ptr(buf
);
275 /* NULL check for p is done in create_pseudo_hdr() */
276 offset
= create_pseudo_hdr(p
, dat_trans_type
, dat_len
);
278 /* shouldn't happen, all invalid packets must be detected by
279 find_next_pkt_dat_type_len() */
280 *err
= WTAP_ERR_INTERNAL
;
284 bytes_read
= read_packet_data(fh
, dat_trans_type
,
285 &p
[offset
], dat_len
, err
, err_info
);
286 /* 0<=bytes_read<=dat_len is very likely a corrupted packet
287 we let the dissector handle this */
290 offset
+= bytes_read
;
292 phdr
->pkt_encap
= WTAP_ENCAP_DVBCI
;
293 /* timestamps aren't supported for now */
294 phdr
->caplen
= offset
;
302 camins_read(wtap
*wth
, int *err
, gchar
**err_info
, gint64
*data_offset
)
304 *data_offset
= file_tell(wth
->fh
);
306 return camins_read_packet(wth
->fh
, &wth
->phdr
, wth
->frame_buffer
, err
,
312 camins_seek_read(wtap
*wth
, gint64 seek_off
,
313 struct wtap_pkthdr
*pkthdr
, Buffer
*buf
, int length _U_
,
314 int *err
, gchar
**err_info
)
316 if (-1 == file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
))
319 return camins_read_packet(wth
->random_fh
, pkthdr
, buf
, err
, err_info
);
324 int camins_open(wtap
*wth
, int *err
, gchar
**err_info _U_
)
326 guint8 found_start_blocks
= 0;
331 /* all CAM Inspector files I've looked at have at least two blocks of
332 0x00 0xE1 within the first 20 bytes */
334 bytes_read
= file_read(block
, sizeof(block
), wth
->fh
);
335 if (bytes_read
!= sizeof(block
))
338 if (block
[0]==0x00 && block
[1] == 0xE1)
339 found_start_blocks
++;
344 if (found_start_blocks
< 2)
345 return 0; /* no CAM Inspector file */
347 /* rewind the fh so we re-read from the beginning */
348 if (-1 == file_seek(wth
->fh
, 0, SEEK_SET
, err
))
351 wth
->file_encap
= WTAP_ENCAP_DVBCI
;
352 wth
->snapshot_length
= 0;
353 wth
->tsprecision
= WTAP_FILE_TSPREC_MSEC
;
357 wth
->subtype_read
= camins_read
;
358 wth
->subtype_seek_read
= camins_seek_read
;
359 wth
->file_type_subtype
= WTAP_FILE_TYPE_SUBTYPE_CAMINS
;
367 * Editor modelines - http://www.wireshark.org/tools/modelines.html
372 * indent-tabs-mode: nil
375 * vi: set shiftwidth=4 tabstop=8 expandtab:
376 * :indentSize=4:tabSize=8:noTabs=true: