4 * routines for importing tektronix k12xx *.rf5 files
6 * Copyright (c) 2005, Luis E. Garia Ontanon <luis.ontanon@gmail.com>
11 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
36 #include "file_wrappers.h"
40 static const guint8 k12_file_magic[] = { 0x00, 0x00, 0x02, 0x00 ,0x12, 0x05, 0x00, 0x10 };
42 #define K12_REC_PACKET 0x00010020
43 #define K12_REC_SRCDSC 0x00070041
45 /* XXX: we don't know what is in these type of records */
46 #define K12_REC_UNK001 0x00070040
47 #define K12_REC_UNK002 0x00070042
48 #define K12_REC_UNK003 0x00070044
50 /* So far we've seen the following appear only at the end of the file */
51 #define K12_REC_UNK004 0x00020030
52 #define K12_REC_UNK005 0x00020031
54 #define K12_HDR_LEN 0x10
74 k12_stack_encap_t* stack_encap;
76 GPtrArray *port_encaps;
80 static const k12_stack_encap_t virgin_stack_encap[] = {
81 {NULL,WTAP_ENCAP_USER0},
82 {NULL,WTAP_ENCAP_USER1},
83 {NULL,WTAP_ENCAP_USER2},
84 {NULL,WTAP_ENCAP_USER3},
85 {NULL,WTAP_ENCAP_USER4},
86 {NULL,WTAP_ENCAP_USER5},
87 {NULL,WTAP_ENCAP_USER6},
88 {NULL,WTAP_ENCAP_USER7},
89 {NULL,WTAP_ENCAP_USER8},
90 {NULL,WTAP_ENCAP_USER9},
91 {NULL,WTAP_ENCAP_USER10},
92 {NULL,WTAP_ENCAP_USER11},
93 {NULL,WTAP_ENCAP_USER12},
94 {NULL,WTAP_ENCAP_USER13},
95 {NULL,WTAP_ENCAP_USER14},
96 /* {NULL,WTAP_ENCAP_USER15}, used for unnknown sources */
101 static guint32 choose_encap(k12_t* file_data, guint32 port_id, gchar* stack_name) {
103 k12_port_encap_t* pe;
106 for (i =0; i < file_data->stack_encap_p; i++) {
108 if (strcmp(stack_name,file_data->stack_encap[i].name) == 0) {
109 encap = file_data->stack_encap[i].encap;
115 if (file_data->stack_encap_p > 14) {
116 /* g_warning("k12_choose_encap: Cannot handle more than 15 stack types"); */
117 return WTAP_ENCAP_USER15;
121 file_data->stack_encap[file_data->stack_encap_p].name = stack_name;
122 encap = file_data->stack_encap[file_data->stack_encap_p].encap;
125 pe = g_malloc(sizeof(k12_port_encap_t));
126 pe->port_id = port_id;
129 g_ptr_array_add(file_data->port_encaps,pe);
133 static guint32 get_encap(k12_t* file_data, guint32 port_id) {
135 k12_port_encap_t* pe;
137 for (i = 0; i < file_data->port_encaps->len; i++) {
138 pe = g_ptr_array_index(file_data->port_encaps,i);
140 if (pe->port_id == port_id)
144 /*g_warning("k12_get_encap: BUG: found no encapsulation for source 0x%.8x\n"
145 "please report this to ethereal-dev@ethereal.com", port_id);*/
147 return WTAP_ENCAP_USER15;
153 * get_k12_hdr: hunt for the next valid header in the file.
157 * the lenght of the preamble (0 if none) if OK.
159 * Record headers are 4 4byte words long,
160 * - the first is the lenght of the record
161 * - the second is the type of the record
162 * - the third is the lenght of the frame in packet records
163 * - the last is the source id to which it refers
165 * Every about 0x2000 bytes up to 4 words are inserted in the file,
166 * not being able yet to understand *exactly* how and where these
167 * are inserted we need to scan the file for the next valid header.
170 gboolean get_k12_hdr(k12_record_hdr_t* hdr, wtap* wth, int* err, gchar **err_info) {
171 guint8 hdr_buf[0x14]; /* five 32bit "slots" */
177 * XXX: as most records are contiguous we could
178 * avoid hunting when not in the "risky zones".
180 * gboolean risky = ( (file_offset-0x210) % 0x2000) > 0x1f00 ||
181 * (file_offset-0x210) % 0x2000) < 0x0100 );
183 * We'll take the conservative approach and avoid trouble altogether.
186 /* read the first three words inserting them from the second slot on */
188 if ((len = file_read(hdr_buf + 0x4, 1, 0xC, wth->fh)) != 0xC) {
190 if (hdr_buf[0x4] == 0xff && hdr_buf[0x5] == 0xff) {
195 *err = file_error(wth->fh);
197 *err = WTAP_ERR_SHORT_READ;
204 * XXX: The stuffing should be be at most 0x10.
206 * We do not know if the record types we know are all of them.
208 * Instead of failing we could try to skip a record whose type we do
209 * not know yet. In that case however it is possible that a "magic"
210 * number appears in the record and unpredictable things would happen.
211 * We won't try, we'll fail and ask for feedback.
215 g_warning("get_k12_hdr: found more than 4 words of stuffing, this should not happen!\n"
216 "please report this issue to ethereal-dev@ethereal.com");
221 /* read the next word into the last slot */
222 if ( file_read( hdr_buf + K12_HDR_LEN, 1, 0x4, wth->fh) != 0x4 ) {
223 *err = WTAP_ERR_SHORT_READ;
224 *err_info = "record too short while reading .rf5 file";
230 /* shift the buffer one word left */
231 /* XXX: working with words this would be faster */
232 for ( i = 0 ; i < 16 ; i++ )
233 hdr_buf[i] = hdr_buf[i + 0x4];
235 /* we'll be done if the second word is a magic number */
236 magic = pntohl( hdr_buf + 0x4 );
238 } while (magic != K12_REC_PACKET &&
239 magic != K12_REC_SRCDSC &&
240 magic != K12_REC_UNK001 &&
241 magic != K12_REC_UNK002 &&
242 magic != K12_REC_UNK003 &&
243 magic != K12_REC_UNK004 &&
244 magic != K12_REC_UNK005 );
246 hdr->len = 0x0000FFFF & pntohl( hdr_buf ); /* the first two bytes off the record len may contain junk */
248 hdr->frame_len = 0x0000FFFF & pntohl( hdr_buf + 0x8 );
249 hdr->port_id = pntohl( hdr_buf + 0xC );
251 return len - K12_HDR_LEN;
254 static gboolean k12_read(wtap *wth, int *err, gchar **err_info, long *data_offset) {
257 guint8* junk[0x1000];
258 k12_record_hdr_t hdr;
261 *data_offset = wth->data_offset;
263 /* ignore the record if it isn't a packet */
270 /* skip the whole record */
272 if ( file_read(junk,1, hdr.len - K12_HDR_LEN , wth->fh) != (gint) (hdr.len - K12_HDR_LEN) ) {
273 *err = WTAP_ERR_SHORT_READ;
274 *err_info = "record too short while reading .rf5 file";
278 } else if (stuffing < 0) {
282 switch ( s = get_k12_hdr(&hdr, wth, err, err_info) ) {
286 *data_offset = wth->data_offset = wth->capture.k12->file_len;
297 } while ( hdr.type != K12_REC_PACKET
298 || hdr.len < hdr.frame_len + 0x20 );
300 wth->data_offset += stuffing + 0x10;
302 if ( wth->file_encap == WTAP_ENCAP_PER_PACKET) {
303 wth->phdr.pkt_encap = get_encap(wth->capture.k12,hdr.port_id);
305 wth->phdr.pkt_encap = WTAP_ENCAP_USER0;
308 /* XXX: is in there something useful in these 8 bytes ? */
309 if ( file_read(b,1,8,wth->fh) != 8 ) {
310 *err = WTAP_ERR_SHORT_READ;
311 *err_info = "record too short while reading .rf5 file";
315 wth->data_offset += 8;
318 /* the next 8 bytes are the timestamp */
319 if ( file_read(b,1,8,wth->fh) != 8 ) {
320 *err = WTAP_ERR_SHORT_READ;
321 *err_info = "record too short while reading .rf5 file";
325 wth->data_offset += 8;
329 wth->phdr.ts.tv_usec = (guint32) ( (ts % 2000000) / 2);
330 wth->phdr.ts.tv_sec = (guint32) ((ts / 2000000) + 631152000);
332 wth->phdr.caplen = wth->phdr.len = hdr.frame_len;
335 buffer_assure_space(wth->frame_buffer, hdr.frame_len);
336 wtap_file_read_expected_bytes(buffer_start_ptr(wth->frame_buffer), hdr.frame_len, wth->fh, err);
337 wth->data_offset += hdr.frame_len;
339 /* XXX: should we read to a junk buffer instead of seeking? */
340 /* XXX: is there useful stuff in the trailer? */
341 if ( file_read(junk,1, hdr.len - ( hdr.frame_len + 0x20) , wth->fh) != (gint) ( hdr.len - ( hdr.frame_len + 0x20)) ) {
342 *err = WTAP_ERR_SHORT_READ;
343 *err_info = "record too short while reading .rf5 file";
347 wth->data_offset += hdr.len - ( hdr.frame_len + 0x20);
352 static gboolean k12_seek_read(wtap *wth, long seek_off, union wtap_pseudo_header *pseudo_header _U_, guchar *pd, int length, int *err _U_, gchar **err_info _U_) {
354 if ( file_seek(wth->random_fh, seek_off+0x20, SEEK_SET, err) == -1)
357 if ( file_read(pd, 1, length, wth->random_fh) != length) {
358 *err = file_error(wth->random_fh);
360 *err = WTAP_ERR_SHORT_READ;
367 static void destroy_k12_file_data(k12_t* file_data) {
369 for (i =0; i<=file_data->stack_encap_p; i++) {
370 if (file_data->stack_encap[i].name) {
371 g_free(file_data->stack_encap[i].name);
372 file_data->stack_encap[i].name = NULL;
376 if (file_data->port_encaps) {
377 g_ptr_array_free(file_data->port_encaps,TRUE);
382 static void k12_close(wtap *wth) {
383 destroy_k12_file_data(wth->capture.k12);
387 * The first few records of a file contain a description of the file:
388 * - the description of the sources (ports or circuits)
389 * - some other useless or yet unknown data.
391 * After that we'll find the packet records. At the end sometimes we find
392 * some other (summary?) records.
395 int k12_open(wtap *wth, int *err, gchar **err_info) {
396 gchar read_buffer[0x1000];
397 k12_record_hdr_t hdr;
408 * let's check the magic number.
410 if ( file_read(read_buffer,1,8,wth->fh) != 8 ) {
413 if ( memcmp(read_buffer,k12_file_magic,8) != 0 )
417 /* the lenght of the file is in the next 4byte word */
418 if ( file_read(read_buffer,1,4,wth->fh) != 4 ) {
422 file_data = g_malloc(sizeof(k12_t));
424 file_data->stack_encap_p = 0;
425 file_data->port_encaps = g_ptr_array_new();
426 file_data->stack_encap = g_memdup(virgin_stack_encap,sizeof(virgin_stack_encap));
427 file_data->file_len = pntohl( read_buffer );
430 * we don't know yet what's in the file header
432 if (file_read(read_buffer,1,0x204,wth->fh) != 0x204 ) {
433 destroy_k12_file_data(file_data);
437 wth->data_offset = offset = 0x210;
440 * start reading the records until we hit the first packet record
444 if (offset > 0x10000) {
445 /* too much to be ok. */
449 stuffing = get_k12_hdr(&hdr, wth, err, err_info);
453 if ( hdr.type == K12_REC_PACKET) {
455 * we are at the first packet record, rewind and leave.
457 if (file_seek(wth->fh, -0x10, SEEK_CUR, err) == -1) {
458 destroy_k12_file_data(file_data);
463 } else if (hdr.type == K12_REC_SRCDSC) {
465 if ( file_read( read_buffer, 1, 0x14, wth->fh) != 0x14 ) {
466 *err = WTAP_ERR_SHORT_READ;
470 name_len = pntohs( read_buffer + 0x10 );
471 stack_len = pntohs( read_buffer + 0x12 );
474 read_len = hdr.len - (0x10 + 0x14 + name_len + stack_len);
477 /* skip the still unknown part */
478 if (file_read(read_buffer,1, read_len,wth->fh) != read_len ) {
479 destroy_k12_file_data(file_data);
480 *err = WTAP_ERR_SHORT_READ;
483 } else if (read_len < 0) {
484 destroy_k12_file_data(file_data);
485 *err = WTAP_ERR_BAD_RECORD;
489 /* the rest of the record contains two null terminated strings:
490 the source label and the "stack" filename */
491 if ( file_read(read_buffer, 1, name_len, wth->fh) != (int)name_len ) {
492 destroy_k12_file_data(file_data);
493 *err = WTAP_ERR_SHORT_READ;
494 *err_info = "record too short while reading .rf5 file";
498 port_name = g_strndup(read_buffer,stack_len);
500 if ( file_read(read_buffer, 1, stack_len, wth->fh) != (int)stack_len ) {
501 destroy_k12_file_data(file_data);
502 *err = WTAP_ERR_SHORT_READ;
503 *err_info = "record too short while reading .rf5 file";
507 stack_file =g_strndup(read_buffer,stack_len);
509 if (choose_encap(file_data,hdr.port_id,stack_file) == WTAP_NUM_ENCAP_TYPES ) {
510 destroy_k12_file_data(file_data);
511 /* more encapsulation types than we can handle */
518 /* we don't need these other fellows */
520 if (file_read(read_buffer,1, hdr.len - K12_HDR_LEN, wth->fh) != (int) hdr.len - K12_HDR_LEN ) {
521 destroy_k12_file_data(file_data);
531 wth->data_offset = offset;
532 wth->file_type = WTAP_FILE_K12;
533 wth->snapshot_length = 0;
534 wth->subtype_read = k12_read;
535 wth->subtype_seek_read = k12_seek_read;
536 wth->subtype_close = k12_close;
537 wth->capture.k12 = file_data;
539 /* if we use just one encapsulation for all the file
540 we will use that for the whole file so we can
541 use more formats to save to */
543 if (file_data->port_encaps->len == 1) {
544 wth->file_encap = ((k12_stack_encap_t*)g_ptr_array_index(file_data->port_encaps,0))->encap;
546 wth->file_encap = WTAP_ENCAP_PER_PACKET;