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"
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 int lanalyzer_open(wtap *wth, int *err, gchar **err_info)
282 LA_RecordHeader rec_header;
283 char header_fixed[2];
286 guint16 board_type, mxslc;
287 guint16 record_type, record_length;
288 guint8 cr_day, cr_month;
291 lanalyzer_t *lanalyzer;
293 errno = WTAP_ERR_CANT_READ;
294 bytes_read = file_read(&rec_header, LA_RecordHeaderSize, wth->fh);
295 if (bytes_read != LA_RecordHeaderSize) {
296 *err = file_error(wth->fh, err_info);
297 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
301 record_type = pletoh16(rec_header.record_type);
302 record_length = pletoh16(rec_header.record_length); /* make sure to do this for while() loop */
304 if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
308 /* Read the major and minor version numbers */
309 if (record_length < 2) {
311 * Not enough room for the major and minor version numbers.
312 * Just treat that as a "not a LANalyzer file" indication.
316 bytes_read = file_read(&header_fixed, sizeof header_fixed, wth->fh);
317 if (bytes_read != sizeof header_fixed) {
318 *err = file_error(wth->fh, err_info);
319 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
323 record_length -= sizeof header_fixed;
325 if (record_length != 0) {
326 /* Read the rest of the record as a comment. */
327 comment = (char *)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);
331 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
335 comment[record_length] = '\0';
336 wth->shb_hdr.opt_comment = comment;
339 /* If we made it this far, then the file is a LANAlyzer file.
340 * Let's get some info from it. Note that we get wth->snapshot_length
341 * from a record later in the file. */
342 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LANALYZER;
343 lanalyzer = (lanalyzer_t *)g_malloc(sizeof(lanalyzer_t));
344 wth->priv = (void *)lanalyzer;
345 wth->subtype_read = lanalyzer_read;
346 wth->subtype_seek_read = lanalyzer_seek_read;
347 wth->snapshot_length = 0;
348 wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
350 /* Read records until we find the start of packets */
352 errno = WTAP_ERR_CANT_READ;
353 bytes_read = file_read(&rec_header, LA_RecordHeaderSize, wth->fh);
354 if (bytes_read != LA_RecordHeaderSize) {
355 *err = file_error(wth->fh, err_info);
357 *err = WTAP_ERR_SHORT_READ;
361 record_type = pletoh16(rec_header.record_type);
362 record_length = pletoh16(rec_header.record_length);
364 /*g_message("Record 0x%04X Length %d", record_type, record_length);*/
365 switch (record_type) {
366 /* Trace Summary Record */
368 errno = WTAP_ERR_CANT_READ;
369 bytes_read = file_read(summary, sizeof summary,
371 if (bytes_read != sizeof summary) {
372 *err = file_error(wth->fh, err_info);
374 *err = WTAP_ERR_SHORT_READ;
378 /* Assume that the date of the creation of the trace file
379 * is the same date of the trace. Lanalyzer doesn't
380 * store the creation date/time of the trace, but only of
381 * the file. Unless you traced at 11:55 PM and saved at 00:05
382 * AM, the assumption that trace.date == file.date is true.
385 cr_month = summary[1];
386 cr_year = pletoh16(&summary[2]);
387 /*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
390 /* Get capture start time. I learned how to do
391 * this from Guy's code in ngsniffer.c
393 tm.tm_year = cr_year - 1900;
394 tm.tm_mon = cr_month - 1;
400 lanalyzer->start = mktime(&tm);
401 /*g_message("Day %d Month %d Year %d", tm.tm_mday,
402 tm.tm_mon, tm.tm_year);*/
403 mxslc = pletoh16(&summary[30]);
404 wth->snapshot_length = mxslc;
406 board_type = pletoh16(&summary[188]);
407 switch (board_type) {
409 wth->file_encap = WTAP_ENCAP_ETHERNET;
412 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
415 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
416 *err_info = g_strdup_printf("lanalyzer: board type %u unknown",
422 /* Trace Packet Data Record */
424 /* Go back header number of bytes so that lanalyzer_read
425 * can read this header */
426 if (file_seek(wth->fh, -LA_RecordHeaderSize, SEEK_CUR, err) == -1) {
432 if (file_seek(wth->fh, record_length, SEEK_CUR, err) == -1) {
440 #define DESCRIPTOR_LEN 32
442 static gboolean lanalyzer_read_trace_record(wtap *wth, FILE_T fh,
443 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
446 char LE_record_type[2];
447 char LE_record_length[2];
448 guint16 record_type, record_length;
449 int record_data_size;
451 gchar descriptor[DESCRIPTOR_LEN];
452 lanalyzer_t *lanalyzer;
453 guint16 time_low, time_med, time_high, true_size;
457 /* read the record type and length. */
458 errno = WTAP_ERR_CANT_READ;
459 bytes_read = file_read(LE_record_type, 2, fh);
460 if (bytes_read != 2) {
461 *err = file_error(fh, err_info);
462 if (*err == 0 && bytes_read != 0) {
463 *err = WTAP_ERR_SHORT_READ;
467 bytes_read = file_read(LE_record_length, 2, fh);
468 if (bytes_read != 2) {
469 *err = file_error(fh, err_info);
471 *err = WTAP_ERR_SHORT_READ;
475 record_type = pletoh16(LE_record_type);
476 record_length = pletoh16(LE_record_length);
478 /* Only Trace Packet Data Records should occur now that we're in
479 * the middle of reading packets. If any other record type exists
480 * after a Trace Packet Data Record, mark it as an error. */
481 if (record_type != RT_PacketData) {
482 *err = WTAP_ERR_BAD_FILE;
483 *err_info = g_strdup_printf("lanalyzer: record type %u seen after trace summary record",
488 if (record_length < DESCRIPTOR_LEN) {
490 * Uh-oh, the record isn't big enough to even have a
493 *err = WTAP_ERR_BAD_FILE;
494 *err_info = g_strdup_printf("lanalyzer: file has a %u-byte record, too small to have even a packet descriptor",
498 record_data_size = record_length - DESCRIPTOR_LEN;
500 /* Read the descriptor data */
501 errno = WTAP_ERR_CANT_READ;
502 bytes_read = file_read(descriptor, DESCRIPTOR_LEN, fh);
503 if (bytes_read != DESCRIPTOR_LEN) {
504 *err = file_error(fh, err_info);
506 *err = WTAP_ERR_SHORT_READ;
510 true_size = pletoh16(&descriptor[4]);
511 packet_size = pletoh16(&descriptor[6]);
514 * OK, is the frame data size greater than than what's left of the
517 if (packet_size > record_data_size) {
519 * Yes - treat this as an error.
521 *err = WTAP_ERR_BAD_FILE;
522 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
526 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
528 time_low = pletoh16(&descriptor[8]);
529 time_med = pletoh16(&descriptor[10]);
530 time_high = pletoh16(&descriptor[12]);
531 t = (((guint64)time_low) << 0) + (((guint64)time_med) << 16) +
532 (((guint64)time_high) << 32);
533 tsecs = (time_t) (t/2000000);
534 lanalyzer = (lanalyzer_t *)wth->priv;
535 phdr->ts.secs = tsecs + lanalyzer->start;
536 phdr->ts.nsecs = ((guint32) (t - tsecs*2000000)) * 500;
538 if (true_size - 4 >= packet_size) {
540 * It appears that the "true size" includes the FCS;
541 * make it reflect the non-FCS size (the "packet size"
542 * appears never to include the FCS, even if no slicing
547 phdr->len = true_size;
548 phdr->caplen = packet_size;
550 switch (wth->file_encap) {
552 case WTAP_ENCAP_ETHERNET:
553 /* We assume there's no FCS in this frame. */
554 phdr->pseudo_header.eth.fcs_len = 0;
558 /* Read the packet data */
559 return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
562 /* Read the next packet */
563 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
566 *data_offset = file_tell(wth->fh);
568 /* Read the record */
569 return lanalyzer_read_trace_record(wth, wth->fh, &wth->phdr,
570 wth->frame_buffer, err, err_info);
573 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
574 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
576 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
579 /* Read the record */
580 if (!lanalyzer_read_trace_record(wth, wth->random_fh, phdr, buf,
583 *err = WTAP_ERR_SHORT_READ;
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)
598 snack = cnt > 64 ? 64 : cnt;
600 if (!wtap_dump_file_write(wdh, z64, snack, err))
604 return TRUE; /* ok */
607 /*---------------------------------------------------
608 * Returns TRUE on success, FALSE on error
609 * Write an 8-bit value with error control
610 *---------------------------------------------------*/
611 static gboolean s8write(wtap_dumper *wdh, const guint8 s8, int *err)
613 return wtap_dump_file_write(wdh, &s8, 1, err);
615 /*---------------------------------------------------
616 * Returns TRUE on success, FALSE on error
617 * Write a 16-bit value with error control
618 *---------------------------------------------------*/
619 static gboolean s16write(wtap_dumper *wdh, const guint16 s16, int *err)
621 return wtap_dump_file_write(wdh, &s16, 2, err);
623 /*---------------------------------------------------
624 * Returns TRUE on success, FALSE on error
625 * Write a 32-bit value with error control
626 *---------------------------------------------------*/
627 static gboolean s32write(wtap_dumper *wdh, const guint32 s32, int *err)
629 return wtap_dump_file_write(wdh, &s32, 4, err);
631 /*---------------------------------------------------
633 * calculates C.c = A.a - B.b
634 *---------------------------------------------------*/
635 static void my_timersub(const struct timeval *a,
636 const struct timeval *b,
639 gint32 usec = (gint32)a->tv_usec;
641 c->tv_sec = a->tv_sec - b->tv_sec;
642 if (b->tv_usec > usec) {
646 c->tv_usec = usec - b->tv_usec;
648 /*---------------------------------------------------
649 * Write a record for a packet to a dump file.
650 * Returns TRUE on success, FALSE on failure.
651 *---------------------------------------------------*/
652 static gboolean lanalyzer_dump(wtap_dumper *wdh,
653 const struct wtap_pkthdr *phdr,
654 const guint8 *pd, int *err)
661 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
663 int thisSize = phdr->caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
665 if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
666 /* printf(" LA_ProFileLimit reached\n"); */
668 return FALSE; /* and don't forget the header */
671 len = phdr->caplen + (phdr->caplen ? LA_PacketRecordSize : 0);
673 /* len goes into a 16-bit field, so there's a hard limit of 65535. */
675 *err = WTAP_ERR_PACKET_TOO_LARGE;
679 if (!s16write(wdh, GUINT16_TO_LE(0x1005), err))
681 if (!s16write(wdh, GUINT16_TO_LE(len), err))
684 tv.tv_sec = (long int) phdr->ts.secs;
685 tv.tv_usec = phdr->ts.nsecs / 1000;
688 /* collect some information for the
689 * finally written header
691 /* XXX - this conversion could probably improved, if the start uses ns */
695 itmp->encap = wdh->encap;
699 my_timersub(&(tv),&(itmp->start),&td);
701 x = (double) td.tv_usec;
702 x += (double) td.tv_sec * 1000000;
705 if (!s16write(wdh, GUINT16_TO_LE(0x0001), err)) /* pr.rx_channels */
707 if (!s16write(wdh, GUINT16_TO_LE(0x0008), err)) /* pr.rx_errors */
709 if (!s16write(wdh, GUINT16_TO_LE(phdr->len + 4), err)) /* pr.rx_frm_len */
711 if (!s16write(wdh, GUINT16_TO_LE(phdr->caplen), err)) /* pr.rx_frm_sln */
714 for (i = 0; i < 3; i++) {
715 if (!s16write(wdh, GUINT16_TO_LE((guint16) x), err)) /* pr.rx_time[i] */
720 if (!s32write(wdh, GUINT32_TO_LE(++itmp->pkts), err)) /* pr.pktno */
722 if (!s16write(wdh, GUINT16_TO_LE(itmp->lastlen), err)) /* pr.prlen */
726 if (!s0write(wdh, 12, err))
729 if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
732 wdh->bytes_dumped += thisSize;
737 /*---------------------------------------------------
738 * Returns 0 if we could write the specified encapsulation type,
739 * an error indication otherwise.
740 *---------------------------------------------------*/
741 int lanalyzer_dump_can_write_encap(int encap)
743 /* Per-packet encapsulations aren't supported. */
744 if (encap == WTAP_ENCAP_PER_PACKET)
745 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
747 if ( encap != WTAP_ENCAP_ETHERNET
748 && encap != WTAP_ENCAP_TOKEN_RING )
749 return WTAP_ERR_UNSUPPORTED_ENCAP;
751 * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
756 /*---------------------------------------------------
757 * Returns TRUE on success, FALSE on failure; sets "*err" to an
758 * error code on failure
759 *---------------------------------------------------*/
760 gboolean lanalyzer_dump_open(wtap_dumper *wdh, int *err)
765 tmp = g_malloc(sizeof(LA_TmpInfo));
771 ((LA_TmpInfo*)tmp)->init = FALSE;
773 wdh->subtype_write = lanalyzer_dump;
774 wdh->subtype_close = lanalyzer_dump_close;
776 /* Some of the fields in the file header aren't known yet so
777 just skip over it for now. It will be created after all
778 of the packets have been written. */
780 jump = sizeof (LA_HeaderRegularFake)
781 + sizeof (LA_RxChannelNameFake)
782 + sizeof (LA_TxChannelNameFake)
783 + sizeof (LA_RxTemplateNameFake)
784 + sizeof (LA_TxTemplateNameFake)
785 + sizeof (LA_DisplayOptionsFake)
786 + LA_SummaryRecordSize
787 + LA_SubfileSummaryRecordSize
788 + sizeof (LA_CyclicInformationFake)
789 + LA_IndexRecordSize;
791 if (wtap_dump_file_seek(wdh, jump, SEEK_SET, err) == -1)
794 wdh->bytes_dumped = jump;
798 /*---------------------------------------------------
800 *---------------------------------------------------*/
801 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
803 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
804 guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
805 ? BOARD_325TR /* LANalyzer Board Type */
806 : BOARD_325; /* LANalyzer Board Type */
810 /* The secs variable is needed to work around 32/64-bit time_t issues.
811 itmp->start is a timeval struct, which declares its tv_sec field
812 (itmp->start.tv_sec) as a long (typically 32 bits). time_t can be 32
813 or 64 bits, depending on the platform. Invoking as follows could
814 pass a pointer to a 32-bit long where a pointer to a 64-bit time_t
815 is expected: localtime((time_t*) &(itmp->start.tv_sec)) */
816 secs = itmp->start.tv_sec;
817 fT = localtime(&secs);
821 if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
824 if (!wtap_dump_file_write(wdh, &LA_HeaderRegularFake,
825 sizeof LA_HeaderRegularFake, err))
827 if (!wtap_dump_file_write(wdh, &LA_RxChannelNameFake,
828 sizeof LA_RxChannelNameFake, err))
830 if (!wtap_dump_file_write(wdh, &LA_TxChannelNameFake,
831 sizeof LA_TxChannelNameFake, err))
833 if (!wtap_dump_file_write(wdh, &LA_RxTemplateNameFake,
834 sizeof LA_RxTemplateNameFake, err))
836 if (!wtap_dump_file_write(wdh, &LA_TxTemplateNameFake,
837 sizeof LA_TxTemplateNameFake, err))
839 if (!wtap_dump_file_write(wdh, &LA_DisplayOptionsFake,
840 sizeof LA_DisplayOptionsFake, err))
842 /*-----------------------------------------------------------------*/
843 if (!s16write(wdh, GUINT16_TO_LE(RT_Summary), err)) /* rid */
845 if (!s16write(wdh, GUINT16_TO_LE(SummarySize), err)) /* rlen */
847 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datcre.day */
849 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datcre.mon */
851 if (!s16write(wdh, GUINT16_TO_LE(fT->tm_year + 1900), err)) /* s.datcre.year */
853 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datclo.day */
855 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datclo.mon */
857 if (!s16write(wdh, GUINT16_TO_LE(fT->tm_year + 1900), err)) /* s.datclo.year */
859 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeopn.second */
861 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeopn.minute */
863 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeopn.hour */
865 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeopn.mday */
867 if (!s0write(wdh, 2, err))
869 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeclo.second */
871 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeclo.minute */
873 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeclo.hour */
875 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeclo.mday */
877 if (!s0write(wdh, 2, err))
879 if (!s0write(wdh, 6, err)) /* EAddr == 0 */
881 if (!s16write(wdh, GUINT16_TO_LE(1), err)) /* s.mxseqno */
883 if (!s16write(wdh, GUINT16_TO_LE(0), err)) /* s.slcoffo */
885 if (!s16write(wdh, GUINT16_TO_LE(1514), err)) /* s.mxslc */
887 if (!s32write(wdh, GUINT32_TO_LE(itmp->pkts), err)) /* s.totpktt */
894 if (!s0write(wdh, 12, err))
896 if (!s32write(wdh, GUINT32_TO_LE(itmp->pkts), err)) /* sr.s.mxpkta[1] */
898 if (!s0write(wdh, 34*4, err)) /* s.mxpkta[2-33]=0 */
900 if (!s16write(wdh, GUINT16_TO_LE(board_type), err))
902 if (!s0write(wdh, 20, err)) /* board_version == 0 */
904 /*-----------------------------------------------------------------*/
905 if (!s16write(wdh, GUINT16_TO_LE(RT_SubfileSummary), err)) /* ssr.rid */
907 if (!s16write(wdh, GUINT16_TO_LE(LA_SubfileSummaryRecordSize-4), err)) /* ssr.rlen */
909 if (!s16write(wdh, GUINT16_TO_LE(1), err)) /* ssr.seqno */
911 if (!s32write(wdh, GUINT32_TO_LE(itmp->pkts), err)) /* ssr.totpkts */
913 /*-----------------------------------------------------------------*/
914 if (!wtap_dump_file_write(wdh, &LA_CyclicInformationFake,
915 sizeof LA_CyclicInformationFake, err))
917 /*-----------------------------------------------------------------*/
918 if (!s16write(wdh, GUINT16_TO_LE(RT_Index), err)) /* rid */
920 if (!s16write(wdh, GUINT16_TO_LE(LA_IndexRecordSize -4), err)) /* rlen */
922 if (!s16write(wdh, GUINT16_TO_LE(LA_IndexSize), err)) /* idxsp */
924 if (!s0write(wdh, LA_IndexRecordSize - 6, err))
930 /*---------------------------------------------------
931 * Finish writing to a dump file.
932 * Returns TRUE on success, FALSE on failure.
933 *---------------------------------------------------*/
934 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err)
936 lanalyzer_dump_header(wdh,err);
937 return *err ? FALSE : TRUE;