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;
281 char header_fixed[2];
284 guint16 board_type, mxslc;
285 guint16 record_type, record_length;
286 guint8 cr_day, cr_month;
289 lanalyzer_t *lanalyzer;
291 errno = WTAP_ERR_CANT_READ;
292 bytes_read = file_read(&rec_header, LA_RecordHeaderSize, wth->fh);
293 if (bytes_read != LA_RecordHeaderSize) {
294 *err = file_error(wth->fh, err_info);
299 wth->data_offset += LA_RecordHeaderSize;
300 record_type = pletohs(rec_header.record_type);
301 record_length = pletohs(rec_header.record_length); /* make sure to do this for while() loop */
303 if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
307 /* Read the major and minor version numbers */
308 if (record_length < 2) {
309 /* Not enough room for the major and minor version numbers. */
310 *err = WTAP_ERR_BAD_FILE;
311 *err_info = g_strdup_printf("lanalyzer: trace header record length %u < 2",
315 bytes_read = file_read(&header_fixed, sizeof header_fixed, wth->fh);
316 if (bytes_read != sizeof header_fixed) {
317 *err = file_error(wth->fh, err_info);
319 *err = WTAP_ERR_SHORT_READ;
322 wth->data_offset += sizeof header_fixed;
323 record_length -= sizeof header_fixed;
325 if (record_length != 0) {
326 /* Read the rest of the record as a comment. */
327 comment = g_malloc(record_length + 1);
328 bytes_read = file_read(comment, record_length, wth->fh);
329 if (bytes_read != record_length) {
330 *err = file_error(wth->fh, err_info);
332 *err = WTAP_ERR_SHORT_READ;
335 comment[record_length] = '\0';
336 wth->data_offset += record_length;
337 wth->shb_hdr.opt_comment = comment;
340 /* If we made it this far, then the file is a LANAlyzer file.
341 * Let's get some info from it. Note that we get wth->snapshot_length
342 * from a record later in the file. */
343 wth->file_type = WTAP_FILE_LANALYZER;
344 lanalyzer = (lanalyzer_t *)g_malloc(sizeof(lanalyzer_t));;
345 wth->priv = (void *)lanalyzer;
346 wth->subtype_read = lanalyzer_read;
347 wth->subtype_seek_read = lanalyzer_seek_read;
348 wth->snapshot_length = 0;
349 wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
351 /* Read records until we find the start of packets */
353 errno = WTAP_ERR_CANT_READ;
354 bytes_read = file_read(&rec_header, LA_RecordHeaderSize, wth->fh);
355 if (bytes_read != LA_RecordHeaderSize) {
356 *err = file_error(wth->fh, err_info);
364 wth->data_offset += LA_RecordHeaderSize;
366 record_type = pletohs(rec_header.record_type);
367 record_length = pletohs(rec_header.record_length);
369 /*g_message("Record 0x%04X Length %d", record_type, record_length);*/
370 switch (record_type) {
371 /* Trace Summary Record */
373 errno = WTAP_ERR_CANT_READ;
374 bytes_read = file_read(summary, sizeof summary,
376 if (bytes_read != sizeof summary) {
377 *err = file_error(wth->fh, err_info);
385 wth->data_offset += sizeof summary;
387 /* Assume that the date of the creation of the trace file
388 * is the same date of the trace. Lanalyzer doesn't
389 * store the creation date/time of the trace, but only of
390 * the file. Unless you traced at 11:55 PM and saved at 00:05
391 * AM, the assumption that trace.date == file.date is true.
394 cr_month = summary[1];
395 cr_year = pletohs(&summary[2]);
396 /*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
399 /* Get capture start time. I learned how to do
400 * this from Guy's code in ngsniffer.c
402 tm.tm_year = cr_year - 1900;
403 tm.tm_mon = cr_month - 1;
409 lanalyzer->start = mktime(&tm);
410 /*g_message("Day %d Month %d Year %d", tm.tm_mday,
411 tm.tm_mon, tm.tm_year);*/
412 mxslc = pletohs(&summary[30]);
413 wth->snapshot_length = mxslc;
415 board_type = pletohs(&summary[188]);
416 switch (board_type) {
418 wth->file_encap = WTAP_ENCAP_ETHERNET;
421 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
425 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
426 *err_info = g_strdup_printf("lanalyzer: board type %u unknown",
432 /* Trace Packet Data Record */
434 /* Go back header number of bytes so that lanalyzer_read
435 * can read this header */
436 if (file_seek(wth->fh, -LA_RecordHeaderSize, SEEK_CUR, err) == -1) {
440 wth->data_offset -= LA_RecordHeaderSize;
444 if (file_seek(wth->fh, record_length, SEEK_CUR, err) == -1) {
448 wth->data_offset += record_length;
454 #define DESCRIPTOR_LEN 32
456 /* Read the next packet */
457 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
462 char LE_record_type[2];
463 char LE_record_length[2];
464 guint16 record_type, record_length;
465 gchar descriptor[DESCRIPTOR_LEN];
466 guint16 time_low, time_med, time_high, true_size;
469 lanalyzer_t *lanalyzer;
471 /* read the record type and length. */
472 errno = WTAP_ERR_CANT_READ;
473 bytes_read = file_read(LE_record_type, 2, wth->fh);
474 if (bytes_read != 2) {
475 *err = file_error(wth->fh, err_info);
476 if (*err == 0 && bytes_read != 0) {
477 *err = WTAP_ERR_SHORT_READ;
481 wth->data_offset += 2;
482 bytes_read = file_read(LE_record_length, 2, wth->fh);
483 if (bytes_read != 2) {
484 *err = file_error(wth->fh, err_info);
486 *err = WTAP_ERR_SHORT_READ;
489 wth->data_offset += 2;
491 record_type = pletohs(LE_record_type);
492 record_length = pletohs(LE_record_length);
494 /* Only Trace Packet Data Records should occur now that we're in
495 * the middle of reading packets. If any other record type exists
496 * after a Trace Packet Data Record, mark it as an error. */
497 if (record_type != RT_PacketData) {
498 *err = WTAP_ERR_BAD_FILE;
499 *err_info = g_strdup_printf("lanalyzer: record type %u seen after trace summary record",
504 if (record_length < DESCRIPTOR_LEN) {
506 * Uh-oh, the record isn't big enough to even have a
509 *err = WTAP_ERR_BAD_FILE;
510 *err_info = g_strdup_printf("lanalyzer: file has a %u-byte record, too small to have even a packet descriptor",
514 packet_size = record_length - DESCRIPTOR_LEN;
517 /* Read the descriptor data */
518 errno = WTAP_ERR_CANT_READ;
519 bytes_read = file_read(descriptor, DESCRIPTOR_LEN, wth->fh);
520 if (bytes_read != DESCRIPTOR_LEN) {
521 *err = file_error(wth->fh, err_info);
523 *err = WTAP_ERR_SHORT_READ;
526 wth->data_offset += DESCRIPTOR_LEN;
528 /* Read the packet data */
529 buffer_assure_space(wth->frame_buffer, packet_size);
530 *data_offset = wth->data_offset;
531 errno = WTAP_ERR_CANT_READ;
532 bytes_read = file_read(buffer_start_ptr(wth->frame_buffer),
533 packet_size, wth->fh);
535 if (bytes_read != packet_size) {
536 *err = file_error(wth->fh, err_info);
538 *err = WTAP_ERR_SHORT_READ;
541 wth->data_offset += packet_size;
543 true_size = pletohs(&descriptor[4]);
544 packet_size = pletohs(&descriptor[6]);
547 * OK, is the frame data size greater than than what's left of the
550 if (packet_size > record_length - DESCRIPTOR_LEN) {
552 * Yes - treat this as an error.
554 *err = WTAP_ERR_BAD_FILE;
555 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
559 wth->phdr.presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
561 time_low = pletohs(&descriptor[8]);
562 time_med = pletohs(&descriptor[10]);
563 time_high = pletohs(&descriptor[12]);
564 t = (((guint64)time_low) << 0) + (((guint64)time_med) << 16) +
565 (((guint64)time_high) << 32);
566 tsecs = (time_t) (t/2000000);
567 lanalyzer = (lanalyzer_t *)wth->priv;
568 wth->phdr.ts.secs = tsecs + lanalyzer->start;
569 wth->phdr.ts.nsecs = ((guint32) (t - tsecs*2000000)) * 500;
571 if (true_size - 4 >= packet_size) {
573 * It appears that the "true size" includes the FCS;
574 * make it reflect the non-FCS size (the "packet size"
575 * appears never to include the FCS, even if no slicing
580 wth->phdr.len = true_size;
581 wth->phdr.caplen = packet_size;
583 switch (wth->file_encap) {
585 case WTAP_ENCAP_ETHERNET:
586 /* We assume there's no FCS in this frame. */
587 wth->pseudo_header.eth.fcs_len = 0;
594 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
595 union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
596 int *err, gchar **err_info)
600 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
604 * Read the packet data.
606 bytes_read = file_read(pd, length, wth->random_fh);
607 if (bytes_read != length) {
608 *err = file_error(wth->random_fh, err_info);
610 *err = WTAP_ERR_SHORT_READ;
614 switch (wth->file_encap) {
616 case WTAP_ENCAP_ETHERNET:
617 /* We assume there's no FCS in this frame. */
618 pseudo_header->eth.fcs_len = 0;
625 /*---------------------------------------------------
626 * Returns TRUE on success, FALSE on error
627 * Write "cnt" bytes of zero with error control
628 *---------------------------------------------------*/
629 static gboolean s0write(wtap_dumper *wdh, size_t cnt, int *err)
631 static const guint8 z64[64];
635 snack = cnt > 64 ? 64 : cnt;
637 if (!wtap_dump_file_write(wdh, z64, snack, err))
641 return TRUE; /* ok */
644 /*---------------------------------------------------
645 * Returns TRUE on success, FALSE on error
646 * Write an 8-bit value with error control
647 *---------------------------------------------------*/
648 static gboolean s8write(wtap_dumper *wdh, const guint8 s8, int *err)
650 return wtap_dump_file_write(wdh, &s8, 1, err);
652 /*---------------------------------------------------
653 * Returns TRUE on success, FALSE on error
654 * Write a 16-bit value with error control
655 *---------------------------------------------------*/
656 static gboolean s16write(wtap_dumper *wdh, const guint16 s16, int *err)
658 return wtap_dump_file_write(wdh, &s16, 2, err);
660 /*---------------------------------------------------
661 * Returns TRUE on success, FALSE on error
662 * Write a 32-bit value with error control
663 *---------------------------------------------------*/
664 static gboolean s32write(wtap_dumper *wdh, const guint32 s32, int *err)
666 return wtap_dump_file_write(wdh, &s32, 4, err);
668 /*---------------------------------------------------
670 * calculates C.c = A.a - B.b
671 *---------------------------------------------------*/
672 static void my_timersub(const struct timeval *a,
673 const struct timeval *b,
676 gint32 usec = a->tv_usec;
678 c->tv_sec = a->tv_sec - b->tv_sec;
679 if (b->tv_usec > usec) {
683 c->tv_usec = usec - b->tv_usec;
685 /*---------------------------------------------------
686 * Write a record for a packet to a dump file.
687 * Returns TRUE on success, FALSE on failure.
688 *---------------------------------------------------*/
689 static gboolean lanalyzer_dump(wtap_dumper *wdh,
690 const struct wtap_pkthdr *phdr,
691 const union wtap_pseudo_header *pseudo_header _U_,
692 const guint8 *pd, int *err)
699 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
701 int thisSize = phdr->caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
703 if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
704 /* printf(" LA_ProFileLimit reached\n"); */
706 return FALSE; /* and don't forget the header */
709 len = phdr->caplen + (phdr->caplen ? LA_PacketRecordSize : 0);
711 if (!s16write(wdh, htoles(0x1005), err))
713 if (!s16write(wdh, htoles(len), err))
716 tv.tv_sec = (long int) phdr->ts.secs;
717 tv.tv_usec = phdr->ts.nsecs / 1000;
720 /* collect some information for the
721 * finally written header
723 /* XXX - this conversion could probably improved, if the start uses ns */
727 itmp->encap = wdh->encap;
731 my_timersub(&(tv),&(itmp->start),&td);
733 x = (double) td.tv_usec;
734 x += (double) td.tv_sec * 1000000;
737 if (!s16write(wdh, htoles(0x0001), err)) /* pr.rx_channels */
739 if (!s16write(wdh, htoles(0x0008), err)) /* pr.rx_errors */
741 if (!s16write(wdh, htoles(phdr->len + 4), err)) /* pr.rx_frm_len */
743 if (!s16write(wdh, htoles(phdr->caplen), err)) /* pr.rx_frm_sln */
746 for (i = 0; i < 3; i++) {
747 if (!s16write(wdh, htoles((guint16) x), err)) /* pr.rx_time[i] */
752 if (!s32write(wdh, htolel(++itmp->pkts), err)) /* pr.pktno */
754 if (!s16write(wdh, htoles(itmp->lastlen), err)) /* pr.prlen */
758 if (!s0write(wdh, 12, err))
761 if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
764 wdh->bytes_dumped += thisSize;
769 /*---------------------------------------------------
770 * Returns 0 if we could write the specified encapsulation type,
771 * an error indication otherwise.
772 *---------------------------------------------------*/
773 int lanalyzer_dump_can_write_encap(int encap)
775 /* Per-packet encapsulations aren't supported. */
776 if (encap == WTAP_ENCAP_PER_PACKET)
777 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
779 if ( encap != WTAP_ENCAP_ETHERNET
780 && encap != WTAP_ENCAP_TOKEN_RING )
781 return WTAP_ERR_UNSUPPORTED_ENCAP;
783 * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
788 /*---------------------------------------------------
789 * Returns TRUE on success, FALSE on failure; sets "*err" to an
790 * error code on failure
791 *---------------------------------------------------*/
792 gboolean lanalyzer_dump_open(wtap_dumper *wdh, int *err)
797 tmp = g_malloc(sizeof(LA_TmpInfo));
803 ((LA_TmpInfo*)tmp)->init = FALSE;
805 wdh->subtype_write = lanalyzer_dump;
806 wdh->subtype_close = lanalyzer_dump_close;
808 /* Some of the fields in the file header aren't known yet so
809 just skip over it for now. It will be created after all
810 of the packets have been written. */
812 jump = sizeof (LA_HeaderRegularFake)
813 + sizeof (LA_RxChannelNameFake)
814 + sizeof (LA_TxChannelNameFake)
815 + sizeof (LA_RxTemplateNameFake)
816 + sizeof (LA_TxTemplateNameFake)
817 + sizeof (LA_DisplayOptionsFake)
818 + LA_SummaryRecordSize
819 + LA_SubfileSummaryRecordSize
820 + sizeof (LA_CyclicInformationFake)
821 + LA_IndexRecordSize;
823 if (fseek(wdh->fh, jump, SEEK_SET) == -1) {
827 wdh->bytes_dumped = jump;
831 /*---------------------------------------------------
833 *---------------------------------------------------*/
834 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
836 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
837 guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
838 ? BOARD_325TR /* LANalyzer Board Type */
839 : BOARD_325; /* LANalyzer Board Type */
843 /* The secs variable is needed to work around 32/64-bit time_t issues.
844 itmp->start is a timeval struct, which declares its tv_sec field
845 (itmp->start.tv_sec) as a long (typically 32 bits). time_t can be 32
846 or 64 bits, depending on the platform. Invoking as follows could
847 pass a pointer to a 32-bit long where a pointer to a 64-bit time_t
848 is expected: localtime((time_t*) &(itmp->start.tv_sec)) */
849 secs = itmp->start.tv_sec;
850 fT = localtime(&secs);
854 fseek(wdh->fh, 0, SEEK_SET);
856 if (!wtap_dump_file_write(wdh, &LA_HeaderRegularFake,
857 sizeof LA_HeaderRegularFake, err))
859 if (!wtap_dump_file_write(wdh, &LA_RxChannelNameFake,
860 sizeof LA_RxChannelNameFake, err))
862 if (!wtap_dump_file_write(wdh, &LA_TxChannelNameFake,
863 sizeof LA_TxChannelNameFake, err))
865 if (!wtap_dump_file_write(wdh, &LA_RxTemplateNameFake,
866 sizeof LA_RxTemplateNameFake, err))
868 if (!wtap_dump_file_write(wdh, &LA_TxTemplateNameFake,
869 sizeof LA_TxTemplateNameFake, err))
871 if (!wtap_dump_file_write(wdh, &LA_DisplayOptionsFake,
872 sizeof LA_DisplayOptionsFake, err))
874 /*-----------------------------------------------------------------*/
875 if (!s16write(wdh, htoles(RT_Summary), err)) /* rid */
877 if (!s16write(wdh, htoles(SummarySize), err)) /* rlen */
879 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datcre.day */
881 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datcre.mon */
883 if (!s16write(wdh, htoles(fT->tm_year + 1900), err)) /* s.datcre.year */
885 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datclo.day */
887 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datclo.mon */
889 if (!s16write(wdh, htoles(fT->tm_year + 1900), err)) /* s.datclo.year */
891 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeopn.second */
893 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeopn.minute */
895 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeopn.hour */
897 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeopn.mday */
899 if (!s0write(wdh, 2, err))
901 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeclo.second */
903 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeclo.minute */
905 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeclo.hour */
907 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeclo.mday */
909 if (!s0write(wdh, 2, err))
911 if (!s0write(wdh, 6, err)) /* EAddr == 0 */
913 if (!s16write(wdh, htoles(1), err)) /* s.mxseqno */
915 if (!s16write(wdh, htoles(0), err)) /* s.slcoffo */
917 if (!s16write(wdh, htoles(1514), err)) /* s.mxslc */
919 if (!s32write(wdh, htolel(itmp->pkts), err)) /* s.totpktt */
926 if (!s0write(wdh, 12, err))
928 if (!s32write(wdh, htolel(itmp->pkts), err)) /* sr.s.mxpkta[1] */
930 if (!s0write(wdh, 34*4, err)) /* s.mxpkta[2-33]=0 */
932 if (!s16write(wdh, htoles(board_type), err))
934 if (!s0write(wdh, 20, err)) /* board_version == 0 */
936 /*-----------------------------------------------------------------*/
937 if (!s16write(wdh, htoles(RT_SubfileSummary), err)) /* ssr.rid */
939 if (!s16write(wdh, htoles(LA_SubfileSummaryRecordSize-4), err)) /* ssr.rlen */
941 if (!s16write(wdh, htoles(1), err)) /* ssr.seqno */
943 if (!s32write(wdh, htolel(itmp->pkts), err)) /* ssr.totpkts */
945 /*-----------------------------------------------------------------*/
946 if (!wtap_dump_file_write(wdh, &LA_CyclicInformationFake,
947 sizeof LA_CyclicInformationFake, err))
949 /*-----------------------------------------------------------------*/
950 if (!s16write(wdh, htoles(RT_Index), err)) /* rid */
952 if (!s16write(wdh, htoles(LA_IndexRecordSize -4), err)) /* rlen */
954 if (!s16write(wdh, htoles(LA_IndexSize), err)) /* idxsp */
956 if (!s0write(wdh, LA_IndexRecordSize - 6, err))
962 /*---------------------------------------------------
963 * Finish writing to a dump file.
964 * Returns TRUE on success, FALSE on failure.
965 *---------------------------------------------------*/
966 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err)
968 lanalyzer_dump_header(wdh,err);
969 return *err ? FALSE : TRUE;