HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / wiretap / network_instruments.c
blob58494cc66b32c8396b8a81603036f255124e17af
1 /*
2 * $Id$
3 */
5 /***************************************************************************
6 network_instruments.c - description
7 -------------------
8 begin : Wed Oct 29 2003
9 copyright : (C) 2003 by root
10 email : scotte[AT}netinst.com
11 ***************************************************************************/
13 /***************************************************************************
14 * *
15 * This program is free software; you can redistribute it and/or modify *
16 * it under the terms of the GNU General Public License as published by *
17 * the Free Software Foundation; either version 2 of the License, or *
18 * (at your option) any later version. *
19 * *
20 ***************************************************************************/
22 #include "config.h"
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <string.h>
27 #include "wtap-int.h"
28 #include "file_wrappers.h"
29 #include "buffer.h"
30 #include "network_instruments.h"
32 static const char network_instruments_magic[] = {"ObserverPktBufferVersion=15.00"};
33 static const int true_magic_length = 17;
35 static const guint32 observer_packet_magic = 0x88888888;
38 * This structure is used to keep state when writing files. An instance is
39 * allocated for each file, and its address is stored in the wtap_dumper.priv
40 * pointer field.
42 typedef struct {
43 guint64 packet_count;
44 guint8 network_type;
45 guint32 time_format;
46 } observer_dump_private_state;
49 * Some time offsets are calculated in advance here, when the first Observer
50 * file is opened for reading or writing, and are then used to adjust frame
51 * timestamps as they are read or written.
53 * The Wiretap API expects timestamps in nanoseconds relative to
54 * January 1, 1970, 00:00:00 GMT (the Wiretap epoch).
56 * Observer versions before 13.10 encode frame timestamps in nanoseconds
57 * relative to January 1, 2000, 00:00:00 local time (the Observer epoch).
58 * Versions 13.10 and later switch over to GMT encoding. Which encoding was used
59 * when saving the file is identified via the time format TLV following
60 * the file header.
62 * Unfortunately, even though Observer versions before 13.10 saved in local
63 * time, they didn't include the timezone from which the frames were captured,
64 * so converting to GMT correctly from all timezones is impossible. So an
65 * assumption is made that the file is being read from within the same timezone
66 * that it was written.
68 * All code herein is normalized to versions 13.10 and later, special casing for
69 * versions earlier. In other words, timestamps are worked with as if
70 * they are GMT-encoded, and adjustments from local time are made only if
71 * the source file warrants it.
73 * All destination files are saved in GMT format.
75 static const time_t ansi_to_observer_epoch_offset = 946684800;
76 static time_t gmt_to_localtime_offset = (time_t) -1;
78 static void init_gmt_to_localtime_offset(void)
80 if (gmt_to_localtime_offset == (time_t) -1) {
81 time_t ansi_epoch_plus_one_day = 86400;
82 struct tm gmt_tm;
83 struct tm local_tm;
86 * Compute the local time zone offset as the number of seconds west
87 * of GMT. There's no obvious cross-platform API for querying this
88 * directly. As a workaround, GMT and local tm structures are populated
89 * relative to the ANSI time_t epoch (plus one day to ensure that
90 * local time stays after 1970/1/1 00:00:00). They are then converted
91 * back to time_t as if they were both local times, resulting in the
92 * time zone offset being the difference between them.
94 gmt_tm = *gmtime(&ansi_epoch_plus_one_day);
95 local_tm = *localtime(&ansi_epoch_plus_one_day);
96 local_tm.tm_isdst = 0;
97 gmt_to_localtime_offset = mktime(&gmt_tm) - mktime(&local_tm);
101 static gboolean observer_read(wtap *wth, int *err, gchar **err_info,
102 gint64 *data_offset);
103 static gboolean observer_seek_read(wtap *wth, gint64 seek_off,
104 struct wtap_pkthdr *phdr, Buffer *buf, int length,
105 int *err, gchar **err_info);
106 static int read_packet_header(FILE_T fh, union wtap_pseudo_header *pseudo_header,
107 packet_entry_header *packet_header, int *err, gchar **err_info);
108 static gboolean process_packet_header(wtap *wth,
109 packet_entry_header *packet_header, struct wtap_pkthdr *phdr, int *err,
110 gchar **err_info);
111 static int read_packet_data(FILE_T fh, int offset_to_frame, int current_offset_from_packet_header,
112 Buffer *buf, int length, int *err, char **err_info);
113 static gboolean skip_to_next_packet(wtap *wth, int offset_to_next_packet,
114 int current_offset_from_packet_header, int *err, char **err_info);
115 static gboolean observer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
116 const guint8 *pd, int *err);
117 static gint observer_to_wtap_encap(int observer_encap);
118 static gint wtap_to_observer_encap(int wtap_encap);
120 int network_instruments_open(wtap *wth, int *err, gchar **err_info)
122 int bytes_read;
123 int offset;
124 capture_file_header file_header;
125 guint i;
126 tlv_header tlvh;
127 int seek_increment;
128 int header_offset;
129 packet_entry_header packet_header;
130 observer_dump_private_state * private_state = NULL;
132 errno = WTAP_ERR_CANT_READ;
133 offset = 0;
135 /* read in the buffer file header */
136 bytes_read = file_read(&file_header, sizeof file_header, wth->fh);
137 if (bytes_read != sizeof file_header) {
138 *err = file_error(wth->fh, err_info);
139 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
140 return -1;
141 return 0;
143 offset += bytes_read;
144 CAPTURE_FILE_HEADER_FROM_LE_IN_PLACE(file_header);
146 /* check if version info is present */
147 if (memcmp(file_header.observer_version, network_instruments_magic, true_magic_length)!=0) {
148 return 0;
151 /* initialize the private state */
152 private_state = (observer_dump_private_state *) g_malloc(sizeof(observer_dump_private_state));
153 private_state->time_format = TIME_INFO_LOCAL;
154 wth->priv = (void *) private_state;
156 /* get the location of the first packet */
157 /* v15 and newer uses high byte offset, in previous versions it will be 0 */
158 header_offset = file_header.offset_to_first_packet + ((int)(file_header.offset_to_first_packet_high_byte)<<16);
160 /* process extra information */
161 for (i = 0; i < file_header.number_of_information_elements; i++) {
162 /* for safety break if we've reached the first packet */
163 if (offset >= header_offset)
164 break;
166 /* read the TLV header */
167 bytes_read = file_read(&tlvh, sizeof tlvh, wth->fh);
168 if (bytes_read != sizeof tlvh) {
169 *err = file_error(wth->fh, err_info);
170 if (*err == 0)
171 *err = WTAP_ERR_SHORT_READ;
172 return -1;
174 offset += bytes_read;
175 TLV_HEADER_FROM_LE_IN_PLACE(tlvh);
177 if (tlvh.length < sizeof tlvh) {
178 *err = WTAP_ERR_BAD_FILE;
179 *err_info = g_strdup_printf("Observer: bad record (TLV length %u < %lu)",
180 tlvh.length, (unsigned long)sizeof tlvh);
181 return -1;
184 /* process (or skip over) the current TLV */
185 switch (tlvh.type) {
186 case INFORMATION_TYPE_TIME_INFO:
187 bytes_read = file_read(&private_state->time_format, sizeof private_state->time_format, wth->fh);
188 if (bytes_read != sizeof private_state->time_format) {
189 *err = file_error(wth->fh, err_info);
190 if (*err == 0)
191 *err = WTAP_ERR_SHORT_READ;
192 return -1;
194 private_state->time_format = GUINT32_FROM_LE(private_state->time_format);
195 offset += bytes_read;
196 break;
197 default:
198 seek_increment = tlvh.length - (int)sizeof tlvh;
199 if (seek_increment > 0) {
200 if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1)
201 return -1;
203 offset += seek_increment;
207 /* get to the first packet */
208 if (header_offset < offset) {
209 *err = WTAP_ERR_BAD_FILE;
210 *err_info = g_strdup_printf("Observer: bad record (offset to first packet %d < %d)",
211 header_offset, offset);
212 return -1;
214 seek_increment = header_offset - offset;
215 if (seek_increment > 0) {
216 if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1)
217 return -1;
220 /* pull off the packet header */
221 bytes_read = file_read(&packet_header, sizeof packet_header, wth->fh);
222 if (bytes_read != sizeof packet_header) {
223 *err = file_error(wth->fh, err_info);
224 if (*err == 0)
225 *err = WTAP_ERR_SHORT_READ;
226 return -1;
228 PACKET_ENTRY_HEADER_FROM_LE_IN_PLACE(packet_header);
230 /* check the packet's magic number */
231 if (packet_header.packet_magic != observer_packet_magic) {
232 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
233 *err_info = g_strdup_printf("Observer: unsupported packet version %ul", packet_header.packet_magic);
234 return -1;
237 /* check the data link type */
238 if (observer_to_wtap_encap(packet_header.network_type) == WTAP_ENCAP_UNKNOWN) {
239 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
240 *err_info = g_strdup_printf("Observer: network type %u unknown or unsupported", packet_header.network_type);
241 return -1;
243 wth->file_encap = observer_to_wtap_encap(packet_header.network_type);
245 /* set up the rest of the capture parameters */
246 private_state->packet_count = 0;
247 private_state->network_type = wtap_to_observer_encap(wth->file_encap);
248 wth->subtype_read = observer_read;
249 wth->subtype_seek_read = observer_seek_read;
250 wth->subtype_close = NULL;
251 wth->subtype_sequential_close = NULL;
252 wth->snapshot_length = 0; /* not available in header */
253 wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
254 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_NETWORK_INSTRUMENTS;
256 /* reset the pointer to the first packet */
257 if (file_seek(wth->fh, header_offset, SEEK_SET, err) == -1)
258 return -1;
260 init_gmt_to_localtime_offset();
262 return 1;
265 /* Reads the next packet. */
266 static gboolean observer_read(wtap *wth, int *err, gchar **err_info,
267 gint64 *data_offset)
269 int header_bytes_consumed;
270 int data_bytes_consumed;
271 packet_entry_header packet_header;
273 /* skip records other than data records */
274 for (;;) {
275 *data_offset = file_tell(wth->fh);
277 /* process the packet header, including TLVs */
278 header_bytes_consumed = read_packet_header(wth->fh, &wth->phdr.pseudo_header, &packet_header, err,
279 err_info);
280 if (header_bytes_consumed <= 0)
281 return FALSE; /* EOF or error */
283 if (packet_header.packet_type == PACKET_TYPE_DATA_PACKET)
284 break;
286 /* skip to next packet */
287 if (!skip_to_next_packet(wth, packet_header.offset_to_next_packet,
288 header_bytes_consumed, err, err_info)) {
289 return FALSE; /* EOF or error */
293 if (!process_packet_header(wth, &packet_header, &wth->phdr, err, err_info))
294 return FALSE;
296 /* read the frame data */
297 data_bytes_consumed = read_packet_data(wth->fh, packet_header.offset_to_frame,
298 header_bytes_consumed, wth->frame_buffer,
299 wth->phdr.caplen, err, err_info);
300 if (data_bytes_consumed < 0) {
301 return FALSE;
304 /* skip over any extra bytes following the frame data */
305 if (!skip_to_next_packet(wth, packet_header.offset_to_next_packet,
306 header_bytes_consumed + data_bytes_consumed, err, err_info)) {
307 return FALSE;
310 return TRUE;
313 /* Reads a packet at an offset. */
314 static gboolean observer_seek_read(wtap *wth, gint64 seek_off,
315 struct wtap_pkthdr *phdr, Buffer *buf, int length,
316 int *err, gchar **err_info)
318 union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
319 packet_entry_header packet_header;
320 int offset;
321 int data_bytes_consumed;
323 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
324 return FALSE;
326 /* process the packet header, including TLVs */
327 offset = read_packet_header(wth->random_fh, pseudo_header, &packet_header, err,
328 err_info);
329 if (offset <= 0)
330 return FALSE; /* EOF or error */
332 if (!process_packet_header(wth, &packet_header, phdr, err, err_info))
333 return FALSE;
335 /* read the frame data */
336 data_bytes_consumed = read_packet_data(wth->random_fh, packet_header.offset_to_frame,
337 offset, buf, length, err, err_info);
338 if (data_bytes_consumed < 0) {
339 return FALSE;
342 return TRUE;
345 static int
346 read_packet_header(FILE_T fh, union wtap_pseudo_header *pseudo_header,
347 packet_entry_header *packet_header, int *err, gchar **err_info)
349 int offset;
350 int bytes_read;
351 guint i;
352 tlv_header tlvh;
353 int seek_increment;
354 tlv_wireless_info wireless_header;
356 offset = 0;
358 /* pull off the packet header */
359 bytes_read = file_read(packet_header, sizeof *packet_header, fh);
360 if (bytes_read != sizeof *packet_header) {
361 *err = file_error(fh, err_info);
362 if (*err != 0)
363 return -1;
364 return 0; /* EOF */
366 offset += bytes_read;
367 PACKET_ENTRY_HEADER_FROM_LE_IN_PLACE(*packet_header);
369 /* check the packet's magic number */
370 if (packet_header->packet_magic != observer_packet_magic) {
373 * Some files are zero-padded at the end. There is no warning of this
374 * in the previous packet header information, such as setting
375 * offset_to_next_packet to zero. So detect this situation by treating
376 * an all-zero header as a sentinel. Return EOF when it is encountered,
377 * rather than treat it as a bad record.
379 for (i = 0; i < sizeof *packet_header; i++) {
380 if (((guint8*) packet_header)[i] != 0)
381 break;
383 if (i == sizeof *packet_header) {
384 *err = 0;
385 return 0; /* EOF */
388 *err = WTAP_ERR_BAD_FILE;
389 *err_info = g_strdup_printf("Observer: bad record: Invalid magic number 0x%08x",
390 packet_header->packet_magic);
391 return -1;
394 /* process extra information */
395 for (i = 0; i < packet_header->number_of_information_elements; i++) {
396 /* read the TLV header */
397 bytes_read = file_read(&tlvh, sizeof tlvh, fh);
398 if (bytes_read != sizeof tlvh) {
399 *err = file_error(fh, err_info);
400 if (*err == 0)
401 *err = WTAP_ERR_SHORT_READ;
402 return -1;
404 offset += bytes_read;
405 TLV_HEADER_FROM_LE_IN_PLACE(tlvh);
407 if (tlvh.length < sizeof tlvh) {
408 *err = WTAP_ERR_BAD_FILE;
409 *err_info = g_strdup_printf("Observer: bad record (TLV length %u < %lu)",
410 tlvh.length, (unsigned long)sizeof tlvh);
411 return -1;
414 /* process (or skip over) the current TLV */
415 switch (tlvh.type) {
416 case INFORMATION_TYPE_WIRELESS:
417 bytes_read = file_read(&wireless_header, sizeof wireless_header, fh);
418 if (bytes_read != sizeof wireless_header) {
419 *err = file_error(fh, err_info);
420 if(*err == 0)
421 *err = WTAP_ERR_SHORT_READ;
422 return -1;
424 /* update the pseudo header */
425 pseudo_header->ieee_802_11.fcs_len = 0;
426 /* set decryption status */
427 pseudo_header->ieee_802_11.decrypted = (wireless_header.conditions & WIRELESS_WEP_SUCCESS) != 0;
428 pseudo_header->ieee_802_11.channel = wireless_header.frequency;
429 pseudo_header->ieee_802_11.data_rate = wireless_header.rate;
430 pseudo_header->ieee_802_11.signal_level = wireless_header.strengthPercent;
431 offset += bytes_read;
432 break;
433 default:
434 /* skip the TLV data */
435 seek_increment = tlvh.length - (int)sizeof tlvh;
436 if (seek_increment > 0) {
437 if (file_seek(fh, seek_increment, SEEK_CUR, err) == -1)
438 return -1;
440 offset += seek_increment;
444 return offset;
447 static gboolean
448 process_packet_header(wtap *wth, packet_entry_header *packet_header,
449 struct wtap_pkthdr *phdr, int *err, gchar **err_info)
451 /* set the wiretap packet header fields */
452 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
453 phdr->pkt_encap = observer_to_wtap_encap(packet_header->network_type);
454 if(wth->file_encap == WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS) {
455 phdr->len = packet_header->network_size;
456 phdr->caplen = packet_header->captured_size;
457 } else {
459 * XXX - what are those 4 bytes?
461 * The comment in the code said "neglect frame markers for wiretap",
462 * but in the captures I've seen, there's no actual data corresponding
463 * to them that might be a "frame marker".
465 * Instead, the packets had a network_size 4 bytes larger than the
466 * captured_size; does the network_size include the CRC, even
467 * though it's not included in a capture? If so, most other
468 * network analyzers that have a "network size" and a "captured
469 * size" don't include the CRC in the "network size" if they
470 * don't include the CRC in a full-length captured packet; the
471 * "captured size" is less than the "network size" only if a
472 * user-specified "snapshot length" caused the packet to be
473 * sliced at a particular point.
475 * That's the model that wiretap and Wireshark/TShark use, so
476 * we implement that model here.
478 if (packet_header->network_size < 4) {
479 *err = WTAP_ERR_BAD_FILE;
480 *err_info = g_strdup_printf("Observer: bad record: Packet length %u < 4",
481 packet_header->network_size);
482 return FALSE;
485 phdr->len = packet_header->network_size - 4;
486 phdr->caplen = MIN(packet_header->captured_size, phdr->len);
489 /* set the wiretap timestamp, assuming for the moment that Observer encoded it in GMT */
490 phdr->ts.secs = (time_t) ((packet_header->nano_seconds_since_2000 / 1000000000) + ansi_to_observer_epoch_offset);
491 phdr->ts.nsecs = (int) (packet_header->nano_seconds_since_2000 % 1000000000);
493 /* adjust to local time, if necessary, also accounting for DST if the frame
494 was captured while it was in effect */
495 if (((observer_dump_private_state*)wth->priv)->time_format == TIME_INFO_LOCAL)
497 struct tm daylight_tm;
498 struct tm standard_tm;
499 time_t dst_offset;
501 /* the Observer timestamp was encoded as local time, so add a
502 correction from local time to GMT */
503 phdr->ts.secs += gmt_to_localtime_offset;
505 /* perform a DST adjustment if necessary */
506 standard_tm = *localtime(&phdr->ts.secs);
507 if (standard_tm.tm_isdst > 0) {
508 daylight_tm = standard_tm;
509 standard_tm.tm_isdst = 0;
510 dst_offset = mktime(&standard_tm) - mktime(&daylight_tm);
511 phdr->ts.secs -= dst_offset;
515 /* update the pseudo header */
516 switch (wth->file_encap) {
517 case WTAP_ENCAP_ETHERNET:
518 /* There is no FCS in the frame */
519 phdr->pseudo_header.eth.fcs_len = 0;
520 break;
521 case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
522 /* Updated in read_packet_header */
523 break;
526 return TRUE;
529 static int
530 read_packet_data(FILE_T fh, int offset_to_frame, int current_offset_from_packet_header, Buffer *buf,
531 int length, int *err, char **err_info)
533 int seek_increment;
534 int bytes_consumed = 0;
536 /* validate offsets */
537 if (offset_to_frame < current_offset_from_packet_header) {
538 *err = WTAP_ERR_BAD_FILE;
539 *err_info = g_strdup_printf("Observer: bad record (offset to packet data %d < %d)",
540 offset_to_frame, current_offset_from_packet_header);
541 return -1;
544 /* skip to the packet data */
545 seek_increment = offset_to_frame - current_offset_from_packet_header;
546 if (seek_increment > 0) {
547 if (file_seek(fh, seek_increment, SEEK_CUR, err) == -1) {
548 return -1;
550 bytes_consumed += seek_increment;
553 /* set-up the packet buffer */
554 buffer_assure_space(buf, length);
556 /* read in the packet data */
557 if (!wtap_read_packet_bytes(fh, buf, length, err, err_info))
558 return FALSE;
559 bytes_consumed += length;
561 return bytes_consumed;
564 static gboolean
565 skip_to_next_packet(wtap *wth, int offset_to_next_packet, int current_offset_from_packet_header, int *err,
566 char **err_info)
568 int seek_increment;
570 /* validate offsets */
571 if (offset_to_next_packet < current_offset_from_packet_header) {
572 *err = WTAP_ERR_BAD_FILE;
573 *err_info = g_strdup_printf("Observer: bad record (offset to next packet %d < %d)",
574 offset_to_next_packet, current_offset_from_packet_header);
575 return FALSE;
578 /* skip to the next packet header */
579 seek_increment = offset_to_next_packet - current_offset_from_packet_header;
580 if (seek_increment > 0) {
581 if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1)
582 return FALSE;
585 return TRUE;
588 /* Returns 0 if we could write the specified encapsulation type,
589 an error indication otherwise. */
590 int network_instruments_dump_can_write_encap(int encap)
592 /* per-packet encapsulations aren't supported */
593 if (encap == WTAP_ENCAP_PER_PACKET)
594 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
596 if (encap < 0 || (wtap_to_observer_encap(encap) == OBSERVER_UNDEFINED))
597 return WTAP_ERR_UNSUPPORTED_ENCAP;
599 return 0;
602 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
603 failure. */
604 gboolean network_instruments_dump_open(wtap_dumper *wdh, int *err)
606 observer_dump_private_state * private_state = NULL;
607 capture_file_header file_header;
609 tlv_header comment_header;
610 tlv_time_info time_header;
611 char comment[64];
612 size_t comment_length;
613 struct tm * current_time;
614 time_t system_time;
616 /* initialize the private state */
617 private_state = (observer_dump_private_state *) g_malloc(sizeof(observer_dump_private_state));
618 private_state->packet_count = 0;
619 private_state->network_type = wtap_to_observer_encap(wdh->encap);
620 private_state->time_format = TIME_INFO_GMT;
622 /* populate the fields of wdh */
623 wdh->priv = (void *) private_state;
624 wdh->subtype_write = observer_dump;
626 /* initialize the file header */
627 memset(&file_header, 0x00, sizeof(file_header));
628 g_strlcpy(file_header.observer_version, network_instruments_magic, 31);
629 file_header.offset_to_first_packet = (guint16)sizeof(file_header);
630 file_header.offset_to_first_packet_high_byte = 0;
632 /* create the file comment TLV */
634 time(&system_time);
635 current_time = localtime(&system_time);
636 memset(&comment, 0x00, sizeof(comment));
637 g_snprintf(comment, 64, "This capture was saved from Wireshark on %s", asctime(current_time));
638 comment_length = strlen(comment);
640 comment_header.type = INFORMATION_TYPE_COMMENT;
641 comment_header.length = (guint16) (sizeof(comment_header) + comment_length);
643 /* update the file header to account for the comment TLV */
644 file_header.number_of_information_elements++;
645 file_header.offset_to_first_packet += comment_header.length;
648 /* create the timestamp encoding TLV */
650 time_header.type = INFORMATION_TYPE_TIME_INFO;
651 time_header.length = (guint16) (sizeof(time_header));
652 time_header.time_format = TIME_INFO_GMT;
654 /* update the file header to account for the timestamp encoding TLV */
655 file_header.number_of_information_elements++;
656 file_header.offset_to_first_packet += time_header.length;
659 /* write the file header, swapping any multibyte fields first */
660 CAPTURE_FILE_HEADER_TO_LE_IN_PLACE(file_header);
661 if (!wtap_dump_file_write(wdh, &file_header, sizeof(file_header), err)) {
662 return FALSE;
664 wdh->bytes_dumped += sizeof(file_header);
666 /* write the comment TLV */
668 TLV_HEADER_TO_LE_IN_PLACE(comment_header);
669 if (!wtap_dump_file_write(wdh, &comment_header, sizeof(comment_header), err)) {
670 return FALSE;
672 wdh->bytes_dumped += sizeof(comment_header);
674 if (!wtap_dump_file_write(wdh, &comment, comment_length, err)) {
675 return FALSE;
677 wdh->bytes_dumped += comment_length;
680 /* write the time info TLV */
682 TLV_TIME_INFO_TO_LE_IN_PLACE(time_header);
683 if (!wtap_dump_file_write(wdh, &time_header, sizeof(time_header), err)) {
684 return FALSE;
686 wdh->bytes_dumped += sizeof(time_header);
689 init_gmt_to_localtime_offset();
691 return TRUE;
694 /* Write a record for a packet to a dump file.
695 Returns TRUE on success, FALSE on failure. */
696 static gboolean observer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
697 const guint8 *pd,
698 int *err)
700 observer_dump_private_state * private_state = NULL;
701 packet_entry_header packet_header;
702 guint64 seconds_since_2000;
704 /* convert the number of seconds since epoch from ANSI-relative to
705 Observer-relative */
706 if (phdr->ts.secs < ansi_to_observer_epoch_offset) {
707 if(phdr->ts.secs > (time_t) 0) {
708 seconds_since_2000 = phdr->ts.secs;
709 } else {
710 seconds_since_2000 = (time_t) 0;
712 } else {
713 seconds_since_2000 = phdr->ts.secs - ansi_to_observer_epoch_offset;
716 /* populate the fields of the packet header */
717 private_state = (observer_dump_private_state *) wdh->priv;
719 memset(&packet_header, 0x00, sizeof(packet_header));
720 packet_header.packet_magic = observer_packet_magic;
721 packet_header.network_speed = 1000000;
722 packet_header.captured_size = (guint16) phdr->caplen;
723 packet_header.network_size = (guint16) (phdr->len + 4);
724 packet_header.offset_to_frame = sizeof(packet_header);
725 /* XXX - what if this doesn't fit in 16 bits? It's not guaranteed to... */
726 packet_header.offset_to_next_packet = (guint16)sizeof(packet_header) + phdr->caplen;
727 packet_header.network_type = private_state->network_type;
728 packet_header.flags = 0x00;
729 packet_header.number_of_information_elements = 0;
730 packet_header.packet_type = PACKET_TYPE_DATA_PACKET;
731 packet_header.packet_number = private_state->packet_count;
732 packet_header.original_packet_number = packet_header.packet_number;
733 packet_header.nano_seconds_since_2000 = seconds_since_2000 * 1000000000 + phdr->ts.nsecs;
735 private_state->packet_count++;
737 /* write the packet header */
738 PACKET_ENTRY_HEADER_TO_LE_IN_PLACE(packet_header);
739 if (!wtap_dump_file_write(wdh, &packet_header, sizeof(packet_header), err)) {
740 return FALSE;
742 wdh->bytes_dumped += sizeof(packet_header);
744 /* write the packet data */
745 if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err)) {
746 return FALSE;
748 wdh->bytes_dumped += phdr->caplen;
750 return TRUE;
753 static gint observer_to_wtap_encap(int observer_encap)
755 switch(observer_encap) {
756 case OBSERVER_ETHERNET:
757 return WTAP_ENCAP_ETHERNET;
758 case OBSERVER_TOKENRING:
759 return WTAP_ENCAP_TOKEN_RING;
760 case OBSERVER_FIBRE_CHANNEL:
761 return WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS;
762 case OBSERVER_WIRELESS_802_11:
763 return WTAP_ENCAP_IEEE_802_11_WITH_RADIO;
764 case OBSERVER_UNDEFINED:
765 return WTAP_ENCAP_UNKNOWN;
767 return WTAP_ENCAP_UNKNOWN;
770 static gint wtap_to_observer_encap(int wtap_encap)
772 switch(wtap_encap) {
773 case WTAP_ENCAP_ETHERNET:
774 return OBSERVER_ETHERNET;
775 case WTAP_ENCAP_TOKEN_RING:
776 return OBSERVER_TOKENRING;
777 case WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS:
778 return OBSERVER_FIBRE_CHANNEL;
779 case WTAP_ENCAP_UNKNOWN:
780 return OBSERVER_UNDEFINED;
782 return OBSERVER_UNDEFINED;