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://www.windowsecurity.com/whitepapers/Description_of_the_LANalysers_output_file.html
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
124 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
125 gint64 *data_offset);
126 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
127 union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
128 int *err, gchar **err_info);
129 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err);
131 int lanalyzer_open(wtap *wth, int *err, gchar **err_info)
134 char LE_record_type[2];
135 char LE_record_length[2];
137 guint16 board_type, mxslc;
138 guint16 record_type, record_length;
139 guint8 cr_day, cr_month;
142 lanalyzer_t *lanalyzer;
144 errno = WTAP_ERR_CANT_READ;
145 bytes_read = file_read(LE_record_type, 2, wth->fh);
146 bytes_read += file_read(LE_record_length, 2, wth->fh);
147 if (bytes_read != 4) {
148 *err = file_error(wth->fh, err_info);
153 wth->data_offset += 4;
154 record_type = pletohs(LE_record_type);
155 record_length = pletohs(LE_record_length); /* make sure to do this for while() loop */
157 if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
161 /* If we made it this far, then the file is a LANAlyzer file.
162 * Let's get some info from it. Note that we get wth->snapshot_length
163 * from a record later in the file. */
164 wth->file_type = WTAP_FILE_LANALYZER;
165 lanalyzer = (lanalyzer_t *)g_malloc(sizeof(lanalyzer_t));;
166 wth->priv = (void *)lanalyzer;
167 wth->subtype_read = lanalyzer_read;
168 wth->subtype_seek_read = lanalyzer_seek_read;
169 wth->snapshot_length = 0;
170 wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
172 /* Read records until we find the start of packets */
174 if (file_seek(wth->fh, record_length, SEEK_CUR, err) == -1) {
178 wth->data_offset += record_length;
179 errno = WTAP_ERR_CANT_READ;
180 bytes_read = file_read(LE_record_type, 2, wth->fh);
181 bytes_read += file_read(LE_record_length, 2, wth->fh);
182 if (bytes_read != 4) {
183 *err = file_error(wth->fh, err_info);
191 wth->data_offset += 4;
193 record_type = pletohs(LE_record_type);
194 record_length = pletohs(LE_record_length);
196 /*g_message("Record 0x%04X Length %d", record_type, record_length);*/
197 switch (record_type) {
198 /* Trace Summary Record */
200 errno = WTAP_ERR_CANT_READ;
201 bytes_read = file_read(summary, sizeof summary,
203 if (bytes_read != sizeof summary) {
204 *err = file_error(wth->fh, err_info);
212 wth->data_offset += sizeof summary;
214 /* Assume that the date of the creation of the trace file
215 * is the same date of the trace. Lanalyzer doesn't
216 * store the creation date/time of the trace, but only of
217 * the file. Unless you traced at 11:55 PM and saved at 00:05
218 * AM, the assumption that trace.date == file.date is true.
221 cr_month = summary[1];
222 cr_year = pletohs(&summary[2]);
223 /*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
226 /* Get capture start time. I learned how to do
227 * this from Guy's code in ngsniffer.c
229 tm.tm_year = cr_year - 1900;
230 tm.tm_mon = cr_month - 1;
236 lanalyzer->start = mktime(&tm);
237 /*g_message("Day %d Month %d Year %d", tm.tm_mday,
238 tm.tm_mon, tm.tm_year);*/
239 mxslc = pletohs(&summary[30]);
240 wth->snapshot_length = mxslc;
242 record_length = 0; /* to fake the next iteration of while() */
243 board_type = pletohs(&summary[188]);
244 switch (board_type) {
246 wth->file_encap = WTAP_ENCAP_ETHERNET;
249 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
253 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
254 *err_info = g_strdup_printf("lanalyzer: board type %u unknown",
260 /* Trace Packet Data Record */
262 /* Go back header number ob ytes so that lanalyzer_read
263 * can read this header */
264 if (file_seek(wth->fh, -bytes_read, SEEK_CUR, err) == -1) {
268 wth->data_offset -= bytes_read;
277 #define DESCRIPTOR_LEN 32
279 /* Read the next packet */
280 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
285 char LE_record_type[2];
286 char LE_record_length[2];
287 guint16 record_type, record_length;
288 gchar descriptor[DESCRIPTOR_LEN];
289 guint16 time_low, time_med, time_high, true_size;
292 lanalyzer_t *lanalyzer;
294 /* read the record type and length. */
295 errno = WTAP_ERR_CANT_READ;
296 bytes_read = file_read(LE_record_type, 2, wth->fh);
297 if (bytes_read != 2) {
298 *err = file_error(wth->fh, err_info);
299 if (*err == 0 && bytes_read != 0) {
300 *err = WTAP_ERR_SHORT_READ;
304 wth->data_offset += 2;
305 bytes_read = file_read(LE_record_length, 2, wth->fh);
306 if (bytes_read != 2) {
307 *err = file_error(wth->fh, err_info);
309 *err = WTAP_ERR_SHORT_READ;
312 wth->data_offset += 2;
314 record_type = pletohs(LE_record_type);
315 record_length = pletohs(LE_record_length);
317 /* Only Trace Packet Data Records should occur now that we're in
318 * the middle of reading packets. If any other record type exists
319 * after a Trace Packet Data Record, mark it as an error. */
320 if (record_type != RT_PacketData) {
321 *err = WTAP_ERR_BAD_RECORD;
322 *err_info = g_strdup_printf("lanalyzer: record type %u seen after trace summary record",
327 packet_size = record_length - DESCRIPTOR_LEN;
330 /* Read the descriptor data */
331 errno = WTAP_ERR_CANT_READ;
332 bytes_read = file_read(descriptor, DESCRIPTOR_LEN, wth->fh);
333 if (bytes_read != DESCRIPTOR_LEN) {
334 *err = file_error(wth->fh, err_info);
336 *err = WTAP_ERR_SHORT_READ;
339 wth->data_offset += DESCRIPTOR_LEN;
341 /* Read the packet data */
342 buffer_assure_space(wth->frame_buffer, packet_size);
343 *data_offset = wth->data_offset;
344 errno = WTAP_ERR_CANT_READ;
345 bytes_read = file_read(buffer_start_ptr(wth->frame_buffer),
346 packet_size, wth->fh);
348 if (bytes_read != packet_size) {
349 *err = file_error(wth->fh, err_info);
351 *err = WTAP_ERR_SHORT_READ;
354 wth->data_offset += packet_size;
356 true_size = pletohs(&descriptor[4]);
357 packet_size = pletohs(&descriptor[6]);
360 * OK, is the frame data size greater than than what's left of the
363 if (packet_size > record_length - DESCRIPTOR_LEN) {
365 * Yes - treat this as an error.
367 *err = WTAP_ERR_BAD_RECORD;
368 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
372 time_low = pletohs(&descriptor[8]);
373 time_med = pletohs(&descriptor[10]);
374 time_high = pletohs(&descriptor[12]);
375 t = (((guint64)time_low) << 0) + (((guint64)time_med) << 16) +
376 (((guint64)time_high) << 32);
377 tsecs = (time_t) (t/2000000);
378 lanalyzer = (lanalyzer_t *)wth->priv;
379 wth->phdr.ts.secs = tsecs + lanalyzer->start;
380 wth->phdr.ts.nsecs = ((guint32) (t - tsecs*2000000)) * 500;
382 if (true_size - 4 >= packet_size) {
384 * It appears that the "true size" includes the FCS;
385 * make it reflect the non-FCS size (the "packet size"
386 * appears never to include the FCS, even if no slicing
391 wth->phdr.len = true_size;
392 wth->phdr.caplen = packet_size;
394 switch (wth->file_encap) {
396 case WTAP_ENCAP_ETHERNET:
397 /* We assume there's no FCS in this frame. */
398 wth->pseudo_header.eth.fcs_len = 0;
405 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
406 union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
407 int *err, gchar **err_info)
411 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
415 * Read the packet data.
417 bytes_read = file_read(pd, length, wth->random_fh);
418 if (bytes_read != length) {
419 *err = file_error(wth->random_fh, err_info);
421 *err = WTAP_ERR_SHORT_READ;
425 switch (wth->file_encap) {
427 case WTAP_ENCAP_ETHERNET:
428 /* We assume there's no FCS in this frame. */
429 pseudo_header->eth.fcs_len = 0;
436 /*---------------------------------------------------
437 * Returns TRUE on success, FALSE on error
438 * Write "cnt" bytes of zero with error control
439 *---------------------------------------------------*/
440 static gboolean s0write(wtap_dumper *wdh, size_t cnt, int *err)
442 static const guint8 z64[64];
446 snack = cnt > 64 ? 64 : cnt;
448 if (!wtap_dump_file_write(wdh, z64, snack, err))
452 return TRUE; /* ok */
455 /*---------------------------------------------------
456 * Returns TRUE on success, FALSE on error
457 * Write an 8-bit value with error control
458 *---------------------------------------------------*/
459 static gboolean s8write(wtap_dumper *wdh, const guint8 s8, int *err)
461 return wtap_dump_file_write(wdh, &s8, 1, err);
463 /*---------------------------------------------------
464 * Returns TRUE on success, FALSE on error
465 * Write a 16-bit value with error control
466 *---------------------------------------------------*/
467 static gboolean s16write(wtap_dumper *wdh, const guint16 s16, int *err)
469 return wtap_dump_file_write(wdh, &s16, 2, err);
471 /*---------------------------------------------------
472 * Returns TRUE on success, FALSE on error
473 * Write a 32-bit value with error control
474 *---------------------------------------------------*/
475 static gboolean s32write(wtap_dumper *wdh, const guint32 s32, int *err)
477 return wtap_dump_file_write(wdh, &s32, 4, err);
479 /*---------------------------------------------------
481 * calculates C.c = A.a - B.b
482 *---------------------------------------------------*/
483 static void my_timersub(const struct timeval *a,
484 const struct timeval *b,
487 gint32 usec = a->tv_usec;
489 c->tv_sec = a->tv_sec - b->tv_sec;
490 if (b->tv_usec > usec) {
494 c->tv_usec = usec - b->tv_usec;
496 /*---------------------------------------------------
497 * Write a record for a packet to a dump file.
498 * Returns TRUE on success, FALSE on failure.
499 *---------------------------------------------------*/
500 static gboolean lanalyzer_dump(wtap_dumper *wdh,
501 const struct wtap_pkthdr *phdr,
502 const union wtap_pseudo_header *pseudo_header _U_,
503 const guchar *pd, int *err)
510 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
512 int thisSize = phdr->caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
514 if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
515 /* printf(" LA_ProFileLimit reached\n"); */
517 return FALSE; /* and don't forget the header */
520 len = phdr->caplen + (phdr->caplen ? LA_PacketRecordSize : 0);
522 if (!s16write(wdh, htoles(0x1005), err))
524 if (!s16write(wdh, htoles(len), err))
527 tv.tv_sec = (long int) phdr->ts.secs;
528 tv.tv_usec = phdr->ts.nsecs / 1000;
531 /* collect some information for the
532 * finally written header
534 /* XXX - this conversion could probably improved, if the start uses ns */
538 itmp->encap = wdh->encap;
542 my_timersub(&(tv),&(itmp->start),&td);
544 x = (double) td.tv_usec;
545 x += (double) td.tv_sec * 1000000;
548 if (!s16write(wdh, htoles(0x0001), err)) /* pr.rx_channels */
550 if (!s16write(wdh, htoles(0x0008), err)) /* pr.rx_errors */
552 if (!s16write(wdh, htoles(phdr->len + 4), err)) /* pr.rx_frm_len */
554 if (!s16write(wdh, htoles(phdr->caplen), err)) /* pr.rx_frm_sln */
557 for (i = 0; i < 3; i++) {
558 if (!s16write(wdh, htoles((guint16) x), err)) /* pr.rx_time[i] */
563 if (!s32write(wdh, htolel(++itmp->pkts), err)) /* pr.pktno */
565 if (!s16write(wdh, htoles(itmp->lastlen), err)) /* pr.prlen */
569 if (!s0write(wdh, 12, err))
572 if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
575 wdh->bytes_dumped += thisSize;
580 /*---------------------------------------------------
581 * Returns 0 if we could write the specified encapsulation type,
582 * an error indication otherwise.
583 *---------------------------------------------------*/
584 int lanalyzer_dump_can_write_encap(int encap)
586 /* Per-packet encapsulations aren't supported. */
587 if (encap == WTAP_ENCAP_PER_PACKET)
588 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
590 if ( encap != WTAP_ENCAP_ETHERNET
591 && encap != WTAP_ENCAP_TOKEN_RING )
592 return WTAP_ERR_UNSUPPORTED_ENCAP;
594 * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
599 /*---------------------------------------------------
600 * Returns TRUE on success, FALSE on failure; sets "*err" to an
601 * error code on failure
602 *---------------------------------------------------*/
603 gboolean lanalyzer_dump_open(wtap_dumper *wdh, int *err)
608 tmp = g_malloc(sizeof(LA_TmpInfo));
614 ((LA_TmpInfo*)tmp)->init = FALSE;
616 wdh->subtype_write = lanalyzer_dump;
617 wdh->subtype_close = lanalyzer_dump_close;
619 /* Some of the fields in the file header aren't known yet so
620 just skip over it for now. It will be created after all
621 of the packets have been written. */
623 jump = sizeof (LA_HeaderRegularFake)
624 + sizeof (LA_RxChannelNameFake)
625 + sizeof (LA_TxChannelNameFake)
626 + sizeof (LA_RxTemplateNameFake)
627 + sizeof (LA_TxTemplateNameFake)
628 + sizeof (LA_DisplayOptionsFake)
629 + LA_SummaryRecordSize
630 + LA_SubfileSummaryRecordSize
631 + sizeof (LA_CyclicInformationFake)
632 + LA_IndexRecordSize;
634 if (fseek(wdh->fh, jump, SEEK_SET) == -1) {
638 wdh->bytes_dumped = jump;
642 /*---------------------------------------------------
644 *---------------------------------------------------*/
645 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
647 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
648 guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
649 ? BOARD_325TR /* LANalyzer Board Type */
650 : BOARD_325; /* LANalyzer Board Type */
654 /* The secs variable is needed to work around 32/64-bit time_t issues.
655 itmp->start is a timeval struct, which declares its tv_sec field
656 (itmp->start.tv_sec) as a long (typically 32 bits). time_t can be 32
657 or 64 bits, depending on the platform. Invoking as follows could
658 pass a pointer to a 32-bit long where a pointer to a 64-bit time_t
659 is expected: localtime((time_t*) &(itmp->start.tv_sec)) */
660 secs = itmp->start.tv_sec;
661 fT = localtime(&secs);
665 fseek(wdh->fh, 0, SEEK_SET);
667 if (!wtap_dump_file_write(wdh, &LA_HeaderRegularFake,
668 sizeof LA_HeaderRegularFake, err))
670 if (!wtap_dump_file_write(wdh, &LA_RxChannelNameFake,
671 sizeof LA_RxChannelNameFake, err))
673 if (!wtap_dump_file_write(wdh, &LA_TxChannelNameFake,
674 sizeof LA_TxChannelNameFake, err))
676 if (!wtap_dump_file_write(wdh, &LA_RxTemplateNameFake,
677 sizeof LA_RxTemplateNameFake, err))
679 if (!wtap_dump_file_write(wdh, &LA_TxTemplateNameFake,
680 sizeof LA_TxTemplateNameFake, err))
682 if (!wtap_dump_file_write(wdh, &LA_DisplayOptionsFake,
683 sizeof LA_DisplayOptionsFake, err))
685 /*-----------------------------------------------------------------*/
686 if (!s16write(wdh, htoles(RT_Summary), err)) /* rid */
688 if (!s16write(wdh, htoles(SummarySize), err)) /* rlen */
690 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datcre.day */
692 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datcre.mon */
694 if (!s16write(wdh, htoles(fT->tm_year + 1900), err)) /* s.datcre.year */
696 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datclo.day */
698 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datclo.mon */
700 if (!s16write(wdh, htoles(fT->tm_year + 1900), err)) /* s.datclo.year */
702 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeopn.second */
704 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeopn.minute */
706 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeopn.hour */
708 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeopn.mday */
710 if (!s0write(wdh, 2, err))
712 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeclo.second */
714 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeclo.minute */
716 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeclo.hour */
718 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeclo.mday */
720 if (!s0write(wdh, 2, err))
722 if (!s0write(wdh, 6, err)) /* EAddr == 0 */
724 if (!s16write(wdh, htoles(1), err)) /* s.mxseqno */
726 if (!s16write(wdh, htoles(0), err)) /* s.slcoffo */
728 if (!s16write(wdh, htoles(1514), err)) /* s.mxslc */
730 if (!s32write(wdh, htolel(itmp->pkts), err)) /* s.totpktt */
737 if (!s0write(wdh, 12, err))
739 if (!s32write(wdh, htolel(itmp->pkts), err)) /* sr.s.mxpkta[1] */
741 if (!s0write(wdh, 34*4, err)) /* s.mxpkta[2-33]=0 */
743 if (!s16write(wdh, htoles(board_type), err))
745 if (!s0write(wdh, 20, err)) /* board_version == 0 */
747 /*-----------------------------------------------------------------*/
748 if (!s16write(wdh, htoles(RT_SubfileSummary), err)) /* ssr.rid */
750 if (!s16write(wdh, htoles(LA_SubfileSummaryRecordSize-4), err)) /* ssr.rlen */
752 if (!s16write(wdh, htoles(1), err)) /* ssr.seqno */
754 if (!s32write(wdh, htolel(itmp->pkts), err)) /* ssr.totpkts */
756 /*-----------------------------------------------------------------*/
757 if (!wtap_dump_file_write(wdh, &LA_CyclicInformationFake,
758 sizeof LA_CyclicInformationFake, err))
760 /*-----------------------------------------------------------------*/
761 if (!s16write(wdh, htoles(RT_Index), err)) /* rid */
763 if (!s16write(wdh, htoles(LA_IndexRecordSize -4), err)) /* rlen */
765 if (!s16write(wdh, htoles(LA_IndexSize), err)) /* idxsp */
767 if (!s0write(wdh, LA_IndexRecordSize - 6, err))
773 /*---------------------------------------------------
774 * Finish writing to a dump file.
775 * Returns TRUE on success, FALSE on failure.
776 *---------------------------------------------------*/
777 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err)
779 lanalyzer_dump_header(wdh,err);
780 return *err ? FALSE : TRUE;