4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include "file_wrappers.h"
14 #include "lanalyzer.h"
17 /* The LANalyzer format is documented (at least in part) in Novell document
18 TID022037, which can be found at, among other places:
20 http://www.windowsecurity.com/whitepapers/Description_of_the_LANalysers_output_file.html
23 /* Record header format */
26 guint8 record_type[2];
27 guint8 record_length[2];
30 #define LA_RecordHeaderSize 4
32 /* Record type codes: */
34 #define RT_HeaderRegular 0x1001
35 #define RT_HeaderCyclic 0x1007
36 #define RT_RxChannelName 0x1006
37 #define RT_TxChannelName 0x100b
38 #define RT_FilterName 0x1032
39 #define RT_RxTemplateName 0x1035
40 #define RT_TxTemplateName 0x1036
41 #define RT_DisplayOptions 0x100a
42 #define RT_Summary 0x1002
43 #define RT_SubfileSummary 0x1003
44 #define RT_CyclicInformation 0x1009
45 #define RT_Index 0x1004
46 #define RT_PacketData 0x1005
48 #define LA_ProFileLimit (1024 * 1024 * 32)
50 typedef guint8 Eadr[6];
51 typedef guint16 TimeStamp[3]; /* 0.5 microseconds since start of trace */
54 * These records have only 2-byte alignment for 4-byte quantities,
55 * so the structures aren't necessarily valid; they're kept as comments
56 * for reference purposes.
94 * gint16 board_version;
99 #define SummarySize (18+22+(4*36)+6+6+6+4+4)
106 * } LA_SummaryRecord;
109 #define LA_SummaryRecordSize (SummarySize + 4)
111 /* LANalyzer board types (which indicate the type of network on which
112 the capture was done). */
113 #define BOARD_325 226 /* LANalyzer 325 (Ethernet) */
114 #define BOARD_325TR 227 /* LANalyzer 325TR (Token-ring) */
123 * } LA_SubfileSummaryRecord;
126 #define LA_SubfileSummaryRecordSize 10
129 #define LA_IndexSize 500
135 * gint16 idxsp; = LA_IndexSize
139 * gint32 trcidx[LA_IndexSize + 2]; +2 undocumented but used by La 2.2
143 #define LA_IndexRecordSize (10 + 4 * (LA_IndexSize + 2))
148 * guint16 rx_channels;
160 * gint16 hwcollschans;
165 #define LA_PacketRecordSize 32
175 static const guint8 LA_HeaderRegularFake[] = {
176 0x01,0x10,0x4c,0x00,0x01,0x05,0x54,0x72,0x61,0x63,0x65,0x20,0x44,0x69,0x73,0x70,
177 0x6c,0x61,0x79,0x20,0x54,0x72,0x61,0x63,0x65,0x20,0x46,0x69,0x6c,0x65,0x00,0x00,
178 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
179 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
180 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
183 static const guint8 LA_RxChannelNameFake[] = {
184 0x06,0x10,0x80,0x00,0x43,0x68,0x61,0x6e ,0x6e,0x65,0x6c,0x31,0x00,0x43,0x68,0x61,
185 0x6e,0x6e,0x65,0x6c,0x32,0x00,0x43,0x68 ,0x61,0x6e,0x6e,0x65,0x6c,0x33,0x00,0x43,
186 0x68,0x61,0x6e,0x6e,0x65,0x6c,0x34,0x00 ,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x35,
187 0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c ,0x36,0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,
188 0x6c,0x37,0x00,0x43,0x68,0x61,0x6e,0x6e ,0x65,0x6c,0x38,0x00,0x00,0x00,0x00,0x00,
189 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,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,
195 static const guint8 LA_TxChannelNameFake[] = {
196 0x0b,0x10,0x36,0x00 ,0x54,0x72,0x61,0x6e,0x73,0x31,0x00,0x00,
197 0x00,0x54,0x72,0x61,0x6e,0x73,0x32,0x00 ,0x00,0x00,0x54,0x72,0x61,0x6e,0x73,0x33,
198 0x00,0x00,0x00,0x54,0x72,0x61,0x6e,0x73 ,0x34,0x00,0x00,0x00,0x54,0x72,0x61,0x6e,
199 0x73,0x35,0x00,0x00,0x00,0x54,0x72,0x61 ,0x6e,0x73,0x36,0x00,0x00,0x00
202 static const guint8 LA_RxTemplateNameFake[] = {
204 0x90,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,
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,
208 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
209 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
210 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
211 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
212 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
216 static const guint8 LA_TxTemplateNameFake[] = {
217 0x36,0x10,0x36,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
223 static const guint8 LA_DisplayOptionsFake[] = {
225 0x00,0x00,0x01,0x00,0x01,0x02,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,
229 0x00,0x00,0x00,0x00,0x00,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,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,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,0x00,0x00,0x00,0x00,
237 0x00,0x00,0x00,0x00,0x00,0x00,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
244 static const guint8 LA_CyclicInformationFake[] = {
245 0x09,0x10,0x1a,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
250 static const guint8 z64[64] = {
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
261 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
262 gint64 *data_offset);
263 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
264 wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
265 static gboolean lanalyzer_dump_finish(wtap_dumper *wdh, int *err);
267 wtap_open_return_val lanalyzer_open(wtap *wth, int *err, gchar **err_info)
269 LA_RecordHeader rec_header;
270 char header_fixed[2];
273 guint16 board_type, mxslc;
274 guint16 record_type, record_length;
275 guint8 cr_day, cr_month;
278 lanalyzer_t *lanalyzer;
280 if (!wtap_read_bytes(wth->fh, &rec_header, LA_RecordHeaderSize,
282 if (*err != WTAP_ERR_SHORT_READ)
283 return WTAP_OPEN_ERROR;
284 return WTAP_OPEN_NOT_MINE;
286 record_type = pletoh16(rec_header.record_type);
287 record_length = pletoh16(rec_header.record_length); /* make sure to do this for while() loop */
289 if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
290 return WTAP_OPEN_NOT_MINE;
293 /* Read the major and minor version numbers */
294 if (record_length < 2) {
296 * Not enough room for the major and minor version numbers.
297 * Just treat that as a "not a LANalyzer file" indication.
299 return WTAP_OPEN_NOT_MINE;
301 if (!wtap_read_bytes(wth->fh, &header_fixed, sizeof header_fixed,
303 if (*err != WTAP_ERR_SHORT_READ)
304 return WTAP_OPEN_ERROR;
305 return WTAP_OPEN_NOT_MINE;
307 record_length -= sizeof header_fixed;
309 if (record_length != 0) {
310 /* Read the rest of the record as a comment. */
311 comment = (char *)g_malloc(record_length + 1);
312 if (!wtap_read_bytes(wth->fh, comment, record_length,
314 if (*err != WTAP_ERR_SHORT_READ) {
316 return WTAP_OPEN_ERROR;
319 return WTAP_OPEN_NOT_MINE;
321 wtap_block_add_string_option(g_array_index(wth->shb_hdrs, wtap_block_t, 0), OPT_COMMENT, comment, record_length);
325 /* If we made it this far, then the file is a LANAlyzer file.
326 * Let's get some info from it. Note that we get wth->snapshot_length
327 * from a record later in the file. */
328 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LANALYZER;
329 lanalyzer = (lanalyzer_t *)g_malloc(sizeof(lanalyzer_t));
330 wth->priv = (void *)lanalyzer;
331 wth->subtype_read = lanalyzer_read;
332 wth->subtype_seek_read = lanalyzer_seek_read;
333 wth->snapshot_length = 0;
334 wth->file_tsprec = WTAP_TSPREC_NSEC;
336 /* Read records until we find the start of packets */
338 if (!wtap_read_bytes_or_eof(wth->fh, &rec_header,
339 LA_RecordHeaderSize, err, err_info)) {
342 * End of file and no packets;
345 return WTAP_OPEN_MINE;
347 return WTAP_OPEN_ERROR;
350 record_type = pletoh16(rec_header.record_type);
351 record_length = pletoh16(rec_header.record_length);
353 /*g_message("Record 0x%04X Length %d", record_type, record_length);*/
354 switch (record_type) {
355 /* Trace Summary Record */
357 if (!wtap_read_bytes(wth->fh, summary,
358 sizeof summary, err, err_info))
359 return WTAP_OPEN_ERROR;
361 /* Assume that the date of the creation of the trace file
362 * is the same date of the trace. Lanalyzer doesn't
363 * store the creation date/time of the trace, but only of
364 * the file. Unless you traced at 11:55 PM and saved at 00:05
365 * AM, the assumption that trace.date == file.date is true.
368 cr_month = summary[1];
369 cr_year = pletoh16(&summary[2]);
370 /*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
373 /* Get capture start time. I learned how to do
374 * this from Guy's code in ngsniffer.c
376 tm.tm_year = cr_year - 1900;
377 tm.tm_mon = cr_month - 1;
383 lanalyzer->start = mktime(&tm);
384 /*g_message("Day %d Month %d Year %d", tm.tm_mday,
385 tm.tm_mon, tm.tm_year);*/
386 mxslc = pletoh16(&summary[30]);
387 wth->snapshot_length = mxslc;
389 board_type = pletoh16(&summary[188]);
390 switch (board_type) {
392 wth->file_encap = WTAP_ENCAP_ETHERNET;
395 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
398 *err = WTAP_ERR_UNSUPPORTED;
399 *err_info = g_strdup_printf("lanalyzer: board type %u unknown",
401 return WTAP_OPEN_ERROR;
405 /* Trace Packet Data Record */
407 /* Go back header number of bytes so that lanalyzer_read
408 * can read this header */
409 if (file_seek(wth->fh, -LA_RecordHeaderSize, SEEK_CUR, err) == -1) {
410 return WTAP_OPEN_ERROR;
412 return WTAP_OPEN_MINE;
415 /* Unknown record type - skip it */
416 if (!wtap_read_bytes(wth->fh, NULL, record_length, err, err_info)) {
417 return WTAP_OPEN_ERROR;
424 #define DESCRIPTOR_LEN 32
426 static gboolean lanalyzer_read_trace_record(wtap *wth, FILE_T fh,
427 wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
429 char LE_record_type[2];
430 char LE_record_length[2];
431 guint16 record_type, record_length;
432 int record_data_size;
434 gchar descriptor[DESCRIPTOR_LEN];
435 lanalyzer_t *lanalyzer;
436 guint16 time_low, time_med, time_high, true_size;
440 /* read the record type and length. */
441 if (!wtap_read_bytes_or_eof(fh, LE_record_type, 2, err, err_info))
443 if (!wtap_read_bytes(fh, LE_record_length, 2, err, err_info))
446 record_type = pletoh16(LE_record_type);
447 record_length = pletoh16(LE_record_length);
449 /* Only Trace Packet Data Records should occur now that we're in
450 * the middle of reading packets. If any other record type exists
451 * after a Trace Packet Data Record, mark it as an error. */
452 if (record_type != RT_PacketData) {
453 *err = WTAP_ERR_BAD_FILE;
454 *err_info = g_strdup_printf("lanalyzer: record type %u seen after trace summary record",
459 if (record_length < DESCRIPTOR_LEN) {
461 * Uh-oh, the record isn't big enough to even have a
464 *err = WTAP_ERR_BAD_FILE;
465 *err_info = g_strdup_printf("lanalyzer: file has a %u-byte record, too small to have even a packet descriptor",
469 record_data_size = record_length - DESCRIPTOR_LEN;
471 /* Read the descriptor data */
472 if (!wtap_read_bytes(fh, descriptor, DESCRIPTOR_LEN, err, err_info))
475 true_size = pletoh16(&descriptor[4]);
476 packet_size = pletoh16(&descriptor[6]);
478 * The maximum value of packet_size is 65535, which is less than
479 * WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check
484 * OK, is the frame data size greater than than what's left of the
487 if (packet_size > record_data_size) {
489 * Yes - treat this as an error.
491 *err = WTAP_ERR_BAD_FILE;
492 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
496 rec->rec_type = REC_TYPE_PACKET;
497 rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
499 time_low = pletoh16(&descriptor[8]);
500 time_med = pletoh16(&descriptor[10]);
501 time_high = pletoh16(&descriptor[12]);
502 t = (((guint64)time_low) << 0) + (((guint64)time_med) << 16) +
503 (((guint64)time_high) << 32);
504 tsecs = (time_t) (t/2000000);
505 lanalyzer = (lanalyzer_t *)wth->priv;
506 rec->ts.secs = tsecs + lanalyzer->start;
507 rec->ts.nsecs = ((guint32) (t - tsecs*2000000)) * 500;
509 if (true_size - 4 >= packet_size) {
511 * It appears that the "true size" includes the FCS;
512 * make it reflect the non-FCS size (the "packet size"
513 * appears never to include the FCS, even if no slicing
518 rec->rec_header.packet_header.len = true_size;
519 rec->rec_header.packet_header.caplen = packet_size;
521 switch (wth->file_encap) {
523 case WTAP_ENCAP_ETHERNET:
524 /* We assume there's no FCS in this frame. */
525 rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0;
529 /* Read the packet data */
530 return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
533 /* Read the next packet */
534 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
537 *data_offset = file_tell(wth->fh);
539 /* Read the record */
540 return lanalyzer_read_trace_record(wth, wth->fh, &wth->rec,
541 wth->rec_data, err, err_info);
544 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
545 wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
547 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
550 /* Read the record */
551 if (!lanalyzer_read_trace_record(wth, wth->random_fh, rec, buf,
554 *err = WTAP_ERR_SHORT_READ;
560 /*---------------------------------------------------
561 * Returns TRUE on success, FALSE on error
562 * Write "cnt" bytes of zero with error control
563 *---------------------------------------------------*/
564 static gboolean s0write(wtap_dumper *wdh, size_t cnt, int *err)
569 snack = cnt > 64 ? 64 : cnt;
571 if (!wtap_dump_file_write(wdh, z64, snack, err))
575 return TRUE; /* ok */
578 /*---------------------------------------------------
579 * Returns TRUE on success, FALSE on error
580 * Write an 8-bit value
581 *---------------------------------------------------*/
582 static gboolean s8write(wtap_dumper *wdh, const guint8 s8, int *err)
584 return wtap_dump_file_write(wdh, &s8, 1, err);
586 /*---------------------------------------------------
587 * Returns TRUE on success, FALSE on error
588 * Write a 16-bit value as little-endian
589 *---------------------------------------------------*/
590 static gboolean s16write(wtap_dumper *wdh, const guint16 s16, int *err)
592 guint16 s16_le = GUINT16_TO_LE(s16);
593 return wtap_dump_file_write(wdh, &s16_le, 2, err);
595 /*---------------------------------------------------
596 * Returns TRUE on success, FALSE on error
597 * Write a 32-bit value as little-endian
598 *---------------------------------------------------*/
599 static gboolean s32write(wtap_dumper *wdh, const guint32 s32, int *err)
601 guint32 s32_le = GUINT32_TO_LE(s32);
602 return wtap_dump_file_write(wdh, &s32_le, 4, err);
604 /*---------------------------------------------------
605 * Returns TRUE on success, FALSE on error
606 * Write a 48-bit value as little-endian
607 *---------------------------------------------------*/
608 static gboolean s48write(wtap_dumper *wdh, const guint64 s48, int *err)
610 #if G_BYTE_ORDER == G_BIG_ENDIAN
611 guint16 s48_upper_le = GUINT16_SWAP_LE_BE((guint16) (s48 >> 32));
612 guint32 s48_lower_le = GUINT32_SWAP_LE_BE((guint32) (s48 & 0xFFFFFFFF));
614 guint16 s48_upper_le = (guint16) (s48 >> 32);
615 guint32 s48_lower_le = (guint32) (s48 & 0xFFFFFFFF);
617 return wtap_dump_file_write(wdh, &s48_lower_le, 4, err) &&
618 wtap_dump_file_write(wdh, &s48_upper_le, 2, err);
620 /*---------------------------------------------------
621 * Write a record for a packet to a dump file.
622 * Returns TRUE on success, FALSE on failure.
623 *---------------------------------------------------*/
624 static gboolean lanalyzer_dump(wtap_dumper *wdh,
626 const guint8 *pd, int *err, gchar **err_info _U_)
631 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
633 int thisSize = rec->rec_header.packet_header.caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
635 /* We can only write packet records. */
636 if (rec->rec_type != REC_TYPE_PACKET) {
637 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
642 * Make sure this packet doesn't have a link-layer type that
643 * differs from the one for the file.
645 if (wdh->encap != rec->rec_header.packet_header.pkt_encap) {
646 *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
650 if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
651 /* printf(" LA_ProFileLimit reached\n"); */
653 return FALSE; /* and don't forget the header */
656 len = rec->rec_header.packet_header.caplen + (rec->rec_header.packet_header.caplen ? LA_PacketRecordSize : 0);
658 /* len goes into a 16-bit field, so there's a hard limit of 65535. */
660 *err = WTAP_ERR_PACKET_TOO_LARGE;
664 if (!s16write(wdh, 0x1005, err))
666 if (!s16write(wdh, (guint16)len, err))
670 /* collect some information for the
671 * finally written header
673 itmp->start = rec->ts;
676 itmp->encap = wdh->encap;
680 if (!s16write(wdh, 0x0001, err)) /* pr.rx_channels */
682 if (!s16write(wdh, 0x0008, err)) /* pr.rx_errors */
684 if (!s16write(wdh, (guint16) (rec->rec_header.packet_header.len + 4), err)) /* pr.rx_frm_len */
686 if (!s16write(wdh, (guint16) rec->rec_header.packet_header.caplen, err)) /* pr.rx_frm_sln */
689 nstime_delta(&td, &rec->ts, &itmp->start);
691 /* Convert to half-microseconds, rounded up. */
692 x = (td.nsecs + 250) / 500; /* nanoseconds -> half-microseconds, rounded */
693 x += td.secs * 2000000; /* seconds -> half-microseconds */
695 if (!s48write(wdh, x, err)) /* pr.rx_time[i] */
698 if (!s32write(wdh, ++itmp->pkts, err)) /* pr.pktno */
700 if (!s16write(wdh, (guint16)itmp->lastlen, err)) /* pr.prlen */
704 if (!s0write(wdh, 12, err))
707 if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err))
710 wdh->bytes_dumped += thisSize;
715 /*---------------------------------------------------
716 * Returns 0 if we could write the specified encapsulation type,
717 * an error indication otherwise.
718 *---------------------------------------------------*/
719 int lanalyzer_dump_can_write_encap(int encap)
721 /* Per-packet encapsulations aren't supported. */
722 if (encap == WTAP_ENCAP_PER_PACKET)
723 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
725 if ( encap != WTAP_ENCAP_ETHERNET
726 && encap != WTAP_ENCAP_TOKEN_RING )
727 return WTAP_ERR_UNWRITABLE_ENCAP;
729 * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
734 /*---------------------------------------------------
735 * Returns TRUE on success, FALSE on failure; sets "*err" to an
736 * error code on failure
737 *---------------------------------------------------*/
738 gboolean lanalyzer_dump_open(wtap_dumper *wdh, int *err)
743 tmp = g_malloc(sizeof(LA_TmpInfo));
749 ((LA_TmpInfo*)tmp)->init = FALSE;
751 wdh->subtype_write = lanalyzer_dump;
752 wdh->subtype_finish = lanalyzer_dump_finish;
754 /* Some of the fields in the file header aren't known yet so
755 just skip over it for now. It will be created after all
756 of the packets have been written. */
758 jump = sizeof (LA_HeaderRegularFake)
759 + sizeof (LA_RxChannelNameFake)
760 + sizeof (LA_TxChannelNameFake)
761 + sizeof (LA_RxTemplateNameFake)
762 + sizeof (LA_TxTemplateNameFake)
763 + sizeof (LA_DisplayOptionsFake)
764 + LA_SummaryRecordSize
765 + LA_SubfileSummaryRecordSize
766 + sizeof (LA_CyclicInformationFake)
767 + LA_IndexRecordSize;
769 if (wtap_dump_file_seek(wdh, jump, SEEK_SET, err) == -1)
772 wdh->bytes_dumped = jump;
776 /*---------------------------------------------------
778 *---------------------------------------------------*/
779 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
781 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
782 guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
783 ? BOARD_325TR /* LANalyzer Board Type */
784 : BOARD_325; /* LANalyzer Board Type */
787 fT = localtime(&itmp->start.secs);
791 if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
794 if (!wtap_dump_file_write(wdh, &LA_HeaderRegularFake,
795 sizeof LA_HeaderRegularFake, err))
797 if (!wtap_dump_file_write(wdh, &LA_RxChannelNameFake,
798 sizeof LA_RxChannelNameFake, err))
800 if (!wtap_dump_file_write(wdh, &LA_TxChannelNameFake,
801 sizeof LA_TxChannelNameFake, err))
803 if (!wtap_dump_file_write(wdh, &LA_RxTemplateNameFake,
804 sizeof LA_RxTemplateNameFake, err))
806 if (!wtap_dump_file_write(wdh, &LA_TxTemplateNameFake,
807 sizeof LA_TxTemplateNameFake, err))
809 if (!wtap_dump_file_write(wdh, &LA_DisplayOptionsFake,
810 sizeof LA_DisplayOptionsFake, err))
812 /*-----------------------------------------------------------------*/
813 if (!s16write(wdh, RT_Summary, err)) /* rid */
815 if (!s16write(wdh, SummarySize, err)) /* rlen */
817 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datcre.day */
819 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datcre.mon */
821 if (!s16write(wdh, (guint16) (fT->tm_year + 1900), err)) /* s.datcre.year */
823 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datclo.day */
825 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datclo.mon */
827 if (!s16write(wdh, (guint16) (fT->tm_year + 1900), err)) /* s.datclo.year */
829 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeopn.second */
831 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeopn.minute */
833 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeopn.hour */
835 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeopn.mday */
837 if (!s0write(wdh, 2, err))
839 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeclo.second */
841 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeclo.minute */
843 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeclo.hour */
845 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeclo.mday */
847 if (!s0write(wdh, 2, err))
849 if (!s0write(wdh, 6, err)) /* EAddr == 0 */
851 if (!s16write(wdh, 1, err)) /* s.mxseqno */
853 if (!s16write(wdh, 0, err)) /* s.slcoffo */
855 if (!s16write(wdh, 1514, err)) /* s.mxslc */
857 if (!s32write(wdh, itmp->pkts, err)) /* s.totpktt */
864 if (!s0write(wdh, 12, err))
866 if (!s32write(wdh, itmp->pkts, err)) /* sr.s.mxpkta[1] */
868 if (!s0write(wdh, 34*4, err)) /* s.mxpkta[2-33]=0 */
870 if (!s16write(wdh, board_type, err))
872 if (!s0write(wdh, 20, err)) /* board_version == 0 */
874 /*-----------------------------------------------------------------*/
875 if (!s16write(wdh, RT_SubfileSummary, err)) /* ssr.rid */
877 if (!s16write(wdh, LA_SubfileSummaryRecordSize-4, err)) /* ssr.rlen */
879 if (!s16write(wdh, 1, err)) /* ssr.seqno */
881 if (!s32write(wdh, itmp->pkts, err)) /* ssr.totpkts */
883 /*-----------------------------------------------------------------*/
884 if (!wtap_dump_file_write(wdh, &LA_CyclicInformationFake,
885 sizeof LA_CyclicInformationFake, err))
887 /*-----------------------------------------------------------------*/
888 if (!s16write(wdh, RT_Index, err)) /* rid */
890 if (!s16write(wdh, LA_IndexRecordSize -4, err)) /* rlen */
892 if (!s16write(wdh, LA_IndexSize, err)) /* idxsp */
894 if (!s0write(wdh, LA_IndexRecordSize - 6, err))
900 /*---------------------------------------------------
901 * Finish writing to a dump file.
902 * Returns TRUE on success, FALSE on failure.
903 *---------------------------------------------------*/
904 static gboolean lanalyzer_dump_finish(wtap_dumper *wdh, int *err)
906 lanalyzer_dump_header(wdh,err);
907 return *err ? FALSE : TRUE;
911 * Editor modelines - http://www.wireshark.org/tools/modelines.html
916 * indent-tabs-mode: nil
919 * vi: set shiftwidth=6 tabstop=8 expandtab:
920 * :indentSize=6:tabSize=8:noTabs=true: