sec_vt_header: dissect drep
[wireshark-wip.git] / wiretap / camins.c
blobc143567f71c44a09893997e3fdf1f810f393cdb0
1 /* camins.c
3 * File format support for Rabbit Labs CAM Inspector files
4 * Copyright (c) 2013 by Martin Kaiser <martin@kaiser.cx>
6 * $Id$
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
55 error handling
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)
62 #include "config.h"
64 #include <string.h>
65 #include <glib.h>
66 #include <wtap.h>
67 #include <wtap-int.h>
68 #include <file_wrappers.h>
69 #include <buffer.h>
71 #include "camins.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)
85 typedef enum {
86 SIZE_HAVE_NONE,
87 SIZE_HAVE_LOW,
88 SIZE_HAVE_HIGH,
89 SIZE_HAVE_ALL
90 } size_read_t;
92 #define RESET_STAT_VALS \
93 { \
94 *dat_trans_type = 0x00; \
95 *dat_len = 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 */
113 static gboolean
114 read_block(FILE_T fh, guint8 *buf, guint16 buf_len, int *err, gchar **err_info)
116 int bytes_read;
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;
125 return FALSE;
128 return TRUE;
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 */
136 static gboolean
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)
142 guint8 block[2];
143 size_read_t size_stat;
145 if (!dat_trans_type || !dat_len)
146 return FALSE;
148 RESET_STAT_VALS;
150 do {
151 if (read_block(fh, block, sizeof(block), err, err_info) == FALSE) {
152 RESET_STAT_VALS;
153 return 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
158 bytes are ignored */
160 switch (block[1]) {
161 case TRANS_READ_SIZE_LOW:
162 if (*dat_trans_type != TRANS_CAM_HOST)
163 RESET_STAT_VALS;
164 *dat_trans_type = TRANS_CAM_HOST;
165 *dat_len |= block[0];
166 SIZE_ADD_LOW;
167 break;
168 case TRANS_READ_SIZE_HIGH:
169 if (*dat_trans_type != TRANS_CAM_HOST)
170 RESET_STAT_VALS;
171 *dat_trans_type = TRANS_CAM_HOST;
172 *dat_len |= (block[0] << 8);
173 SIZE_ADD_HIGH;
174 break;
175 case TRANS_WRITE_SIZE_LOW:
176 if (*dat_trans_type != TRANS_HOST_CAM)
177 RESET_STAT_VALS;
178 *dat_trans_type = TRANS_HOST_CAM;
179 *dat_len |= block[0];
180 SIZE_ADD_LOW;
181 break;
182 case TRANS_WRITE_SIZE_HIGH:
183 if (*dat_trans_type != TRANS_HOST_CAM)
184 RESET_STAT_VALS;
185 *dat_trans_type = TRANS_HOST_CAM;
186 *dat_len |= (block[0] << 8);
187 SIZE_ADD_HIGH;
188 break;
189 default:
190 break;
192 } while (size_stat != SIZE_HAVE_ALL);
194 return TRUE;
198 /* buffer allocated by the caller, must be long enough to hold
199 dat_len bytes, ... */
200 static gint
201 read_packet_data(FILE_T fh, guint8 dat_trans_type, guint8 *buf, guint16 dat_len,
202 int *err, gchar **err_info)
204 guint8 *p;
205 guint8 block[2];
206 guint16 bytes_count = 0;
208 if (!buf)
209 return -1;
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 */
215 p = buf;
216 while (bytes_count < dat_len) {
217 if (read_block(fh, block, sizeof(block), err, err_info) == FALSE)
218 break;
220 if (block[1] == dat_trans_type) {
221 *p++ = block[0];
222 bytes_count++;
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))
228 return -1;
229 break;
233 return bytes_count;
237 /* create a DVB-CI pseudo header
238 return its length or -1 for error */
239 static gint
240 create_pseudo_hdr(guint8 *buf, guint8 dat_trans_type, guint16 dat_len)
242 if (!buf)
243 return -1;
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;
251 else
252 return -1;
254 buf[2] = (dat_len>>8) & 0xFF;
255 buf[3] = dat_len & 0xFF;
257 return DVB_CI_PSEUDO_HDR_LEN;
261 static gboolean
262 camins_read_packet(FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
263 int *err, gchar **err_info)
265 guint8 dat_trans_type;
266 guint16 dat_len;
267 guint8 *p;
268 gint offset, bytes_read;
270 if (!find_next_pkt_dat_type_len(fh, &dat_trans_type, &dat_len, err, err_info))
271 return FALSE;
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);
277 if (offset<0) {
278 /* shouldn't happen, all invalid packets must be detected by
279 find_next_pkt_dat_type_len() */
280 *err = WTAP_ERR_INTERNAL;
281 return FALSE;
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 */
288 if (bytes_read < 0)
289 return FALSE;
290 offset += bytes_read;
292 phdr->pkt_encap = WTAP_ENCAP_DVBCI;
293 /* timestamps aren't supported for now */
294 phdr->caplen = offset;
295 phdr->len = offset;
297 return TRUE;
301 static gboolean
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,
307 err_info);
311 static gboolean
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))
317 return FALSE;
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;
327 guint8 count = 0;
328 guint8 block[2];
329 int bytes_read;
331 /* all CAM Inspector files I've looked at have at least two blocks of
332 0x00 0xE1 within the first 20 bytes */
333 do {
334 bytes_read = file_read(block, sizeof(block), wth->fh);
335 if (bytes_read != sizeof(block))
336 break;
338 if (block[0]==0x00 && block[1] == 0xE1)
339 found_start_blocks++;
341 count++;
342 } while (count<20);
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))
349 return -1;
351 wth->file_encap = WTAP_ENCAP_DVBCI;
352 wth->snapshot_length = 0;
353 wth->tsprecision = WTAP_FILE_TSPREC_MSEC;
355 wth->priv = NULL;
357 wth->subtype_read = camins_read;
358 wth->subtype_seek_read = camins_seek_read;
359 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_CAMINS;
361 *err = 0;
362 return 1;
367 * Editor modelines - http://www.wireshark.org/tools/modelines.html
369 * Local variables:
370 * c-basic-offset: 4
371 * tab-width: 8
372 * indent-tabs-mode: nil
373 * End:
375 * vi: set shiftwidth=4 tabstop=8 expandtab:
376 * :indentSize=4:tabSize=8:noTabs=true: