3 * $Id: lanalyzer.c,v 1.38 2003/06/30 00:41:33 guy Exp $
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 gint8 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 gint8 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 gint8 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 gint8 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 gint8 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 gint8 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 gint8 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, long *data_offset);
121 static void lanalyzer_close(wtap *wth);
122 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err);
124 int lanalyzer_open(wtap *wth, int *err)
127 char LE_record_type[2];
128 char LE_record_length[2];
130 guint16 board_type, mxslc;
131 guint16 record_type, record_length;
132 guint8 cr_day, cr_month, cr_year;
135 errno = WTAP_ERR_CANT_READ;
136 bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
137 bytes_read += file_read(LE_record_length, 1, 2, wth->fh);
138 if (bytes_read != 4) {
139 *err = file_error(wth->fh);
144 wth->data_offset += 4;
145 record_type = pletohs(LE_record_type);
146 record_length = pletohs(LE_record_length); /* make sure to do this for while() loop */
148 if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
152 /* If we made it this far, then the file is a LANAlyzer file.
153 * Let's get some info from it. Note that we get wth->snapshot_length
154 * from a record later in the file. */
155 wth->file_type = WTAP_FILE_LANALYZER;
156 wth->capture.lanalyzer = g_malloc(sizeof(lanalyzer_t));
157 wth->subtype_read = lanalyzer_read;
158 wth->subtype_seek_read = wtap_def_seek_read;
159 wth->subtype_close = lanalyzer_close;
160 wth->snapshot_length = 0;
162 /* Read records until we find the start of packets */
164 if (file_seek(wth->fh, record_length, SEEK_CUR, err) == -1) {
165 g_free(wth->capture.lanalyzer);
168 wth->data_offset += record_length;
169 errno = WTAP_ERR_CANT_READ;
170 bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
171 bytes_read += file_read(LE_record_length, 1, 2, wth->fh);
172 if (bytes_read != 4) {
173 *err = file_error(wth->fh);
175 g_free(wth->capture.lanalyzer);
178 g_free(wth->capture.lanalyzer);
181 wth->data_offset += 4;
183 record_type = pletohs(LE_record_type);
184 record_length = pletohs(LE_record_length);
186 /*g_message("Record 0x%04X Length %d", record_type, record_length);*/
187 switch (record_type) {
188 /* Trace Summary Record */
190 errno = WTAP_ERR_CANT_READ;
191 bytes_read = file_read(summary, 1, sizeof summary,
193 if (bytes_read != sizeof summary) {
194 *err = file_error(wth->fh);
196 g_free(wth->capture.lanalyzer);
199 g_free(wth->capture.lanalyzer);
202 wth->data_offset += sizeof summary;
204 /* Assume that the date of the creation of the trace file
205 * is the same date of the trace. Lanalyzer doesn't
206 * store the creation date/time of the trace, but only of
207 * the file. Unless you traced at 11:55 PM and saved at 00:05
208 * AM, the assumption that trace.date == file.date is true.
211 cr_month = summary[1];
212 cr_year = pletohs(&summary[2]);
213 /*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
216 /* Get capture start time. I learned how to do
217 * this from Guy's code in ngsniffer.c
219 /* this strange year offset is not in the
220 * lanalyzer file format documentation, but it
222 tm.tm_year = cr_year - (1900 - 1792);
223 tm.tm_mon = cr_month - 1;
229 wth->capture.lanalyzer->start = mktime(&tm);
230 /*g_message("Day %d Month %d Year %d", tm.tm_mday,
231 tm.tm_mon, tm.tm_year);*/
232 mxslc = pletohs(&summary[30]);
233 wth->snapshot_length = mxslc;
235 record_length = 0; /* to fake the next iteration of while() */
236 board_type = pletohs(&summary[188]);
237 switch (board_type) {
239 wth->file_encap = WTAP_ENCAP_ETHERNET;
242 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
245 g_message("lanalyzer: board type %u unknown",
247 g_free(wth->capture.lanalyzer);
248 *err = WTAP_ERR_UNSUPPORTED;
253 /* Trace Packet Data Record */
255 /* Go back header number ob ytes so that lanalyzer_read
256 * can read this header */
257 if (file_seek(wth->fh, -bytes_read, SEEK_CUR, err) == -1) {
258 g_free(wth->capture.lanalyzer);
261 wth->data_offset -= bytes_read;
270 #define DESCRIPTOR_LEN 32
272 /* Read the next packet */
273 static gboolean lanalyzer_read(wtap *wth, int *err, long *data_offset)
277 char LE_record_type[2];
278 char LE_record_length[2];
279 guint16 record_type, record_length;
280 gchar descriptor[DESCRIPTOR_LEN];
281 guint16 time_low, time_med, time_high, true_size;
284 /* read the record type and length. */
285 errno = WTAP_ERR_CANT_READ;
286 bytes_read = file_read(LE_record_type, 1, 2, wth->fh);
287 if (bytes_read != 2) {
288 *err = file_error(wth->fh);
289 if (*err == 0 && bytes_read != 0) {
290 *err = WTAP_ERR_SHORT_READ;
294 wth->data_offset += 2;
295 bytes_read = file_read(LE_record_length, 1, 2, wth->fh);
296 if (bytes_read != 2) {
297 *err = file_error(wth->fh);
299 *err = WTAP_ERR_SHORT_READ;
302 wth->data_offset += 2;
304 record_type = pletohs(LE_record_type);
305 record_length = pletohs(LE_record_length);
307 /* Only Trace Packet Data Records should occur now that we're in
308 * the middle of reading packets. If any other record type exists
309 * after a Trace Packet Data Record, mark it as an error. */
310 if (record_type != RT_PacketData) {
311 g_message("lanalyzer: record type %u seen after trace summary record",
313 *err = WTAP_ERR_BAD_RECORD;
317 packet_size = record_length - DESCRIPTOR_LEN;
320 /* Read the descriptor data */
321 errno = WTAP_ERR_CANT_READ;
322 bytes_read = file_read(descriptor, 1, DESCRIPTOR_LEN, wth->fh);
323 if (bytes_read != DESCRIPTOR_LEN) {
324 *err = file_error(wth->fh);
326 *err = WTAP_ERR_SHORT_READ;
329 wth->data_offset += DESCRIPTOR_LEN;
331 /* Read the packet data */
332 buffer_assure_space(wth->frame_buffer, packet_size);
333 *data_offset = wth->data_offset;
334 errno = WTAP_ERR_CANT_READ;
335 bytes_read = file_read(buffer_start_ptr(wth->frame_buffer), 1,
336 packet_size, wth->fh);
338 if (bytes_read != packet_size) {
339 *err = file_error(wth->fh);
341 *err = WTAP_ERR_SHORT_READ;
344 wth->data_offset += packet_size;
346 true_size = pletohs(&descriptor[4]);
347 packet_size = pletohs(&descriptor[6]);
348 time_low = pletohs(&descriptor[8]);
349 time_med = pletohs(&descriptor[10]);
350 time_high = pletohs(&descriptor[12]);
353 * OK, is the frame data size greater than than what's left of the
356 if (packet_size > record_length - DESCRIPTOR_LEN) {
358 * Yes - treat this as an error.
360 g_message("lanalyzer: Record length is less than packet size");
361 *err = WTAP_ERR_BAD_RECORD;
365 t = (double)time_low+(double)(time_med)*65536.0 +
366 (double)time_high*4294967296.0;
367 t = t/1000000.0 * 0.5; /* t = # of secs */
368 t += wth->capture.lanalyzer->start;
370 wth->phdr.ts.tv_sec = (long)t;
371 wth->phdr.ts.tv_usec = (unsigned long)((t-(double)(wth->phdr.ts.tv_sec))
374 if (true_size - 4 >= packet_size) {
376 * It appears that the "true size" includes the FCS;
377 * make it reflect the non-FCS size (the "packet size"
378 * appears never to include the FCS, even if no slicing
383 wth->phdr.len = true_size;
384 wth->phdr.caplen = packet_size;
385 wth->phdr.pkt_encap = wth->file_encap;
391 lanalyzer_close(wtap *wth)
393 g_free(wth->capture.lanalyzer);
396 /*---------------------------------------------------
398 * Write one block with error control
399 *---------------------------------------------------*/
400 static int swrite(const void* what, guint size, FILE *hd)
404 nwritten = fwrite(what, 1, size, hd);
405 if (nwritten != size) {
406 if (nwritten == 0 && ferror(hd))
409 return WTAP_ERR_SHORT_WRITE;
414 /*---------------------------------------------------
416 * Write one block with error control
417 *---------------------------------------------------*/
418 static int s0write(guint cnt, FILE *hd)
420 static gint8 z64[64];
425 snack = cnt > 64 ? 64 : cnt;
426 nwritten = fwrite(z64, 1, snack, hd);
427 if (nwritten != snack) {
428 if (nwritten == 0 && ferror(hd))
431 return WTAP_ERR_SHORT_WRITE;
438 /*---------------------------------------------------
440 * Write one block with error control
441 *---------------------------------------------------*/
442 static int s8write(const guint8 s8, FILE *hd)
446 nwritten = fwrite(&s8, 1, 1, hd);
448 if (nwritten == 0 && ferror(hd))
451 return WTAP_ERR_SHORT_WRITE;
455 /*---------------------------------------------------
457 * Write one block with error control
458 *---------------------------------------------------*/
459 static int s16write(const guint16 s16, FILE *hd)
463 nwritten = fwrite(&s16, 1, 2, hd);
465 if (nwritten == 0 && ferror(hd))
468 return WTAP_ERR_SHORT_WRITE;
472 /*---------------------------------------------------
474 * Write one block with error control
475 *---------------------------------------------------*/
476 static int s32write(const guint32 s32, FILE *hd)
480 nwritten = fwrite(&s32, 1, 4, hd);
482 if (nwritten == 0 && ferror(hd))
485 return WTAP_ERR_SHORT_WRITE;
489 /*---------------------------------------------------
491 * calculates C.c = A.a - B.b
492 *---------------------------------------------------*/
493 static void my_timersub(const struct timeval *a,
494 const struct timeval *b,
497 gint32 usec = a->tv_usec;
499 c->tv_sec = a->tv_sec - b->tv_sec;
500 if (b->tv_usec > usec) {
504 c->tv_usec = usec - b->tv_usec;
506 /*---------------------------------------------------
507 * Write a record for a packet to a dump file.
508 * Returns TRUE on success, FALSE on failure.
509 *---------------------------------------------------*/
510 static gboolean lanalyzer_dump(wtap_dumper *wdh,
511 const struct wtap_pkthdr *phdr,
512 const union wtap_pseudo_header *pseudo_header _U_,
513 const guchar *pd, int *err)
519 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->dump.opaque);
521 int thisSize = phdr->caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
523 if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
524 /* printf(" LA_ProFileLimit reached\n"); */
526 return FALSE; /* and don't forget the header */
529 len = phdr->caplen + (phdr->caplen ? LA_PacketRecordSize : 0);
531 *err = s16write(htoles(0x1005), wdh->fh);
534 *err = s16write(htoles(len), wdh->fh);
540 /* collect some information for the
541 * finally written header
543 itmp->start = phdr->ts;
546 itmp->encap = wdh->encap;
550 my_timersub(&(phdr->ts),&(itmp->start),&td);
552 x = (double) td.tv_usec;
553 x += (double) td.tv_sec * 1000000;
556 *err = s16write(htoles(0x0001), wdh->fh); /* pr.rx_channels */
559 *err = s16write(htoles(0x0008), wdh->fh); /* pr.rx_errors */
562 *err = s16write(htoles(phdr->len + 4), wdh->fh); /* pr.rx_frm_len */
565 *err = s16write(htoles(phdr->caplen), wdh->fh); /* pr.rx_frm_sln */
569 for (i = 0; i < 3; i++) {
570 *err = s16write(htoles((guint16) x), wdh->fh);/* pr.rx_time[i] */
576 *err = s32write(htolel(++itmp->pkts), wdh->fh); /* pr.pktno */
579 *err = s16write(htoles(itmp->lastlen), wdh->fh); /* pr.prlen */
584 *err = s0write(12, wdh->fh);
588 *err = swrite(pd , phdr->caplen , wdh->fh);
592 wdh->bytes_dumped += thisSize;
597 /*---------------------------------------------------
598 * Returns 0 if we could write the specified encapsulation type,
599 * an error indication otherwise.
600 *---------------------------------------------------*/
601 int lanalyzer_dump_can_write_encap(int encap)
603 /* Per-packet encapsulations aren't supported. */
604 if (encap == WTAP_ENCAP_PER_PACKET)
605 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
607 if ( encap != WTAP_ENCAP_ETHERNET
608 && encap != WTAP_ENCAP_TOKEN_RING )
609 return WTAP_ERR_UNSUPPORTED_ENCAP;
611 * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
616 /*---------------------------------------------------
617 * Returns TRUE on success, FALSE on failure; sets "*err" to an
618 * error code on failure
619 *---------------------------------------------------*/
620 gboolean lanalyzer_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err)
625 /* This is a LANalyzer file. We can't fill in some fields in the
626 header until all the packets have been written, so we can't
629 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
633 tmp = g_malloc(sizeof(LA_TmpInfo));
639 ((LA_TmpInfo*)tmp)->init = FALSE;
640 wdh->dump.opaque = tmp;
641 wdh->subtype_write = lanalyzer_dump;
642 wdh->subtype_close = lanalyzer_dump_close;
644 /* Some of the fields in the file header aren't known yet so
645 just skip over it for now. It will be created after all
646 of the packets have been written. */
648 jump = sizeof (LA_HeaderRegularFake)
649 + sizeof (LA_RxChannelNameFake)
650 + sizeof (LA_TxChannelNameFake)
651 + sizeof (LA_RxTemplateNameFake)
652 + sizeof (LA_TxTemplateNameFake)
653 + sizeof (LA_DisplayOptionsFake)
654 + LA_SummaryRecordSize
655 + LA_SubfileSummaryRecordSize
656 + sizeof (LA_CyclicInformationFake)
657 + LA_IndexRecordSize;
659 if (fseek(wdh->fh, jump, SEEK_SET) == -1) {
663 wdh->bytes_dumped = jump;
667 /*---------------------------------------------------
669 *---------------------------------------------------*/
670 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
672 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->dump.opaque);
673 struct tm *fT = localtime(&(itmp->start.tv_sec));
674 guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
675 ? BOARD_325TR /* LANalyzer Board Type */
676 : BOARD_325; /* LANalyzer Board Type */
678 fseek(wdh->fh, 0, SEEK_SET);
680 *err = swrite(&LA_HeaderRegularFake, sizeof LA_HeaderRegularFake, wdh->fh);
683 *err = swrite(&LA_RxChannelNameFake , sizeof LA_RxChannelNameFake , wdh->fh);
686 *err = swrite(&LA_TxChannelNameFake , sizeof LA_TxChannelNameFake , wdh->fh);
689 *err = swrite(&LA_RxTemplateNameFake, sizeof LA_RxTemplateNameFake, wdh->fh);
692 *err = swrite(&LA_TxTemplateNameFake, sizeof LA_TxTemplateNameFake, wdh->fh);
695 *err = swrite(&LA_DisplayOptionsFake, sizeof LA_DisplayOptionsFake, wdh->fh);
698 /*-----------------------------------------------------------------*/
699 *err = s16write(htoles(RT_Summary), wdh->fh); /* rid */
702 *err = s16write(htoles(SummarySize), wdh->fh); /* rlen */
705 *err = s8write(fT->tm_mday, wdh->fh); /* s.datcre.day */
708 *err = s8write(fT->tm_mon+1, wdh->fh); /* s.datcre.mon */
711 *err = s16write(htoles(fT->tm_year + 1900), wdh->fh);/* s.datcre.year */
714 *err = s8write(fT->tm_mday, wdh->fh); /* s.datclo.day */
717 *err = s8write(fT->tm_mon+1, wdh->fh); /* s.datclo.mon */
720 *err = s16write(htoles(fT->tm_year + 1900), wdh->fh);/* s.datclo.year */
723 *err = s8write(fT->tm_sec, wdh->fh); /* s.timeopn.second */
726 *err = s8write(fT->tm_min, wdh->fh); /* s.timeopn.minute */
729 *err = s8write(fT->tm_hour, wdh->fh); /* s.timeopn.hour */
732 *err = s8write(fT->tm_mday, wdh->fh); /* s.timeopn.mday */
735 *err = s0write(2, wdh->fh);
738 *err = s8write(fT->tm_sec, wdh->fh); /* s.timeclo.second */
741 *err = s8write(fT->tm_min, wdh->fh); /* s.timeclo.minute */
744 *err = s8write(fT->tm_hour, wdh->fh); /* s.timeclo.hour */
747 *err = s8write(fT->tm_mday, wdh->fh); /* s.timeclo.mday */
750 *err = s0write(2, wdh->fh);
753 *err = s0write(6, wdh->fh); /* EAddr == 0 */
756 *err = s16write(htoles(1), wdh->fh); /* s.mxseqno */
759 *err = s16write(htoles(0), wdh->fh); /* s.slcoffo */
762 *err = s16write(htoles(1514), wdh->fh); /* s.mxslc */
765 *err = s32write(htolel(itmp->pkts), wdh->fh); /* s.totpktt */
768 *err = s0write(12, wdh->fh); /* statrg == 0; ? -1*/
769 if (*err) /* stptrg == 0; ? -1*/
770 return FALSE; /* s.mxpkta[0]=0 */
771 *err = s32write(htolel(itmp->pkts), wdh->fh); /* sr.s.mxpkta[1] */
774 *err = s0write(34*4, wdh->fh); /* s.mxpkta[2-33]=0 */
777 *err = s16write(htoles(board_type), wdh->fh);
780 *err = s0write(20, wdh->fh); /* board_version == 0 */
783 /*-----------------------------------------------------------------*/
784 *err = s16write(htoles(RT_SubfileSummary), wdh->fh); /* ssr.rid */
787 *err = s16write(htoles(LA_SubfileSummaryRecordSize-4), wdh->fh); /* ssr.rlen */
790 *err = s16write(htoles(1), wdh->fh); /* ssr.seqno */
793 *err = s32write(htolel(itmp->pkts), wdh->fh); /* ssr.totpkts */
796 /*-----------------------------------------------------------------*/
797 *err = swrite(&LA_CyclicInformationFake, sizeof LA_CyclicInformationFake, wdh->fh);
800 /*-----------------------------------------------------------------*/
801 *err = s16write(htoles(RT_Index), wdh->fh); /* rid */
804 *err = s16write(htoles(LA_IndexRecordSize -4), wdh->fh);/* rlen */
807 *err = s16write(htoles(LA_IndexSize), wdh->fh); /* idxsp */
810 *err = s0write(LA_IndexRecordSize - 6, wdh->fh);
817 /*---------------------------------------------------
818 * Finish writing to a dump file.
819 * Returns TRUE on success, FALSE on failure.
820 *---------------------------------------------------*/
821 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err)
823 if (wdh->dump.opaque) {
824 lanalyzer_dump_header(wdh,err);
825 g_free(wdh->dump.opaque);
826 wdh->dump.opaque = 0;
828 return *err ? FALSE : TRUE;