Revert "UNUSED enc_key_id_{equal,hash}"
[wireshark-sm.git] / wiretap / lanalyzer.c
blob97b19b0538b82a7e318772e9404db530c61a8411
1 /* lanalyzer.c
3 * Wiretap Library
4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
9 #include "config.h"
11 #define WS_LOG_DOMAIN LOG_DOMAIN_WIRETAP
12 #include "lanalyzer.h"
14 #include <stdlib.h>
15 #include <errno.h>
16 #include "wtap-int.h"
17 #include "file_wrappers.h"
19 /* The LANalyzer format is documented (at least in part) in Novell document
20 TID022037, which can be found at, among other places:
22 http://www.blacksheepnetworks.com/security/info/nw/lan/trace.txt
25 /* Record header format */
27 typedef struct {
28 uint8_t record_type[2];
29 uint8_t record_length[2];
30 } LA_RecordHeader;
32 #define LA_RecordHeaderSize 4
34 /* Record type codes: */
36 #define RT_HeaderRegular 0x1001
37 #define RT_HeaderCyclic 0x1007
38 #define RT_RxChannelName 0x1006
39 #define RT_TxChannelName 0x100b
40 #define RT_FilterName 0x1032
41 #define RT_RxTemplateName 0x1035
42 #define RT_TxTemplateName 0x1036
43 #define RT_DisplayOptions 0x100a
44 #define RT_Summary 0x1002
45 #define RT_SubfileSummary 0x1003
46 #define RT_CyclicInformation 0x1009
47 #define RT_Index 0x1004
48 #define RT_PacketData 0x1005
50 #define LA_ProFileLimit (1024 * 1024 * 32)
52 typedef uint8_t Eadr[6];
53 typedef uint16_t TimeStamp[3]; /* 0.5 microseconds since start of trace */
56 * These records have only 2-byte alignment for 4-byte quantities,
57 * so the structures aren't necessarily valid; they're kept as comments
58 * for reference purposes.
62 * typedef struct {
63 * uint8_t day;
64 * uint8_t mon;
65 * int16_t year;
66 * } Date;
70 * typedef struct {
71 * uint8_t second;
72 * uint8_t minute;
73 * uint8_t hour;
74 * uint8_t day;
75 * int16_t reserved;
76 * } Time;
80 * RT_Summary:
82 * typedef struct {
83 * Date datcre;
84 * Date datclo;
85 * Time timeopn;
86 * Time timeclo;
87 * Eadr statadr;
88 * int16_t mxseqno;
89 * int16_t slcoff;
90 * int16_t mxslc;
91 * int32_t totpktt;
92 * int32_t statrg;
93 * int32_t stptrg;
94 * int32_t mxpkta[36];
95 * int16_t board_type;
96 * int16_t board_version;
97 * int8_t reserved[18];
98 * } Summary;
101 #define SummarySize (18+22+(4*36)+6+6+6+4+4)
104 * typedef struct {
105 * int16_t rid;
106 * int16_t rlen;
107 * Summary s;
108 * } LA_SummaryRecord;
111 #define LA_SummaryRecordSize (SummarySize + 4)
113 /* LANalyzer board types (which indicate the type of network on which
114 the capture was done). */
115 #define BOARD_325 226 /* LANalyzer 325 (Ethernet) */
116 #define BOARD_325TR 227 /* LANalyzer 325TR (Token-ring) */
120 * typedef struct {
121 * int16_t rid;
122 * int16_t rlen;
123 * int16_t seqno;
124 * int32_t totpktf;
125 * } LA_SubfileSummaryRecord;
128 #define LA_SubfileSummaryRecordSize 10
131 #define LA_IndexSize 500
134 * typedef struct {
135 * int16_t rid;
136 * int16_t rlen;
137 * int16_t idxsp; = LA_IndexSize
138 * int16_t idxct;
139 * int8_t idxgranu;
140 * int8_t idxvd;
141 * int32_t trcidx[LA_IndexSize + 2]; +2 undocumented but used by La 2.2
142 * } LA_IndexRecord;
145 #define LA_IndexRecordSize (10 + 4 * (LA_IndexSize + 2))
149 * typedef struct {
150 * uint16_t rx_channels;
151 * uint16_t rx_errors;
152 * int16_t rx_frm_len;
153 * int16_t rx_frm_sln;
154 * TimeStamp rx_time;
155 * uint32_t pktno;
156 * int16_t prvlen;
157 * int16_t offset;
158 * int16_t tx_errs;
159 * int16_t rx_filters;
160 * int8_t unused[2];
161 * int16_t hwcolls;
162 * int16_t hwcollschans;
163 * Packetdata ....;
164 * } LA_PacketRecord;
167 #define LA_PacketRecordSize 32
169 typedef struct {
170 bool init;
171 nstime_t start;
172 uint32_t pkts;
173 int encap;
174 int lastlen;
175 } LA_TmpInfo;
177 static const uint8_t LA_HeaderRegularFake[] = {
178 0x01,0x10,0x4c,0x00,0x01,0x05,0x54,0x72,0x61,0x63,0x65,0x20,0x44,0x69,0x73,0x70,
179 0x6c,0x61,0x79,0x20,0x54,0x72,0x61,0x63,0x65,0x20,0x46,0x69,0x6c,0x65,0x00,0x00,
180 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
181 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
182 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
185 static const uint8_t LA_RxChannelNameFake[] = {
186 0x06,0x10,0x80,0x00,0x43,0x68,0x61,0x6e ,0x6e,0x65,0x6c,0x31,0x00,0x43,0x68,0x61,
187 0x6e,0x6e,0x65,0x6c,0x32,0x00,0x43,0x68 ,0x61,0x6e,0x6e,0x65,0x6c,0x33,0x00,0x43,
188 0x68,0x61,0x6e,0x6e,0x65,0x6c,0x34,0x00 ,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x35,
189 0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c ,0x36,0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,
190 0x6c,0x37,0x00,0x43,0x68,0x61,0x6e,0x6e ,0x65,0x6c,0x38,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,
193 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
194 0x00,0x00,0x00,0x00
197 static const uint8_t LA_TxChannelNameFake[] = {
198 0x0b,0x10,0x36,0x00 ,0x54,0x72,0x61,0x6e,0x73,0x31,0x00,0x00,
199 0x00,0x54,0x72,0x61,0x6e,0x73,0x32,0x00 ,0x00,0x00,0x54,0x72,0x61,0x6e,0x73,0x33,
200 0x00,0x00,0x00,0x54,0x72,0x61,0x6e,0x73 ,0x34,0x00,0x00,0x00,0x54,0x72,0x61,0x6e,
201 0x73,0x35,0x00,0x00,0x00,0x54,0x72,0x61 ,0x6e,0x73,0x36,0x00,0x00,0x00
204 static const uint8_t LA_RxTemplateNameFake[] = {
205 0x35,0x10,
206 0x90,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,
213 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
214 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
215 0x00,0x00
218 static const uint8_t LA_TxTemplateNameFake[] = {
219 0x36,0x10,0x36,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
225 static const uint8_t LA_DisplayOptionsFake[] = {
226 0x0a,0x10,0x0a,0x01,
227 0x00,0x00,0x01,0x00,0x01,0x02,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,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
246 static const uint8_t LA_CyclicInformationFake[] = {
247 0x09,0x10,0x1a,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
252 static const uint8_t z64[64] = {
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,0x00,0x00,0x00,0x00,0x00,0x00,
256 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
259 typedef struct {
260 time_t start;
261 } lanalyzer_t;
263 static bool lanalyzer_read(wtap *wth, wtap_rec *rec,
264 Buffer *buf, int *err, char **err_info, int64_t *data_offset);
265 static bool lanalyzer_seek_read(wtap *wth, int64_t seek_off,
266 wtap_rec *rec, Buffer *buf, int *err, char **err_info);
267 static bool lanalyzer_dump_finish(wtap_dumper *wdh, int *err,
268 char **err_info);
270 static int lanalyzer_file_type_subtype = -1;
272 void register_lanalyzer(void);
274 wtap_open_return_val lanalyzer_open(wtap *wth, int *err, char **err_info)
276 LA_RecordHeader rec_header;
277 char header_fixed[2];
278 char *comment;
279 bool found_summary;
280 char summary[210];
281 uint16_t board_type, mxslc;
282 uint16_t record_type, record_length;
283 uint8_t cr_day, cr_month;
284 uint16_t cr_year;
285 struct tm tm;
286 time_t start;
287 int file_encap;
288 lanalyzer_t *lanalyzer;
290 if (!wtap_read_bytes(wth->fh, &rec_header, LA_RecordHeaderSize,
291 err, err_info)) {
292 if (*err != WTAP_ERR_SHORT_READ)
293 return WTAP_OPEN_ERROR;
294 return WTAP_OPEN_NOT_MINE;
296 record_type = pletoh16(rec_header.record_type);
297 record_length = pletoh16(rec_header.record_length); /* make sure to do this for while() loop */
299 if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
300 return WTAP_OPEN_NOT_MINE;
303 /* Read the major and minor version numbers */
304 if (record_length < sizeof header_fixed) {
306 * Not enough room for the major and minor version numbers.
307 * Just treat that as a "not a LANalyzer file" indication.
309 return WTAP_OPEN_NOT_MINE;
311 if (!wtap_read_bytes(wth->fh, &header_fixed, sizeof header_fixed,
312 err, err_info)) {
313 if (*err != WTAP_ERR_SHORT_READ)
314 return WTAP_OPEN_ERROR;
315 return WTAP_OPEN_NOT_MINE;
317 record_length -= sizeof header_fixed;
319 if (record_length != 0) {
320 /* Read the rest of the record as a comment. */
321 comment = (char *)g_malloc(record_length + 1);
322 if (!wtap_read_bytes(wth->fh, comment, record_length,
323 err, err_info)) {
324 if (*err != WTAP_ERR_SHORT_READ) {
325 g_free(comment);
326 return WTAP_OPEN_ERROR;
328 g_free(comment);
329 return WTAP_OPEN_NOT_MINE;
331 wtap_block_add_string_option(g_array_index(wth->shb_hdrs, wtap_block_t, 0), OPT_COMMENT, comment, record_length);
332 g_free(comment);
336 * Read records until we find the start of packets.
337 * The document cited above claims that the first 11 records are
338 * in a particular sequence of types, but at least one capture
339 * doesn't have all the types listed in the order listed.
341 * If we don't have a summary record, we don't know the link-layer
342 * header type, so we can't read the file.
344 found_summary = false;
345 while (1) {
346 if (!wtap_read_bytes_or_eof(wth->fh, &rec_header,
347 LA_RecordHeaderSize, err, err_info)) {
348 if (*err == 0) {
350 * End of file and no packets;
351 * accept this file.
353 break;
355 return WTAP_OPEN_ERROR;
358 record_type = pletoh16(rec_header.record_type);
359 record_length = pletoh16(rec_header.record_length);
361 /*ws_message("Record 0x%04X Length %d", record_type, record_length);*/
362 switch (record_type) {
363 /* Trace Summary Record */
364 case RT_Summary:
365 if (record_length < sizeof summary) {
366 *err = WTAP_ERR_BAD_FILE;
367 *err_info = ws_strdup_printf("lanalyzer: summary record length %u is too short",
368 record_length);
369 return WTAP_OPEN_ERROR;
371 if (!wtap_read_bytes(wth->fh, summary,
372 sizeof summary, err, err_info))
373 return WTAP_OPEN_ERROR;
375 /* Assume that the date of the creation of the trace file
376 * is the same date of the trace. Lanalyzer doesn't
377 * store the creation date/time of the trace, but only of
378 * the file. Unless you traced at 11:55 PM and saved at 00:05
379 * AM, the assumption that trace.date == file.date is true.
381 cr_day = summary[0];
382 cr_month = summary[1];
383 cr_year = pletoh16(&summary[2]);
384 /*ws_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
385 cr_year, cr_year);*/
387 /* Get capture start time. I learned how to do
388 * this from Guy's code in ngsniffer.c
390 tm.tm_year = cr_year - 1900;
391 tm.tm_mon = cr_month - 1;
392 tm.tm_mday = cr_day;
393 tm.tm_hour = 0;
394 tm.tm_min = 0;
395 tm.tm_sec = 0;
396 tm.tm_isdst = -1;
397 start = mktime(&tm);
398 /*ws_message("Day %d Month %d Year %d", tm.tm_mday,
399 tm.tm_mon, tm.tm_year);*/
400 mxslc = pletoh16(&summary[30]);
402 board_type = pletoh16(&summary[188]);
403 switch (board_type) {
404 case BOARD_325:
405 file_encap = WTAP_ENCAP_ETHERNET;
406 break;
407 case BOARD_325TR:
408 file_encap = WTAP_ENCAP_TOKEN_RING;
409 break;
410 default:
411 *err = WTAP_ERR_UNSUPPORTED;
412 *err_info = ws_strdup_printf("lanalyzer: board type %u unknown",
413 board_type);
414 return WTAP_OPEN_ERROR;
417 if (found_summary) {
418 *err = WTAP_ERR_BAD_FILE;
419 *err_info = ws_strdup_printf("lanalyzer: file has more than one summary record");
420 return WTAP_OPEN_ERROR;
422 found_summary = true;
424 /* Skip the rest of the record */
425 record_length -= sizeof summary;
426 if (record_length != 0) {
427 if (!wtap_read_bytes(wth->fh, NULL, record_length, err, err_info)) {
428 return WTAP_OPEN_ERROR;
431 break;
433 /* Trace Packet Data Record */
434 case RT_PacketData:
435 /* Go back header number of bytes so that lanalyzer_read
436 * can read this header */
437 if (file_seek(wth->fh, -LA_RecordHeaderSize, SEEK_CUR, err) == -1) {
438 return WTAP_OPEN_ERROR;
440 goto done;
442 default:
443 /* Unknown record type - skip it */
444 if (!wtap_read_bytes(wth->fh, NULL, record_length, err, err_info)) {
445 return WTAP_OPEN_ERROR;
447 break;
451 done:
452 if (!found_summary) {
453 *err = WTAP_ERR_BAD_FILE;
454 *err_info = ws_strdup_printf("lanalyzer: file has no summary record");
455 return WTAP_OPEN_ERROR;
458 /* If we made it this far, then the file is a readable LANAlyzer file.
459 * Let's get some info from it. Note that we get wth->snapshot_length
460 * from a record later in the file. */
461 wth->file_type_subtype = lanalyzer_file_type_subtype;
462 lanalyzer = g_new(lanalyzer_t, 1);
463 lanalyzer->start = start;
464 wth->priv = (void *)lanalyzer;
465 wth->subtype_read = lanalyzer_read;
466 wth->subtype_seek_read = lanalyzer_seek_read;
467 wth->file_encap = file_encap;
468 wth->snapshot_length = mxslc;
469 wth->file_tsprec = WTAP_TSPREC_NSEC;
472 * Add an IDB; we don't know how many interfaces were involved,
473 * so we just say one interface, about which we only know
474 * the link-layer type, snapshot length, and time stamp
475 * resolution.
477 wtap_add_generated_idb(wth);
479 return WTAP_OPEN_MINE;
482 #define DESCRIPTOR_LEN 32
484 static bool lanalyzer_read_trace_record(wtap *wth, FILE_T fh,
485 wtap_rec *rec, Buffer *buf, int *err, char **err_info)
487 char LE_record_type[2];
488 char LE_record_length[2];
489 uint16_t record_type, record_length;
490 int record_data_size;
491 int packet_size;
492 char descriptor[DESCRIPTOR_LEN];
493 lanalyzer_t *lanalyzer;
494 uint16_t time_low, time_med, time_high, true_size;
495 uint64_t t;
496 time_t tsecs;
498 /* read the record type and length. */
499 if (!wtap_read_bytes_or_eof(fh, LE_record_type, 2, err, err_info))
500 return false;
501 if (!wtap_read_bytes(fh, LE_record_length, 2, err, err_info))
502 return false;
504 record_type = pletoh16(LE_record_type);
505 record_length = pletoh16(LE_record_length);
507 /* Only Trace Packet Data Records should occur now that we're in
508 * the middle of reading packets. If any other record type exists
509 * after a Trace Packet Data Record, mark it as an error. */
510 if (record_type != RT_PacketData) {
511 *err = WTAP_ERR_BAD_FILE;
512 *err_info = ws_strdup_printf("lanalyzer: record type %u seen after trace summary record",
513 record_type);
514 return false;
517 if (record_length < DESCRIPTOR_LEN) {
519 * Uh-oh, the record isn't big enough to even have a
520 * descriptor.
522 *err = WTAP_ERR_BAD_FILE;
523 *err_info = ws_strdup_printf("lanalyzer: file has a %u-byte record, too small to have even a packet descriptor",
524 record_length);
525 return false;
527 record_data_size = record_length - DESCRIPTOR_LEN;
529 /* Read the descriptor data */
530 if (!wtap_read_bytes(fh, descriptor, DESCRIPTOR_LEN, err, err_info))
531 return false;
533 true_size = pletoh16(&descriptor[4]);
534 packet_size = pletoh16(&descriptor[6]);
536 * The maximum value of packet_size is 65535, which is less than
537 * WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check
538 * it.
542 * OK, is the frame data size greater than what's left of the
543 * record?
545 if (packet_size > record_data_size) {
547 * Yes - treat this as an error.
549 *err = WTAP_ERR_BAD_FILE;
550 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
551 return false;
554 rec->rec_type = REC_TYPE_PACKET;
555 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
556 rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
558 time_low = pletoh16(&descriptor[8]);
559 time_med = pletoh16(&descriptor[10]);
560 time_high = pletoh16(&descriptor[12]);
561 t = (((uint64_t)time_low) << 0) + (((uint64_t)time_med) << 16) +
562 (((uint64_t)time_high) << 32);
563 tsecs = (time_t) (t/2000000);
564 lanalyzer = (lanalyzer_t *)wth->priv;
565 rec->ts.secs = tsecs + lanalyzer->start;
566 rec->ts.nsecs = ((uint32_t) (t - tsecs*2000000)) * 500;
568 if (true_size - 4 >= packet_size) {
570 * It appears that the "true size" includes the FCS;
571 * make it reflect the non-FCS size (the "packet size"
572 * appears never to include the FCS, even if no slicing
573 * is done).
575 true_size -= 4;
577 rec->rec_header.packet_header.len = true_size;
578 rec->rec_header.packet_header.caplen = packet_size;
580 switch (wth->file_encap) {
582 case WTAP_ENCAP_ETHERNET:
583 /* We assume there's no FCS in this frame. */
584 rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0;
585 break;
588 /* Read the packet data */
589 return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
592 /* Read the next packet */
593 static bool lanalyzer_read(wtap *wth, wtap_rec *rec, Buffer *buf,
594 int *err, char **err_info, int64_t *data_offset)
596 *data_offset = file_tell(wth->fh);
598 /* Read the record */
599 return lanalyzer_read_trace_record(wth, wth->fh, rec, buf, err,
600 err_info);
603 static bool lanalyzer_seek_read(wtap *wth, int64_t seek_off,
604 wtap_rec *rec, Buffer *buf, int *err, char **err_info)
606 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
607 return false;
609 /* Read the record */
610 if (!lanalyzer_read_trace_record(wth, wth->random_fh, rec, buf,
611 err, err_info)) {
612 if (*err == 0)
613 *err = WTAP_ERR_SHORT_READ;
614 return false;
616 return true;
619 /*---------------------------------------------------
620 * Returns true on success, false on error
621 * Write "cnt" bytes of zero with error control
622 *---------------------------------------------------*/
623 static bool s0write(wtap_dumper *wdh, size_t cnt, int *err)
625 size_t snack;
627 while (cnt) {
628 snack = cnt > 64 ? 64 : cnt;
630 if (!wtap_dump_file_write(wdh, z64, snack, err))
631 return false;
632 cnt -= snack;
634 return true; /* ok */
637 /*---------------------------------------------------
638 * Returns true on success, false on error
639 * Write an 8-bit value
640 *---------------------------------------------------*/
641 static bool s8write(wtap_dumper *wdh, const uint8_t s8, int *err)
643 return wtap_dump_file_write(wdh, &s8, 1, err);
645 /*---------------------------------------------------
646 * Returns true on success, false on error
647 * Write a 16-bit value as little-endian
648 *---------------------------------------------------*/
649 static bool s16write(wtap_dumper *wdh, const uint16_t s16, int *err)
651 uint16_t s16_le = GUINT16_TO_LE(s16);
652 return wtap_dump_file_write(wdh, &s16_le, 2, err);
654 /*---------------------------------------------------
655 * Returns true on success, false on error
656 * Write a 32-bit value as little-endian
657 *---------------------------------------------------*/
658 static bool s32write(wtap_dumper *wdh, const uint32_t s32, int *err)
660 uint32_t s32_le = GUINT32_TO_LE(s32);
661 return wtap_dump_file_write(wdh, &s32_le, 4, err);
663 /*---------------------------------------------------
664 * Returns true on success, false on error
665 * Write a 48-bit value as little-endian
666 *---------------------------------------------------*/
667 static bool s48write(wtap_dumper *wdh, const uint64_t s48, int *err)
669 #if G_BYTE_ORDER == G_BIG_ENDIAN
670 uint16_t s48_upper_le = GUINT16_SWAP_LE_BE((uint16_t) (s48 >> 32));
671 uint32_t s48_lower_le = GUINT32_SWAP_LE_BE((uint32_t) (s48 & 0xFFFFFFFF));
672 #else
673 uint16_t s48_upper_le = (uint16_t) (s48 >> 32);
674 uint32_t s48_lower_le = (uint32_t) (s48 & 0xFFFFFFFF);
675 #endif
676 return wtap_dump_file_write(wdh, &s48_lower_le, 4, err) &&
677 wtap_dump_file_write(wdh, &s48_upper_le, 2, err);
679 /*---------------------------------------------------
680 * Write a record for a packet to a dump file.
681 * Returns true on success, false on failure.
682 *---------------------------------------------------*/
683 static bool lanalyzer_dump(wtap_dumper *wdh,
684 const wtap_rec *rec,
685 const uint8_t *pd, int *err, char **err_info _U_)
687 uint64_t x;
688 int len;
690 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
691 nstime_t td;
692 int thisSize = rec->rec_header.packet_header.caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
694 /* We can only write packet records. */
695 if (rec->rec_type != REC_TYPE_PACKET) {
696 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
697 return false;
701 * Make sure this packet doesn't have a link-layer type that
702 * differs from the one for the file.
704 if (wdh->file_encap != rec->rec_header.packet_header.pkt_encap) {
705 *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
706 return false;
709 if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
710 /* printf(" LA_ProFileLimit reached\n"); */
711 *err = EFBIG;
712 return false; /* and don't forget the header */
715 len = rec->rec_header.packet_header.caplen + (rec->rec_header.packet_header.caplen ? LA_PacketRecordSize : 0);
717 /* len goes into a 16-bit field, so there's a hard limit of 65535. */
718 if (len > 65535) {
719 *err = WTAP_ERR_PACKET_TOO_LARGE;
720 return false;
723 if (!s16write(wdh, 0x1005, err))
724 return false;
725 if (!s16write(wdh, (uint16_t)len, err))
726 return false;
728 if (!itmp->init) {
729 /* collect some information for the
730 * finally written header
732 itmp->start = rec->ts;
733 itmp->pkts = 0;
734 itmp->init = true;
735 itmp->encap = wdh->file_encap;
736 itmp->lastlen = 0;
739 if (!s16write(wdh, 0x0001, err)) /* pr.rx_channels */
740 return false;
741 if (!s16write(wdh, 0x0008, err)) /* pr.rx_errors */
742 return false;
743 if (!s16write(wdh, (uint16_t) (rec->rec_header.packet_header.len + 4), err)) /* pr.rx_frm_len */
744 return false;
745 if (!s16write(wdh, (uint16_t) rec->rec_header.packet_header.caplen, err)) /* pr.rx_frm_sln */
746 return false;
748 nstime_delta(&td, &rec->ts, &itmp->start);
750 /* Convert to half-microseconds, rounded up. */
751 x = (td.nsecs + 250) / 500; /* nanoseconds -> half-microseconds, rounded */
752 x += td.secs * 2000000; /* seconds -> half-microseconds */
754 if (!s48write(wdh, x, err)) /* pr.rx_time[i] */
755 return false;
757 if (!s32write(wdh, ++itmp->pkts, err)) /* pr.pktno */
758 return false;
759 if (!s16write(wdh, (uint16_t)itmp->lastlen, err)) /* pr.prlen */
760 return false;
761 itmp->lastlen = len;
763 if (!s0write(wdh, 12, err))
764 return false;
766 if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err))
767 return false;
769 return true;
772 /*---------------------------------------------------
773 * Returns 0 if we could write the specified encapsulation type,
774 * an error indication otherwise.
775 *---------------------------------------------------*/
776 static int lanalyzer_dump_can_write_encap(int encap)
778 /* Per-packet encapsulations aren't supported. */
779 if (encap == WTAP_ENCAP_PER_PACKET)
780 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
782 if ( encap != WTAP_ENCAP_ETHERNET
783 && encap != WTAP_ENCAP_TOKEN_RING )
784 return WTAP_ERR_UNWRITABLE_ENCAP;
786 * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
788 return 0;
791 /*---------------------------------------------------
792 * Returns true on success, false on failure; sets "*err" to an
793 * error code on failure
794 *---------------------------------------------------*/
795 static bool lanalyzer_dump_open(wtap_dumper *wdh, int *err, char **err_info _U_)
797 int jump;
798 void *tmp;
800 tmp = g_malloc(sizeof(LA_TmpInfo));
801 if (!tmp) {
802 *err = errno;
803 return false;
806 ((LA_TmpInfo*)tmp)->init = false;
807 wdh->priv = tmp;
808 wdh->subtype_write = lanalyzer_dump;
809 wdh->subtype_finish = lanalyzer_dump_finish;
811 /* Some of the fields in the file header aren't known yet so
812 just skip over it for now. It will be created after all
813 of the packets have been written. */
815 jump = sizeof (LA_HeaderRegularFake)
816 + sizeof (LA_RxChannelNameFake)
817 + sizeof (LA_TxChannelNameFake)
818 + sizeof (LA_RxTemplateNameFake)
819 + sizeof (LA_TxTemplateNameFake)
820 + sizeof (LA_DisplayOptionsFake)
821 + LA_SummaryRecordSize
822 + LA_SubfileSummaryRecordSize
823 + sizeof (LA_CyclicInformationFake)
824 + LA_IndexRecordSize;
826 if (wtap_dump_file_seek(wdh, jump, SEEK_SET, err) == -1)
827 return false;
829 wdh->bytes_dumped = jump;
830 return true;
833 /*---------------------------------------------------
835 *---------------------------------------------------*/
836 static bool lanalyzer_dump_header(wtap_dumper *wdh, int *err)
838 LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
839 uint16_t board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
840 ? BOARD_325TR /* LANalyzer Board Type */
841 : BOARD_325; /* LANalyzer Board Type */
842 struct tm *fT;
844 fT = localtime(&itmp->start.secs);
845 if (fT == NULL)
846 return false;
848 if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
849 return false;
851 if (!wtap_dump_file_write(wdh, &LA_HeaderRegularFake,
852 sizeof LA_HeaderRegularFake, err))
853 return false;
854 if (!wtap_dump_file_write(wdh, &LA_RxChannelNameFake,
855 sizeof LA_RxChannelNameFake, err))
856 return false;
857 if (!wtap_dump_file_write(wdh, &LA_TxChannelNameFake,
858 sizeof LA_TxChannelNameFake, err))
859 return false;
860 if (!wtap_dump_file_write(wdh, &LA_RxTemplateNameFake,
861 sizeof LA_RxTemplateNameFake, err))
862 return false;
863 if (!wtap_dump_file_write(wdh, &LA_TxTemplateNameFake,
864 sizeof LA_TxTemplateNameFake, err))
865 return false;
866 if (!wtap_dump_file_write(wdh, &LA_DisplayOptionsFake,
867 sizeof LA_DisplayOptionsFake, err))
868 return false;
869 /*-----------------------------------------------------------------*/
870 if (!s16write(wdh, RT_Summary, err)) /* rid */
871 return false;
872 if (!s16write(wdh, SummarySize, err)) /* rlen */
873 return false;
874 if (!s8write(wdh, (uint8_t) fT->tm_mday, err)) /* s.datcre.day */
875 return false;
876 if (!s8write(wdh, (uint8_t) (fT->tm_mon+1), err)) /* s.datcre.mon */
877 return false;
878 if (!s16write(wdh, (uint16_t) (fT->tm_year + 1900), err)) /* s.datcre.year */
879 return false;
880 if (!s8write(wdh, (uint8_t) fT->tm_mday, err)) /* s.datclo.day */
881 return false;
882 if (!s8write(wdh, (uint8_t) (fT->tm_mon+1), err)) /* s.datclo.mon */
883 return false;
884 if (!s16write(wdh, (uint16_t) (fT->tm_year + 1900), err)) /* s.datclo.year */
885 return false;
886 if (!s8write(wdh, (uint8_t) fT->tm_sec, err)) /* s.timeopn.second */
887 return false;
888 if (!s8write(wdh, (uint8_t) fT->tm_min, err)) /* s.timeopn.minute */
889 return false;
890 if (!s8write(wdh, (uint8_t) fT->tm_hour, err)) /* s.timeopn.hour */
891 return false;
892 if (!s8write(wdh, (uint8_t) fT->tm_mday, err)) /* s.timeopn.mday */
893 return false;
894 if (!s0write(wdh, 2, err))
895 return false;
896 if (!s8write(wdh, (uint8_t) fT->tm_sec, err)) /* s.timeclo.second */
897 return false;
898 if (!s8write(wdh, (uint8_t) fT->tm_min, err)) /* s.timeclo.minute */
899 return false;
900 if (!s8write(wdh, (uint8_t) fT->tm_hour, err)) /* s.timeclo.hour */
901 return false;
902 if (!s8write(wdh, (uint8_t) fT->tm_mday, err)) /* s.timeclo.mday */
903 return false;
904 if (!s0write(wdh, 2, err))
905 return false;
906 if (!s0write(wdh, 6, err)) /* EAddr == 0 */
907 return false;
908 if (!s16write(wdh, 1, err)) /* s.mxseqno */
909 return false;
910 if (!s16write(wdh, 0, err)) /* s.slcoffo */
911 return false;
912 if (!s16write(wdh, 1514, err)) /* s.mxslc */
913 return false;
914 if (!s32write(wdh, itmp->pkts, err)) /* s.totpktt */
915 return false;
917 * statrg == 0; ? -1
918 * stptrg == 0; ? -1
919 * s.mxpkta[0]=0
921 if (!s0write(wdh, 12, err))
922 return false;
923 if (!s32write(wdh, itmp->pkts, err)) /* sr.s.mxpkta[1] */
924 return false;
925 if (!s0write(wdh, 34*4, err)) /* s.mxpkta[2-33]=0 */
926 return false;
927 if (!s16write(wdh, board_type, err))
928 return false;
929 if (!s0write(wdh, 20, err)) /* board_version == 0 */
930 return false;
931 /*-----------------------------------------------------------------*/
932 if (!s16write(wdh, RT_SubfileSummary, err)) /* ssr.rid */
933 return false;
934 if (!s16write(wdh, LA_SubfileSummaryRecordSize-4, err)) /* ssr.rlen */
935 return false;
936 if (!s16write(wdh, 1, err)) /* ssr.seqno */
937 return false;
938 if (!s32write(wdh, itmp->pkts, err)) /* ssr.totpkts */
939 return false;
940 /*-----------------------------------------------------------------*/
941 if (!wtap_dump_file_write(wdh, &LA_CyclicInformationFake,
942 sizeof LA_CyclicInformationFake, err))
943 return false;
944 /*-----------------------------------------------------------------*/
945 if (!s16write(wdh, RT_Index, err)) /* rid */
946 return false;
947 if (!s16write(wdh, LA_IndexRecordSize -4, err)) /* rlen */
948 return false;
949 if (!s16write(wdh, LA_IndexSize, err)) /* idxsp */
950 return false;
951 if (!s0write(wdh, LA_IndexRecordSize - 6, err))
952 return false;
954 return true;
957 /*---------------------------------------------------
958 * Finish writing to a dump file.
959 * Returns true on success, false on failure.
960 *---------------------------------------------------*/
961 static bool lanalyzer_dump_finish(wtap_dumper *wdh, int *err,
962 char **err_info _U_)
964 /* bytes_dumped already accounts for the size of the header,
965 * but lanalyzer_dump_header() (via wtap_dump_file_write())
966 * will keep incrementing it.
968 int64_t saved_bytes_dumped = wdh->bytes_dumped;
969 lanalyzer_dump_header(wdh,err);
970 wdh->bytes_dumped = saved_bytes_dumped;
971 return *err ? false : true;
974 static const struct supported_block_type lanalyzer_blocks_supported[] = {
976 * We support packet blocks, with no comments or other options.
978 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
981 static const struct file_type_subtype_info lanalyzer_info = {
982 "Novell LANalyzer","lanalyzer", "tr1", NULL,
983 true, BLOCKS_SUPPORTED(lanalyzer_blocks_supported),
984 lanalyzer_dump_can_write_encap, lanalyzer_dump_open, NULL
987 void register_lanalyzer(void)
989 lanalyzer_file_type_subtype = wtap_register_file_type_subtype(&lanalyzer_info);
992 * Register name for backwards compatibility with the
993 * wtap_filetypes table in Lua.
995 wtap_register_backwards_compatibility_lua_name("LANALYZER",
996 lanalyzer_file_type_subtype);
1000 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1002 * Local variables:
1003 * c-basic-offset: 6
1004 * tab-width: 8
1005 * indent-tabs-mode: nil
1006 * End:
1008 * vi: set shiftwidth=6 tabstop=8 expandtab:
1009 * :indentSize=6:tabSize=8:noTabs=true: