4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "file_wrappers.h"
26 #include <wsutil/buffer.h>
27 #include "lanalyzer.h"
29 /* The LANalyzer format is documented (at least in part) in Novell document
30 TID022037, which can be found at, among other places:
32 http://www.windowsecurity.com/whitepapers/Description_of_the_LANalysers_output_file.html
35 /* Record header format */
38 guint8 record_type[2];
39 guint8 record_length[2];
42 #define LA_RecordHeaderSize 4
44 /* Record type codes: */
46 #define RT_HeaderRegular 0x1001
47 #define RT_HeaderCyclic 0x1007
48 #define RT_RxChannelName 0x1006
49 #define RT_TxChannelName 0x100b
50 #define RT_FilterName 0x1032
51 #define RT_RxTemplateName 0x1035
52 #define RT_TxTemplateName 0x1036
53 #define RT_DisplayOptions 0x100a
54 #define RT_Summary 0x1002
55 #define RT_SubfileSummary 0x1003
56 #define RT_CyclicInformation 0x1009
57 #define RT_Index 0x1004
58 #define RT_PacketData 0x1005
60 #define LA_ProFileLimit (1024 * 1024 * 32)
62 typedef guint8 Eadr[6];
63 typedef guint16 TimeStamp[3]; /* 0.5 microseconds since start of trace */
66 * These records have only 2-byte alignment for 4-byte quantities,
67 * so the structures aren't necessarily valid; they're kept as comments
68 * for reference purposes.
106 * gint16 board_version;
107 * gint8 reserved[18];
111 #define SummarySize (18+22+(4*36)+6+6+6+4+4)
118 * } LA_SummaryRecord;
121 #define LA_SummaryRecordSize (SummarySize + 4)
123 /* LANalyzer board types (which indicate the type of network on which
124 the capture was done). */
125 #define BOARD_325 226 /* LANalyzer 325 (Ethernet) */
126 #define BOARD_325TR 227 /* LANalyzer 325TR (Token-ring) */
135 * } LA_SubfileSummaryRecord;
138 #define LA_SubfileSummaryRecordSize 10
141 #define LA_IndexSize 500
147 * gint16 idxsp; = LA_IndexSize
151 * gint32 trcidx[LA_IndexSize + 2]; +2 undocumented but used by La 2.2
155 #define LA_IndexRecordSize (10 + 4 * (LA_IndexSize + 2))
160 * guint16 rx_channels;
172 * gint16 hwcollschans;
177 #define LA_PacketRecordSize 32
181 struct timeval start;
187 static const guint8 LA_HeaderRegularFake[] = {
188 0x01,0x10,0x4c,0x00,0x01,0x05,0x54,0x72,0x61,0x63,0x65,0x20,0x44,0x69,0x73,0x70,
189 0x6c,0x61,0x79,0x20,0x54,0x72,0x61,0x63,0x65,0x20,0x46,0x69,0x6c,0x65,0x00,0x00,
190 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
191 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
192 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
195 static const guint8 LA_RxChannelNameFake[] = {
196 0x06,0x10,0x80,0x00,0x43,0x68,0x61,0x6e ,0x6e,0x65,0x6c,0x31,0x00,0x43,0x68,0x61,
197 0x6e,0x6e,0x65,0x6c,0x32,0x00,0x43,0x68 ,0x61,0x6e,0x6e,0x65,0x6c,0x33,0x00,0x43,
198 0x68,0x61,0x6e,0x6e,0x65,0x6c,0x34,0x00 ,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x35,
199 0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c ,0x36,0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,
200 0x6c,0x37,0x00,0x43,0x68,0x61,0x6e,0x6e ,0x65,0x6c,0x38,0x00,0x00,0x00,0x00,0x00,
201 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
202 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
203 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
207 static const guint8 LA_TxChannelNameFake[] = {
208 0x0b,0x10,0x36,0x00 ,0x54,0x72,0x61,0x6e,0x73,0x31,0x00,0x00,
209 0x00,0x54,0x72,0x61,0x6e,0x73,0x32,0x00 ,0x00,0x00,0x54,0x72,0x61,0x6e,0x73,0x33,
210 0x00,0x00,0x00,0x54,0x72,0x61,0x6e,0x73 ,0x34,0x00,0x00,0x00,0x54,0x72,0x61,0x6e,
211 0x73,0x35,0x00,0x00,0x00,0x54,0x72,0x61 ,0x6e,0x73,0x36,0x00,0x00,0x00
214 static const guint8 LA_RxTemplateNameFake[] = {
216 0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
217 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
218 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
219 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
220 0x00,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,
228 static const guint8 LA_TxTemplateNameFake[] = {
229 0x36,0x10,0x36,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
230 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
231 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
232 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00
235 static const guint8 LA_DisplayOptionsFake[] = {
237 0x00,0x00,0x01,0x00,0x01,0x02,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
238 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
239 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
240 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
241 0x00,0x00,0x00,0x00,0x00,0x00,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
256 static const guint8 LA_CyclicInformationFake[] = {
257 0x09,0x10,0x1a,0x00,0x00,0x00,
258 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
259 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
262 static const guint8 z64[64] = {
263 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
264 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
265 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
266 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
273 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
274 gint64 *data_offset);
275 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
276 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
277 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err);
279 wtap_open_return_val lanalyzer_open(wtap *wth, int *err, gchar **err_info)
281 LA_RecordHeader rec_header;
282 char header_fixed[2];
285 guint16 board_type, mxslc;
286 guint16 record_type, record_length;
287 guint8 cr_day, cr_month;
290 lanalyzer_t *lanalyzer;
292 if (!wtap_read_bytes(wth->fh, &rec_header, LA_RecordHeaderSize,
294 if (*err != WTAP_ERR_SHORT_READ)
295 return WTAP_OPEN_ERROR;
296 return WTAP_OPEN_NOT_MINE;
298 record_type = pletoh16(rec_header.record_type);
299 record_length = pletoh16(rec_header.record_length); /* make sure to do this for while() loop */
301 if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
302 return WTAP_OPEN_NOT_MINE;
305 /* Read the major and minor version numbers */
306 if (record_length < 2) {
308 * Not enough room for the major and minor version numbers.
309 * Just treat that as a "not a LANalyzer file" indication.
311 return WTAP_OPEN_NOT_MINE;
313 if (!wtap_read_bytes(wth->fh, &header_fixed, sizeof header_fixed,
315 if (*err != WTAP_ERR_SHORT_READ)
316 return WTAP_OPEN_ERROR;
317 return WTAP_OPEN_NOT_MINE;
319 record_length -= sizeof header_fixed;
321 if (record_length != 0) {
322 /* Read the rest of the record as a comment. */
323 comment = (char *)g_malloc(record_length + 1);
324 if (!wtap_read_bytes(wth->fh, comment, record_length,
326 if (*err != WTAP_ERR_SHORT_READ)
327 return WTAP_OPEN_ERROR;
328 return WTAP_OPEN_NOT_MINE;
330 comment[record_length] = '\0';
331 wth->shb_hdr.opt_comment = comment;
334 /* If we made it this far, then the file is a LANAlyzer file.
335 * Let's get some info from it. Note that we get wth->snapshot_length
336 * from a record later in the file. */
337 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LANALYZER;
338 lanalyzer = (lanalyzer_t *)g_malloc(sizeof(lanalyzer_t));
339 wth->priv = (void *)lanalyzer;
340 wth->subtype_read = lanalyzer_read;
341 wth->subtype_seek_read = lanalyzer_seek_read;
342 wth->snapshot_length = 0;
343 wth->file_tsprec = WTAP_TSPREC_NSEC;
345 /* Read records until we find the start of packets */
347 if (!wtap_read_bytes_or_eof(wth->fh, &rec_header,
348 LA_RecordHeaderSize, err, err_info)) {
351 * End of file and no packets;
354 return WTAP_OPEN_MINE;
356 return WTAP_OPEN_ERROR;
359 record_type = pletoh16(rec_header.record_type);
360 record_length = pletoh16(rec_header.record_length);
362 /*g_message("Record 0x%04X Length %d", record_type, record_length);*/
363 switch (record_type) {
364 /* Trace Summary Record */
366 if (!wtap_read_bytes(wth->fh, summary,
367 sizeof summary, err, err_info))
368 return WTAP_OPEN_ERROR;
370 /* Assume that the date of the creation of the trace file
371 * is the same date of the trace. Lanalyzer doesn't
372 * store the creation date/time of the trace, but only of
373 * the file. Unless you traced at 11:55 PM and saved at 00:05
374 * AM, the assumption that trace.date == file.date is true.
377 cr_month = summary[1];
378 cr_year = pletoh16(&summary[2]);
379 /*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
382 /* Get capture start time. I learned how to do
383 * this from Guy's code in ngsniffer.c
385 tm.tm_year = cr_year - 1900;
386 tm.tm_mon = cr_month - 1;
392 lanalyzer->start = mktime(&tm);
393 /*g_message("Day %d Month %d Year %d", tm.tm_mday,
394 tm.tm_mon, tm.tm_year);*/
395 mxslc = pletoh16(&summary[30]);
396 wth->snapshot_length = mxslc;
398 board_type = pletoh16(&summary[188]);
399 switch (board_type) {
401 wth->file_encap = WTAP_ENCAP_ETHERNET;
404 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
407 *err = WTAP_ERR_UNSUPPORTED;
408 *err_info = g_strdup_printf("lanalyzer: board type %u unknown",
410 return WTAP_OPEN_ERROR;
414 /* Trace Packet Data Record */
416 /* Go back header number of bytes so that lanalyzer_read
417 * can read this header */
418 if (file_seek(wth->fh, -LA_RecordHeaderSize, SEEK_CUR, err) == -1) {
419 return WTAP_OPEN_ERROR;
421 return WTAP_OPEN_MINE;
424 if (file_seek(wth->fh, record_length, SEEK_CUR, err) == -1) {
425 return WTAP_OPEN_ERROR;
432 #define DESCRIPTOR_LEN 32
434 static gboolean lanalyzer_read_trace_record(wtap *wth, FILE_T fh,
435 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
437 char LE_record_type[2];
438 char LE_record_length[2];
439 guint16 record_type, record_length;
440 int record_data_size;
442 gchar descriptor[DESCRIPTOR_LEN];
443 lanalyzer_t *lanalyzer;
444 guint16 time_low, time_med, time_high, true_size;
448 /* read the record type and length. */
449 if (!wtap_read_bytes_or_eof(fh, LE_record_type, 2, err, err_info))
451 if (!wtap_read_bytes(fh, LE_record_length, 2, err, err_info))
454 record_type = pletoh16(LE_record_type);
455 record_length = pletoh16(LE_record_length);
457 /* Only Trace Packet Data Records should occur now that we're in
458 * the middle of reading packets. If any other record type exists
459 * after a Trace Packet Data Record, mark it as an error. */
460 if (record_type != RT_PacketData) {
461 *err = WTAP_ERR_BAD_FILE;
462 *err_info = g_strdup_printf("lanalyzer: record type %u seen after trace summary record",
467 if (record_length < DESCRIPTOR_LEN) {
469 * Uh-oh, the record isn't big enough to even have a
472 *err = WTAP_ERR_BAD_FILE;
473 *err_info = g_strdup_printf("lanalyzer: file has a %u-byte record, too small to have even a packet descriptor",
477 record_data_size = record_length - DESCRIPTOR_LEN;
479 /* Read the descriptor data */
480 if (!wtap_read_bytes(fh, descriptor, DESCRIPTOR_LEN, err, err_info))
483 true_size = pletoh16(&descriptor[4]);
484 packet_size = pletoh16(&descriptor[6]);
487 * OK, is the frame data size greater than than what's left of the
490 if (packet_size > record_data_size) {
492 * Yes - treat this as an error.
494 *err = WTAP_ERR_BAD_FILE;
495 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
499 phdr->rec_type = REC_TYPE_PACKET;
500 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
502 time_low = pletoh16(&descriptor[8]);
503 time_med = pletoh16(&descriptor[10]);
504 time_high = pletoh16(&descriptor[12]);
505 t = (((guint64)time_low) << 0) + (((guint64)time_med) << 16) +
506 (((guint64)time_high) << 32);
507 tsecs = (time_t) (t/2000000);
508 lanalyzer = (lanalyzer_t *)wth->priv;
509 phdr->ts.secs = tsecs + lanalyzer->start;
510 phdr->ts.nsecs = ((guint32) (t - tsecs*2000000)) * 500;
512 if (true_size - 4 >= packet_size) {
514 * It appears that the "true size" includes the FCS;
515 * make it reflect the non-FCS size (the "packet size"
516 * appears never to include the FCS, even if no slicing
521 phdr->len = true_size;
522 phdr->caplen = packet_size;
524 switch (wth->file_encap) {
526 case WTAP_ENCAP_ETHERNET:
527 /* We assume there's no FCS in this frame. */
528 phdr->pseudo_header.eth.fcs_len = 0;
532 /* Read the packet data */
533 return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
536 /* Read the next packet */
537 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
540 *data_offset = file_tell(wth->fh);
542 /* Read the record */
543 return lanalyzer_read_trace_record(wth, wth->fh, &wth->phdr,
544 wth->frame_buffer, err, err_info);
547 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
548 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
550 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
553 /* Read the record */
554 if (!lanalyzer_read_trace_record(wth, wth->random_fh, phdr, buf,
557 *err = WTAP_ERR_SHORT_READ;
563 /*---------------------------------------------------
564 * Returns TRUE on success, FALSE on error
565 * Write "cnt" bytes of zero with error control
566 *---------------------------------------------------*/
567 static gboolean s0write(wtap_dumper *wdh, size_t cnt, int *err)
572 snack = cnt > 64 ? 64 : cnt;
574 if (!wtap_dump_file_write(wdh, z64, snack, err))
578 return TRUE; /* ok */
581 /*---------------------------------------------------
582 * Returns TRUE on success, FALSE on error
583 * Write an 8-bit value with error control
584 *---------------------------------------------------*/
585 static gboolean s8write(wtap_dumper *wdh, const guint8 s8, int *err)
587 return wtap_dump_file_write(wdh, &s8, 1, err);
589 /*---------------------------------------------------
590 * Returns TRUE on success, FALSE on error
591 * Write a 16-bit value with error control
592 *---------------------------------------------------*/
593 static gboolean s16write(wtap_dumper *wdh, const guint16 s16, int *err)
595 return wtap_dump_file_write(wdh, &s16, 2, err);
597 /*---------------------------------------------------
598 * Returns TRUE on success, FALSE on error
599 * Write a 32-bit value with error control
600 *---------------------------------------------------*/
601 static gboolean s32write(wtap_dumper *wdh, const guint32 s32, int *err)
603 return wtap_dump_file_write(wdh, &s32, 4, err);
605 /*---------------------------------------------------
607 * calculates C.c = A.a - B.b
608 *---------------------------------------------------*/
609 static void my_timersub(const struct timeval *a,
610 const struct timeval *b,
613 gint32 usec = (gint32)a->tv_usec;
615 c->tv_sec = a->tv_sec - b->tv_sec;
616 if (b->tv_usec > usec) {
620 c->tv_usec = usec - b->tv_usec;
622 /*---------------------------------------------------
623 * Write a record for a packet to a dump file.
624 * Returns TRUE on success, FALSE on failure.
625 *---------------------------------------------------*/
626 static gboolean lanalyzer_dump(wtap_dumper *wdh,
627 const struct wtap_pkthdr *phdr,
628 const guint8 *pd, int *err, gchar **err_info _U_)
635 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
637 int thisSize = phdr->caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
639 /* We can only write packet records. */
640 if (phdr->rec_type != REC_TYPE_PACKET) {
641 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
645 if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
646 /* printf(" LA_ProFileLimit reached\n"); */
648 return FALSE; /* and don't forget the header */
651 len = phdr->caplen + (phdr->caplen ? LA_PacketRecordSize : 0);
653 /* len goes into a 16-bit field, so there's a hard limit of 65535. */
655 *err = WTAP_ERR_PACKET_TOO_LARGE;
659 if (!s16write(wdh, GUINT16_TO_LE(0x1005), err))
661 if (!s16write(wdh, GUINT16_TO_LE(len), err))
664 tv.tv_sec = (long int) phdr->ts.secs;
665 tv.tv_usec = phdr->ts.nsecs / 1000;
668 /* collect some information for the
669 * finally written header
671 /* XXX - this conversion could probably improved, if the start uses ns */
675 itmp->encap = wdh->encap;
679 my_timersub(&(tv),&(itmp->start),&td);
681 x = (double) td.tv_usec;
682 x += (double) td.tv_sec * 1000000;
685 if (!s16write(wdh, GUINT16_TO_LE(0x0001), err)) /* pr.rx_channels */
687 if (!s16write(wdh, GUINT16_TO_LE(0x0008), err)) /* pr.rx_errors */
689 if (!s16write(wdh, GUINT16_TO_LE(phdr->len + 4), err)) /* pr.rx_frm_len */
691 if (!s16write(wdh, GUINT16_TO_LE(phdr->caplen), err)) /* pr.rx_frm_sln */
694 for (i = 0; i < 3; i++) {
695 if (!s16write(wdh, GUINT16_TO_LE((guint16) x), err)) /* pr.rx_time[i] */
700 if (!s32write(wdh, GUINT32_TO_LE(++itmp->pkts), err)) /* pr.pktno */
702 if (!s16write(wdh, GUINT16_TO_LE(itmp->lastlen), err)) /* pr.prlen */
706 if (!s0write(wdh, 12, err))
709 if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
712 wdh->bytes_dumped += thisSize;
717 /*---------------------------------------------------
718 * Returns 0 if we could write the specified encapsulation type,
719 * an error indication otherwise.
720 *---------------------------------------------------*/
721 int lanalyzer_dump_can_write_encap(int encap)
723 /* Per-packet encapsulations aren't supported. */
724 if (encap == WTAP_ENCAP_PER_PACKET)
725 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
727 if ( encap != WTAP_ENCAP_ETHERNET
728 && encap != WTAP_ENCAP_TOKEN_RING )
729 return WTAP_ERR_UNWRITABLE_ENCAP;
731 * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
736 /*---------------------------------------------------
737 * Returns TRUE on success, FALSE on failure; sets "*err" to an
738 * error code on failure
739 *---------------------------------------------------*/
740 gboolean lanalyzer_dump_open(wtap_dumper *wdh, int *err)
745 tmp = g_malloc(sizeof(LA_TmpInfo));
751 ((LA_TmpInfo*)tmp)->init = FALSE;
753 wdh->subtype_write = lanalyzer_dump;
754 wdh->subtype_close = lanalyzer_dump_close;
756 /* Some of the fields in the file header aren't known yet so
757 just skip over it for now. It will be created after all
758 of the packets have been written. */
760 jump = sizeof (LA_HeaderRegularFake)
761 + sizeof (LA_RxChannelNameFake)
762 + sizeof (LA_TxChannelNameFake)
763 + sizeof (LA_RxTemplateNameFake)
764 + sizeof (LA_TxTemplateNameFake)
765 + sizeof (LA_DisplayOptionsFake)
766 + LA_SummaryRecordSize
767 + LA_SubfileSummaryRecordSize
768 + sizeof (LA_CyclicInformationFake)
769 + LA_IndexRecordSize;
771 if (wtap_dump_file_seek(wdh, jump, SEEK_SET, err) == -1)
774 wdh->bytes_dumped = jump;
778 /*---------------------------------------------------
780 *---------------------------------------------------*/
781 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
783 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
784 guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
785 ? BOARD_325TR /* LANalyzer Board Type */
786 : BOARD_325; /* LANalyzer Board Type */
790 /* The secs variable is needed to work around 32/64-bit time_t issues.
791 itmp->start is a timeval struct, which declares its tv_sec field
792 (itmp->start.tv_sec) as a long (typically 32 bits). time_t can be 32
793 or 64 bits, depending on the platform. Invoking as follows could
794 pass a pointer to a 32-bit long where a pointer to a 64-bit time_t
795 is expected: localtime((time_t*) &(itmp->start.tv_sec)) */
796 secs = itmp->start.tv_sec;
797 fT = localtime(&secs);
801 if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
804 if (!wtap_dump_file_write(wdh, &LA_HeaderRegularFake,
805 sizeof LA_HeaderRegularFake, err))
807 if (!wtap_dump_file_write(wdh, &LA_RxChannelNameFake,
808 sizeof LA_RxChannelNameFake, err))
810 if (!wtap_dump_file_write(wdh, &LA_TxChannelNameFake,
811 sizeof LA_TxChannelNameFake, err))
813 if (!wtap_dump_file_write(wdh, &LA_RxTemplateNameFake,
814 sizeof LA_RxTemplateNameFake, err))
816 if (!wtap_dump_file_write(wdh, &LA_TxTemplateNameFake,
817 sizeof LA_TxTemplateNameFake, err))
819 if (!wtap_dump_file_write(wdh, &LA_DisplayOptionsFake,
820 sizeof LA_DisplayOptionsFake, err))
822 /*-----------------------------------------------------------------*/
823 if (!s16write(wdh, GUINT16_TO_LE(RT_Summary), err)) /* rid */
825 if (!s16write(wdh, GUINT16_TO_LE(SummarySize), err)) /* rlen */
827 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datcre.day */
829 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datcre.mon */
831 if (!s16write(wdh, GUINT16_TO_LE(fT->tm_year + 1900), err)) /* s.datcre.year */
833 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datclo.day */
835 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datclo.mon */
837 if (!s16write(wdh, GUINT16_TO_LE(fT->tm_year + 1900), err)) /* s.datclo.year */
839 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeopn.second */
841 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeopn.minute */
843 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeopn.hour */
845 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeopn.mday */
847 if (!s0write(wdh, 2, err))
849 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeclo.second */
851 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeclo.minute */
853 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeclo.hour */
855 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeclo.mday */
857 if (!s0write(wdh, 2, err))
859 if (!s0write(wdh, 6, err)) /* EAddr == 0 */
861 if (!s16write(wdh, GUINT16_TO_LE(1), err)) /* s.mxseqno */
863 if (!s16write(wdh, GUINT16_TO_LE(0), err)) /* s.slcoffo */
865 if (!s16write(wdh, GUINT16_TO_LE(1514), err)) /* s.mxslc */
867 if (!s32write(wdh, GUINT32_TO_LE(itmp->pkts), err)) /* s.totpktt */
874 if (!s0write(wdh, 12, err))
876 if (!s32write(wdh, GUINT32_TO_LE(itmp->pkts), err)) /* sr.s.mxpkta[1] */
878 if (!s0write(wdh, 34*4, err)) /* s.mxpkta[2-33]=0 */
880 if (!s16write(wdh, GUINT16_TO_LE(board_type), err))
882 if (!s0write(wdh, 20, err)) /* board_version == 0 */
884 /*-----------------------------------------------------------------*/
885 if (!s16write(wdh, GUINT16_TO_LE(RT_SubfileSummary), err)) /* ssr.rid */
887 if (!s16write(wdh, GUINT16_TO_LE(LA_SubfileSummaryRecordSize-4), err)) /* ssr.rlen */
889 if (!s16write(wdh, GUINT16_TO_LE(1), err)) /* ssr.seqno */
891 if (!s32write(wdh, GUINT32_TO_LE(itmp->pkts), err)) /* ssr.totpkts */
893 /*-----------------------------------------------------------------*/
894 if (!wtap_dump_file_write(wdh, &LA_CyclicInformationFake,
895 sizeof LA_CyclicInformationFake, err))
897 /*-----------------------------------------------------------------*/
898 if (!s16write(wdh, GUINT16_TO_LE(RT_Index), err)) /* rid */
900 if (!s16write(wdh, GUINT16_TO_LE(LA_IndexRecordSize -4), err)) /* rlen */
902 if (!s16write(wdh, GUINT16_TO_LE(LA_IndexSize), err)) /* idxsp */
904 if (!s0write(wdh, LA_IndexRecordSize - 6, err))
910 /*---------------------------------------------------
911 * Finish writing to a dump file.
912 * Returns TRUE on success, FALSE on failure.
913 *---------------------------------------------------*/
914 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err)
916 lanalyzer_dump_header(wdh,err);
917 return *err ? FALSE : TRUE;