set compiler option "treat warnings as errors" - to prevent new warnings for wiretap
[obnox/wireshark/wip.git] / wiretap / k12.c
1 /*
2  * k12.c
3  *
4  *  routines for importing tektronix k12xx *.rf5 files
5  *
6  *  Copyright (c) 2005, Luis E. Garia Ontanon <luis.ontanon@gmail.com>
7  *
8  * $Id$
9  *
10  * Wiretap Library
11  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
12  *
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.
17  *
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.
22  *
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.
26  */
27
28 /* #define DEBUG_K12 */
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include "wtap-int.h"
36 #include "wtap.h"
37 #include "file_wrappers.h"
38 #include "buffer.h"
39 #include "k12.h"
40
41 /*#define DEBUG_K12*/
42 #ifdef DEBUG_K12
43 #include <stdio.h>
44 #include <ctype.h>
45 #include <stdarg.h>
46
47
48 FILE* dbg_out = NULL;
49 char* env_file = NULL;
50
51 static unsigned debug_level = 0;
52
53 void k12_fprintf(char* fmt, ...) {
54     va_list ap;
55     
56     va_start(ap,fmt);
57     vfprintf(dbg_out, fmt, ap);
58     va_end(ap);    
59 }
60
61 #define CAT(a,b) a##b
62 #define K12_DBG(level,args) do { if (level <= debug_level) { \
63         fprintf(dbg_out,"%s:%d: ",CAT(__FI,LE__),CAT(__LI,NE__)); \
64         k12_fprintf args ; \
65         fprintf(dbg_out,"\n"); \
66 } } while(0)
67
68 void k12_hexdump(guint level, gint64 offset, char* label, unsigned char* b, unsigned len) {
69     static const char* c2t[] = {
70         "00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f", 
71         "10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f", 
72         "20","21","22","23","24","25","26","27","28","29","2a","2b","2c","2d","2e","2f", 
73         "30","31","32","33","34","35","36","37","38","39","3a","3b","3c","3d","3e","3f", 
74         "40","41","42","43","44","45","46","47","48","49","4a","4b","4c","4d","4e","4f", 
75         "50","51","52","53","54","55","56","57","58","59","5a","5b","5c","5d","5e","5f", 
76         "60","61","62","63","64","65","66","67","68","69","6a","6b","6c","6d","6e","6f", 
77         "70","71","72","73","74","75","76","77","78","79","7a","7b","7c","7d","7e","7f", 
78         "80","81","82","83","84","85","86","87","88","89","8a","8b","8c","8d","8e","8f", 
79         "90","91","92","93","94","95","96","97","98","99","9a","9b","9c","9d","9e","9f", 
80         "a0","a1","a2","a3","a4","a5","a6","a7","a8","a9","aa","ab","ac","ad","ae","af", 
81         "b0","b1","b2","b3","b4","b5","b6","b7","b8","b9","ba","bb","bc","bd","be","bf", 
82         "c0","c1","c2","c3","c4","c5","c6","c7","c8","c9","ca","cb","cc","cd","ce","cf", 
83         "d0","d1","d2","d3","d4","d5","d6","d7","d8","d9","da","db","dc","dd","de","df", 
84         "e0","e1","e2","e3","e4","e5","e6","e7","e8","e9","ea","eb","ec","ed","ee","ef", 
85         "f0","f1","f2","f3","f4","f5","f6","f7","f8","f9","fa","fb","fc","fd","fe","ff"
86     };
87     unsigned i;
88         
89     if (debug_level < level) return;
90     
91     fprintf(dbg_out,"%s(%.8llx,%.4x): ",label,offset,len);
92     
93     for (i=0 ; i<len ; i++) {
94                 
95         if (!(i%32))
96             fprintf(dbg_out,"\n");
97         else if (!(i%4))
98             fprintf(dbg_out," ");
99                 
100         fprintf(dbg_out,c2t[b[i]]);
101     }
102         
103         fprintf(dbg_out,"\n");
104 }
105
106 #define K12_HEXDMP(x,a,b,c,d) k12_hexdump(x,a,b,c,d)
107
108 #else
109 #define K12_DBG(level,args) (void)0
110 #define K12_HEXDMP(x,a,b,c,d)
111 #endif
112
113
114
115 /*
116  * the 32 bits .rf5 file contains:
117  *  an 8 byte magic number
118  *  32bit lenght
119  *  32bit number of records
120  *  other 0x200 bytes bytes of uncharted territory
121  *     1 or more copies of the num_of_records in there
122  *  the records whose first 32bits word is the length
123  *     they are stuffed by one to four words every 0x2000 bytes
124  *  and a 2 byte terminator FFFF
125  */
126
127 static const guint8 k12_file_magic[] = { 0x00, 0x00, 0x02, 0x00 ,0x12, 0x05, 0x00, 0x10 };
128
129 struct _k12_t {
130     guint32 file_len;
131     guint32 num_of_records; /* XXX: not sure about this */
132     
133     GHashTable* src_by_id; /* k12_srcdsc_recs by input */
134     GHashTable* src_by_name; /* k12_srcdsc_recs by stack_name */
135
136     Buffer extra_info; /* Buffer to hold per packet extra information */
137 };
138
139 typedef struct _k12_src_desc_t {
140     guint32 input;
141     guint32 input_type;
142     gchar* input_name;
143     gchar* stack_file;
144     k12_input_info_t input_info;
145 } k12_src_desc_t;
146
147
148 /* so far we've seen these types of records */
149 #define K12_REC_PACKET        0x00010020 /* an actual packet */
150 #define K12_REC_SRCDSC        0x00070041 /* port-stack mapping + more, the key of the whole thing */
151 #define K12_REC_SCENARIO      0x00070040 /* what appears as the window's title */
152 #define K12_REC_STK_FILE      0x00070042 /* a dump of an stk file */
153 #define K12_REC_SRCDSC2       0x00070043 /* another port-stack mapping */
154 #define K12_REC_TEXT          0x00070044 /* a string containing something with a grammar (conditions/responses?) */
155 #define K12_REC_START         0x00020030 /* a string containing human readable start time  */ 
156 #define K12_REC_STOP          0x00020031 /* a string containing human readable stop time */
157
158 #define K12_MASK_PACKET       0xfffffff0  /* the last nibble in packet records somentimes change (not yet understood why) */
159
160 /* offsets of elements in the records */
161 #define K12_RECORD_LEN         0x0 /* uint32, in bytes */ 
162 #define K12_RECORD_TYPE        0x4 /* uint32, see above */
163 #define K12_RECORD_FRAME_LEN   0x8 /* uint32, in bytes */
164 #define K12_RECORD_SRC_ID      0xc /* uint32 */
165
166 /* elements of packet records */
167 #define K12_PACKET_TIMESTAMP  0x18 /* int64 (8b) representing 1/2us since 01-01-1990 Z00:00:00 */
168
169 #define K12_PACKET_FRAME      0x20 /* start of the actual frame in the record */
170
171 #define K12_PACKET_OFFSET_VP  0x08 /* 2 bytes, big endian */ 
172 #define K12_PACKET_OFFSET_VC  0x0a /* 2 bytes, big endian */ 
173 #define K12_PACKET_OFFSET_CID 0x0c /* 1 byte */
174
175 /* elements of the source description records */
176 #define K12_SRCDESC_COLOR_FOREGROUND 0x12 /* 1 byte */
177 #define K12_SRCDESC_COLOR_BACKGROUND 0x13 /* 1 byte */
178
179 #define K12_SRCDESC_PORT_TYPE  0x1a   /* 1 byte */
180 #define K12_SRCDESC_EXTRALEN   0x1e   /* uint16, big endian */
181 #define K12_SRCDESC_NAMELEN    0x20   /* uint16, big endian */
182 #define K12_SRCDESC_STACKLEN   0x22   /* uint16, big endian */
183
184 #define K12_SRCDESC_EXTRATYPE  0x24   /* uint32, big endian */
185 #define K12_SRCDESC_ATM_VPI    0x38   /* uint16, big endian */
186 #define K12_SRCDESC_ATM_VCI    0x3a   /* uint16, big endian */
187
188 #define K12_SRCDESC_ATM_AAL    0x3c    /* 1 byte */
189 #define K12_SRCDESC_DS0_MASK   0x3c    /* 1 byte */
190
191
192 /*
193  * get_record: Get the next record into a buffer
194  *   Every about 0x2000 bytes 0x10 bytes are inserted in the file,
195  *   even in the middle of a record.
196  *   This reads the next record without the eventual 0x10 bytes.
197  *   returns the lenght of the record + the stuffing (if any)
198  *
199  * XXX: works at most with 0x1FFF bytes per record 
200  */
201 static gint get_record(guint8** bufferp, FILE* fh, gint64 file_offset) {
202         static guint8* buffer = NULL;
203         static guint buffer_len = 0x2000 ;
204     guint read;
205         guint last_read;
206     guint actual_len, left;
207         guint8 junk[0x14];
208         guint8* writep;
209         
210         /* where the next unknown 0x10 bytes are stuffed to the file */
211         gint junky_offset = 0x2000 - (gint) ( (file_offset - 0x200) % 0x2000 );
212         
213         K12_DBG(6,("get_record: ENTER: junky_offset=%lld, file_offset=%lld",junky_offset,file_offset));
214
215         /* no buffer is given, lets create it */
216         if (buffer == NULL) {
217                 buffer = g_malloc(0x2000);
218                 buffer_len = 0x2000;
219         }
220         
221         *bufferp = buffer;
222         
223         if  ( junky_offset == 0x2000 ) {
224                 /* the lenght of the record is 0x10 bytes ahead from we are reading */
225                 read = file_read(junk,1,0x14,fh);
226         
227         if (read == 2 && junk[0] == 0xff && junk[1] == 0xff) {
228             K12_DBG(1,("get_record: EOF"));            
229             return 0;
230         } else if ( read < 0x14 ){
231             K12_DBG(1,("get_record: SHORT READ"));
232             return -1;
233         }
234                 
235                 memcpy(buffer,&(junk[0x10]),4);
236         } else {
237                 /* the lenght of the record is right where we are reading */
238                 read = file_read(buffer,1, 0x4, fh);
239                 
240                 if (read == 2 && buffer[0] == 0xff && buffer[1] == 0xff) {
241             K12_DBG(1,("get_record: EOF"));
242             return 0;
243         } else if ( read != 0x4 ) {
244             K12_DBG(1,("get_record: SHORT READ"));
245             return -1;
246         }
247         }
248         
249         actual_len = left = pntohl(buffer);
250         junky_offset -= 0x4;
251         
252         K12_DBG(5,("get_record: GET length=%d",left));
253
254         g_assert(left >= 4);
255         
256         while (left > buffer_len) *bufferp = buffer = g_realloc(buffer,buffer_len*=2);
257         
258         writep = buffer + 4;
259         left -= 4;
260         
261         do {
262                 K12_DBG(6,("get_record: looping left=%d junky_offset=%lld",left,junky_offset));
263
264                 if (junky_offset > left) {
265                         read += last_read = file_read(writep,1, left, fh);
266                         
267                         if ( last_read != left ) {
268                                 K12_DBG(1,("get_record: SHORT READ"));
269                                 return -1;
270                         } else {
271                                 K12_HEXDMP(5,file_offset, "GOT record", buffer, actual_len);
272                                 return read;
273                         }
274                 } else {
275                         read += last_read = file_read(writep,1, junky_offset, fh);
276                         
277                         if ( last_read != junky_offset ) {
278                                 K12_DBG(1,("get_record: SHORT READ, read=%d expected=%d",last_read, junky_offset));
279                                 return -1;
280                         }
281                         
282                         writep += last_read;
283
284                         read += last_read = file_read(junk,1, 0x10, fh);
285                         
286                         if ( last_read != 0x10 ) {
287                                 K12_DBG(1,("get_record: SHORT READ"));
288                                 return -1;
289                         }
290                         
291                         left -= junky_offset;
292                         junky_offset = 0x2000;
293                 }
294                 
295         } while(left);
296         
297         K12_HEXDMP(5,file_offset, "GOT record", buffer, actual_len);
298         return read;
299 }
300
301 static gboolean k12_read(wtap *wth, int *err, gchar **err_info _U_, gint64 *data_offset) {
302     k12_src_desc_t* src_desc;
303     guint8* buffer = NULL;
304     gint64 offset;
305     long len;
306     guint32 type;
307         guint32 src_id;
308     guint64 ts;
309     guint32 extra_len;
310     
311     offset = wth->data_offset;
312     
313     /* ignore the record if it isn't a packet */    
314     do {
315                 K12_DBG(5,("k12_read: offset=%i",offset));
316                 
317         *data_offset = offset;
318         
319         len = get_record(&buffer, wth->fh, offset);
320         
321         if (len < 0) {
322             *err = WTAP_ERR_SHORT_READ;
323             return FALSE;
324         } else if (len == 0) {
325             *err = 0;
326             return FALSE;
327         }
328         
329         type = pntohl(buffer + K12_RECORD_TYPE);
330         src_id = pntohl(buffer + K12_RECORD_SRC_ID);
331                 src_desc = g_hash_table_lookup(wth->capture.k12->src_by_id,GUINT_TO_POINTER(src_id));
332
333         K12_DBG(5,("k12_read: record type=%x src_id=%x",type,src_id));
334         
335         offset += len;
336         
337     } while ( ((type & K12_MASK_PACKET) != K12_REC_PACKET) || !src_id || !src_desc );
338     
339     wth->data_offset = offset;
340     
341     ts = pntohll(buffer + K12_PACKET_TIMESTAMP);
342     
343     wth->phdr.ts.secs = (guint32) ((ts / 2000000) + 631152000);
344     wth->phdr.ts.nsecs = (guint32) ( (ts % 2000000) * 500 );
345     
346     K12_DBG(3,("k12_read: PACKET RECORD type=%x src_id=%x secs=%u nsecs=%u",type,src_id, wth->phdr.ts.secs,wth->phdr.ts.nsecs));
347     
348     wth->phdr.len = wth->phdr.caplen = pntohl(buffer + K12_RECORD_FRAME_LEN) & 0x00001FFF;
349     extra_len = len - K12_PACKET_FRAME - wth->phdr.caplen;
350     
351     /* the frame */
352     buffer_assure_space(wth->frame_buffer, wth->phdr.caplen);
353     memcpy(buffer_start_ptr(wth->frame_buffer), buffer + K12_PACKET_FRAME, wth->phdr.caplen);
354     
355     /* extra information need by some protocols */
356     buffer_assure_space(&(wth->capture.k12->extra_info), extra_len);
357     memcpy(buffer_start_ptr(&(wth->capture.k12->extra_info)),
358            buffer + K12_PACKET_FRAME + wth->phdr.caplen, extra_len);
359     wth->pseudo_header.k12.extra_info = (void*)buffer_start_ptr(&(wth->capture.k12->extra_info));
360     wth->pseudo_header.k12.extra_length = extra_len;
361
362     wth->pseudo_header.k12.input = src_id;
363     
364     K12_DBG(5,("k12_read: wth->pseudo_header.k12.input=%x wth->phdr.len=%i",wth->pseudo_header.k12.input,wth->phdr.len));
365         
366     if (src_desc) {
367         
368         K12_DBG(5,("k12_read: input_name='%s' stack_file='%s' type=%x",src_desc->input_name,src_desc->stack_file,src_desc->input_type));
369         wth->pseudo_header.k12.input_name = src_desc->input_name;
370         wth->pseudo_header.k12.stack_file = src_desc->stack_file;
371         wth->pseudo_header.k12.input_type = src_desc->input_type;
372         
373         switch(src_desc->input_type) {
374             case K12_PORT_ATMPVC:
375             if ((long)(K12_PACKET_FRAME + wth->phdr.len + K12_PACKET_OFFSET_CID) < len) {
376                 wth->pseudo_header.k12.input_info.atm.vp =  pntohs(buffer + (K12_PACKET_FRAME + wth->phdr.caplen + K12_PACKET_OFFSET_VP));
377                 wth->pseudo_header.k12.input_info.atm.vc =  pntohs(buffer + (K12_PACKET_FRAME + wth->phdr.caplen + K12_PACKET_OFFSET_VC));
378                 wth->pseudo_header.k12.input_info.atm.cid =  *((unsigned char*)(buffer + K12_PACKET_FRAME + wth->phdr.len + K12_PACKET_OFFSET_CID));
379                 break;
380             }
381             /* Fall through */
382             default:
383             memcpy(&(wth->pseudo_header.k12.input_info),&(src_desc->input_info),sizeof(src_desc->input_info));
384             break;
385             
386         }
387     } else {
388         K12_DBG(5,("k12_read: NO RECORD FOUND"));
389
390         memset(&(wth->pseudo_header),0,sizeof(wth->pseudo_header));
391         wth->pseudo_header.k12.input_name = "unknown port";
392         wth->pseudo_header.k12.stack_file = "unknown stack file";
393     }
394     
395     wth->pseudo_header.k12.stuff = wth->capture.k12;
396     
397     return TRUE;
398 }
399
400
401 static gboolean k12_seek_read(wtap *wth, gint64 seek_off, union wtap_pseudo_header *pseudo_header, guchar *pd, int length, int *err _U_, gchar **err_info _U_) {
402     k12_src_desc_t* src_desc;
403     guint8* buffer;
404     long len;
405     guint32 extra_len;
406     guint32 input;
407     
408     K12_DBG(5,("k12_seek_read: ENTER"));
409     
410     if ( file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) {
411         K12_DBG(5,("k12_seek_read: SEEK ERROR"));
412         return FALSE;
413     }
414     
415     if ((len = get_record(&buffer, wth->random_fh, seek_off)) < 1) {
416         K12_DBG(5,("k12_seek_read: READ ERROR"));
417         return FALSE;
418     }
419     
420     memcpy(pd, buffer + K12_PACKET_FRAME, length);
421
422     extra_len = len - K12_PACKET_FRAME - length;
423     buffer_assure_space(&(wth->capture.k12->extra_info), extra_len);
424     memcpy(buffer_start_ptr(&(wth->capture.k12->extra_info)),
425            buffer + K12_PACKET_FRAME + length, extra_len);
426     wth->pseudo_header.k12.extra_info = (void*)buffer_start_ptr(&(wth->capture.k12->extra_info));
427     wth->pseudo_header.k12.extra_length = extra_len;
428     if (pseudo_header) {
429         pseudo_header->k12.extra_info = (void*)buffer_start_ptr(&(wth->capture.k12->extra_info));
430         pseudo_header->k12.extra_length = extra_len;
431     }
432     
433     input = pntohl(buffer + K12_RECORD_SRC_ID);
434     K12_DBG(5,("k12_seek_read: input=%.8x",input));
435     
436     src_desc = g_hash_table_lookup(wth->capture.k12->src_by_id,GUINT_TO_POINTER(input));
437     
438     if (src_desc) {
439         K12_DBG(5,("k12_seek_read: input_name='%s' stack_file='%s' type=%x",src_desc->input_name,src_desc->stack_file,src_desc->input_type));
440         if (pseudo_header) {
441             pseudo_header->k12.input_name = src_desc->input_name;
442             pseudo_header->k12.stack_file = src_desc->stack_file;
443             pseudo_header->k12.input_type = src_desc->input_type;
444             
445             switch(src_desc->input_type) {
446             case K12_PORT_ATMPVC:
447                 if ((long)(K12_PACKET_FRAME + length + K12_PACKET_OFFSET_CID) < len) {
448                 pseudo_header->k12.input_info.atm.vp =  pntohs(buffer + K12_PACKET_FRAME + length + K12_PACKET_OFFSET_VP);
449                 pseudo_header->k12.input_info.atm.vc =  pntohs(buffer + K12_PACKET_FRAME + length + K12_PACKET_OFFSET_VC);
450                 pseudo_header->k12.input_info.atm.cid =  *((unsigned char*)(buffer + K12_PACKET_FRAME + length + K12_PACKET_OFFSET_CID));
451                 break;
452                 }
453                 /* Fall through */
454             default:
455                 memcpy(&(pseudo_header->k12.input_info),&(src_desc->input_info),sizeof(src_desc->input_info));
456                 break;
457             }
458         }
459         
460         wth->pseudo_header.k12.input_name = src_desc->input_name;
461         wth->pseudo_header.k12.stack_file = src_desc->stack_file;
462         wth->pseudo_header.k12.input_type = src_desc->input_type;
463             
464         switch(src_desc->input_type) {
465             case K12_PORT_ATMPVC:
466             if ((long)(K12_PACKET_FRAME + length + K12_PACKET_OFFSET_CID) < len) {
467                 wth->pseudo_header.k12.input_info.atm.vp =  pntohs(buffer + K12_PACKET_FRAME + length + K12_PACKET_OFFSET_VP);
468                 wth->pseudo_header.k12.input_info.atm.vc =  pntohs(buffer + K12_PACKET_FRAME + length + K12_PACKET_OFFSET_VC);
469                 wth->pseudo_header.k12.input_info.atm.cid =  *((unsigned char*)(buffer + K12_PACKET_FRAME + length + K12_PACKET_OFFSET_CID));
470             }
471             break;
472             /* Fall through */
473             default:
474             memcpy(&(wth->pseudo_header.k12.input_info),&(src_desc->input_info),sizeof(src_desc->input_info));
475             break;
476         }
477         
478     } else {
479         K12_DBG(5,("k12_seek_read: NO SRC_RECORD FOUND"));
480
481         if (pseudo_header) {
482             memset(&(pseudo_header->k12),0,sizeof(pseudo_header->k12));
483             pseudo_header->k12.input_name = "unknown port";
484             pseudo_header->k12.stack_file = "unknown stack file";
485         }
486
487         memset(&(wth->pseudo_header.k12),0,sizeof(wth->pseudo_header.k12));
488         wth->pseudo_header.k12.input_name = "unknown port";
489         wth->pseudo_header.k12.stack_file = "unknown stack file";
490         
491     }
492     
493     if (pseudo_header) {
494         pseudo_header->k12.input = input;
495         pseudo_header->k12.stuff = wth->capture.k12;
496     }
497     
498     wth->pseudo_header.k12.input = input;
499     wth->pseudo_header.k12.stuff = wth->capture.k12;
500
501     K12_DBG(5,("k12_seek_read: DONE OK"));
502
503     return TRUE;
504 }
505
506
507 static k12_t* new_k12_file_data() {
508     k12_t* fd = g_malloc(sizeof(k12_t));
509     
510     fd->file_len = 0;
511     fd->num_of_records = 0;
512     fd->src_by_name = g_hash_table_new(g_str_hash,g_str_equal);
513     fd->src_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
514
515     buffer_init(&(fd->extra_info), 100);
516     
517     return fd;
518 }
519
520 static gboolean destroy_srcdsc(gpointer k _U_, gpointer v, gpointer p _U_) {
521     k12_src_desc_t* rec = v;
522     
523     if(rec->input_name)
524         g_free(rec->input_name);
525     
526     if(rec->stack_file)
527         g_free(rec->stack_file);
528     
529     g_free(rec);
530     
531     return TRUE;
532 }
533
534 static void destroy_k12_file_data(k12_t* fd) {
535     g_hash_table_destroy(fd->src_by_id);
536     g_hash_table_foreach_remove(fd->src_by_name,destroy_srcdsc,NULL);    
537     g_hash_table_destroy(fd->src_by_name);
538     buffer_free(&(fd->extra_info));
539     g_free(fd);
540 }
541
542 static void k12_close(wtap *wth) {
543     destroy_k12_file_data(wth->capture.k12);
544 #ifdef DEBUG_K12
545     K12_DBG(5,("k12_close: CLOSED"));
546     if (env_file) fclose(dbg_out);
547 #endif
548 }
549
550
551 int k12_open(wtap *wth, int *err, gchar **err_info _U_) {
552     k12_src_desc_t* rec;
553     guint8 header_buffer[0x200];
554     guint8* read_buffer;
555     guint32 type;
556     long offset;
557     long len;
558     guint32 rec_len;
559     guint32 extra_len;
560     guint32 name_len;
561     guint32 stack_len;
562     guint i;
563     k12_t* file_data;
564     
565 #ifdef DEBUG_K12
566     gchar* env_level = getenv("K12_DEBUG_LEVEL");
567     env_file = getenv("K12_DEBUG_FILENAME");
568     if ( env_file ) dbg_out = fopen(env_file,"w");
569     else dbg_out = stderr;
570     if ( env_level ) debug_level = strtoul(env_level,NULL,10);
571     K12_DBG(1,("k12_open: ENTER debug_level=%u",debug_level));
572 #endif
573     
574     if ( file_read(header_buffer,1,0x200,wth->fh) != 0x200 ) {
575         K12_DBG(1,("k12_open: FILE HEADER TOO SHORT"));
576         return 0;
577     } else {
578         if ( memcmp(header_buffer,k12_file_magic,8) != 0 ) {
579             K12_DBG(1,("k12_open: BAD MAGIC"));
580             return 0;
581         }
582     }
583     
584     offset = 0x200;
585     
586     file_data = new_k12_file_data();
587     
588     file_data->file_len = pntohl( header_buffer + 0x8);
589     file_data->num_of_records = pntohl( header_buffer + 0xC );
590     
591     K12_DBG(5,("k12_open: FILE_HEADER OK: offset=%x file_len=%i records=%i",
592             offset,
593             file_data->file_len,
594             file_data->num_of_records ));
595     
596     do {
597         
598         len = get_record(&read_buffer, wth->fh, offset);
599         
600         if ( len <= 0 ) {
601             K12_DBG(1,("k12_open: BAD HEADER RECORD",len));
602             return -1;
603         }
604         
605         
606         type = pntohl( read_buffer + K12_RECORD_TYPE );
607         
608         if ( (type & K12_MASK_PACKET) == K12_REC_PACKET) {
609             /*
610              * we are at the first packet record, rewind and leave.
611              */
612             if (file_seek(wth->fh, offset, SEEK_SET, err) == -1) {
613                 destroy_k12_file_data(file_data);
614                 return -1;
615             }
616             K12_DBG(5,("k12_open: FIRST PACKET offset=%x",offset));
617             break;
618         } else if (type == K12_REC_SRCDSC || type == K12_REC_SRCDSC2 ) {
619             rec = g_malloc0(sizeof(k12_src_desc_t));
620             
621             rec_len = pntohl( read_buffer + K12_RECORD_LEN );
622             extra_len = pntohs( read_buffer + K12_SRCDESC_EXTRALEN );
623             name_len = pntohs( read_buffer + K12_SRCDESC_NAMELEN );
624             stack_len = pntohs( read_buffer + K12_SRCDESC_STACKLEN );
625             
626             rec->input = pntohl( read_buffer + K12_RECORD_SRC_ID );
627             
628             K12_DBG(5,("k12_open: INTERFACE RECORD offset=%x interface=%x",offset,rec->input));
629             
630             if (name_len == 0 || stack_len == 0
631                 || 0x20 + extra_len + name_len + stack_len > rec_len ) {
632                 g_free(rec);
633                 K12_DBG(5,("k12_open: failed (name_len == 0 || stack_len == 0 "
634                         "|| 0x20 + extra_len + name_len + stack_len > rec_len)  extra_len=%i name_len=%i stack_len=%i"));
635                 return 0;
636             }
637
638             if (extra_len)
639                 switch(( rec->input_type = pntohl( read_buffer + K12_SRCDESC_EXTRATYPE ) )) {
640                     case K12_PORT_DS0S:
641                         rec->input_info.ds0mask = 0x00000000;
642                         
643                         for (i = 0; i < 32; i++) {
644                             rec->input_info.ds0mask |= ( *(read_buffer + K12_SRCDESC_DS0_MASK + i) == 0xff ) ? 0x1<<(31-i) : 0x0; 
645                         }
646                         
647                             break;
648                     case K12_PORT_ATMPVC:
649                         rec->input_info.atm.vp = pntohs( read_buffer + K12_SRCDESC_ATM_VPI );
650                         rec->input_info.atm.vc = pntohs( read_buffer + K12_SRCDESC_ATM_VCI );
651                         break;
652                     default:
653                         break;
654                 }
655             else {    /* Record viewer generated files
656                    don't have this information */
657                 if (read_buffer[K12_SRCDESC_PORT_TYPE] >= 0x14
658                     && read_buffer[K12_SRCDESC_PORT_TYPE] <= 0x17)
659                     /* For ATM2_E1DS1, ATM2_E3DS3, 
660                        ATM2_STM1EL and ATM2_STM1OP */
661                     rec->input_type = K12_PORT_ATMPVC;
662             }
663
664             rec->input_name = g_memdup(read_buffer + K12_SRCDESC_EXTRATYPE + extra_len, name_len);
665             rec->stack_file = g_memdup(read_buffer + K12_SRCDESC_EXTRATYPE + extra_len + name_len, stack_len);
666             
667             g_strdown(rec->stack_file);
668             
669             g_hash_table_insert(file_data->src_by_id,GUINT_TO_POINTER(rec->input),rec);
670             g_hash_table_insert(file_data->src_by_name,rec->stack_file,rec);
671             
672             offset += len;
673             continue;
674         } else {
675             offset += len;
676             continue;
677         }
678     } while(1);
679     
680     wth->data_offset = offset;
681     wth->file_type = WTAP_FILE_K12;
682     wth->file_encap = WTAP_ENCAP_K12;
683     wth->snapshot_length = 0;
684     wth->subtype_read = k12_read;
685     wth->subtype_seek_read = k12_seek_read;
686     wth->subtype_close = k12_close;
687     wth->capture.k12 = file_data;
688     wth->tsprecision = WTAP_FILE_TSPREC_NSEC;    
689
690     return 1;
691 }
692
693 int k12_dump_can_write_encap(int encap) {
694     
695     if (encap == WTAP_ENCAP_PER_PACKET)
696         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
697     
698     if (encap != WTAP_ENCAP_K12)
699         return WTAP_ERR_UNSUPPORTED_ENCAP;
700     
701     return 0;
702 }
703
704 static const gchar dumpy_junk[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
705
706 static void k12_dump_record(wtap_dumper *wdh, long len,  guint8* buffer) {
707     long junky_offset = (0x2000 - ( (wdh->dump.k12->file_offset - 0x200) % 0x2000 )) % 0x2000;
708     
709     if (len > junky_offset) {
710         
711         if (junky_offset)
712             fwrite(buffer, 1, junky_offset, wdh->fh);
713         
714         fwrite(dumpy_junk, 1, 0x10, wdh->fh);
715         
716         fwrite(buffer+junky_offset, 1, len - junky_offset, wdh->fh);
717         
718         wdh->dump.k12->file_offset += len + 0x10;
719     } else {
720         fwrite(buffer, 1, len, wdh->fh);
721         wdh->dump.k12->file_offset += len;
722     }
723     
724     wdh->dump.k12->num_of_records++;
725 }
726
727 static void k12_dump_src_setting(gpointer k _U_, gpointer v, gpointer p) {
728     k12_src_desc_t* src_desc = v;
729     wtap_dumper *wdh = p;
730     guint32 len;
731     guint offset;
732     guint i;
733     
734     union {
735         guint8 buffer[0x2000];
736         
737         struct {
738             guint32 len;
739             guint32 type;
740             guint32 unk32_1;
741             guint32 input;
742             
743             guint16 unk32_2;
744             guint16 color;
745             guint32 unk32_3;
746             guint32 unk32_4;
747             guint16 unk16_1;
748             guint16 extra_len;
749             
750             guint16 name_len;
751             guint16 stack_len;
752             
753             struct {
754                 guint32 type;
755                 
756                 union {
757                     struct {
758                         guint32 unk32;
759                         guint8 mask[32];
760                     } ds0mask;
761                     
762                     struct {
763                         guint8 unk_data[0x10];
764                         guint16 vp;
765                         guint16 vc;
766                     } atm;
767                     
768                     guint32 unk;
769                 } desc;
770             } extra;
771         } record;
772     } obj;
773     
774     obj.record.type = g_htonl(K12_REC_SRCDSC);
775     obj.record.unk32_1 = g_htonl(0x00000001);
776     obj.record.input = g_htonl(src_desc->input);
777     
778     obj.record.unk32_2 = g_htons(0x0000);
779     obj.record.color = g_htons(0x060f);
780     obj.record.unk32_3 = g_htonl(0x00000003);
781     switch (src_desc->input_type) {
782         case K12_PORT_ATMPVC:
783             obj.record.unk32_4 = g_htonl(0x01001400);
784             break;
785         default:
786             obj.record.unk32_4 = g_htonl(0x01000100);
787     }
788     
789     obj.record.unk16_1 = g_htons(0x0000);
790     obj.record.name_len = strlen(src_desc->input_name) + 1;
791     obj.record.stack_len = strlen(src_desc->stack_file) + 1;
792     
793     obj.record.extra.type = g_htonl(src_desc->input_type);
794     
795     switch (src_desc->input_type) {
796         case K12_PORT_ATMPVC:
797             obj.record.extra_len = g_htons(0x18);
798             obj.record.extra.desc.atm.vp = g_htons(src_desc->input_info.atm.vp);
799             obj.record.extra.desc.atm.vc = g_htons(src_desc->input_info.atm.vc);
800             offset = 0x3c;
801             break;
802         case K12_PORT_DS0S:
803             obj.record.extra_len = g_htons(0x18);
804             for( i=0; i<32; i++ ) {
805                 obj.record.extra.desc.ds0mask.mask[i] =
806                 (src_desc->input_info.ds0mask & (1 << i)) ? 0xff : 0x00;
807             }
808                 offset = 0x3c;
809             break;
810         default:
811             obj.record.extra_len = g_htons(0x08);
812             offset = 0x2c;
813             break;
814     }
815     
816     memcpy(obj.buffer + offset,
817            src_desc->input_name,
818            obj.record.name_len);
819     
820     memcpy(obj.buffer + offset + obj.record.name_len,
821            src_desc->stack_file,
822            obj.record.stack_len);
823     
824     len = offset + obj.record.name_len + obj.record.stack_len;
825     len += (len % 4) ? 4 - (len % 4) : 0;
826     
827     obj.record.len = g_htonl(len);
828     obj.record.name_len =  g_htons(obj.record.name_len);
829     obj.record.stack_len = g_htons(obj.record.stack_len);
830     
831     k12_dump_record(wdh,len,obj.buffer);
832 }
833
834 static gboolean k12_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
835                          const union wtap_pseudo_header *pseudo_header,
836                          const guchar *pd, int *err _U_) {
837     long len;
838     union {
839         guint8 buffer[0x2000];
840         struct {
841             guint32 len;
842             guint32 type;
843             guint32 frame_len;
844             guint32 input;
845             
846             guint32 datum_1;
847             guint32 datum_2;
848             guint64 ts;
849             
850             guint8 frame[0x1fc0];
851         } record;
852     } obj;
853     
854     if (wdh->dump.k12->num_of_records == 0) {
855         k12_t* file_data = pseudo_header->k12.stuff;
856         g_hash_table_foreach(file_data->src_by_id,k12_dump_src_setting,wdh);
857     }
858     
859     obj.record.len = 0x20 + phdr->len;
860     obj.record.len += (obj.record.len % 4) ? 4 - obj.record.len % 4 : 0;
861     
862     len = obj.record.len;
863     
864     obj.record.len = g_htonl(obj.record.len);
865     
866     obj.record.type = g_htonl(K12_REC_PACKET);
867     obj.record.frame_len = g_htonl(phdr->len);
868     obj.record.input = g_htonl(pseudo_header->k12.input);
869     
870     obj.record.ts = GUINT64_TO_BE((((guint64)phdr->ts.secs - 631152000) * 2000000) + (phdr->ts.nsecs / 1000 * 2));
871     
872     memcpy(obj.record.frame,pd,phdr->len);
873     
874     k12_dump_record(wdh,len,obj.buffer);
875     
876     /* XXX if OK */
877     return TRUE;
878 }
879
880 static const guint8 k12_eof[] = {0xff,0xff};
881
882 static gboolean k12_dump_close(wtap_dumper *wdh, int *err) {
883     union {
884         guint8 b[sizeof(guint32)];
885         guint32 u;
886     } d;
887     
888     fwrite(k12_eof, 1, 2, wdh->fh);
889     
890     if (fseek(wdh->fh, 8, SEEK_SET) == -1) {
891         *err = errno;
892         return FALSE;
893     }
894     
895     d.u = g_htonl(wdh->dump.k12->file_len);
896     
897     fwrite(d.b, 1, 4, wdh->fh);
898     
899     d.u = g_htonl(wdh->dump.k12->num_of_records);
900     
901     fwrite(d.b, 1, 4, wdh->fh);
902     
903     return TRUE;
904 }
905
906
907 gboolean k12_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err) {
908     
909     if (cant_seek) {
910         *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
911         return FALSE;
912     }
913     
914     if ( fwrite(k12_file_magic, 1, 8, wdh->fh) != 8 ) {
915         *err = errno;
916         return FALSE;
917     }
918     
919     if (fseek(wdh->fh, 0x200, SEEK_SET) == -1) {
920         *err = errno;
921         return FALSE;
922     }
923     
924     wdh->subtype_write = k12_dump;
925     wdh->subtype_close = k12_dump_close;
926     
927     wdh->dump.k12 = g_malloc(sizeof(k12_dump_t));
928     wdh->dump.k12->file_len = 0x200;
929     wdh->dump.k12->num_of_records = 0;
930     wdh->dump.k12->file_offset  = 0x200;
931     
932     return TRUE;
933 }
934
935