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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "file_wrappers.h"
29 #include "lanalyzer.h"
31 /* The LANalyzer format is documented (at least in part) in Novell document
32 TID022037, which can be found at, among other places:
34 http://www.windowsecurity.com/whitepapers/Description_of_the_LANalysers_output_file.html
37 /* Record header format */
40 guint8 record_type[2];
41 guint8 record_length[2];
44 #define LA_RecordHeaderSize 4
46 /* Record type codes: */
48 #define RT_HeaderRegular 0x1001
49 #define RT_HeaderCyclic 0x1007
50 #define RT_RxChannelName 0x1006
51 #define RT_TxChannelName 0x100b
52 #define RT_FilterName 0x1032
53 #define RT_RxTemplateName 0x1035
54 #define RT_TxTemplateName 0x1036
55 #define RT_DisplayOptions 0x100a
56 #define RT_Summary 0x1002
57 #define RT_SubfileSummary 0x1003
58 #define RT_CyclicInformation 0x1009
59 #define RT_Index 0x1004
60 #define RT_PacketData 0x1005
62 #define LA_ProFileLimit (1024 * 1024 * 32)
64 typedef guint8 Eadr[6];
65 typedef guint16 TimeStamp[3]; /* 0.5 microseconds since start of trace */
68 * These records have only 2-byte alignment for 4-byte quantities,
69 * so the structures aren't necessarily valid; they're kept as comments
70 * for reference purposes.
108 * gint16 board_version;
109 * gint8 reserved[18];
113 #define SummarySize (18+22+(4*36)+6+6+6+4+4)
120 * } LA_SummaryRecord;
123 #define LA_SummaryRecordSize (SummarySize + 4)
125 /* LANalyzer board types (which indicate the type of network on which
126 the capture was done). */
127 #define BOARD_325 226 /* LANalyzer 325 (Ethernet) */
128 #define BOARD_325TR 227 /* LANalyzer 325TR (Token-ring) */
137 * } LA_SubfileSummaryRecord;
140 #define LA_SubfileSummaryRecordSize 10
143 #define LA_IndexSize 500
149 * gint16 idxsp; = LA_IndexSize
153 * gint32 trcidx[LA_IndexSize + 2]; +2 undocumented but used by La 2.2
157 #define LA_IndexRecordSize (10 + 4 * (LA_IndexSize + 2))
162 * guint16 rx_channels;
174 * gint16 hwcollschans;
179 #define LA_PacketRecordSize 32
183 struct timeval start;
189 static const guint8 LA_HeaderRegularFake[] = {
190 0x01,0x10,0x4c,0x00,0x01,0x05,0x54,0x72,0x61,0x63,0x65,0x20,0x44,0x69,0x73,0x70,
191 0x6c,0x61,0x79,0x20,0x54,0x72,0x61,0x63,0x65,0x20,0x46,0x69,0x6c,0x65,0x00,0x00,
192 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
193 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
194 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
197 static const guint8 LA_RxChannelNameFake[] = {
198 0x06,0x10,0x80,0x00,0x43,0x68,0x61,0x6e ,0x6e,0x65,0x6c,0x31,0x00,0x43,0x68,0x61,
199 0x6e,0x6e,0x65,0x6c,0x32,0x00,0x43,0x68 ,0x61,0x6e,0x6e,0x65,0x6c,0x33,0x00,0x43,
200 0x68,0x61,0x6e,0x6e,0x65,0x6c,0x34,0x00 ,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x35,
201 0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c ,0x36,0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,
202 0x6c,0x37,0x00,0x43,0x68,0x61,0x6e,0x6e ,0x65,0x6c,0x38,0x00,0x00,0x00,0x00,0x00,
203 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
204 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
205 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
209 static const guint8 LA_TxChannelNameFake[] = {
210 0x0b,0x10,0x36,0x00 ,0x54,0x72,0x61,0x6e,0x73,0x31,0x00,0x00,
211 0x00,0x54,0x72,0x61,0x6e,0x73,0x32,0x00 ,0x00,0x00,0x54,0x72,0x61,0x6e,0x73,0x33,
212 0x00,0x00,0x00,0x54,0x72,0x61,0x6e,0x73 ,0x34,0x00,0x00,0x00,0x54,0x72,0x61,0x6e,
213 0x73,0x35,0x00,0x00,0x00,0x54,0x72,0x61 ,0x6e,0x73,0x36,0x00,0x00,0x00
216 static const guint8 LA_RxTemplateNameFake[] = {
218 0x90,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,
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,
230 static const guint8 LA_TxTemplateNameFake[] = {
231 0x36,0x10,0x36,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
232 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
233 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
234 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00
237 static const guint8 LA_DisplayOptionsFake[] = {
239 0x00,0x00,0x01,0x00,0x01,0x02,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,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
258 static const guint8 LA_CyclicInformationFake[] = {
259 0x09,0x10,0x1a,0x00,0x00,0x00,
260 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
261 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
264 static const guint8 z64[64] = {
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,
267 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
268 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
275 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
276 gint64 *data_offset);
277 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
278 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
279 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err);
281 int lanalyzer_open(wtap *wth, int *err, gchar **err_info)
284 LA_RecordHeader rec_header;
285 char header_fixed[2];
288 guint16 board_type, mxslc;
289 guint16 record_type, record_length;
290 guint8 cr_day, cr_month;
293 lanalyzer_t *lanalyzer;
295 errno = WTAP_ERR_CANT_READ;
296 bytes_read = file_read(&rec_header, LA_RecordHeaderSize, wth->fh);
297 if (bytes_read != LA_RecordHeaderSize) {
298 *err = file_error(wth->fh, err_info);
299 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
303 record_type = pletoh16(rec_header.record_type);
304 record_length = pletoh16(rec_header.record_length); /* make sure to do this for while() loop */
306 if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
310 /* Read the major and minor version numbers */
311 if (record_length < 2) {
313 * Not enough room for the major and minor version numbers.
314 * Just treat that as a "not a LANalyzer file" indication.
318 bytes_read = file_read(&header_fixed, sizeof header_fixed, wth->fh);
319 if (bytes_read != sizeof header_fixed) {
320 *err = file_error(wth->fh, err_info);
321 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
325 record_length -= sizeof header_fixed;
327 if (record_length != 0) {
328 /* Read the rest of the record as a comment. */
329 comment = (char *)g_malloc(record_length + 1);
330 bytes_read = file_read(comment, record_length, wth->fh);
331 if (bytes_read != record_length) {
332 *err = file_error(wth->fh, err_info);
333 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
337 comment[record_length] = '\0';
338 wth->shb_hdr.opt_comment = comment;
341 /* If we made it this far, then the file is a LANAlyzer file.
342 * Let's get some info from it. Note that we get wth->snapshot_length
343 * from a record later in the file. */
344 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LANALYZER;
345 lanalyzer = (lanalyzer_t *)g_malloc(sizeof(lanalyzer_t));
346 wth->priv = (void *)lanalyzer;
347 wth->subtype_read = lanalyzer_read;
348 wth->subtype_seek_read = lanalyzer_seek_read;
349 wth->snapshot_length = 0;
350 wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
352 /* Read records until we find the start of packets */
354 errno = WTAP_ERR_CANT_READ;
355 bytes_read = file_read(&rec_header, LA_RecordHeaderSize, wth->fh);
356 if (bytes_read != LA_RecordHeaderSize) {
357 *err = file_error(wth->fh, err_info);
359 *err = WTAP_ERR_SHORT_READ;
363 record_type = pletoh16(rec_header.record_type);
364 record_length = pletoh16(rec_header.record_length);
366 /*g_message("Record 0x%04X Length %d", record_type, record_length);*/
367 switch (record_type) {
368 /* Trace Summary Record */
370 errno = WTAP_ERR_CANT_READ;
371 bytes_read = file_read(summary, sizeof summary,
373 if (bytes_read != sizeof summary) {
374 *err = file_error(wth->fh, err_info);
376 *err = WTAP_ERR_SHORT_READ;
380 /* Assume that the date of the creation of the trace file
381 * is the same date of the trace. Lanalyzer doesn't
382 * store the creation date/time of the trace, but only of
383 * the file. Unless you traced at 11:55 PM and saved at 00:05
384 * AM, the assumption that trace.date == file.date is true.
387 cr_month = summary[1];
388 cr_year = pletoh16(&summary[2]);
389 /*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
392 /* Get capture start time. I learned how to do
393 * this from Guy's code in ngsniffer.c
395 tm.tm_year = cr_year - 1900;
396 tm.tm_mon = cr_month - 1;
402 lanalyzer->start = mktime(&tm);
403 /*g_message("Day %d Month %d Year %d", tm.tm_mday,
404 tm.tm_mon, tm.tm_year);*/
405 mxslc = pletoh16(&summary[30]);
406 wth->snapshot_length = mxslc;
408 board_type = pletoh16(&summary[188]);
409 switch (board_type) {
411 wth->file_encap = WTAP_ENCAP_ETHERNET;
414 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
417 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
418 *err_info = g_strdup_printf("lanalyzer: board type %u unknown",
424 /* Trace Packet Data Record */
426 /* Go back header number of bytes so that lanalyzer_read
427 * can read this header */
428 if (file_seek(wth->fh, -LA_RecordHeaderSize, SEEK_CUR, err) == -1) {
434 if (file_seek(wth->fh, record_length, SEEK_CUR, err) == -1) {
442 #define DESCRIPTOR_LEN 32
444 static gboolean lanalyzer_read_trace_record(wtap *wth, FILE_T fh,
445 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
448 char LE_record_type[2];
449 char LE_record_length[2];
450 guint16 record_type, record_length;
451 int record_data_size;
453 gchar descriptor[DESCRIPTOR_LEN];
454 lanalyzer_t *lanalyzer;
455 guint16 time_low, time_med, time_high, true_size;
459 /* read the record type and length. */
460 errno = WTAP_ERR_CANT_READ;
461 bytes_read = file_read(LE_record_type, 2, fh);
462 if (bytes_read != 2) {
463 *err = file_error(fh, err_info);
464 if (*err == 0 && bytes_read != 0) {
465 *err = WTAP_ERR_SHORT_READ;
469 bytes_read = file_read(LE_record_length, 2, fh);
470 if (bytes_read != 2) {
471 *err = file_error(fh, err_info);
473 *err = WTAP_ERR_SHORT_READ;
477 record_type = pletoh16(LE_record_type);
478 record_length = pletoh16(LE_record_length);
480 /* Only Trace Packet Data Records should occur now that we're in
481 * the middle of reading packets. If any other record type exists
482 * after a Trace Packet Data Record, mark it as an error. */
483 if (record_type != RT_PacketData) {
484 *err = WTAP_ERR_BAD_FILE;
485 *err_info = g_strdup_printf("lanalyzer: record type %u seen after trace summary record",
490 if (record_length < DESCRIPTOR_LEN) {
492 * Uh-oh, the record isn't big enough to even have a
495 *err = WTAP_ERR_BAD_FILE;
496 *err_info = g_strdup_printf("lanalyzer: file has a %u-byte record, too small to have even a packet descriptor",
500 record_data_size = record_length - DESCRIPTOR_LEN;
502 /* Read the descriptor data */
503 errno = WTAP_ERR_CANT_READ;
504 bytes_read = file_read(descriptor, DESCRIPTOR_LEN, fh);
505 if (bytes_read != DESCRIPTOR_LEN) {
506 *err = file_error(fh, err_info);
508 *err = WTAP_ERR_SHORT_READ;
512 true_size = pletoh16(&descriptor[4]);
513 packet_size = pletoh16(&descriptor[6]);
516 * OK, is the frame data size greater than than what's left of the
519 if (packet_size > record_data_size) {
521 * Yes - treat this as an error.
523 *err = WTAP_ERR_BAD_FILE;
524 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
528 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
530 time_low = pletoh16(&descriptor[8]);
531 time_med = pletoh16(&descriptor[10]);
532 time_high = pletoh16(&descriptor[12]);
533 t = (((guint64)time_low) << 0) + (((guint64)time_med) << 16) +
534 (((guint64)time_high) << 32);
535 tsecs = (time_t) (t/2000000);
536 lanalyzer = (lanalyzer_t *)wth->priv;
537 phdr->ts.secs = tsecs + lanalyzer->start;
538 phdr->ts.nsecs = ((guint32) (t - tsecs*2000000)) * 500;
540 if (true_size - 4 >= packet_size) {
542 * It appears that the "true size" includes the FCS;
543 * make it reflect the non-FCS size (the "packet size"
544 * appears never to include the FCS, even if no slicing
549 phdr->len = true_size;
550 phdr->caplen = packet_size;
552 switch (wth->file_encap) {
554 case WTAP_ENCAP_ETHERNET:
555 /* We assume there's no FCS in this frame. */
556 phdr->pseudo_header.eth.fcs_len = 0;
560 /* Read the packet data */
561 return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
564 /* Read the next packet */
565 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
568 *data_offset = file_tell(wth->fh);
570 /* Read the record */
571 return lanalyzer_read_trace_record(wth, wth->fh, &wth->phdr,
572 wth->frame_buffer, err, err_info);
575 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
576 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
578 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
581 /* Read the record */
582 if (!lanalyzer_read_trace_record(wth, wth->random_fh, phdr, buf,
585 *err = WTAP_ERR_SHORT_READ;
591 /*---------------------------------------------------
592 * Returns TRUE on success, FALSE on error
593 * Write "cnt" bytes of zero with error control
594 *---------------------------------------------------*/
595 static gboolean s0write(wtap_dumper *wdh, size_t cnt, int *err)
600 snack = cnt > 64 ? 64 : cnt;
602 if (!wtap_dump_file_write(wdh, z64, snack, err))
606 return TRUE; /* ok */
609 /*---------------------------------------------------
610 * Returns TRUE on success, FALSE on error
611 * Write an 8-bit value with error control
612 *---------------------------------------------------*/
613 static gboolean s8write(wtap_dumper *wdh, const guint8 s8, int *err)
615 return wtap_dump_file_write(wdh, &s8, 1, err);
617 /*---------------------------------------------------
618 * Returns TRUE on success, FALSE on error
619 * Write a 16-bit value with error control
620 *---------------------------------------------------*/
621 static gboolean s16write(wtap_dumper *wdh, const guint16 s16, int *err)
623 return wtap_dump_file_write(wdh, &s16, 2, err);
625 /*---------------------------------------------------
626 * Returns TRUE on success, FALSE on error
627 * Write a 32-bit value with error control
628 *---------------------------------------------------*/
629 static gboolean s32write(wtap_dumper *wdh, const guint32 s32, int *err)
631 return wtap_dump_file_write(wdh, &s32, 4, err);
633 /*---------------------------------------------------
635 * calculates C.c = A.a - B.b
636 *---------------------------------------------------*/
637 static void my_timersub(const struct timeval *a,
638 const struct timeval *b,
641 gint32 usec = (gint32)a->tv_usec;
643 c->tv_sec = a->tv_sec - b->tv_sec;
644 if (b->tv_usec > usec) {
648 c->tv_usec = usec - b->tv_usec;
650 /*---------------------------------------------------
651 * Write a record for a packet to a dump file.
652 * Returns TRUE on success, FALSE on failure.
653 *---------------------------------------------------*/
654 static gboolean lanalyzer_dump(wtap_dumper *wdh,
655 const struct wtap_pkthdr *phdr,
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 /* len goes into a 16-bit field, so there's a hard limit of 65535. */
677 *err = WTAP_ERR_PACKET_TOO_LARGE;
681 if (!s16write(wdh, GUINT16_TO_LE(0x1005), err))
683 if (!s16write(wdh, GUINT16_TO_LE(len), err))
686 tv.tv_sec = (long int) phdr->ts.secs;
687 tv.tv_usec = phdr->ts.nsecs / 1000;
690 /* collect some information for the
691 * finally written header
693 /* XXX - this conversion could probably improved, if the start uses ns */
697 itmp->encap = wdh->encap;
701 my_timersub(&(tv),&(itmp->start),&td);
703 x = (double) td.tv_usec;
704 x += (double) td.tv_sec * 1000000;
707 if (!s16write(wdh, GUINT16_TO_LE(0x0001), err)) /* pr.rx_channels */
709 if (!s16write(wdh, GUINT16_TO_LE(0x0008), err)) /* pr.rx_errors */
711 if (!s16write(wdh, GUINT16_TO_LE(phdr->len + 4), err)) /* pr.rx_frm_len */
713 if (!s16write(wdh, GUINT16_TO_LE(phdr->caplen), err)) /* pr.rx_frm_sln */
716 for (i = 0; i < 3; i++) {
717 if (!s16write(wdh, GUINT16_TO_LE((guint16) x), err)) /* pr.rx_time[i] */
722 if (!s32write(wdh, GUINT32_TO_LE(++itmp->pkts), err)) /* pr.pktno */
724 if (!s16write(wdh, GUINT16_TO_LE(itmp->lastlen), err)) /* pr.prlen */
728 if (!s0write(wdh, 12, err))
731 if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
734 wdh->bytes_dumped += thisSize;
739 /*---------------------------------------------------
740 * Returns 0 if we could write the specified encapsulation type,
741 * an error indication otherwise.
742 *---------------------------------------------------*/
743 int lanalyzer_dump_can_write_encap(int encap)
745 /* Per-packet encapsulations aren't supported. */
746 if (encap == WTAP_ENCAP_PER_PACKET)
747 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
749 if ( encap != WTAP_ENCAP_ETHERNET
750 && encap != WTAP_ENCAP_TOKEN_RING )
751 return WTAP_ERR_UNSUPPORTED_ENCAP;
753 * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
758 /*---------------------------------------------------
759 * Returns TRUE on success, FALSE on failure; sets "*err" to an
760 * error code on failure
761 *---------------------------------------------------*/
762 gboolean lanalyzer_dump_open(wtap_dumper *wdh, int *err)
767 tmp = g_malloc(sizeof(LA_TmpInfo));
773 ((LA_TmpInfo*)tmp)->init = FALSE;
775 wdh->subtype_write = lanalyzer_dump;
776 wdh->subtype_close = lanalyzer_dump_close;
778 /* Some of the fields in the file header aren't known yet so
779 just skip over it for now. It will be created after all
780 of the packets have been written. */
782 jump = sizeof (LA_HeaderRegularFake)
783 + sizeof (LA_RxChannelNameFake)
784 + sizeof (LA_TxChannelNameFake)
785 + sizeof (LA_RxTemplateNameFake)
786 + sizeof (LA_TxTemplateNameFake)
787 + sizeof (LA_DisplayOptionsFake)
788 + LA_SummaryRecordSize
789 + LA_SubfileSummaryRecordSize
790 + sizeof (LA_CyclicInformationFake)
791 + LA_IndexRecordSize;
793 if (wtap_dump_file_seek(wdh, jump, SEEK_SET, err) == -1)
796 wdh->bytes_dumped = jump;
800 /*---------------------------------------------------
802 *---------------------------------------------------*/
803 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
805 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
806 guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
807 ? BOARD_325TR /* LANalyzer Board Type */
808 : BOARD_325; /* LANalyzer Board Type */
812 /* The secs variable is needed to work around 32/64-bit time_t issues.
813 itmp->start is a timeval struct, which declares its tv_sec field
814 (itmp->start.tv_sec) as a long (typically 32 bits). time_t can be 32
815 or 64 bits, depending on the platform. Invoking as follows could
816 pass a pointer to a 32-bit long where a pointer to a 64-bit time_t
817 is expected: localtime((time_t*) &(itmp->start.tv_sec)) */
818 secs = itmp->start.tv_sec;
819 fT = localtime(&secs);
823 if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
826 if (!wtap_dump_file_write(wdh, &LA_HeaderRegularFake,
827 sizeof LA_HeaderRegularFake, err))
829 if (!wtap_dump_file_write(wdh, &LA_RxChannelNameFake,
830 sizeof LA_RxChannelNameFake, err))
832 if (!wtap_dump_file_write(wdh, &LA_TxChannelNameFake,
833 sizeof LA_TxChannelNameFake, err))
835 if (!wtap_dump_file_write(wdh, &LA_RxTemplateNameFake,
836 sizeof LA_RxTemplateNameFake, err))
838 if (!wtap_dump_file_write(wdh, &LA_TxTemplateNameFake,
839 sizeof LA_TxTemplateNameFake, err))
841 if (!wtap_dump_file_write(wdh, &LA_DisplayOptionsFake,
842 sizeof LA_DisplayOptionsFake, err))
844 /*-----------------------------------------------------------------*/
845 if (!s16write(wdh, GUINT16_TO_LE(RT_Summary), err)) /* rid */
847 if (!s16write(wdh, GUINT16_TO_LE(SummarySize), err)) /* rlen */
849 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datcre.day */
851 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datcre.mon */
853 if (!s16write(wdh, GUINT16_TO_LE(fT->tm_year + 1900), err)) /* s.datcre.year */
855 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datclo.day */
857 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datclo.mon */
859 if (!s16write(wdh, GUINT16_TO_LE(fT->tm_year + 1900), err)) /* s.datclo.year */
861 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeopn.second */
863 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeopn.minute */
865 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeopn.hour */
867 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeopn.mday */
869 if (!s0write(wdh, 2, err))
871 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeclo.second */
873 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeclo.minute */
875 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeclo.hour */
877 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeclo.mday */
879 if (!s0write(wdh, 2, err))
881 if (!s0write(wdh, 6, err)) /* EAddr == 0 */
883 if (!s16write(wdh, GUINT16_TO_LE(1), err)) /* s.mxseqno */
885 if (!s16write(wdh, GUINT16_TO_LE(0), err)) /* s.slcoffo */
887 if (!s16write(wdh, GUINT16_TO_LE(1514), err)) /* s.mxslc */
889 if (!s32write(wdh, GUINT32_TO_LE(itmp->pkts), err)) /* s.totpktt */
896 if (!s0write(wdh, 12, err))
898 if (!s32write(wdh, GUINT32_TO_LE(itmp->pkts), err)) /* sr.s.mxpkta[1] */
900 if (!s0write(wdh, 34*4, err)) /* s.mxpkta[2-33]=0 */
902 if (!s16write(wdh, GUINT16_TO_LE(board_type), err))
904 if (!s0write(wdh, 20, err)) /* board_version == 0 */
906 /*-----------------------------------------------------------------*/
907 if (!s16write(wdh, GUINT16_TO_LE(RT_SubfileSummary), err)) /* ssr.rid */
909 if (!s16write(wdh, GUINT16_TO_LE(LA_SubfileSummaryRecordSize-4), err)) /* ssr.rlen */
911 if (!s16write(wdh, GUINT16_TO_LE(1), err)) /* ssr.seqno */
913 if (!s32write(wdh, GUINT32_TO_LE(itmp->pkts), err)) /* ssr.totpkts */
915 /*-----------------------------------------------------------------*/
916 if (!wtap_dump_file_write(wdh, &LA_CyclicInformationFake,
917 sizeof LA_CyclicInformationFake, err))
919 /*-----------------------------------------------------------------*/
920 if (!s16write(wdh, GUINT16_TO_LE(RT_Index), err)) /* rid */
922 if (!s16write(wdh, GUINT16_TO_LE(LA_IndexRecordSize -4), err)) /* rlen */
924 if (!s16write(wdh, GUINT16_TO_LE(LA_IndexSize), err)) /* idxsp */
926 if (!s0write(wdh, LA_IndexRecordSize - 6, err))
932 /*---------------------------------------------------
933 * Finish writing to a dump file.
934 * Returns TRUE on success, FALSE on failure.
935 *---------------------------------------------------*/
936 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err)
938 lanalyzer_dump_header(wdh,err);
939 return *err ? FALSE : TRUE;