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 /* Record header format */
42 guint8 record_type[2];
43 guint8 record_length[2];
46 #define LA_RecordHeaderSize 4
48 /* Record type codes: */
50 #define RT_HeaderRegular 0x1001
51 #define RT_HeaderCyclic 0x1007
52 #define RT_RxChannelName 0x1006
53 #define RT_TxChannelName 0x100b
54 #define RT_FilterName 0x1032
55 #define RT_RxTemplateName 0x1035
56 #define RT_TxTemplateName 0x1036
57 #define RT_DisplayOptions 0x100a
58 #define RT_Summary 0x1002
59 #define RT_SubfileSummary 0x1003
60 #define RT_CyclicInformation 0x1009
61 #define RT_Index 0x1004
62 #define RT_PacketData 0x1005
64 #define LA_ProFileLimit (1024 * 1024 * 32)
66 typedef guint8 Eadr[6];
67 typedef guint16 TimeStamp[3]; /* 0.5 microseconds since start of trace */
70 * These records have only 2-byte alignment for 4-byte quantities,
71 * so the structures aren't necessarily valid; they're kept as comments
72 * for reference purposes.
110 * gint16 board_version;
111 * gint8 reserved[18];
115 #define SummarySize (18+22+(4*36)+6+6+6+4+4)
122 * } LA_SummaryRecord;
125 #define LA_SummaryRecordSize (SummarySize + 4)
127 /* LANalyzer board types (which indicate the type of network on which
128 the capture was done). */
129 #define BOARD_325 226 /* LANalyzer 325 (Ethernet) */
130 #define BOARD_325TR 227 /* LANalyzer 325TR (Token-ring) */
139 * } LA_SubfileSummaryRecord;
142 #define LA_SubfileSummaryRecordSize 10
145 #define LA_IndexSize 500
151 * gint16 idxsp; = LA_IndexSize
155 * gint32 trcidx[LA_IndexSize + 2]; +2 undocumented but used by La 2.2
159 #define LA_IndexRecordSize (10 + 4 * (LA_IndexSize + 2))
164 * guint16 rx_channels;
176 * gint16 hwcollschans;
181 #define LA_PacketRecordSize 32
185 struct timeval start;
191 static const guint8 LA_HeaderRegularFake[] = {
192 0x01,0x10,0x4c,0x00,0x01,0x05,0x54,0x72,0x61,0x63,0x65,0x20,0x44,0x69,0x73,0x70,
193 0x6c,0x61,0x79,0x20,0x54,0x72,0x61,0x63,0x65,0x20,0x46,0x69,0x6c,0x65,0x00,0x00,
194 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
195 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
196 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
199 static const guint8 LA_RxChannelNameFake[] = {
200 0x06,0x10,0x80,0x00,0x43,0x68,0x61,0x6e ,0x6e,0x65,0x6c,0x31,0x00,0x43,0x68,0x61,
201 0x6e,0x6e,0x65,0x6c,0x32,0x00,0x43,0x68 ,0x61,0x6e,0x6e,0x65,0x6c,0x33,0x00,0x43,
202 0x68,0x61,0x6e,0x6e,0x65,0x6c,0x34,0x00 ,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x35,
203 0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c ,0x36,0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,
204 0x6c,0x37,0x00,0x43,0x68,0x61,0x6e,0x6e ,0x65,0x6c,0x38,0x00,0x00,0x00,0x00,0x00,
205 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
206 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
207 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
211 static const guint8 LA_TxChannelNameFake[] = {
212 0x0b,0x10,0x36,0x00 ,0x54,0x72,0x61,0x6e,0x73,0x31,0x00,0x00,
213 0x00,0x54,0x72,0x61,0x6e,0x73,0x32,0x00 ,0x00,0x00,0x54,0x72,0x61,0x6e,0x73,0x33,
214 0x00,0x00,0x00,0x54,0x72,0x61,0x6e,0x73 ,0x34,0x00,0x00,0x00,0x54,0x72,0x61,0x6e,
215 0x73,0x35,0x00,0x00,0x00,0x54,0x72,0x61 ,0x6e,0x73,0x36,0x00,0x00,0x00
218 static const guint8 LA_RxTemplateNameFake[] = {
220 0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
221 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
222 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
223 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
224 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
225 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
226 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
227 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
228 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
232 static const guint8 LA_TxTemplateNameFake[] = {
233 0x36,0x10,0x36,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
234 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
235 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
236 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00
239 static const guint8 LA_DisplayOptionsFake[] = {
241 0x00,0x00,0x01,0x00,0x01,0x02,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
242 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
243 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
244 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
245 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
246 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
247 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
248 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
249 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
250 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
251 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
252 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
253 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
254 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
255 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
256 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
257 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00
260 static const guint8 LA_CyclicInformationFake[] = {
261 0x09,0x10,0x1a,0x00,0x00,0x00,
262 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
263 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
270 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
271 gint64 *data_offset);
272 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
273 union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
274 int *err, gchar **err_info);
275 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err);
277 int lanalyzer_open(wtap *wth, int *err, gchar **err_info)
280 LA_RecordHeader rec_header;
282 guint16 board_type, mxslc;
283 guint16 record_type, record_length;
284 guint8 cr_day, cr_month;
287 lanalyzer_t *lanalyzer;
289 errno = WTAP_ERR_CANT_READ;
290 bytes_read = file_read(&rec_header, LA_RecordHeaderSize, wth->fh);
291 if (bytes_read != LA_RecordHeaderSize) {
292 *err = file_error(wth->fh, err_info);
297 wth->data_offset += LA_RecordHeaderSize;
298 record_type = pletohs(rec_header.record_type);
299 record_length = pletohs(rec_header.record_length); /* make sure to do this for while() loop */
301 if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
305 /* If we made it this far, then the file is a LANAlyzer file.
306 * Let's get some info from it. Note that we get wth->snapshot_length
307 * from a record later in the file. */
308 wth->file_type = WTAP_FILE_LANALYZER;
309 lanalyzer = (lanalyzer_t *)g_malloc(sizeof(lanalyzer_t));;
310 wth->priv = (void *)lanalyzer;
311 wth->subtype_read = lanalyzer_read;
312 wth->subtype_seek_read = lanalyzer_seek_read;
313 wth->snapshot_length = 0;
314 wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
316 /* Read records until we find the start of packets */
318 if (file_seek(wth->fh, record_length, SEEK_CUR, err) == -1) {
322 wth->data_offset += record_length;
323 errno = WTAP_ERR_CANT_READ;
324 bytes_read = file_read(&rec_header, LA_RecordHeaderSize, wth->fh);
325 if (bytes_read != LA_RecordHeaderSize) {
326 *err = file_error(wth->fh, err_info);
334 wth->data_offset += LA_RecordHeaderSize;
336 record_type = pletohs(rec_header.record_type);
337 record_length = pletohs(rec_header.record_length);
339 /*g_message("Record 0x%04X Length %d", record_type, record_length);*/
340 switch (record_type) {
341 /* Trace Summary Record */
343 errno = WTAP_ERR_CANT_READ;
344 bytes_read = file_read(summary, sizeof summary,
346 if (bytes_read != sizeof summary) {
347 *err = file_error(wth->fh, err_info);
355 wth->data_offset += sizeof summary;
357 /* Assume that the date of the creation of the trace file
358 * is the same date of the trace. Lanalyzer doesn't
359 * store the creation date/time of the trace, but only of
360 * the file. Unless you traced at 11:55 PM and saved at 00:05
361 * AM, the assumption that trace.date == file.date is true.
364 cr_month = summary[1];
365 cr_year = pletohs(&summary[2]);
366 /*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
369 /* Get capture start time. I learned how to do
370 * this from Guy's code in ngsniffer.c
372 tm.tm_year = cr_year - 1900;
373 tm.tm_mon = cr_month - 1;
379 lanalyzer->start = mktime(&tm);
380 /*g_message("Day %d Month %d Year %d", tm.tm_mday,
381 tm.tm_mon, tm.tm_year);*/
382 mxslc = pletohs(&summary[30]);
383 wth->snapshot_length = mxslc;
385 record_length = 0; /* to fake the next iteration of while() */
386 board_type = pletohs(&summary[188]);
387 switch (board_type) {
389 wth->file_encap = WTAP_ENCAP_ETHERNET;
392 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
396 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
397 *err_info = g_strdup_printf("lanalyzer: board type %u unknown",
403 /* Trace Packet Data Record */
405 /* Go back header number of bytes so that lanalyzer_read
406 * can read this header */
407 if (file_seek(wth->fh, -LA_RecordHeaderSize, SEEK_CUR, err) == -1) {
411 wth->data_offset -= LA_RecordHeaderSize;
420 #define DESCRIPTOR_LEN 32
422 /* Read the next packet */
423 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
428 char LE_record_type[2];
429 char LE_record_length[2];
430 guint16 record_type, record_length;
431 gchar descriptor[DESCRIPTOR_LEN];
432 guint16 time_low, time_med, time_high, true_size;
435 lanalyzer_t *lanalyzer;
437 /* read the record type and length. */
438 errno = WTAP_ERR_CANT_READ;
439 bytes_read = file_read(LE_record_type, 2, wth->fh);
440 if (bytes_read != 2) {
441 *err = file_error(wth->fh, err_info);
442 if (*err == 0 && bytes_read != 0) {
443 *err = WTAP_ERR_SHORT_READ;
447 wth->data_offset += 2;
448 bytes_read = file_read(LE_record_length, 2, wth->fh);
449 if (bytes_read != 2) {
450 *err = file_error(wth->fh, err_info);
452 *err = WTAP_ERR_SHORT_READ;
455 wth->data_offset += 2;
457 record_type = pletohs(LE_record_type);
458 record_length = pletohs(LE_record_length);
460 /* Only Trace Packet Data Records should occur now that we're in
461 * the middle of reading packets. If any other record type exists
462 * after a Trace Packet Data Record, mark it as an error. */
463 if (record_type != RT_PacketData) {
464 *err = WTAP_ERR_BAD_FILE;
465 *err_info = g_strdup_printf("lanalyzer: record type %u seen after trace summary record",
470 if (record_length < DESCRIPTOR_LEN) {
472 * Uh-oh, the record isn't big enough to even have a
475 *err = WTAP_ERR_BAD_FILE;
476 *err_info = g_strdup_printf("lanalyzer: file has a %u-byte record, too small to have even a packet descriptor",
480 packet_size = record_length - DESCRIPTOR_LEN;
483 /* Read the descriptor data */
484 errno = WTAP_ERR_CANT_READ;
485 bytes_read = file_read(descriptor, DESCRIPTOR_LEN, wth->fh);
486 if (bytes_read != DESCRIPTOR_LEN) {
487 *err = file_error(wth->fh, err_info);
489 *err = WTAP_ERR_SHORT_READ;
492 wth->data_offset += DESCRIPTOR_LEN;
494 /* Read the packet data */
495 buffer_assure_space(wth->frame_buffer, packet_size);
496 *data_offset = wth->data_offset;
497 errno = WTAP_ERR_CANT_READ;
498 bytes_read = file_read(buffer_start_ptr(wth->frame_buffer),
499 packet_size, wth->fh);
501 if (bytes_read != packet_size) {
502 *err = file_error(wth->fh, err_info);
504 *err = WTAP_ERR_SHORT_READ;
507 wth->data_offset += packet_size;
509 true_size = pletohs(&descriptor[4]);
510 packet_size = pletohs(&descriptor[6]);
513 * OK, is the frame data size greater than than what's left of the
516 if (packet_size > record_length - DESCRIPTOR_LEN) {
518 * Yes - treat this as an error.
520 *err = WTAP_ERR_BAD_FILE;
521 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
525 time_low = pletohs(&descriptor[8]);
526 time_med = pletohs(&descriptor[10]);
527 time_high = pletohs(&descriptor[12]);
528 t = (((guint64)time_low) << 0) + (((guint64)time_med) << 16) +
529 (((guint64)time_high) << 32);
530 tsecs = (time_t) (t/2000000);
531 lanalyzer = (lanalyzer_t *)wth->priv;
532 wth->phdr.ts.secs = tsecs + lanalyzer->start;
533 wth->phdr.ts.nsecs = ((guint32) (t - tsecs*2000000)) * 500;
535 if (true_size - 4 >= packet_size) {
537 * It appears that the "true size" includes the FCS;
538 * make it reflect the non-FCS size (the "packet size"
539 * appears never to include the FCS, even if no slicing
544 wth->phdr.len = true_size;
545 wth->phdr.caplen = packet_size;
547 switch (wth->file_encap) {
549 case WTAP_ENCAP_ETHERNET:
550 /* We assume there's no FCS in this frame. */
551 wth->pseudo_header.eth.fcs_len = 0;
558 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
559 union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
560 int *err, gchar **err_info)
564 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
568 * Read the packet data.
570 bytes_read = file_read(pd, length, wth->random_fh);
571 if (bytes_read != length) {
572 *err = file_error(wth->random_fh, err_info);
574 *err = WTAP_ERR_SHORT_READ;
578 switch (wth->file_encap) {
580 case WTAP_ENCAP_ETHERNET:
581 /* We assume there's no FCS in this frame. */
582 pseudo_header->eth.fcs_len = 0;
589 /*---------------------------------------------------
590 * Returns TRUE on success, FALSE on error
591 * Write "cnt" bytes of zero with error control
592 *---------------------------------------------------*/
593 static gboolean s0write(wtap_dumper *wdh, size_t cnt, int *err)
595 static const guint8 z64[64];
599 snack = cnt > 64 ? 64 : cnt;
601 if (!wtap_dump_file_write(wdh, z64, snack, err))
605 return TRUE; /* ok */
608 /*---------------------------------------------------
609 * Returns TRUE on success, FALSE on error
610 * Write an 8-bit value with error control
611 *---------------------------------------------------*/
612 static gboolean s8write(wtap_dumper *wdh, const guint8 s8, int *err)
614 return wtap_dump_file_write(wdh, &s8, 1, err);
616 /*---------------------------------------------------
617 * Returns TRUE on success, FALSE on error
618 * Write a 16-bit value with error control
619 *---------------------------------------------------*/
620 static gboolean s16write(wtap_dumper *wdh, const guint16 s16, int *err)
622 return wtap_dump_file_write(wdh, &s16, 2, err);
624 /*---------------------------------------------------
625 * Returns TRUE on success, FALSE on error
626 * Write a 32-bit value with error control
627 *---------------------------------------------------*/
628 static gboolean s32write(wtap_dumper *wdh, const guint32 s32, int *err)
630 return wtap_dump_file_write(wdh, &s32, 4, err);
632 /*---------------------------------------------------
634 * calculates C.c = A.a - B.b
635 *---------------------------------------------------*/
636 static void my_timersub(const struct timeval *a,
637 const struct timeval *b,
640 gint32 usec = a->tv_usec;
642 c->tv_sec = a->tv_sec - b->tv_sec;
643 if (b->tv_usec > usec) {
647 c->tv_usec = usec - b->tv_usec;
649 /*---------------------------------------------------
650 * Write a record for a packet to a dump file.
651 * Returns TRUE on success, FALSE on failure.
652 *---------------------------------------------------*/
653 static gboolean lanalyzer_dump(wtap_dumper *wdh,
654 const struct wtap_pkthdr *phdr,
655 const union wtap_pseudo_header *pseudo_header _U_,
656 const guint8 *pd, int *err)
663 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
665 int thisSize = phdr->caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
667 if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
668 /* printf(" LA_ProFileLimit reached\n"); */
670 return FALSE; /* and don't forget the header */
673 len = phdr->caplen + (phdr->caplen ? LA_PacketRecordSize : 0);
675 if (!s16write(wdh, htoles(0x1005), err))
677 if (!s16write(wdh, htoles(len), err))
680 tv.tv_sec = (long int) phdr->ts.secs;
681 tv.tv_usec = phdr->ts.nsecs / 1000;
684 /* collect some information for the
685 * finally written header
687 /* XXX - this conversion could probably improved, if the start uses ns */
691 itmp->encap = wdh->encap;
695 my_timersub(&(tv),&(itmp->start),&td);
697 x = (double) td.tv_usec;
698 x += (double) td.tv_sec * 1000000;
701 if (!s16write(wdh, htoles(0x0001), err)) /* pr.rx_channels */
703 if (!s16write(wdh, htoles(0x0008), err)) /* pr.rx_errors */
705 if (!s16write(wdh, htoles(phdr->len + 4), err)) /* pr.rx_frm_len */
707 if (!s16write(wdh, htoles(phdr->caplen), err)) /* pr.rx_frm_sln */
710 for (i = 0; i < 3; i++) {
711 if (!s16write(wdh, htoles((guint16) x), err)) /* pr.rx_time[i] */
716 if (!s32write(wdh, htolel(++itmp->pkts), err)) /* pr.pktno */
718 if (!s16write(wdh, htoles(itmp->lastlen), err)) /* pr.prlen */
722 if (!s0write(wdh, 12, err))
725 if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
728 wdh->bytes_dumped += thisSize;
733 /*---------------------------------------------------
734 * Returns 0 if we could write the specified encapsulation type,
735 * an error indication otherwise.
736 *---------------------------------------------------*/
737 int lanalyzer_dump_can_write_encap(int encap)
739 /* Per-packet encapsulations aren't supported. */
740 if (encap == WTAP_ENCAP_PER_PACKET)
741 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
743 if ( encap != WTAP_ENCAP_ETHERNET
744 && encap != WTAP_ENCAP_TOKEN_RING )
745 return WTAP_ERR_UNSUPPORTED_ENCAP;
747 * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
752 /*---------------------------------------------------
753 * Returns TRUE on success, FALSE on failure; sets "*err" to an
754 * error code on failure
755 *---------------------------------------------------*/
756 gboolean lanalyzer_dump_open(wtap_dumper *wdh, int *err)
761 tmp = g_malloc(sizeof(LA_TmpInfo));
767 ((LA_TmpInfo*)tmp)->init = FALSE;
769 wdh->subtype_write = lanalyzer_dump;
770 wdh->subtype_close = lanalyzer_dump_close;
772 /* Some of the fields in the file header aren't known yet so
773 just skip over it for now. It will be created after all
774 of the packets have been written. */
776 jump = sizeof (LA_HeaderRegularFake)
777 + sizeof (LA_RxChannelNameFake)
778 + sizeof (LA_TxChannelNameFake)
779 + sizeof (LA_RxTemplateNameFake)
780 + sizeof (LA_TxTemplateNameFake)
781 + sizeof (LA_DisplayOptionsFake)
782 + LA_SummaryRecordSize
783 + LA_SubfileSummaryRecordSize
784 + sizeof (LA_CyclicInformationFake)
785 + LA_IndexRecordSize;
787 if (fseek(wdh->fh, jump, SEEK_SET) == -1) {
791 wdh->bytes_dumped = jump;
795 /*---------------------------------------------------
797 *---------------------------------------------------*/
798 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
800 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
801 guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
802 ? BOARD_325TR /* LANalyzer Board Type */
803 : BOARD_325; /* LANalyzer Board Type */
807 /* The secs variable is needed to work around 32/64-bit time_t issues.
808 itmp->start is a timeval struct, which declares its tv_sec field
809 (itmp->start.tv_sec) as a long (typically 32 bits). time_t can be 32
810 or 64 bits, depending on the platform. Invoking as follows could
811 pass a pointer to a 32-bit long where a pointer to a 64-bit time_t
812 is expected: localtime((time_t*) &(itmp->start.tv_sec)) */
813 secs = itmp->start.tv_sec;
814 fT = localtime(&secs);
818 fseek(wdh->fh, 0, SEEK_SET);
820 if (!wtap_dump_file_write(wdh, &LA_HeaderRegularFake,
821 sizeof LA_HeaderRegularFake, err))
823 if (!wtap_dump_file_write(wdh, &LA_RxChannelNameFake,
824 sizeof LA_RxChannelNameFake, err))
826 if (!wtap_dump_file_write(wdh, &LA_TxChannelNameFake,
827 sizeof LA_TxChannelNameFake, err))
829 if (!wtap_dump_file_write(wdh, &LA_RxTemplateNameFake,
830 sizeof LA_RxTemplateNameFake, err))
832 if (!wtap_dump_file_write(wdh, &LA_TxTemplateNameFake,
833 sizeof LA_TxTemplateNameFake, err))
835 if (!wtap_dump_file_write(wdh, &LA_DisplayOptionsFake,
836 sizeof LA_DisplayOptionsFake, err))
838 /*-----------------------------------------------------------------*/
839 if (!s16write(wdh, htoles(RT_Summary), err)) /* rid */
841 if (!s16write(wdh, htoles(SummarySize), err)) /* rlen */
843 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datcre.day */
845 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datcre.mon */
847 if (!s16write(wdh, htoles(fT->tm_year + 1900), err)) /* s.datcre.year */
849 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datclo.day */
851 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datclo.mon */
853 if (!s16write(wdh, htoles(fT->tm_year + 1900), err)) /* s.datclo.year */
855 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeopn.second */
857 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeopn.minute */
859 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeopn.hour */
861 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeopn.mday */
863 if (!s0write(wdh, 2, err))
865 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeclo.second */
867 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeclo.minute */
869 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeclo.hour */
871 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeclo.mday */
873 if (!s0write(wdh, 2, err))
875 if (!s0write(wdh, 6, err)) /* EAddr == 0 */
877 if (!s16write(wdh, htoles(1), err)) /* s.mxseqno */
879 if (!s16write(wdh, htoles(0), err)) /* s.slcoffo */
881 if (!s16write(wdh, htoles(1514), err)) /* s.mxslc */
883 if (!s32write(wdh, htolel(itmp->pkts), err)) /* s.totpktt */
890 if (!s0write(wdh, 12, err))
892 if (!s32write(wdh, htolel(itmp->pkts), err)) /* sr.s.mxpkta[1] */
894 if (!s0write(wdh, 34*4, err)) /* s.mxpkta[2-33]=0 */
896 if (!s16write(wdh, htoles(board_type), err))
898 if (!s0write(wdh, 20, err)) /* board_version == 0 */
900 /*-----------------------------------------------------------------*/
901 if (!s16write(wdh, htoles(RT_SubfileSummary), err)) /* ssr.rid */
903 if (!s16write(wdh, htoles(LA_SubfileSummaryRecordSize-4), err)) /* ssr.rlen */
905 if (!s16write(wdh, htoles(1), err)) /* ssr.seqno */
907 if (!s32write(wdh, htolel(itmp->pkts), err)) /* ssr.totpkts */
909 /*-----------------------------------------------------------------*/
910 if (!wtap_dump_file_write(wdh, &LA_CyclicInformationFake,
911 sizeof LA_CyclicInformationFake, err))
913 /*-----------------------------------------------------------------*/
914 if (!s16write(wdh, htoles(RT_Index), err)) /* rid */
916 if (!s16write(wdh, htoles(LA_IndexRecordSize -4), err)) /* rlen */
918 if (!s16write(wdh, htoles(LA_IndexSize), err)) /* idxsp */
920 if (!s0write(wdh, LA_IndexRecordSize - 6, err))
926 /*---------------------------------------------------
927 * Finish writing to a dump file.
928 * Returns TRUE on success, FALSE on failure.
929 *---------------------------------------------------*/
930 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err)
932 lanalyzer_dump_header(wdh,err);
933 return *err ? FALSE : TRUE;