DCERPC: factor out proto_tree_add_dcerpc_drep()
[wireshark-wip.git] / wiretap / lanalyzer.c
blob4e7104c6d18f492a4462665016930d2ad68069cb
1 /* lanalyzer.c
3 * $Id$
5 * Wiretap Library
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.
23 #include "config.h"
24 #include <stdlib.h>
25 #include <errno.h>
26 #include "wtap-int.h"
27 #include "file_wrappers.h"
28 #include "buffer.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 */
39 typedef struct {
40 guint8 record_type[2];
41 guint8 record_length[2];
42 } LA_RecordHeader;
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.
74 * typedef struct {
75 * guint8 day;
76 * guint8 mon;
77 * gint16 year;
78 * } Date;
82 * typedef struct {
83 * guint8 second;
84 * guint8 minute;
85 * guint8 hour;
86 * guint8 day;
87 * gint16 reserved;
88 * } Time;
92 * RT_Summary:
94 * typedef struct {
95 * Date datcre;
96 * Date datclo;
97 * Time timeopn;
98 * Time timeclo;
99 * Eadr statadr;
100 * gint16 mxseqno;
101 * gint16 slcoff;
102 * gint16 mxslc;
103 * gint32 totpktt;
104 * gint32 statrg;
105 * gint32 stptrg;
106 * gint32 mxpkta[36];
107 * gint16 board_type;
108 * gint16 board_version;
109 * gint8 reserved[18];
110 * } Summary;
113 #define SummarySize (18+22+(4*36)+6+6+6+4+4)
116 * typedef struct {
117 * gint16 rid;
118 * gint16 rlen;
119 * Summary s;
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) */
132 * typedef struct {
133 * gint16 rid;
134 * gint16 rlen;
135 * gint16 seqno;
136 * gint32 totpktf;
137 * } LA_SubfileSummaryRecord;
140 #define LA_SubfileSummaryRecordSize 10
143 #define LA_IndexSize 500
146 * typedef struct {
147 * gint16 rid;
148 * gint16 rlen;
149 * gint16 idxsp; = LA_IndexSize
150 * gint16 idxct;
151 * gint8 idxgranu;
152 * gint8 idxvd;
153 * gint32 trcidx[LA_IndexSize + 2]; +2 undocumented but used by La 2.2
154 * } LA_IndexRecord;
157 #define LA_IndexRecordSize (10 + 4 * (LA_IndexSize + 2))
161 * typedef struct {
162 * guint16 rx_channels;
163 * guint16 rx_errors;
164 * gint16 rx_frm_len;
165 * gint16 rx_frm_sln;
166 * TimeStamp rx_time;
167 * guint32 pktno;
168 * gint16 prvlen;
169 * gint16 offset;
170 * gint16 tx_errs;
171 * gint16 rx_filters;
172 * gint8 unused[2];
173 * gint16 hwcolls;
174 * gint16 hwcollschans;
175 * Packetdata ....;
176 * } LA_PacketRecord;
179 #define LA_PacketRecordSize 32
181 typedef struct {
182 gboolean init;
183 struct timeval start;
184 guint32 pkts;
185 int encap;
186 int lastlen;
187 } LA_TmpInfo;
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,
206 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[] = {
217 0x35,0x10,
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,
227 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[] = {
238 0x0a,0x10,0x0a,0x01,
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
271 typedef struct {
272 time_t start;
273 } lanalyzer_t;
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 length,
279 int *err, gchar **err_info);
280 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err);
282 int lanalyzer_open(wtap *wth, int *err, gchar **err_info)
284 int bytes_read;
285 LA_RecordHeader rec_header;
286 char header_fixed[2];
287 char *comment;
288 char summary[210];
289 guint16 board_type, mxslc;
290 guint16 record_type, record_length;
291 guint8 cr_day, cr_month;
292 guint16 cr_year;
293 struct tm tm;
294 lanalyzer_t *lanalyzer;
296 errno = WTAP_ERR_CANT_READ;
297 bytes_read = file_read(&rec_header, LA_RecordHeaderSize, wth->fh);
298 if (bytes_read != LA_RecordHeaderSize) {
299 *err = file_error(wth->fh, err_info);
300 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
301 return -1;
302 return 0;
304 record_type = pletohs(rec_header.record_type);
305 record_length = pletohs(rec_header.record_length); /* make sure to do this for while() loop */
307 if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
308 return 0;
311 /* Read the major and minor version numbers */
312 if (record_length < 2) {
314 * Not enough room for the major and minor version numbers.
315 * Just treat that as a "not a LANalyzer file" indication.
317 return 0;
319 bytes_read = file_read(&header_fixed, sizeof header_fixed, wth->fh);
320 if (bytes_read != sizeof header_fixed) {
321 *err = file_error(wth->fh, err_info);
322 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
323 return -1;
324 return 0;
326 record_length -= sizeof header_fixed;
328 if (record_length != 0) {
329 /* Read the rest of the record as a comment. */
330 comment = (char *)g_malloc(record_length + 1);
331 bytes_read = file_read(comment, record_length, wth->fh);
332 if (bytes_read != record_length) {
333 *err = file_error(wth->fh, err_info);
334 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
335 return -1;
336 return 0;
338 comment[record_length] = '\0';
339 wth->shb_hdr.opt_comment = comment;
342 /* If we made it this far, then the file is a LANAlyzer file.
343 * Let's get some info from it. Note that we get wth->snapshot_length
344 * from a record later in the file. */
345 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LANALYZER;
346 lanalyzer = (lanalyzer_t *)g_malloc(sizeof(lanalyzer_t));
347 wth->priv = (void *)lanalyzer;
348 wth->subtype_read = lanalyzer_read;
349 wth->subtype_seek_read = lanalyzer_seek_read;
350 wth->snapshot_length = 0;
351 wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
353 /* Read records until we find the start of packets */
354 while (1) {
355 errno = WTAP_ERR_CANT_READ;
356 bytes_read = file_read(&rec_header, LA_RecordHeaderSize, wth->fh);
357 if (bytes_read != LA_RecordHeaderSize) {
358 *err = file_error(wth->fh, err_info);
359 if (*err == 0)
360 *err = WTAP_ERR_SHORT_READ;
361 return -1;
364 record_type = pletohs(rec_header.record_type);
365 record_length = pletohs(rec_header.record_length);
367 /*g_message("Record 0x%04X Length %d", record_type, record_length);*/
368 switch (record_type) {
369 /* Trace Summary Record */
370 case RT_Summary:
371 errno = WTAP_ERR_CANT_READ;
372 bytes_read = file_read(summary, sizeof summary,
373 wth->fh);
374 if (bytes_read != sizeof summary) {
375 *err = file_error(wth->fh, err_info);
376 if (*err == 0)
377 *err = WTAP_ERR_SHORT_READ;
378 return -1;
381 /* Assume that the date of the creation of the trace file
382 * is the same date of the trace. Lanalyzer doesn't
383 * store the creation date/time of the trace, but only of
384 * the file. Unless you traced at 11:55 PM and saved at 00:05
385 * AM, the assumption that trace.date == file.date is true.
387 cr_day = summary[0];
388 cr_month = summary[1];
389 cr_year = pletohs(&summary[2]);
390 /*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
391 cr_year, cr_year);*/
393 /* Get capture start time. I learned how to do
394 * this from Guy's code in ngsniffer.c
396 tm.tm_year = cr_year - 1900;
397 tm.tm_mon = cr_month - 1;
398 tm.tm_mday = cr_day;
399 tm.tm_hour = 0;
400 tm.tm_min = 0;
401 tm.tm_sec = 0;
402 tm.tm_isdst = -1;
403 lanalyzer->start = mktime(&tm);
404 /*g_message("Day %d Month %d Year %d", tm.tm_mday,
405 tm.tm_mon, tm.tm_year);*/
406 mxslc = pletohs(&summary[30]);
407 wth->snapshot_length = mxslc;
409 board_type = pletohs(&summary[188]);
410 switch (board_type) {
411 case BOARD_325:
412 wth->file_encap = WTAP_ENCAP_ETHERNET;
413 break;
414 case BOARD_325TR:
415 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
416 break;
417 default:
418 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
419 *err_info = g_strdup_printf("lanalyzer: board type %u unknown",
420 board_type);
421 return -1;
423 break;
425 /* Trace Packet Data Record */
426 case RT_PacketData:
427 /* Go back header number of bytes so that lanalyzer_read
428 * can read this header */
429 if (file_seek(wth->fh, -LA_RecordHeaderSize, SEEK_CUR, err) == -1) {
430 return -1;
432 return 1;
434 default:
435 if (file_seek(wth->fh, record_length, SEEK_CUR, err) == -1) {
436 return -1;
438 break;
443 #define DESCRIPTOR_LEN 32
445 static gboolean lanalyzer_read_trace_record(wtap *wth, FILE_T fh,
446 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
448 int bytes_read;
449 char LE_record_type[2];
450 char LE_record_length[2];
451 guint16 record_type, record_length;
452 int record_data_size;
453 int packet_size;
454 gchar descriptor[DESCRIPTOR_LEN];
455 lanalyzer_t *lanalyzer;
456 guint16 time_low, time_med, time_high, true_size;
457 guint64 t;
458 time_t tsecs;
460 /* read the record type and length. */
461 errno = WTAP_ERR_CANT_READ;
462 bytes_read = file_read(LE_record_type, 2, fh);
463 if (bytes_read != 2) {
464 *err = file_error(fh, err_info);
465 if (*err == 0 && bytes_read != 0) {
466 *err = WTAP_ERR_SHORT_READ;
468 return FALSE;
470 bytes_read = file_read(LE_record_length, 2, fh);
471 if (bytes_read != 2) {
472 *err = file_error(fh, err_info);
473 if (*err == 0)
474 *err = WTAP_ERR_SHORT_READ;
475 return FALSE;
478 record_type = pletohs(LE_record_type);
479 record_length = pletohs(LE_record_length);
481 /* Only Trace Packet Data Records should occur now that we're in
482 * the middle of reading packets. If any other record type exists
483 * after a Trace Packet Data Record, mark it as an error. */
484 if (record_type != RT_PacketData) {
485 *err = WTAP_ERR_BAD_FILE;
486 *err_info = g_strdup_printf("lanalyzer: record type %u seen after trace summary record",
487 record_type);
488 return FALSE;
491 if (record_length < DESCRIPTOR_LEN) {
493 * Uh-oh, the record isn't big enough to even have a
494 * descriptor.
496 *err = WTAP_ERR_BAD_FILE;
497 *err_info = g_strdup_printf("lanalyzer: file has a %u-byte record, too small to have even a packet descriptor",
498 record_length);
499 return FALSE;
501 record_data_size = record_length - DESCRIPTOR_LEN;
503 /* Read the descriptor data */
504 errno = WTAP_ERR_CANT_READ;
505 bytes_read = file_read(descriptor, DESCRIPTOR_LEN, fh);
506 if (bytes_read != DESCRIPTOR_LEN) {
507 *err = file_error(fh, err_info);
508 if (*err == 0)
509 *err = WTAP_ERR_SHORT_READ;
510 return FALSE;
513 true_size = pletohs(&descriptor[4]);
514 packet_size = pletohs(&descriptor[6]);
517 * OK, is the frame data size greater than than what's left of the
518 * record?
520 if (packet_size > record_data_size) {
522 * Yes - treat this as an error.
524 *err = WTAP_ERR_BAD_FILE;
525 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
526 return FALSE;
529 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
531 time_low = pletohs(&descriptor[8]);
532 time_med = pletohs(&descriptor[10]);
533 time_high = pletohs(&descriptor[12]);
534 t = (((guint64)time_low) << 0) + (((guint64)time_med) << 16) +
535 (((guint64)time_high) << 32);
536 tsecs = (time_t) (t/2000000);
537 lanalyzer = (lanalyzer_t *)wth->priv;
538 phdr->ts.secs = tsecs + lanalyzer->start;
539 phdr->ts.nsecs = ((guint32) (t - tsecs*2000000)) * 500;
541 if (true_size - 4 >= packet_size) {
543 * It appears that the "true size" includes the FCS;
544 * make it reflect the non-FCS size (the "packet size"
545 * appears never to include the FCS, even if no slicing
546 * is done).
548 true_size -= 4;
550 phdr->len = true_size;
551 phdr->caplen = packet_size;
553 switch (wth->file_encap) {
555 case WTAP_ENCAP_ETHERNET:
556 /* We assume there's no FCS in this frame. */
557 phdr->pseudo_header.eth.fcs_len = 0;
558 break;
561 /* Read the packet data */
562 return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
565 /* Read the next packet */
566 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
567 gint64 *data_offset)
569 *data_offset = file_tell(wth->fh);
571 /* Read the record */
572 return lanalyzer_read_trace_record(wth, wth->fh, &wth->phdr,
573 wth->frame_buffer, err, err_info);
576 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
577 struct wtap_pkthdr *phdr, Buffer *buf, int length _U_, int *err,
578 gchar **err_info)
580 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
581 return FALSE;
583 /* Read the record */
584 if (!lanalyzer_read_trace_record(wth, wth->random_fh, phdr, buf,
585 err, err_info)) {
586 if (*err == 0)
587 *err = WTAP_ERR_SHORT_READ;
588 return FALSE;
590 return TRUE;
593 /*---------------------------------------------------
594 * Returns TRUE on success, FALSE on error
595 * Write "cnt" bytes of zero with error control
596 *---------------------------------------------------*/
597 static gboolean s0write(wtap_dumper *wdh, size_t cnt, int *err)
599 size_t snack;
601 while (cnt) {
602 snack = cnt > 64 ? 64 : cnt;
604 if (!wtap_dump_file_write(wdh, z64, snack, err))
605 return FALSE;
606 cnt -= snack;
608 return TRUE; /* ok */
611 /*---------------------------------------------------
612 * Returns TRUE on success, FALSE on error
613 * Write an 8-bit value with error control
614 *---------------------------------------------------*/
615 static gboolean s8write(wtap_dumper *wdh, const guint8 s8, int *err)
617 return wtap_dump_file_write(wdh, &s8, 1, err);
619 /*---------------------------------------------------
620 * Returns TRUE on success, FALSE on error
621 * Write a 16-bit value with error control
622 *---------------------------------------------------*/
623 static gboolean s16write(wtap_dumper *wdh, const guint16 s16, int *err)
625 return wtap_dump_file_write(wdh, &s16, 2, err);
627 /*---------------------------------------------------
628 * Returns TRUE on success, FALSE on error
629 * Write a 32-bit value with error control
630 *---------------------------------------------------*/
631 static gboolean s32write(wtap_dumper *wdh, const guint32 s32, int *err)
633 return wtap_dump_file_write(wdh, &s32, 4, err);
635 /*---------------------------------------------------
637 * calculates C.c = A.a - B.b
638 *---------------------------------------------------*/
639 static void my_timersub(const struct timeval *a,
640 const struct timeval *b,
641 struct timeval *c)
643 gint32 usec = (gint32)a->tv_usec;
645 c->tv_sec = a->tv_sec - b->tv_sec;
646 if (b->tv_usec > usec) {
647 c->tv_sec--;
648 usec += 1000000;
650 c->tv_usec = usec - b->tv_usec;
652 /*---------------------------------------------------
653 * Write a record for a packet to a dump file.
654 * Returns TRUE on success, FALSE on failure.
655 *---------------------------------------------------*/
656 static gboolean lanalyzer_dump(wtap_dumper *wdh,
657 const struct wtap_pkthdr *phdr,
658 const guint8 *pd, int *err)
660 double x;
661 int i;
662 int len;
663 struct timeval tv;
665 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
666 struct timeval td;
667 int thisSize = phdr->caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
669 if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
670 /* printf(" LA_ProFileLimit reached\n"); */
671 *err = EFBIG;
672 return FALSE; /* and don't forget the header */
675 len = phdr->caplen + (phdr->caplen ? LA_PacketRecordSize : 0);
677 if (!s16write(wdh, htoles(0x1005), err))
678 return FALSE;
679 if (!s16write(wdh, htoles(len), err))
680 return FALSE;
682 tv.tv_sec = (long int) phdr->ts.secs;
683 tv.tv_usec = phdr->ts.nsecs / 1000;
685 if (!itmp->init) {
686 /* collect some information for the
687 * finally written header
689 /* XXX - this conversion could probably improved, if the start uses ns */
690 itmp->start = tv;
691 itmp->pkts = 0;
692 itmp->init = TRUE;
693 itmp->encap = wdh->encap;
694 itmp->lastlen = 0;
697 my_timersub(&(tv),&(itmp->start),&td);
699 x = (double) td.tv_usec;
700 x += (double) td.tv_sec * 1000000;
701 x *= 2;
703 if (!s16write(wdh, htoles(0x0001), err)) /* pr.rx_channels */
704 return FALSE;
705 if (!s16write(wdh, htoles(0x0008), err)) /* pr.rx_errors */
706 return FALSE;
707 if (!s16write(wdh, htoles(phdr->len + 4), err)) /* pr.rx_frm_len */
708 return FALSE;
709 if (!s16write(wdh, htoles(phdr->caplen), err)) /* pr.rx_frm_sln */
710 return FALSE;
712 for (i = 0; i < 3; i++) {
713 if (!s16write(wdh, htoles((guint16) x), err)) /* pr.rx_time[i] */
714 return FALSE;
715 x /= 0xffff;
718 if (!s32write(wdh, htolel(++itmp->pkts), err)) /* pr.pktno */
719 return FALSE;
720 if (!s16write(wdh, htoles(itmp->lastlen), err)) /* pr.prlen */
721 return FALSE;
722 itmp->lastlen = len;
724 if (!s0write(wdh, 12, err))
725 return FALSE;
727 if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
728 return FALSE;
730 wdh->bytes_dumped += thisSize;
732 return TRUE;
735 /*---------------------------------------------------
736 * Returns 0 if we could write the specified encapsulation type,
737 * an error indication otherwise.
738 *---------------------------------------------------*/
739 int lanalyzer_dump_can_write_encap(int encap)
741 /* Per-packet encapsulations aren't supported. */
742 if (encap == WTAP_ENCAP_PER_PACKET)
743 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
745 if ( encap != WTAP_ENCAP_ETHERNET
746 && encap != WTAP_ENCAP_TOKEN_RING )
747 return WTAP_ERR_UNSUPPORTED_ENCAP;
749 * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
751 return 0;
754 /*---------------------------------------------------
755 * Returns TRUE on success, FALSE on failure; sets "*err" to an
756 * error code on failure
757 *---------------------------------------------------*/
758 gboolean lanalyzer_dump_open(wtap_dumper *wdh, int *err)
760 int jump;
761 void *tmp;
763 tmp = g_malloc(sizeof(LA_TmpInfo));
764 if (!tmp) {
765 *err = errno;
766 return FALSE;
769 ((LA_TmpInfo*)tmp)->init = FALSE;
770 wdh->priv = tmp;
771 wdh->subtype_write = lanalyzer_dump;
772 wdh->subtype_close = lanalyzer_dump_close;
774 /* Some of the fields in the file header aren't known yet so
775 just skip over it for now. It will be created after all
776 of the packets have been written. */
778 jump = sizeof (LA_HeaderRegularFake)
779 + sizeof (LA_RxChannelNameFake)
780 + sizeof (LA_TxChannelNameFake)
781 + sizeof (LA_RxTemplateNameFake)
782 + sizeof (LA_TxTemplateNameFake)
783 + sizeof (LA_DisplayOptionsFake)
784 + LA_SummaryRecordSize
785 + LA_SubfileSummaryRecordSize
786 + sizeof (LA_CyclicInformationFake)
787 + LA_IndexRecordSize;
789 if (wtap_dump_file_seek(wdh, jump, SEEK_SET, err) == -1)
790 return FALSE;
792 wdh->bytes_dumped = jump;
793 return TRUE;
796 /*---------------------------------------------------
798 *---------------------------------------------------*/
799 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
801 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
802 guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
803 ? BOARD_325TR /* LANalyzer Board Type */
804 : BOARD_325; /* LANalyzer Board Type */
805 time_t secs;
806 struct tm *fT;
808 /* The secs variable is needed to work around 32/64-bit time_t issues.
809 itmp->start is a timeval struct, which declares its tv_sec field
810 (itmp->start.tv_sec) as a long (typically 32 bits). time_t can be 32
811 or 64 bits, depending on the platform. Invoking as follows could
812 pass a pointer to a 32-bit long where a pointer to a 64-bit time_t
813 is expected: localtime((time_t*) &(itmp->start.tv_sec)) */
814 secs = itmp->start.tv_sec;
815 fT = localtime(&secs);
816 if (fT == NULL)
817 return FALSE;
819 if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
820 return FALSE;
822 if (!wtap_dump_file_write(wdh, &LA_HeaderRegularFake,
823 sizeof LA_HeaderRegularFake, err))
824 return FALSE;
825 if (!wtap_dump_file_write(wdh, &LA_RxChannelNameFake,
826 sizeof LA_RxChannelNameFake, err))
827 return FALSE;
828 if (!wtap_dump_file_write(wdh, &LA_TxChannelNameFake,
829 sizeof LA_TxChannelNameFake, err))
830 return FALSE;
831 if (!wtap_dump_file_write(wdh, &LA_RxTemplateNameFake,
832 sizeof LA_RxTemplateNameFake, err))
833 return FALSE;
834 if (!wtap_dump_file_write(wdh, &LA_TxTemplateNameFake,
835 sizeof LA_TxTemplateNameFake, err))
836 return FALSE;
837 if (!wtap_dump_file_write(wdh, &LA_DisplayOptionsFake,
838 sizeof LA_DisplayOptionsFake, err))
839 return FALSE;
840 /*-----------------------------------------------------------------*/
841 if (!s16write(wdh, htoles(RT_Summary), err)) /* rid */
842 return FALSE;
843 if (!s16write(wdh, htoles(SummarySize), err)) /* rlen */
844 return FALSE;
845 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datcre.day */
846 return FALSE;
847 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datcre.mon */
848 return FALSE;
849 if (!s16write(wdh, htoles(fT->tm_year + 1900), err)) /* s.datcre.year */
850 return FALSE;
851 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.datclo.day */
852 return FALSE;
853 if (!s8write(wdh, (guint8) (fT->tm_mon+1), err)) /* s.datclo.mon */
854 return FALSE;
855 if (!s16write(wdh, htoles(fT->tm_year + 1900), err)) /* s.datclo.year */
856 return FALSE;
857 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeopn.second */
858 return FALSE;
859 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeopn.minute */
860 return FALSE;
861 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeopn.hour */
862 return FALSE;
863 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeopn.mday */
864 return FALSE;
865 if (!s0write(wdh, 2, err))
866 return FALSE;
867 if (!s8write(wdh, (guint8) fT->tm_sec, err)) /* s.timeclo.second */
868 return FALSE;
869 if (!s8write(wdh, (guint8) fT->tm_min, err)) /* s.timeclo.minute */
870 return FALSE;
871 if (!s8write(wdh, (guint8) fT->tm_hour, err)) /* s.timeclo.hour */
872 return FALSE;
873 if (!s8write(wdh, (guint8) fT->tm_mday, err)) /* s.timeclo.mday */
874 return FALSE;
875 if (!s0write(wdh, 2, err))
876 return FALSE;
877 if (!s0write(wdh, 6, err)) /* EAddr == 0 */
878 return FALSE;
879 if (!s16write(wdh, htoles(1), err)) /* s.mxseqno */
880 return FALSE;
881 if (!s16write(wdh, htoles(0), err)) /* s.slcoffo */
882 return FALSE;
883 if (!s16write(wdh, htoles(1514), err)) /* s.mxslc */
884 return FALSE;
885 if (!s32write(wdh, htolel(itmp->pkts), err)) /* s.totpktt */
886 return FALSE;
888 * statrg == 0; ? -1
889 * stptrg == 0; ? -1
890 * s.mxpkta[0]=0
892 if (!s0write(wdh, 12, err))
893 return FALSE;
894 if (!s32write(wdh, htolel(itmp->pkts), err)) /* sr.s.mxpkta[1] */
895 return FALSE;
896 if (!s0write(wdh, 34*4, err)) /* s.mxpkta[2-33]=0 */
897 return FALSE;
898 if (!s16write(wdh, htoles(board_type), err))
899 return FALSE;
900 if (!s0write(wdh, 20, err)) /* board_version == 0 */
901 return FALSE;
902 /*-----------------------------------------------------------------*/
903 if (!s16write(wdh, htoles(RT_SubfileSummary), err)) /* ssr.rid */
904 return FALSE;
905 if (!s16write(wdh, htoles(LA_SubfileSummaryRecordSize-4), err)) /* ssr.rlen */
906 return FALSE;
907 if (!s16write(wdh, htoles(1), err)) /* ssr.seqno */
908 return FALSE;
909 if (!s32write(wdh, htolel(itmp->pkts), err)) /* ssr.totpkts */
910 return FALSE;
911 /*-----------------------------------------------------------------*/
912 if (!wtap_dump_file_write(wdh, &LA_CyclicInformationFake,
913 sizeof LA_CyclicInformationFake, err))
914 return FALSE;
915 /*-----------------------------------------------------------------*/
916 if (!s16write(wdh, htoles(RT_Index), err)) /* rid */
917 return FALSE;
918 if (!s16write(wdh, htoles(LA_IndexRecordSize -4), err)) /* rlen */
919 return FALSE;
920 if (!s16write(wdh, htoles(LA_IndexSize), err)) /* idxsp */
921 return FALSE;
922 if (!s0write(wdh, LA_IndexRecordSize - 6, err))
923 return FALSE;
925 return TRUE;
928 /*---------------------------------------------------
929 * Finish writing to a dump file.
930 * Returns TRUE on success, FALSE on failure.
931 *---------------------------------------------------*/
932 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err)
934 lanalyzer_dump_header(wdh,err);
935 return *err ? FALSE : TRUE;