- packet records with AAL5 Pdus or AAL2 Sdus contain VP/VC and CID info in the packet...
[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_EXTRALEN   0x1e
159 #define K12_SRCDESC_NAMELEN    0x20
160 #define K12_SRCDESC_STACKLEN   0x22
161
162 #define K12_SRCDESC_EXTRATYPE  0x24
163 #define K12_SRCDESC_ATM_VPI    0x38
164 #define K12_SRCDESC_ATM_VCI    0x3a
165 #define K12_SRCDESC_DS0_MASK   0x3c
166
167
168 /*
169  * get_record: Get the next record into a buffer
170  *   Every about 0x2000 bytes 0x10 bytes are inserted in the file,
171  *   even in the middle of a record.
172  *   This reads the next record without the eventual 0x10 bytes.
173  *   returns the lenght of the record + the stuffing (if any)
174  *
175  * XXX: works at most with 0x1FFF bytes per record 
176  */
177 static gint get_record(guint8* buffer, FILE* fh, guint file_offset) {
178         long read;
179         long len;
180         int i;
181         long junky_offset = 0x2000 - ( (file_offset - 0x200) % 0x2000 );
182     
183 #ifdef DEBUG_K12
184     k12_dbg(5,"k12:get_record: ENTER offset=%u",file_offset);
185 #endif
186     
187         if  ( junky_offset != 0x2000 ) {
188                 
189                 /* safe header */
190                 read = file_read(buffer,1, 0x4,fh);
191                 
192                 if (read == 2 && buffer[0] == 0xff && buffer[1] == 0xff) {
193 #ifdef DEBUG_K12
194             k12_dbg(1,"k12:get_record: EOF");
195 #endif
196             
197                         return 0;
198                 } else if ( read != 0x4 ) {
199 #ifdef DEBUG_K12
200             k12_dbg(1,"k12:get_record: SHORT READ");
201 #endif
202             
203                         return -1;
204                 }
205                 
206                 len = pntohl(buffer) & 0x00001FFF;
207                 
208                 if (junky_offset > len) {
209                         /* safe body */
210                         if (len - 0x4 <= 0) {
211 #ifdef DEBUG_K12
212                 k12_dbg(1,"k12:get_record: TOO SHORT");
213 #endif                
214                                 return -1;
215                         }
216                         
217                         if ( file_read(buffer+0x4, 1, len - 0x4, fh) < len - 0x4 ) {
218 #ifdef DEBUG_K12
219                 k12_dbg(1,"k12:get_record: SHORT READ");
220 #endif
221                 
222                                 return -1;
223                         } else {
224 #ifdef DEBUG_K12
225                 k12_hexdump(file_offset, "GOT record", buffer, len);
226 #endif
227                 
228                                 return len;
229                         }
230                 } else {
231                         if ( file_read(buffer+0x4, 1, len + 0xC, fh) < len ) {
232                                 return -1;
233                         }
234                         
235                         for (i = junky_offset; i < len; i++) {
236                                 buffer[i] = buffer[i+0x10];
237                         }
238 #ifdef DEBUG_K12
239             k12_hexdump(file_offset, "GOT record", buffer, len);
240 #endif
241             
242                         return len + 0x10;
243                 }
244         } else {
245                 /* unsafe header */
246                 
247                 read = file_read(buffer,1,0x14,fh);
248                 
249                 if (read == 2 && buffer[0] == 0xff && buffer[1] == 0xff) {
250 #ifdef DEBUG_K12
251             k12_dbg(1,"k12:get_record: EOF");
252 #endif
253             
254                         return 0;
255                 } else if ( read < 0x14 ){
256 #ifdef DEBUG_K12
257             k12_dbg(1,"k12:get_record: SHORT READ");
258 #endif
259             
260                         return -1;
261                 }
262                 
263                 for (i = 0; i < 0x10; i++) {
264                         buffer[i] = buffer[i+0x10];
265                 }
266                 
267                 len = pntohl(buffer) & 0x00001FFF;
268                 
269                 if (len - 0x4 <= 0) {
270 #ifdef DEBUG_K12
271             k12_dbg(1,"k12:get_record: SHORT RECORD");
272 #endif
273                         return -1;
274         }
275                 /* safe body */
276                 if ( file_read(buffer + 0x4, 1, len - 0x4,fh) < len - 0x4 ) {
277 #ifdef DEBUG_K12
278             k12_dbg(1,"k12:get_record: READ ERROR");
279 #endif
280                         return -1;
281                 } else {
282             
283 #ifdef DEBUG_K12
284             k12_hexdump(file_offset, "GOT stuffed record", buffer, len);
285 #endif
286             
287                         return len + 0x10;
288                 }
289         }
290 }
291
292 static gboolean k12_read(wtap *wth, int *err, gchar **err_info _U_, long *data_offset) {
293         k12_src_desc_t* src_desc;
294         guint8 buffer[0x2000];
295         long offset;
296         long len;
297         guint32 type;
298         guint64 ts;
299         
300         offset = wth->data_offset;
301     
302 #ifdef DEBUG_K12
303     k12_dbg(5,"k12_read: offset=%i",offset);
304 #endif
305     
306         /* ignore the record if it isn't a packet */    
307         do {
308                 *data_offset = offset;
309                 
310                 len = get_record(buffer, wth->fh, offset);
311                 
312                 if (len < 0) {
313                         *err = WTAP_ERR_SHORT_READ;
314                         return FALSE;
315                 } else if (len == 0) {
316                         *err = 0;
317                         return FALSE;
318                 }
319                 
320                 type = pntohl(buffer + K12_RECORD_TYPE);
321         
322 #ifdef DEBUG_K12
323         k12_dbg(5,"k12_read: record type=%i",offset);
324 #endif
325         
326                 offset += len;
327                 
328         } while ( (type & K12_MASK_PACKET) != K12_REC_PACKET );
329         
330         wth->data_offset = offset;
331         
332         ts = pntohll(buffer + K12_PACKET_TIMESTAMP);
333         
334     
335         wth->phdr.ts.secs = (guint32) ((ts / 2000000) + 631152000);
336         wth->phdr.ts.nsecs = (guint32) ( (ts % 2000000) * 500 );
337     
338 #ifdef DEBUG_K12
339     k12_dbg(5,"k12_read: secs=%u nsecs=%u", wth->phdr.ts.secs,wth->phdr.ts.nsecs);
340 #endif
341     
342         wth->phdr.len = wth->phdr.caplen = pntohl(buffer + K12_RECORD_FRAME_LEN) & 0x00001FFF;
343         
344         /* the frame */
345         buffer_assure_space(wth->frame_buffer, wth->phdr.caplen);
346         memcpy(buffer_start_ptr(wth->frame_buffer), buffer + K12_PACKET_FRAME, wth->phdr.caplen);
347         
348         wth->pseudo_header.k12.input = pntohl(buffer + K12_RECORD_INPUT);
349     
350 #ifdef DEBUG_K12
351     k12_dbg(5,"k12_read: wth->pseudo_header.k12.input=%x wth->phdr.len=%i",wth->pseudo_header.k12.input,wth->phdr.len);
352 #endif
353     
354     src_desc = g_hash_table_lookup(wth->capture.k12->src_by_id,GUINT_TO_POINTER(wth->pseudo_header.k12.input));
355         
356         if (src_desc) {
357         
358 #ifdef DEBUG_K12
359         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);
360 #endif
361         wth->pseudo_header.k12.input_name = src_desc->input_name;
362                 wth->pseudo_header.k12.stack_file = src_desc->stack_file;
363                 wth->pseudo_header.k12.input_type = src_desc->input_type;
364         
365         switch(src_desc->input_type) {
366             case K12_PORT_ATMPVC:
367                 wth->pseudo_header.k12.input_info.atm.vp =  pntohs(buffer + (K12_PACKET_FRAME + wth->phdr.caplen + K12_PACKET_OFFSET_VP));
368                 wth->pseudo_header.k12.input_info.atm.vc =  pntohs(buffer + (K12_PACKET_FRAME + wth->phdr.caplen + K12_PACKET_OFFSET_VC));
369                 wth->pseudo_header.k12.input_info.atm.cid =  *((unsigned char*)(buffer + K12_PACKET_FRAME + wth->phdr.len + K12_PACKET_OFFSET_CID));
370                 break;
371             default:
372                 memcpy(&(wth->pseudo_header.k12.input_info),&(src_desc->input_info),sizeof(src_desc->input_info));
373                 break;
374                 
375         }
376         } else {
377         
378 #ifdef DEBUG_K12
379         k12_dbg(5,"k12_read: NO RECORD FOUND");
380 #endif
381         
382                 memset(&(wth->pseudo_header),0,sizeof(wth->pseudo_header));
383                 wth->pseudo_header.k12.input_name = "unknown port";
384                 wth->pseudo_header.k12.stack_file = "unknown stack file";
385         }
386         
387         wth->pseudo_header.k12.stuff = wth->capture.k12;
388     
389         return TRUE;
390 }
391
392
393 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_) {
394         k12_src_desc_t* src_desc;
395         guint8 buffer[0x2000];
396     guint32 input;
397     
398 #ifdef DEBUG_K12
399     k12_dbg(5,"k12_seek_read: ENTER");
400 #endif
401     
402         if ( file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) {
403 #ifdef DEBUG_K12
404         k12_dbg(5,"k12_seek_read: SEEK ERROR");
405 #endif
406                 return FALSE;
407         }
408         
409         if (get_record(buffer, wth->random_fh, seek_off) < 1) {
410 #ifdef DEBUG_K12
411         k12_dbg(5,"k12_seek_read: READ ERROR");
412 #endif
413                 return FALSE;
414         }
415         
416         memcpy(pd, buffer + K12_PACKET_FRAME, length);
417         
418     input = pntohl(buffer + K12_RECORD_INPUT);
419 #ifdef DEBUG_K12
420     k12_dbg(5,"k12_seek_read: input=%.8x",input);
421 #endif
422     
423         src_desc = g_hash_table_lookup(wth->capture.k12->src_by_id,GUINT_TO_POINTER(input));
424     
425         if (src_desc) {
426         
427 #ifdef DEBUG_K12
428         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);
429 #endif
430         if (pseudo_header) {
431             pseudo_header->k12.input_name = src_desc->input_name;
432             pseudo_header->k12.stack_file = src_desc->stack_file;
433             pseudo_header->k12.input_type = src_desc->input_type;
434             
435             switch(src_desc->input_type) {
436                 case K12_PORT_ATMPVC:
437                     pseudo_header->k12.input_info.atm.vp =  pntohs(buffer + K12_PACKET_FRAME + length + K12_PACKET_OFFSET_VP);
438                     pseudo_header->k12.input_info.atm.vc =  pntohs(buffer + K12_PACKET_FRAME + length + K12_PACKET_OFFSET_VC);
439                     pseudo_header->k12.input_info.atm.cid =  *((unsigned char*)(buffer + K12_PACKET_FRAME + length + K12_PACKET_OFFSET_CID));
440                     break;
441                 default:
442                     memcpy(&(pseudo_header->k12.input_info),&(src_desc->input_info),sizeof(src_desc->input_info));
443                     break;
444             }
445             
446         }
447         
448         wth->pseudo_header.k12.input_name = src_desc->input_name;
449                 wth->pseudo_header.k12.stack_file = src_desc->stack_file;
450                 wth->pseudo_header.k12.input_type = src_desc->input_type;
451                 
452         switch(src_desc->input_type) {
453             case K12_PORT_ATMPVC:
454                 wth->pseudo_header.k12.input_info.atm.vp =  pntohs(buffer + K12_PACKET_FRAME + length + K12_PACKET_OFFSET_VP);
455                 wth->pseudo_header.k12.input_info.atm.vc =  pntohs(buffer + K12_PACKET_FRAME + length + K12_PACKET_OFFSET_VC);
456                 wth->pseudo_header.k12.input_info.atm.cid =  *((unsigned char*)(buffer + K12_PACKET_FRAME + length + K12_PACKET_OFFSET_CID));
457                 break;
458             default:
459                 memcpy(&(wth->pseudo_header.k12.input_info),&(src_desc->input_info),sizeof(src_desc->input_info));
460                 break;
461         }
462         
463         } else {
464         
465 #ifdef DEBUG_K12
466         k12_dbg(5,"k12_seek_read: NO SRC_RECORD FOUND");
467 #endif
468         
469         if (pseudo_header) {
470             memset(&(pseudo_header->k12),0,sizeof(pseudo_header->k12));
471             pseudo_header->k12.input_name = "unknown port";
472             pseudo_header->k12.stack_file = "unknown stack file";
473         }
474         
475                 memset(&(wth->pseudo_header.k12),0,sizeof(wth->pseudo_header.k12));
476                 wth->pseudo_header.k12.input_name = "unknown port";
477                 wth->pseudo_header.k12.stack_file = "unknown stack file";
478         
479     }
480         
481     if (pseudo_header) {
482         pseudo_header->k12.input = input;
483         pseudo_header->k12.stuff = wth->capture.k12;
484     }
485     
486     wth->pseudo_header.k12.input = input;
487         wth->pseudo_header.k12.stuff = wth->capture.k12;
488     
489 #ifdef DEBUG_K12
490     k12_dbg(5,"k12_seek_read: DONE OK");
491 #endif
492     
493         return TRUE;
494 }
495
496
497 static k12_t* new_k12_file_data() {
498         k12_t* fd = g_malloc(sizeof(k12_t));
499         
500         fd->file_len = 0;
501         fd->num_of_records = 0;
502         fd->src_by_name = g_hash_table_new(g_str_hash,g_str_equal);
503         fd->src_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
504         
505         return fd;
506 }
507
508 static gboolean destroy_srcdsc(gpointer k _U_, gpointer v, gpointer p _U_) {
509         k12_src_desc_t* rec = v;
510         
511         if(rec->input_name)
512                 g_free(rec->input_name);
513         
514         if(rec->stack_file)
515                 g_free(rec->stack_file);
516         
517         g_free(rec);
518         
519         return TRUE;
520 }
521
522 static void destroy_k12_file_data(k12_t* fd) {
523         g_hash_table_destroy(fd->src_by_id);
524         g_hash_table_foreach_remove(fd->src_by_name,destroy_srcdsc,NULL);       
525         g_hash_table_destroy(fd->src_by_name);
526         g_free(fd);
527 }
528
529 static void k12_close(wtap *wth) {
530         destroy_k12_file_data(wth->capture.k12);
531 #ifdef DEBUG_K12
532     k12_dbg(5,"k12_close: CLOSED");
533     if (env_file) fclose(dbg_out);
534 #endif
535 }
536
537
538 int k12_open(wtap *wth, int *err, gchar **err_info _U_) {
539         k12_src_desc_t* rec;
540         guint8 read_buffer[0x2000];
541         guint32 type;
542         long offset;
543         long len;
544         guint32 rec_len;
545         guint32 extra_len;
546         guint32 name_len;
547         guint32 stack_len;
548         guint i;
549         k12_t* file_data;
550     
551 #ifdef DEBUG_K12
552     gchar* env_level = getenv("K12_DEBUG_LEVEL");
553     env_file = getenv("K12_DEBUG_FILENAME");
554     if ( env_file ) dbg_out = fopen(env_file,"w");
555     else dbg_out = stderr;
556     if ( env_level ) debug_level = strtoul(env_level,NULL,10);
557     k12_dbg(1,"k12_open: ENTER debug_level=%u",debug_level);
558 #endif
559     
560         if ( file_read(read_buffer,1,0x200,wth->fh) != 0x200 ) {
561         
562 #ifdef DEBUG_K12
563         k12_dbg(1,"k12_open: FILE HEADER TOO SHORT");
564 #endif
565         
566                 return 0;
567         } else {
568                 if ( memcmp(read_buffer,k12_file_magic,8) != 0 ) {
569 #ifdef DEBUG_K12
570             k12_dbg(1,"k12_open: BAD MAGIC");
571 #endif
572                         return 0;
573                 }
574         }
575         
576         offset = 0x200;
577     
578         file_data = new_k12_file_data();
579         
580         file_data->file_len = pntohl( read_buffer + 0x8);
581         file_data->num_of_records = pntohl( read_buffer + 0xC );
582     
583 #ifdef DEBUG_K12
584     k12_dbg(5,"k12_open: FILE_HEADER OK: offset=%x file_len=%i records=%i",
585             offset,
586             file_data->file_len,
587             file_data->num_of_records );
588 #endif
589     
590         do {
591                 
592                 len = get_record(read_buffer, wth->fh, offset);
593         
594                 if ( len <= 0 ) {
595 #ifdef DEBUG_K12
596             k12_dbg(1,"k12_open: BAD HEADER RECORD");
597 #endif            
598                         return -1;
599                 }
600         
601         
602                 type = pntohl( read_buffer + K12_RECORD_TYPE );
603         
604                 if ( (type & K12_MASK_PACKET) == K12_REC_PACKET) {
605                         /*
606                          * we are at the first packet record, rewind and leave.
607                          */
608                         if (file_seek(wth->fh, offset, SEEK_SET, err) == -1) {
609                                 destroy_k12_file_data(file_data);
610                                 return -1;
611                         }
612 #ifdef DEBUG_K12
613             k12_dbg(5,"k12_open: FIRST PACKET offset=%x",offset);
614 #endif                                  
615                         break;
616                 } else if (type == K12_REC_SRCDSC) {
617                         rec = g_malloc0(sizeof(k12_src_desc_t));
618                         
619                         rec_len = pntohl( read_buffer + K12_RECORD_LEN );
620                         extra_len = pntohs( read_buffer + K12_SRCDESC_EXTRALEN );
621                         name_len = pntohs( read_buffer + K12_SRCDESC_NAMELEN );
622                         stack_len = pntohs( read_buffer + K12_SRCDESC_STACKLEN );
623             
624             rec->input = pntohl( read_buffer + K12_RECORD_INPUT );
625             
626 #ifdef DEBUG_K12
627             k12_dbg(5,"k12_open: INTERFACE RECORD offset=%x interface=%x",offset,rec->input);
628 #endif
629             
630                         if (extra_len == 0 || name_len == 0 || stack_len == 0
631                                 || 0x20 + extra_len + name_len + stack_len > rec_len ) {
632                                 g_free(rec);
633 #ifdef DEBUG_K12
634                 k12_dbg(5,"k12_open: failed (extra_len == 0 || name_len == 0 || stack_len == 0 "
635                         "|| 0x20 + extra_len + name_len + stack_len > rec_len)  extra_len=%i name_len=%i stack_len=%i");
636 #endif
637                 
638                                 return 0;
639                         }
640                         
641                         switch(( rec->input_type = pntohl( read_buffer + K12_SRCDESC_EXTRATYPE ) )) {
642                                 case K12_PORT_DS0S:
643                                         rec->input_info.ds0mask = 0x00000000;
644                                         
645                                         for (i = 0; i < 32; i++) {
646                                                 rec->input_info.ds0mask |= ( *(read_buffer + K12_SRCDESC_DS0_MASK + i) == 0xff ) ? 0x1<<(31-i) : 0x0; 
647                                         }
648                                                 
649                                                 break;
650                                 case K12_PORT_ATMPVC:
651                                         rec->input_info.atm.vp = pntohs( read_buffer + K12_SRCDESC_ATM_VPI );
652                                         rec->input_info.atm.vc = pntohs( read_buffer + K12_SRCDESC_ATM_VCI );
653                                         break;
654                                 default:
655                                         break;
656                         }
657                         
658                         rec->input_name = g_memdup(read_buffer + K12_SRCDESC_EXTRATYPE + extra_len, name_len);
659                         rec->stack_file = g_memdup(read_buffer + K12_SRCDESC_EXTRATYPE + extra_len + name_len, stack_len);
660                         
661                         g_strdown(rec->stack_file);
662             
663                         g_hash_table_insert(file_data->src_by_id,GUINT_TO_POINTER(rec->input),rec);
664                         g_hash_table_insert(file_data->src_by_name,rec->stack_file,rec);
665                         
666                         offset += len;
667                         continue;
668                 } else {
669                         offset += len;
670                         continue;
671                 }
672         } while(1);
673         
674         wth->data_offset = offset;
675         wth->file_type = WTAP_FILE_K12;
676         wth->file_encap = WTAP_ENCAP_K12;
677         wth->snapshot_length = 0;
678         wth->subtype_read = k12_read;
679         wth->subtype_seek_read = k12_seek_read;
680         wth->subtype_close = k12_close;
681         wth->capture.k12 = file_data;
682         wth->tsprecision = WTAP_FILE_TSPREC_NSEC;       
683         
684         return 1;
685 }
686
687 int k12_dump_can_write_encap(int encap) {
688         
689         if (encap == WTAP_ENCAP_PER_PACKET)
690                 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
691         
692         if (encap != WTAP_ENCAP_K12)
693                 return WTAP_ERR_UNSUPPORTED_ENCAP;
694         
695         return 0;
696 }
697
698 static const gchar dumpy_junk[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
699
700 static void k12_dump_record(wtap_dumper *wdh, long len,  guint8* buffer) {
701         long junky_offset = (0x2000 - ( (wdh->dump.k12->file_offset - 0x200) % 0x2000 )) % 0x2000;
702         
703         if (len > junky_offset) {
704                 
705                 if (junky_offset)
706                         fwrite(buffer, 1, junky_offset, wdh->fh);
707                 
708                 fwrite(dumpy_junk, 1, 0x10, wdh->fh);
709                 
710                 fwrite(buffer+junky_offset, 1, len - junky_offset, wdh->fh);
711                 
712                 wdh->dump.k12->file_offset += len + 0x10;
713         } else {
714                 fwrite(buffer, 1, len, wdh->fh);
715                 wdh->dump.k12->file_offset += len;
716         }
717         
718         wdh->dump.k12->num_of_records++;
719 }
720
721 static void k12_dump_src_setting(gpointer k _U_, gpointer v, gpointer p) {
722         k12_src_desc_t* src_desc = v;
723         wtap_dumper *wdh = p;
724         guint32 len;
725         guint offset;
726         guint i;
727         
728         union {
729                 guint8 buffer[0x2000];
730                 
731                 struct {
732                         guint32 len;
733                         guint32 type;
734                         guint32 unk32_1;
735                         guint32 input;
736                         
737                         guint32 unk32_2;
738                         guint32 unk32_3;
739                         guint32 unk32_4;
740                         guint16 unk16_1;
741                         guint16 extra_len;
742                         
743                         guint16 name_len;
744                         guint16 stack_len;
745                         
746                         struct {
747                                 guint32 type;
748                                 
749                                 union {
750                                         struct {
751                                                 guint32 unk32;
752                                                 guint8 mask[32];
753                                         } ds0mask;
754                                         
755                                         struct {
756                                                 guint8 unk_data[0x10];
757                                                 guint16 vp;
758                                                 guint16 vc;
759                                         } atm;
760                                         
761                                         guint32 unk;
762                                 } desc;
763                         } extra;
764                 } record;
765         } obj;
766         
767         obj.record.type = g_htonl(K12_REC_SRCDSC);
768         obj.record.unk32_1 = g_htonl(0x00000001);
769         obj.record.input = g_htonl(src_desc->input);
770         
771         obj.record.unk32_2 = g_htonl(0x0000060f);
772         obj.record.unk32_3 = g_htonl(0x00000003);
773         obj.record.unk32_4 = g_htonl(0x01000100);
774     
775         obj.record.unk16_1 = g_htons(0x0000);
776         obj.record.name_len = strlen(src_desc->input_name) + 1;
777         obj.record.stack_len = strlen(src_desc->stack_file) + 1;
778     
779         obj.record.extra.type = g_htonl(src_desc->input_type);
780         
781         switch (src_desc->input_type) {
782                 case K12_PORT_ATMPVC:
783                         obj.record.extra_len = g_htons(0x18);
784                         obj.record.extra.desc.atm.vp = g_htons(src_desc->input_info.atm.vp);
785                         obj.record.extra.desc.atm.vc = g_htons(src_desc->input_info.atm.vc);
786                         offset = 0x3c;
787                         break;
788                 case K12_PORT_DS0S:
789                         obj.record.extra_len = g_htons(0x18);
790                         for( i=0; i<32; i++ ) {
791                                 obj.record.extra.desc.ds0mask.mask[i] =
792                 (src_desc->input_info.ds0mask & (1 << i)) ? 0xff : 0x00;
793                         }
794                 offset = 0x3c;
795                         break;
796                 default:
797                         obj.record.extra_len = g_htons(0x08);
798                         offset = 0x2c;
799                         break;
800         }
801         
802         memcpy(obj.buffer + offset,
803                    src_desc->input_name,
804                    obj.record.name_len);
805         
806         memcpy(obj.buffer + offset + obj.record.name_len,
807                    src_desc->stack_file,
808                    obj.record.stack_len);
809         
810         len = offset + obj.record.name_len + obj.record.stack_len;
811         len += (len % 4) ? 4 - (len % 4) : 0;
812         
813         obj.record.len = g_htonl(len);
814         obj.record.name_len =  g_htons(obj.record.name_len);
815         obj.record.stack_len = g_htons(obj.record.stack_len);
816     
817         k12_dump_record(wdh,len,obj.buffer);
818 }
819
820 static gboolean k12_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
821                          const union wtap_pseudo_header *pseudo_header,
822                          const guchar *pd, int *err _U_) {
823         long len;
824         union {
825                 guint8 buffer[0x2000];
826                 struct {
827                         guint32 len;
828                         guint32 type;
829                         guint32 frame_len;
830                         guint32 input;
831                         
832                         guint32 datum_1;
833                         guint32 datum_2;
834                         guint64 ts;
835                         
836                         guint8 frame[0x1fc0];
837                 } record;
838         } obj;
839         
840         if (wdh->dump.k12->num_of_records == 0) {
841                 k12_t* file_data = pseudo_header->k12.stuff;
842                 g_hash_table_foreach(file_data->src_by_id,k12_dump_src_setting,wdh);
843         }
844         
845         obj.record.len = 0x20 + phdr->len;
846         obj.record.len += (obj.record.len % 4) ? 4 - obj.record.len % 4 : 0;
847     
848         len = obj.record.len;
849         
850         obj.record.len = g_htonl(obj.record.len);
851     
852         obj.record.type = g_htonl(K12_REC_PACKET);
853         obj.record.frame_len = g_htonl(phdr->len);
854         obj.record.input = g_htonl(pseudo_header->k12.input);
855         
856         obj.record.ts = GUINT64_TO_BE((((guint64)phdr->ts.secs - 631152000) * 2000000) + (phdr->ts.nsecs / 1000 * 2));
857     
858         memcpy(obj.record.frame,pd,phdr->len);
859         
860         k12_dump_record(wdh,len,obj.buffer);
861         
862         /* XXX if OK */
863         return TRUE;
864 }
865
866 static const guint8 k12_eof[] = {0xff,0xff};
867
868 static gboolean k12_dump_close(wtap_dumper *wdh, int *err) {
869         union {
870                 guint8 b[sizeof(guint32)];
871                 guint32 u;
872         } d;
873         
874         fwrite(k12_eof, 1, 2, wdh->fh);
875     
876         if (fseek(wdh->fh, 8, SEEK_SET) == -1) {
877                 *err = errno;
878                 return FALSE;
879         }
880         
881         d.u = g_htonl(wdh->dump.k12->file_len);
882         
883         fwrite(d.b, 1, 4, wdh->fh);
884     
885         d.u = g_htonl(wdh->dump.k12->num_of_records);
886         
887         fwrite(d.b, 1, 4, wdh->fh);
888     
889         return TRUE;
890 }
891
892
893 gboolean k12_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err) {
894         
895         if (cant_seek) {
896                 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
897                 return FALSE;
898         }
899         
900         if ( fwrite(k12_file_magic, 1, 8, wdh->fh) != 8 ) {
901                 *err = errno;
902                 return FALSE;
903         }
904         
905         if (fseek(wdh->fh, 0x200, SEEK_SET) == -1) {
906                 *err = errno;
907                 return FALSE;
908         }
909     
910         wdh->subtype_write = k12_dump;
911         wdh->subtype_close = k12_dump_close;
912         
913         wdh->dump.k12 = g_malloc(sizeof(k12_dump_t));
914         wdh->dump.k12->file_len = 0x200;
915         wdh->dump.k12->num_of_records = 0;
916         wdh->dump.k12->file_offset  = 0x200;
917         
918         return TRUE;
919 }
920
921