diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common index 1a07751cc1..2b145d42b2 100644 --- a/epan/dissectors/Makefile.common +++ b/epan/dissectors/Makefile.common @@ -349,6 +349,7 @@ DISSECTOR_SRC = \ packet-jabber.c \ packet-juniper.c \ packet-jxta.c \ + packet-k12.c \ packet-kadm5.c \ packet-kerberos.c \ packet-kerberos4.c \ diff --git a/epan/dissectors/packet-k12.c b/epan/dissectors/packet-k12.c new file mode 100644 index 0000000000..e684435818 --- /dev/null +++ b/epan/dissectors/packet-k12.c @@ -0,0 +1,199 @@ +/* packet-k12.c +* Routines for displaying frames from k12 rf5 files +* +* Luis E. Garcia Ontanon +* +* $Id$ +* +* Ethereal - Network traffic analyzer +* By Gerald Combs +* Copyright 1998 +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include + +static int proto_k12 = -1; + +static int hf_k12_port_id = -1; +static int hf_k12_port_name = -1; +static int hf_k12_stack_file = -1; + +static gint ett_k12 = -1; + +static dissector_handle_t k12_handle; +static dissector_handle_t data_handle; + +static module_t *k12_module; + +static char* k12_config_filename = ""; + +static GHashTable* k12_cfg = NULL; + +static void dissect_k12(tvbuff_t* tvb,packet_info* pinfo,proto_tree* tree) { + proto_item* k12_item; + proto_tree* k12_tree; + dissector_handle_t sub_handle; + + k12_item = proto_tree_add_protocol_format(tree, proto_k12, tvb, 0, 0, "Packet from: '%s' (0x%.8x)", + pinfo->pseudo_header->k12.src_name, + pinfo->pseudo_header->k12.src_id); + + k12_tree = proto_item_add_subtree(k12_item, ett_k12); + + proto_tree_add_uint(k12_tree, hf_k12_port_id, tvb, 0,0,pinfo->pseudo_header->k12.src_id); + proto_tree_add_string(k12_tree, hf_k12_port_name, tvb, 0,0,pinfo->pseudo_header->k12.src_name); + proto_tree_add_string(k12_tree, hf_k12_stack_file, tvb, 0,0,pinfo->pseudo_header->k12.stack_file); + + + if (! k12_cfg ) { + sub_handle = data_handle; + } else { + sub_handle = g_hash_table_lookup(k12_cfg,pinfo->pseudo_header->k12.stack_file); + + if (! sub_handle ) + sub_handle = data_handle; + } + + call_dissector(sub_handle, tvb, pinfo, tree); + +} + +static gboolean free_just_key (gpointer k, gpointer v _U_, gpointer p _U_) { + g_free(k); + return TRUE; +} + + +static GHashTable* k12_load_config(FILE* fp) { + gchar buffer[0x10000]; + size_t len; + GHashTable* hash = g_hash_table_new(g_str_hash,g_str_equal); + gchar** curr; + gchar** lines = NULL; + guint i; + dissector_handle_t handle; + + len = fread(buffer,1,0xFFFF,fp); + + if (len > 0) { + lines = g_strsplit(buffer,"\n",0); + + for (i = 0 ; lines[i]; i++) { + g_strstrip(lines[i]); + + if(*(lines[i]) == '#') continue; + if(*(lines[i]) == '\0') break; + + curr = g_strsplit(lines[i]," ",0); + + if (! (curr[0] != NULL && *curr[0] != '\0' && curr[1] != NULL && *curr[1] != '\0' ) ) { + /* XXX report_error */ + g_warning("K12xx: Format error in line %u",i+1); + g_strfreev(curr); + g_strfreev(lines); + g_hash_table_foreach_remove(hash,free_just_key,NULL); + g_hash_table_destroy(hash); + return NULL; + } + + g_strstrip(curr[0]); + g_strstrip(curr[1]); + handle = find_dissector(curr[1]); + + if (! handle ) { + /* XXX report_error */ + g_warning("k12: proto %s not found",curr[1]); + handle = data_handle; + } + + g_hash_table_insert(hash,g_strdup(curr[0]),handle); + g_strfreev(curr); + + } + + g_strfreev(lines); + return hash; + + } + + g_hash_table_destroy(hash); + /* XXX report_error */ + g_warning("K12xx: I/O error"); + return NULL; +} + + +static void k12_load_prefs(void) { + FILE* fp; + + if (k12_cfg) { + g_hash_table_foreach_remove(k12_cfg,free_just_key,NULL); + g_hash_table_destroy(k12_cfg); + k12_cfg = NULL; + } + + if (*k12_config_filename != '\0') { + if (( fp = fopen(k12_config_filename,"r") )) { + k12_cfg = k12_load_config(fp); + return; + } else { + /* XXX report_error */ + g_warning("failed to open: %s",k12_config_filename); + } + } +} + +void proto_reg_handoff_k12(void) { + k12_handle = find_dissector("k12"); + data_handle = find_dissector("data"); + dissector_add("wtap_encap", WTAP_ENCAP_K12, k12_handle); +} + +void +proto_register_k12(void) +{ + static hf_register_info hf[] = { + { &hf_k12_port_id, { "Port Id", "k12.port_id", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }}, + { &hf_k12_port_name, { "Port Name", "k12.port_name", FT_STRING, BASE_NONE, NULL, 0x0,"", HFILL }}, + { &hf_k12_stack_file, { "Stack file used", "k12.stack_file", FT_STRING, BASE_NONE, NULL, 0x0,"", HFILL }} + }; + + static gint *ett[] = { + &ett_k12, + }; + + proto_k12 = proto_register_protocol("K12xx", "K12xx", "k12"); + proto_register_field_array(proto_k12, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + register_dissector("k12", dissect_k12, proto_k12); + + k12_module = prefs_register_protocol(proto_k12, k12_load_prefs); + + prefs_register_string_preference(k12_module, "config", + "Configuration filename", + "K12 module configuration filename", + &k12_config_filename); + +} diff --git a/wiretap/k12.c b/wiretap/k12.c index 660382f24c..d622fff1f3 100644 --- a/wiretap/k12.c +++ b/wiretap/k12.c @@ -36,116 +36,78 @@ #include "file_wrappers.h" #include "buffer.h" +/* + * the 32 bits .rf5 file contains: + * an 8 byte magic number + * 32bit lenght + * 32bit number of records + * other 0x200 bytes bytes of uncharted territory + * 1 or more copies of the num_of_records in there + * the records whose first 32bits word is the length + * they are stuffed by one to four words every 0x2000 bytes + * and a 2 byte terminator FFFF + */ static const guint8 k12_file_magic[] = { 0x00, 0x00, 0x02, 0x00 ,0x12, 0x05, 0x00, 0x10 }; -#define K12_REC_PACKET 0x00010020 -#define K12_REC_SRCDSC 0x00070041 - -/* XXX: we don't know what is in these type of records */ -#define K12_REC_UNK001 0x00070040 -#define K12_REC_UNK002 0x00070042 -#define K12_REC_UNK003 0x00070044 - -/* So far we've seen the following appear only at the end of the file */ -#define K12_REC_UNK004 0x00020030 -#define K12_REC_UNK005 0x00020031 +struct _k12_t { + guint32 file_len; + guint32 num_of_records; /* XXX: not sure about this */ + + GHashTable* src_by_id; /* k12_srcdsc_recs by src_id */ + GHashTable* src_by_name; /* k12_srcdsc_recs by stack_name */ +}; #define K12_HDR_LEN 0x10 -typedef struct { +typedef struct _k12_record_hdr_t { guint32 len; guint32 type; guint32 frame_len; - guint32 port_id; + guint32 input; } k12_record_hdr_t; -typedef struct { - gchar* name; - guint32 encap; -} k12_stack_encap_t; +/* so far we've seen only 7 types of records */ +#define K12_REC_PACKET 0x00010020 +#define K12_REC_SRCDSC 0x00070041 /* port-stack mapping + more, the key of the whole thing */ +#define K12_REC_SCENARIO 0x00070040 /* what appears as the window's title */ +#define K12_REC_70042 0x00070042 /* XXX: ??? */ +#define K12_REC_70044 0x00070044 /* text with a grammar (conditions/responses) */ +#define K12_REC_20030 0x00020030 /* human readable start time */ +#define K12_REC_20032 0x00020031 /* human readable stop time */ -typedef struct { - guint32 port_id; - guint32 encap; -} k12_port_encap_t; +typedef struct _k12_src_desc_t { + k12_record_hdr_t hdr; -struct _k12_t { - k12_stack_encap_t* stack_encap; - guint stack_encap_p; - GPtrArray *port_encaps; - guint32 file_len; -}; + struct _record { + guint32 unk_10; + guint32 unk_14; + guint16 unk_18; + guint16 extra_len; + guint16 name_len; + guint16 stack_len; + } record; + + struct _variable { + guint8* extra_blob; + gchar* port_name; + gchar* stack_file; + } variable; +} k12_src_desc_t; -static const k12_stack_encap_t virgin_stack_encap[] = { - {NULL,WTAP_ENCAP_USER0}, - {NULL,WTAP_ENCAP_USER1}, - {NULL,WTAP_ENCAP_USER2}, - {NULL,WTAP_ENCAP_USER3}, - {NULL,WTAP_ENCAP_USER4}, - {NULL,WTAP_ENCAP_USER5}, - {NULL,WTAP_ENCAP_USER6}, - {NULL,WTAP_ENCAP_USER7}, - {NULL,WTAP_ENCAP_USER8}, - {NULL,WTAP_ENCAP_USER9}, - {NULL,WTAP_ENCAP_USER10}, - {NULL,WTAP_ENCAP_USER11}, - {NULL,WTAP_ENCAP_USER12}, - {NULL,WTAP_ENCAP_USER13}, - {NULL,WTAP_ENCAP_USER14}, - /* {NULL,WTAP_ENCAP_USER15}, used for unnknown sources */ - {NULL,0} -}; +typedef struct { + k12_record_hdr_t hdr; - -static guint32 choose_encap(k12_t* file_data, guint32 port_id, gchar* stack_name) { - guint32 encap = 0; - k12_port_encap_t* pe; - guint i; + struct { + guint32 unk_10; /* some bit of the second nibble is set in some frames */ + guint32 unk_14; /* made of several fields, it increases always, + in consecutive packets from the same port it increases by one. + */ + guint64 ts; + } record; - for (i =0; i < file_data->stack_encap_p; i++) { - - if (strcmp(stack_name,file_data->stack_encap[i].name) == 0) { - encap = file_data->stack_encap[i].encap; - g_free(stack_name); - break; - } - } - - if (file_data->stack_encap_p > 14) { - /* g_warning("k12_choose_encap: Cannot handle more than 15 stack types"); */ - return WTAP_ENCAP_USER15; - } - - if ( encap == 0 ) { - file_data->stack_encap[file_data->stack_encap_p].name = stack_name; - encap = file_data->stack_encap[file_data->stack_encap_p].encap; - } - - pe = g_malloc(sizeof(k12_port_encap_t)); - pe->port_id = port_id; - pe->encap = encap; - - g_ptr_array_add(file_data->port_encaps,pe); - return encap; -} - -static guint32 get_encap(k12_t* file_data, guint32 port_id) { - guint i; - k12_port_encap_t* pe; - - for (i = 0; i < file_data->port_encaps->len; i++) { - pe = g_ptr_array_index(file_data->port_encaps,i); - - if (pe->port_id == port_id) - return pe->encap; - } - - /*g_warning("k12_get_encap: BUG: found no encapsulation for source 0x%.8x\n" - "please report this to ethereal-dev@ethereal.com", port_id);*/ - - return WTAP_ENCAP_USER15; -} + guint8* variable; +} k12_packet_t; @@ -156,48 +118,66 @@ static guint32 get_encap(k12_t* file_data, guint32 port_id) { * -1 at EOF * the lenght of the preamble (0 if none) if OK. * - * Record headers are 4 4byte words long, - * - the first is the lenght of the record - * - the second is the type of the record - * - the third is the lenght of the frame in packet records - * - the last is the source id to which it refers - * * Every about 0x2000 bytes up to 4 words are inserted in the file, * not being able yet to understand *exactly* how and where these * are inserted we need to scan the file for the next valid header. * */ -gboolean get_k12_hdr(k12_record_hdr_t* hdr, wtap* wth, int* err, gchar **err_info) { - guint8 hdr_buf[0x14]; /* five 32bit "slots" */ +gboolean get_k12_hdr(k12_record_hdr_t* hdr, wtap* wth, int* err) { + guint32 hdr_buf[5]; guint32 magic; guint i; guint len; - +#if 0 /* * XXX: as most records are contiguous we could * avoid hunting when not in the "risky zones". - * - * gboolean risky = ( (file_offset-0x210) % 0x2000) > 0x1f00 || - * (file_offset-0x210) % 0x2000) < 0x0100 ); - * + */ + + gboolean risky = ( (wth->data_offset-0x210) % 0x2000 > 0x1e00 || + (wth->data_offset-0x210) % 0x2000 < 0x0200 ); + if (! risky) { + if ( file_read(hdr, 1, sizeof(*hdr), wth->fh) != sizeof(*hdr) ) { + if (! (*err = file_error(wth->fh) ) ) + *err = WTAP_ERR_SHORT_READ; + return -1; + } else { + hdr->len = 0x0000FFFF & pntohl(hdr->len); + hdr->type = pntohl(hdr->type); + hdr->frame_len = 0x0000FFFF & pntohl(hdr->frame_len); + hdr->input = pntohl( hdr->input ); + return 0; + } + } + + /* * We'll take the conservative approach and avoid trouble altogether. */ +#endif + + /* + * we'll hunt for valid headers by loading the candidate header + * in a buffer one word longer, and checking it. + * If it is ok we'll copy it and return ok. + * If it doesn't we'll load the next word shinfting and trying again + */ /* read the first three words inserting them from the second slot on */ - - if ((len = file_read(hdr_buf + 0x4, 1, 0xC, wth->fh)) != 0xC) { + if ((len = file_read(hdr_buf + 1, 1, 0xC, wth->fh)) != 0xC) { if (len == 2) { - if (hdr_buf[0x4] == 0xff && hdr_buf[0x5] == 0xff) { + if ( hdr_buf[1] >> 16 == 0xffff ) { + /* EOF */ + *err = 0; return -1; } } - *err = file_error(wth->fh); - if (*err == 0) + if (! (*err = file_error(wth->fh) ) ) *err = WTAP_ERR_SHORT_READ; + return -2; } - + do { /* @@ -205,58 +185,53 @@ gboolean get_k12_hdr(k12_record_hdr_t* hdr, wtap* wth, int* err, gchar **err_inf * * We do not know if the record types we know are all of them. * - * Instead of failing we could try to skip a record whose type we do + * Instead of failing we could try to skip a record whose type we do * not know yet. In that case however it is possible that a "magic" * number appears in the record and unpredictable things would happen. * We won't try, we'll fail and ask for feedback. */ if ( len > 0x20) { - /* g_warning("get_k12_hdr: found more than 4 words of stuffing, this should not happen!\n" "please report this issue to ethereal-dev@ethereal.com"); - */ return -2; } /* read the next word into the last slot */ - if ( file_read( hdr_buf + K12_HDR_LEN, 1, 0x4, wth->fh) != 0x4 ) { + if ( file_read( hdr_buf + 4 , 1, 0x4, wth->fh) != 0x4 ) { *err = WTAP_ERR_SHORT_READ; - *err_info = "record too short while reading .rf5 file"; return -2; } len += 0x4; - /* shift the buffer one word left */ - /* XXX: working with words this would be faster */ - for ( i = 0 ; i < 16 ; i++ ) - hdr_buf[i] = hdr_buf[i + 0x4]; + for ( i = 0 ; i < 4 ; i++ ) + hdr_buf[i] = hdr_buf[i + 1]; /* we'll be done if the second word is a magic number */ - magic = pntohl( hdr_buf + 0x4 ); + magic = pntohl( hdr_buf + 1 ); } while (magic != K12_REC_PACKET && magic != K12_REC_SRCDSC && - magic != K12_REC_UNK001 && - magic != K12_REC_UNK002 && - magic != K12_REC_UNK003 && - magic != K12_REC_UNK004 && - magic != K12_REC_UNK005 ); + magic != K12_REC_SCENARIO && + magic != K12_REC_70042 && + magic != K12_REC_70044 && + magic != K12_REC_20030 && + magic != K12_REC_20032 ); - hdr->len = 0x0000FFFF & pntohl( hdr_buf ); /* the first two bytes off the record len may contain junk */ + hdr->len = 0x0000FFFF & hdr_buf[0]; /* the first two bytes off the record len may be altered */ hdr->type = magic; - hdr->frame_len = 0x0000FFFF & pntohl( hdr_buf + 0x8 ); - hdr->port_id = pntohl( hdr_buf + 0xC ); - + hdr->frame_len = 0x0000FFFF & pntohl( hdr_buf + 2 ); /* play defensive */ + hdr->input = pntohl( hdr_buf + 3 ); + return len - K12_HDR_LEN; } static gboolean k12_read(wtap *wth, int *err, gchar **err_info, long *data_offset) { - guint64 ts; - guint8 b[8]; - guint8* junk[0x1000]; - k12_record_hdr_t hdr; + guint8* b[0x1000]; + k12_packet_t pkt; gint stuffing = -1; + gint read_len; + k12_src_desc_t* src_desc; *data_offset = wth->data_offset; @@ -265,11 +240,11 @@ static gboolean k12_read(wtap *wth, int *err, gchar **err_info, long *data_offse gint s; if (stuffing >= 0) { - stuffing += hdr.len; + stuffing += pkt.hdr.len; /* skip the whole record */ - if ( file_read(junk,1, hdr.len - K12_HDR_LEN , wth->fh) != (gint) (hdr.len - K12_HDR_LEN) ) { + if ( file_read(b,1, pkt.hdr.len - K12_HDR_LEN , wth->fh) != (gint) (pkt.hdr.len - K12_HDR_LEN) ) { *err = WTAP_ERR_SHORT_READ; *err_info = "record too short while reading .rf5 file"; return FALSE; @@ -279,7 +254,7 @@ static gboolean k12_read(wtap *wth, int *err, gchar **err_info, long *data_offse stuffing = 0; } - switch ( s = get_k12_hdr(&hdr, wth, err, err_info) ) { + switch ( s = get_k12_hdr(&pkt.hdr, wth, err) ) { case -1: /* eof */ *err = 0; @@ -294,66 +269,69 @@ static gboolean k12_read(wtap *wth, int *err, gchar **err_info, long *data_offse stuffing += s; - } while ( hdr.type != K12_REC_PACKET - || hdr.len < hdr.frame_len + 0x20 ); - + } while ( pkt.hdr.type != K12_REC_PACKET + || pkt.hdr.len < pkt.hdr.frame_len + 0x20 ); wth->data_offset += stuffing + 0x10; + - if ( wth->file_encap == WTAP_ENCAP_PER_PACKET) { - wth->phdr.pkt_encap = get_encap(wth->capture.k12,hdr.port_id); - } else { - wth->phdr.pkt_encap = WTAP_ENCAP_USER0; - } - - /* XXX: is in there something useful in these 8 bytes ? */ - if ( file_read(b,1,8,wth->fh) != 8 ) { + if ( file_read(&pkt.record,1,sizeof(pkt.record),wth->fh) != sizeof(pkt.record) ) { *err = WTAP_ERR_SHORT_READ; - *err_info = "record too short while reading .rf5 file"; return FALSE; } - wth->data_offset += 8; + wth->data_offset += sizeof(pkt.record); + + pkt.record.ts = pntohll(&pkt.record.ts); + wth->phdr.ts.tv_usec = (guint32) ( (pkt.record.ts % 2000000) / 2); + wth->phdr.ts.tv_sec = (guint32) ((pkt.record.ts / 2000000) + 631152000); - /* the next 8 bytes are the timestamp */ - if ( file_read(b,1,8,wth->fh) != 8 ) { - *err = WTAP_ERR_SHORT_READ; - *err_info = "record too short while reading .rf5 file"; - return FALSE; - } - - wth->data_offset += 8; - - ts = pntohll(b); - - wth->phdr.ts.tv_usec = (guint32) ( (ts % 2000000) / 2); - wth->phdr.ts.tv_sec = (guint32) ((ts / 2000000) + 631152000); - - wth->phdr.caplen = wth->phdr.len = hdr.frame_len; + wth->phdr.caplen = wth->phdr.len = pkt.hdr.frame_len; /* the frame */ - buffer_assure_space(wth->frame_buffer, hdr.frame_len); - wtap_file_read_expected_bytes(buffer_start_ptr(wth->frame_buffer), hdr.frame_len, wth->fh, err); - wth->data_offset += hdr.frame_len; + buffer_assure_space(wth->frame_buffer, pkt.hdr.frame_len); + wtap_file_read_expected_bytes(buffer_start_ptr(wth->frame_buffer), pkt.hdr.frame_len, wth->fh, err); + wth->data_offset += pkt.hdr.frame_len; - /* XXX: should we read to a junk buffer instead of seeking? */ - /* XXX: is there useful stuff in the trailer? */ - if ( file_read(junk,1, hdr.len - ( hdr.frame_len + 0x20) , wth->fh) != (gint) ( hdr.len - ( hdr.frame_len + 0x20)) ) { + /* (undef,$vp,$vc) = unpack "C12SS"; */ + + read_len = pkt.hdr.len - ( pkt.hdr.frame_len + 0x20); + + if ( file_read(b,1, read_len , wth->fh) != read_len ) { *err = WTAP_ERR_SHORT_READ; - *err_info = "record too short while reading .rf5 file"; return FALSE; } - wth->data_offset += hdr.len - ( hdr.frame_len + 0x20); + wth->data_offset += read_len; + + src_desc = g_hash_table_lookup(wth->capture.k12->src_by_id,GUINT_TO_POINTER(pkt.hdr.input)); + + wth->pseudo_header.k12.src_id = pkt.hdr.input; + wth->pseudo_header.k12.src_name = src_desc ? src_desc->variable.port_name : "unknown port"; + wth->pseudo_header.k12.stack_file = src_desc ? src_desc->variable.stack_file : "unknown port"; return TRUE; } -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_) { +static gboolean k12_seek_read(wtap *wth, long seek_off, union wtap_pseudo_header *pseudo_header, guchar *pd, int length, int *err _U_, gchar **err_info _U_) { + guint8 read_buffer[0x20]; + k12_src_desc_t* src_desc; + guint32 input; - if ( file_seek(wth->random_fh, seek_off+0x20, SEEK_SET, err) == -1) + if ( file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) return FALSE; + if( file_read(read_buffer,1,0x20,wth->random_fh) != 0x20 ) + return FALSE; + + input = pntohl(read_buffer + 0xC); + + src_desc = g_hash_table_lookup(wth->capture.k12->src_by_id,GUINT_TO_POINTER(input)); + + pseudo_header->k12.src_id = input; + pseudo_header->k12.src_name = src_desc ? src_desc->variable.port_name : "unknown port"; + pseudo_header->k12.stack_file = src_desc ? src_desc->variable.stack_file : "unknown stack_file"; + if ( file_read(pd, 1, length, wth->random_fh) != length) { *err = file_error(wth->random_fh); if (*err == 0) @@ -364,25 +342,79 @@ static gboolean k12_seek_read(wtap *wth, long seek_off, union wtap_pseudo_header return TRUE; } -static void destroy_k12_file_data(k12_t* file_data) { - guint i; - for (i =0; i<=file_data->stack_encap_p; i++) { - if (file_data->stack_encap[i].name) { - g_free(file_data->stack_encap[i].name); - file_data->stack_encap[i].name = NULL; - } - } +static k12_t* new_k12_file_data() { + k12_t* fd = g_malloc(sizeof(k12_t)); - if (file_data->port_encaps) { - g_ptr_array_free(file_data->port_encaps,TRUE); - } + fd->file_len = 0; + fd->num_of_records = 0; + fd->src_by_name = g_hash_table_new(g_str_hash,g_str_equal); + fd->src_by_id = g_hash_table_new(g_direct_hash,g_direct_equal); + return fd; +} + +static gboolean destroy_srcdsc(gpointer k _U_, gpointer v, gpointer p _U_) { + k12_src_desc_t* rec = v; + + if(rec->variable.extra_blob) + g_free(rec->variable.extra_blob); + + if(rec->variable.port_name) + g_free(rec->variable.port_name); + + if(rec->variable.stack_file) + g_free(rec->variable.stack_file); + + g_free(rec); + + return TRUE; +} + +static void destroy_k12_file_data(k12_t* fd) { + g_hash_table_destroy(fd->src_by_id); + g_hash_table_foreach_remove(fd->src_by_name,destroy_srcdsc,NULL); + g_hash_table_destroy(fd->src_by_name); + g_free(fd); } static void k12_close(wtap *wth) { destroy_k12_file_data(wth->capture.k12); } +static void add_k12_src(k12_t* fd, k12_src_desc_t* rec) { + k12_src_desc_t* r = g_memdup(rec,sizeof(k12_src_desc_t)); + + g_hash_table_insert(fd->src_by_id,GUINT_TO_POINTER(r->hdr.input),r); + g_hash_table_insert(fd->src_by_name,r->variable.stack_file,r); +} + + + +static int get_srcdsc_record(k12_src_desc_t* rec, FILE* fp, int *err) { + gchar read_buffer[0x1000]; + + if ( file_read( read_buffer, 1, 0x14, fp) != 0x14 ) { + *err = WTAP_ERR_SHORT_READ; + return FALSE; + } + + /* XXX missing some */ + rec->record.extra_len = pntohs( read_buffer + 0xE ); + rec->record.name_len = pntohs( read_buffer + 0x10 ); + rec->record.stack_len = pntohs( read_buffer + 0x12 ); + + if (file_read(read_buffer,1, rec->hdr.len - 0x24,fp) != (gint)rec->hdr.len - 0x24 ) { + *err = WTAP_ERR_SHORT_READ; + return FALSE; + } + + rec->variable.extra_blob = g_memdup(read_buffer, rec->record.extra_len); + rec->variable.port_name = g_memdup(read_buffer + rec->record.extra_len,rec->record.name_len); + rec->variable.stack_file = g_memdup(read_buffer + rec->record.extra_len + rec->record.name_len,rec->record.stack_len); + + return TRUE; +} + /* * The first few records of a file contain a description of the file: * - the description of the sources (ports or circuits) @@ -392,17 +424,12 @@ static void k12_close(wtap *wth) { * some other (summary?) records. */ -int k12_open(wtap *wth, int *err, gchar **err_info) { +int k12_open(wtap *wth, int *err, gchar **err_info _U_) { gchar read_buffer[0x1000]; - k12_record_hdr_t hdr; long offset = 0; - gchar* stack_file; - gchar* port_name; - guint32 name_len; - guint32 stack_len; - gint read_len; - guint stuffing; k12_t* file_data; + k12_src_desc_t rec; + gint stuffing; /* * let's check the magic number. @@ -415,21 +442,18 @@ int k12_open(wtap *wth, int *err, gchar **err_info) { } /* the lenght of the file is in the next 4byte word */ - if ( file_read(read_buffer,1,4,wth->fh) != 4 ) { + if ( file_read(read_buffer,1,8,wth->fh) != 8 ) { return -1; } - - file_data = g_malloc(sizeof(k12_t)); - - file_data->stack_encap_p = 0; - file_data->port_encaps = g_ptr_array_new(); - file_data->stack_encap = g_memdup(virgin_stack_encap,sizeof(virgin_stack_encap)); + file_data = new_k12_file_data(); + file_data->file_len = pntohl( read_buffer ); + file_data->num_of_records = pntohl( read_buffer + 4 ); /* * we don't know yet what's in the file header */ - if (file_read(read_buffer,1,0x204,wth->fh) != 0x204 ) { + if (file_read(read_buffer,1,0x200,wth->fh) != 0x200 ) { destroy_k12_file_data(file_data); return -1; } @@ -441,16 +465,22 @@ int k12_open(wtap *wth, int *err, gchar **err_info) { */ do { + memset(&rec,0,sizeof(k12_src_desc_t)); + if (offset > 0x10000) { /* too much to be ok. */ return 0; } - stuffing = get_k12_hdr(&hdr, wth, err, err_info); + stuffing = get_k12_hdr(&(rec.hdr), wth, err); + + if ( stuffing < 0) { + return 0; + } offset += stuffing; - if ( hdr.type == K12_REC_PACKET) { + if ( rec.hdr.type == K12_REC_PACKET) { /* * we are at the first packet record, rewind and leave. */ @@ -460,69 +490,25 @@ int k12_open(wtap *wth, int *err, gchar **err_info) { } break; - } else if (hdr.type == K12_REC_SRCDSC) { + } else if (rec.hdr.type == K12_REC_SRCDSC) { - if ( file_read( read_buffer, 1, 0x14, wth->fh) != 0x14 ) { - *err = WTAP_ERR_SHORT_READ; - return FALSE; - } - - name_len = pntohs( read_buffer + 0x10 ); - stack_len = pntohs( read_buffer + 0x12 ); - - - read_len = hdr.len - (0x10 + 0x14 + name_len + stack_len); - - if (read_len > 0) { - /* skip the still unknown part */ - if (file_read(read_buffer,1, read_len,wth->fh) != read_len ) { - destroy_k12_file_data(file_data); - *err = WTAP_ERR_SHORT_READ; - return -1; - } - } else if (read_len < 0) { + if(!get_srcdsc_record(&rec, wth->fh, err)) { destroy_k12_file_data(file_data); - *err = WTAP_ERR_BAD_RECORD; return -1; } + + offset += rec.hdr.len; - /* the rest of the record contains two null terminated strings: - the source label and the "stack" filename */ - if ( file_read(read_buffer, 1, name_len, wth->fh) != (int)name_len ) { - destroy_k12_file_data(file_data); - *err = WTAP_ERR_SHORT_READ; - *err_info = "record too short while reading .rf5 file"; - return -1; - } + add_k12_src(file_data,&rec); - port_name = g_strndup(read_buffer,stack_len); - - if ( file_read(read_buffer, 1, stack_len, wth->fh) != (int)stack_len ) { - destroy_k12_file_data(file_data); - *err = WTAP_ERR_SHORT_READ; - *err_info = "record too short while reading .rf5 file"; - return -1; - } - - stack_file =g_strndup(read_buffer,stack_len); - - if (choose_encap(file_data,hdr.port_id,stack_file) == WTAP_NUM_ENCAP_TYPES ) { - destroy_k12_file_data(file_data); - /* more encapsulation types than we can handle */ - return 0; - } - - offset += hdr.len; continue; } else { - /* we don't need these other fellows */ - - if (file_read(read_buffer,1, hdr.len - K12_HDR_LEN, wth->fh) != (int) hdr.len - K12_HDR_LEN ) { + if (file_read(read_buffer,1, rec.hdr.len - K12_HDR_LEN, wth->fh) != (int) rec.hdr.len - K12_HDR_LEN ) { destroy_k12_file_data(file_data); return -1; } - offset += hdr.len; + offset += rec.hdr.len; continue; } @@ -530,6 +516,7 @@ int k12_open(wtap *wth, int *err, gchar **err_info) { wth->data_offset = offset; wth->file_type = WTAP_FILE_K12; + wth->file_encap = WTAP_ENCAP_K12; wth->snapshot_length = 0; wth->subtype_read = k12_read; wth->subtype_seek_read = k12_seek_read; @@ -540,11 +527,6 @@ int k12_open(wtap *wth, int *err, gchar **err_info) { we will use that for the whole file so we can use more formats to save to */ - if (file_data->port_encaps->len == 1) { - wth->file_encap = ((k12_stack_encap_t*)g_ptr_array_index(file_data->port_encaps,0))->encap; - } else { - wth->file_encap = WTAP_ENCAP_PER_PACKET; - } return 1; } diff --git a/wiretap/wtap.h b/wiretap/wtap.h index 2e299be268..3d4f9f86da 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -169,8 +169,9 @@ #define WTAP_GCOM_TIE1 78 #define WTAP_GCOM_SERIAL 79 #define WTAP_ENCAP_NETTL_X25 80 +#define WTAP_ENCAP_K12 81 /* last WTAP_ENCAP_ value + 1 */ -#define WTAP_NUM_ENCAP_TYPES 81 +#define WTAP_NUM_ENCAP_TYPES 82 /* File types that can be read by wiretap. We support writing some many of these file types, too, so we @@ -450,6 +451,14 @@ struct mtp2_phdr { guint16 link_number; }; +/* Packet "pseudo-header" for K12 files. */ + +struct k12_phdr { + guint32 src_id; + gchar* src_name; + gchar* stack_file; +}; + union wtap_pseudo_header { struct eth_phdr eth; struct x25_phdr x25; @@ -462,6 +471,7 @@ union wtap_pseudo_header { struct irda_phdr irda; struct nettl_phdr nettl; struct mtp2_phdr mtp2; + struct k12_phdr k12; }; struct wtap_pkthdr {