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