6 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #include "file_wrappers.h"
31 #include "lanalyzer.h"
33 /* The LANalyzer format is documented (at least in part) in Novell document
34 TID022037, which can be found at, among other places:
36 http://secinf.net/info/nw/lan/trace.txt
39 /* LANalyzer board types (which indicate the type of network on which
40 the capture was done). */
41 #define BOARD_325 226 /* LANalyzer 325 (Ethernet) */
42 #define BOARD_325TR 227 /* LANalyzer 325TR (Token-ring) */
45 static const guint8 LA_HeaderRegularFake[] = {
46 0x01,0x10,0x4c,0x00,0x01,0x05,0x54,0x72,0x61,0x63,0x65,0x20,0x44,0x69,0x73,0x70,
47 0x6c,0x61,0x79,0x20,0x54,0x72,0x61,0x63,0x65,0x20,0x46,0x69,0x6c,0x65,0x00,0x00,
48 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
49 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
50 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
53 static const guint8 LA_RxChannelNameFake[] = {
54 0x06,0x10,0x80,0x00,0x43,0x68,0x61,0x6e ,0x6e,0x65,0x6c,0x31,0x00,0x43,0x68,0x61,
55 0x6e,0x6e,0x65,0x6c,0x32,0x00,0x43,0x68 ,0x61,0x6e,0x6e,0x65,0x6c,0x33,0x00,0x43,
56 0x68,0x61,0x6e,0x6e,0x65,0x6c,0x34,0x00 ,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x35,
57 0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c ,0x36,0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,
58 0x6c,0x37,0x00,0x43,0x68,0x61,0x6e,0x6e ,0x65,0x6c,0x38,0x00,0x00,0x00,0x00,0x00,
59 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
60 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
61 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
65 static const guint8 LA_TxChannelNameFake[] = {
66 0x0b,0x10,0x36,0x00 ,0x54,0x72,0x61,0x6e,0x73,0x31,0x00,0x00,
67 0x00,0x54,0x72,0x61,0x6e,0x73,0x32,0x00 ,0x00,0x00,0x54,0x72,0x61,0x6e,0x73,0x33,
68 0x00,0x00,0x00,0x54,0x72,0x61,0x6e,0x73 ,0x34,0x00,0x00,0x00,0x54,0x72,0x61,0x6e,
69 0x73,0x35,0x00,0x00,0x00,0x54,0x72,0x61 ,0x6e,0x73,0x36,0x00,0x00,0x00
72 static const guint8 LA_RxTemplateNameFake[] = {
74 0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
75 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
76 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
77 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
78 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
79 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
80 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
81 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
82 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
86 static const guint8 LA_TxTemplateNameFake[] = {
87 0x36,0x10,0x36,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
88 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
89 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
90 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00
93 static const guint8 LA_DisplayOptionsFake[] = {
95 0x00,0x00,0x01,0x00,0x01,0x02,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
96 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
97 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
98 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
99 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
100 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
101 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
102 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
103 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
104 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
105 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
106 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
107 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
108 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
109 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
110 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
111 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00
114 static const guint8 LA_CyclicInformationFake[] = {
115 0x09,0x10,0x1a,0x00,0x00,0x00,
116 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
117 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
120 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
122 static gboolean lanalyzer_seek_read(wtap *wth, long seek_off,
123 union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
124 int *err, gchar **err_info);
125 static void lanalyzer_close(wtap *wth);
126 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err);
128 int lanalyzer_open(wtap *wth, int *err, gchar **err_info)
131 char LE_record_type[2];
132 char LE_record_length[2];
134 guint16 board_type, mxslc;
135 guint16 record_type, record_length;
136 guint8 cr_day, cr_month;
140 errno = WTAP_ERR_CANT_READ;
141 bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
142 bytes_read += file_read(LE_record_length, 1, 2, wth->fh);
143 if (bytes_read != 4) {
144 *err = file_error(wth->fh);
149 wth->data_offset += 4;
150 record_type = pletohs(LE_record_type);
151 record_length = pletohs(LE_record_length); /* make sure to do this for while() loop */
153 if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
157 /* If we made it this far, then the file is a LANAlyzer file.
158 * Let's get some info from it. Note that we get wth->snapshot_length
159 * from a record later in the file. */
160 wth->file_type = WTAP_FILE_LANALYZER;
161 wth->capture.lanalyzer = g_malloc(sizeof(lanalyzer_t));
162 wth->subtype_read = lanalyzer_read;
163 wth->subtype_seek_read = lanalyzer_seek_read;
164 wth->subtype_close = lanalyzer_close;
165 wth->snapshot_length = 0;
166 wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
168 /* Read records until we find the start of packets */
170 if (file_seek(wth->fh, record_length, SEEK_CUR, err) == -1) {
171 g_free(wth->capture.lanalyzer);
174 wth->data_offset += record_length;
175 errno = WTAP_ERR_CANT_READ;
176 bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
177 bytes_read += file_read(LE_record_length, 1, 2, wth->fh);
178 if (bytes_read != 4) {
179 *err = file_error(wth->fh);
181 g_free(wth->capture.lanalyzer);
184 g_free(wth->capture.lanalyzer);
187 wth->data_offset += 4;
189 record_type = pletohs(LE_record_type);
190 record_length = pletohs(LE_record_length);
192 /*g_message("Record 0x%04X Length %d", record_type, record_length);*/
193 switch (record_type) {
194 /* Trace Summary Record */
196 errno = WTAP_ERR_CANT_READ;
197 bytes_read = file_read(summary, 1, sizeof summary,
199 if (bytes_read != sizeof summary) {
200 *err = file_error(wth->fh);
202 g_free(wth->capture.lanalyzer);
205 g_free(wth->capture.lanalyzer);
208 wth->data_offset += sizeof summary;
210 /* Assume that the date of the creation of the trace file
211 * is the same date of the trace. Lanalyzer doesn't
212 * store the creation date/time of the trace, but only of
213 * the file. Unless you traced at 11:55 PM and saved at 00:05
214 * AM, the assumption that trace.date == file.date is true.
217 cr_month = summary[1];
218 cr_year = pletohs(&summary[2]);
219 /*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
222 /* Get capture start time. I learned how to do
223 * this from Guy's code in ngsniffer.c
225 tm.tm_year = cr_year - 1900;
226 tm.tm_mon = cr_month - 1;
232 wth->capture.lanalyzer->start = mktime(&tm);
233 /*g_message("Day %d Month %d Year %d", tm.tm_mday,
234 tm.tm_mon, tm.tm_year);*/
235 mxslc = pletohs(&summary[30]);
236 wth->snapshot_length = mxslc;
238 record_length = 0; /* to fake the next iteration of while() */
239 board_type = pletohs(&summary[188]);
240 switch (board_type) {
242 wth->file_encap = WTAP_ENCAP_ETHERNET;
245 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
248 g_free(wth->capture.lanalyzer);
249 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
250 *err_info = g_strdup_printf("lanalyzer: board type %u unknown",
256 /* Trace Packet Data Record */
258 /* Go back header number ob ytes so that lanalyzer_read
259 * can read this header */
260 if (file_seek(wth->fh, -bytes_read, SEEK_CUR, err) == -1) {
261 g_free(wth->capture.lanalyzer);
264 wth->data_offset -= bytes_read;
273 #define DESCRIPTOR_LEN 32
275 /* Read the next packet */
276 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
281 char LE_record_type[2];
282 char LE_record_length[2];
283 guint16 record_type, record_length;
284 gchar descriptor[DESCRIPTOR_LEN];
285 guint16 time_low, time_med, time_high, true_size;
288 /* read the record type and length. */
289 errno = WTAP_ERR_CANT_READ;
290 bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
291 if (bytes_read != 2) {
292 *err = file_error(wth->fh);
293 if (*err == 0 && bytes_read != 0) {
294 *err = WTAP_ERR_SHORT_READ;
298 wth->data_offset += 2;
299 bytes_read = file_read(LE_record_length, 1, 2, wth->fh);
300 if (bytes_read != 2) {
301 *err = file_error(wth->fh);
303 *err = WTAP_ERR_SHORT_READ;
306 wth->data_offset += 2;
308 record_type = pletohs(LE_record_type);
309 record_length = pletohs(LE_record_length);
311 /* Only Trace Packet Data Records should occur now that we're in
312 * the middle of reading packets. If any other record type exists
313 * after a Trace Packet Data Record, mark it as an error. */
314 if (record_type != RT_PacketData) {
315 *err = WTAP_ERR_BAD_RECORD;
316 *err_info = g_strdup_printf("lanalyzer: record type %u seen after trace summary record",
321 packet_size = record_length - DESCRIPTOR_LEN;
324 /* Read the descriptor data */
325 errno = WTAP_ERR_CANT_READ;
326 bytes_read = file_read(descriptor, 1, DESCRIPTOR_LEN, wth->fh);
327 if (bytes_read != DESCRIPTOR_LEN) {
328 *err = file_error(wth->fh);
330 *err = WTAP_ERR_SHORT_READ;
333 wth->data_offset += DESCRIPTOR_LEN;
335 /* Read the packet data */
336 buffer_assure_space(wth->frame_buffer, packet_size);
337 *data_offset = wth->data_offset;
338 errno = WTAP_ERR_CANT_READ;
339 bytes_read = file_read(buffer_start_ptr(wth->frame_buffer), 1,
340 packet_size, wth->fh);
342 if (bytes_read != packet_size) {
343 *err = file_error(wth->fh);
345 *err = WTAP_ERR_SHORT_READ;
348 wth->data_offset += packet_size;
350 true_size = pletohs(&descriptor[4]);
351 packet_size = pletohs(&descriptor[6]);
352 time_low = pletohs(&descriptor[8]);
353 time_med = pletohs(&descriptor[10]);
354 time_high = pletohs(&descriptor[12]);
357 * OK, is the frame data size greater than than what's left of the
360 if (packet_size > record_length - DESCRIPTOR_LEN) {
362 * Yes - treat this as an error.
364 *err = WTAP_ERR_BAD_RECORD;
365 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
369 t = (double)time_low+(double)(time_med)*65536.0 +
370 (double)time_high*4294967296.0;
371 t = t/1000000.0 * 0.5; /* t = # of secs */
372 t += wth->capture.lanalyzer->start;
374 wth->phdr.ts.secs = (long)t;
375 wth->phdr.ts.nsecs = (unsigned long)((t-(double)(wth->phdr.ts.secs))
378 if (true_size - 4 >= packet_size) {
380 * It appears that the "true size" includes the FCS;
381 * make it reflect the non-FCS size (the "packet size"
382 * appears never to include the FCS, even if no slicing
387 wth->phdr.len = true_size;
388 wth->phdr.caplen = packet_size;
390 switch (wth->file_encap) {
392 case WTAP_ENCAP_ETHERNET:
393 /* We assume there's no FCS in this frame. */
394 wth->pseudo_header.eth.fcs_len = 0;
401 static gboolean lanalyzer_seek_read(wtap *wth, long seek_off,
402 union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
403 int *err, gchar **err_info _U_)
407 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
411 * Read the packet data.
413 bytes_read = file_read(pd, sizeof(guint8), length, wth->random_fh);
414 if (bytes_read != length) {
415 *err = file_error(wth->random_fh);
417 *err = WTAP_ERR_SHORT_READ;
421 switch (wth->file_encap) {
423 case WTAP_ENCAP_ETHERNET:
424 /* We assume there's no FCS in this frame. */
425 pseudo_header->eth.fcs_len = 0;
433 lanalyzer_close(wtap *wth)
435 g_free(wth->capture.lanalyzer);
438 /*---------------------------------------------------
440 * Write one block with error control
441 *---------------------------------------------------*/
442 static int swrite(const void* what, guint size, FILE *hd)
446 nwritten = fwrite(what, 1, size, hd);
447 if (nwritten != size) {
448 if (nwritten == 0 && ferror(hd))
451 return WTAP_ERR_SHORT_WRITE;
456 /*---------------------------------------------------
458 * Write one block with error control
459 *---------------------------------------------------*/
460 static int s0write(guint cnt, FILE *hd)
462 static guint8 z64[64];
467 snack = cnt > 64 ? 64 : cnt;
468 nwritten = fwrite(z64, 1, snack, hd);
469 if (nwritten != snack) {
470 if (nwritten == 0 && ferror(hd))
473 return WTAP_ERR_SHORT_WRITE;
480 /*---------------------------------------------------
482 * Write one block with error control
483 *---------------------------------------------------*/
484 static int s8write(const guint8 s8, FILE *hd)
488 nwritten = fwrite(&s8, 1, 1, hd);
490 if (nwritten == 0 && ferror(hd))
493 return WTAP_ERR_SHORT_WRITE;
497 /*---------------------------------------------------
499 * Write one block with error control
500 *---------------------------------------------------*/
501 static int s16write(const guint16 s16, FILE *hd)
505 nwritten = fwrite(&s16, 1, 2, hd);
507 if (nwritten == 0 && ferror(hd))
510 return WTAP_ERR_SHORT_WRITE;
514 /*---------------------------------------------------
516 * Write one block with error control
517 *---------------------------------------------------*/
518 static int s32write(const guint32 s32, FILE *hd)
522 nwritten = fwrite(&s32, 1, 4, hd);
524 if (nwritten == 0 && ferror(hd))
527 return WTAP_ERR_SHORT_WRITE;
531 /*---------------------------------------------------
533 * calculates C.c = A.a - B.b
534 *---------------------------------------------------*/
535 static void my_timersub(const struct timeval *a,
536 const struct timeval *b,
539 gint32 usec = a->tv_usec;
541 c->tv_sec = a->tv_sec - b->tv_sec;
542 if (b->tv_usec > usec) {
546 c->tv_usec = usec - b->tv_usec;
548 /*---------------------------------------------------
549 * Write a record for a packet to a dump file.
550 * Returns TRUE on success, FALSE on failure.
551 *---------------------------------------------------*/
552 static gboolean lanalyzer_dump(wtap_dumper *wdh,
553 const struct wtap_pkthdr *phdr,
554 const union wtap_pseudo_header *pseudo_header _U_,
555 const guchar *pd, int *err)
562 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->dump.opaque);
564 int thisSize = phdr->caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
566 if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
567 /* printf(" LA_ProFileLimit reached\n"); */
569 return FALSE; /* and don't forget the header */
572 len = phdr->caplen + (phdr->caplen ? LA_PacketRecordSize : 0);
574 *err = s16write(htoles(0x1005), wdh->fh);
577 *err = s16write(htoles(len), wdh->fh);
581 tv.tv_sec = phdr->ts.secs;
582 tv.tv_usec = phdr->ts.nsecs / 1000;
585 /* collect some information for the
586 * finally written header
588 /* XXX - this conversion could probably improved, if the start uses ns */
592 itmp->encap = wdh->encap;
596 my_timersub(&(tv),&(itmp->start),&td);
598 x = (double) td.tv_usec;
599 x += (double) td.tv_sec * 1000000;
602 *err = s16write(htoles(0x0001), wdh->fh); /* pr.rx_channels */
605 *err = s16write(htoles(0x0008), wdh->fh); /* pr.rx_errors */
608 *err = s16write(htoles(phdr->len + 4), wdh->fh); /* pr.rx_frm_len */
611 *err = s16write(htoles(phdr->caplen), wdh->fh); /* pr.rx_frm_sln */
615 for (i = 0; i < 3; i++) {
616 *err = s16write(htoles((guint16) x), wdh->fh);/* pr.rx_time[i] */
622 *err = s32write(htolel(++itmp->pkts), wdh->fh); /* pr.pktno */
625 *err = s16write(htoles(itmp->lastlen), wdh->fh); /* pr.prlen */
630 *err = s0write(12, wdh->fh);
634 *err = swrite(pd , phdr->caplen , wdh->fh);
638 wdh->bytes_dumped += thisSize;
643 /*---------------------------------------------------
644 * Returns 0 if we could write the specified encapsulation type,
645 * an error indication otherwise.
646 *---------------------------------------------------*/
647 int lanalyzer_dump_can_write_encap(int encap)
649 /* Per-packet encapsulations aren't supported. */
650 if (encap == WTAP_ENCAP_PER_PACKET)
651 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
653 if ( encap != WTAP_ENCAP_ETHERNET
654 && encap != WTAP_ENCAP_TOKEN_RING )
655 return WTAP_ERR_UNSUPPORTED_ENCAP;
657 * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
662 /*---------------------------------------------------
663 * Returns TRUE on success, FALSE on failure; sets "*err" to an
664 * error code on failure
665 *---------------------------------------------------*/
666 gboolean lanalyzer_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err)
671 /* This is a LANalyzer file. We can't fill in some fields in the
672 header until all the packets have been written, so we can't
675 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
679 tmp = g_malloc(sizeof(LA_TmpInfo));
685 ((LA_TmpInfo*)tmp)->init = FALSE;
686 wdh->dump.opaque = tmp;
687 wdh->subtype_write = lanalyzer_dump;
688 wdh->subtype_close = lanalyzer_dump_close;
690 /* Some of the fields in the file header aren't known yet so
691 just skip over it for now. It will be created after all
692 of the packets have been written. */
694 jump = sizeof (LA_HeaderRegularFake)
695 + sizeof (LA_RxChannelNameFake)
696 + sizeof (LA_TxChannelNameFake)
697 + sizeof (LA_RxTemplateNameFake)
698 + sizeof (LA_TxTemplateNameFake)
699 + sizeof (LA_DisplayOptionsFake)
700 + LA_SummaryRecordSize
701 + LA_SubfileSummaryRecordSize
702 + sizeof (LA_CyclicInformationFake)
703 + LA_IndexRecordSize;
705 if (fseek(wdh->fh, jump, SEEK_SET) == -1) {
709 wdh->bytes_dumped = jump;
713 /*---------------------------------------------------
715 *---------------------------------------------------*/
716 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
718 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->dump.opaque);
719 struct tm *fT = localtime(&(itmp->start.tv_sec));
720 guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
721 ? BOARD_325TR /* LANalyzer Board Type */
722 : BOARD_325; /* LANalyzer Board Type */
724 fseek(wdh->fh, 0, SEEK_SET);
726 *err = swrite(&LA_HeaderRegularFake, sizeof LA_HeaderRegularFake, wdh->fh);
729 *err = swrite(&LA_RxChannelNameFake , sizeof LA_RxChannelNameFake , wdh->fh);
732 *err = swrite(&LA_TxChannelNameFake , sizeof LA_TxChannelNameFake , wdh->fh);
735 *err = swrite(&LA_RxTemplateNameFake, sizeof LA_RxTemplateNameFake, wdh->fh);
738 *err = swrite(&LA_TxTemplateNameFake, sizeof LA_TxTemplateNameFake, wdh->fh);
741 *err = swrite(&LA_DisplayOptionsFake, sizeof LA_DisplayOptionsFake, wdh->fh);
744 /*-----------------------------------------------------------------*/
745 *err = s16write(htoles(RT_Summary), wdh->fh); /* rid */
748 *err = s16write(htoles(SummarySize), wdh->fh); /* rlen */
751 *err = s8write((guint8) fT->tm_mday, wdh->fh); /* s.datcre.day */
754 *err = s8write((guint8) (fT->tm_mon+1), wdh->fh); /* s.datcre.mon */
757 *err = s16write(htoles(fT->tm_year + 1900), wdh->fh);/* s.datcre.year */
760 *err = s8write((guint8) fT->tm_mday, wdh->fh); /* s.datclo.day */
763 *err = s8write((guint8) (fT->tm_mon+1), wdh->fh); /* s.datclo.mon */
766 *err = s16write(htoles(fT->tm_year + 1900), wdh->fh);/* s.datclo.year */
769 *err = s8write((guint8) fT->tm_sec, wdh->fh); /* s.timeopn.second */
772 *err = s8write((guint8) fT->tm_min, wdh->fh); /* s.timeopn.minute */
775 *err = s8write((guint8) fT->tm_hour, wdh->fh); /* s.timeopn.hour */
778 *err = s8write((guint8) fT->tm_mday, wdh->fh); /* s.timeopn.mday */
781 *err = s0write(2, wdh->fh);
784 *err = s8write((guint8) fT->tm_sec, wdh->fh); /* s.timeclo.second */
787 *err = s8write((guint8) fT->tm_min, wdh->fh); /* s.timeclo.minute */
790 *err = s8write((guint8) fT->tm_hour, wdh->fh); /* s.timeclo.hour */
793 *err = s8write((guint8) fT->tm_mday, wdh->fh); /* s.timeclo.mday */
796 *err = s0write(2, wdh->fh);
799 *err = s0write(6, wdh->fh); /* EAddr == 0 */
802 *err = s16write(htoles(1), wdh->fh); /* s.mxseqno */
805 *err = s16write(htoles(0), wdh->fh); /* s.slcoffo */
808 *err = s16write(htoles(1514), wdh->fh); /* s.mxslc */
811 *err = s32write(htolel(itmp->pkts), wdh->fh); /* s.totpktt */
814 *err = s0write(12, wdh->fh); /* statrg == 0; ? -1*/
815 if (*err) /* stptrg == 0; ? -1*/
816 return FALSE; /* s.mxpkta[0]=0 */
817 *err = s32write(htolel(itmp->pkts), wdh->fh); /* sr.s.mxpkta[1] */
820 *err = s0write(34*4, wdh->fh); /* s.mxpkta[2-33]=0 */
823 *err = s16write(htoles(board_type), wdh->fh);
826 *err = s0write(20, wdh->fh); /* board_version == 0 */
829 /*-----------------------------------------------------------------*/
830 *err = s16write(htoles(RT_SubfileSummary), wdh->fh); /* ssr.rid */
833 *err = s16write(htoles(LA_SubfileSummaryRecordSize-4), wdh->fh); /* ssr.rlen */
836 *err = s16write(htoles(1), wdh->fh); /* ssr.seqno */
839 *err = s32write(htolel(itmp->pkts), wdh->fh); /* ssr.totpkts */
842 /*-----------------------------------------------------------------*/
843 *err = swrite(&LA_CyclicInformationFake, sizeof LA_CyclicInformationFake, wdh->fh);
846 /*-----------------------------------------------------------------*/
847 *err = s16write(htoles(RT_Index), wdh->fh); /* rid */
850 *err = s16write(htoles(LA_IndexRecordSize -4), wdh->fh);/* rlen */
853 *err = s16write(htoles(LA_IndexSize), wdh->fh); /* idxsp */
856 *err = s0write(LA_IndexRecordSize - 6, wdh->fh);
863 /*---------------------------------------------------
864 * Finish writing to a dump file.
865 * Returns TRUE on success, FALSE on failure.
866 *---------------------------------------------------*/
867 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err)
869 lanalyzer_dump_header(wdh,err);
870 return *err ? FALSE : TRUE;