5 /***************************************************************************
6 network_instruments.c - description
8 begin : Wed Oct 29 2003
9 copyright : (C) 2003 by root
10 email : scotte[AT}netinst.com
11 ***************************************************************************/
13 /***************************************************************************
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. *
20 ***************************************************************************/
28 #include "file_wrappers.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
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
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;
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
,
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
)
124 capture_file_header file_header
;
129 packet_entry_header packet_header
;
130 observer_dump_private_state
* private_state
= NULL
;
132 errno
= WTAP_ERR_CANT_READ
;
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
)
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) {
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
)
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
);
171 *err
= WTAP_ERR_SHORT_READ
;
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
);
184 /* process (or skip over) the current TLV */
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
);
191 *err
= WTAP_ERR_SHORT_READ
;
194 private_state
->time_format
= GUINT32_FROM_LE(private_state
->time_format
);
195 offset
+= bytes_read
;
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)
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
);
214 seek_increment
= header_offset
- offset
;
215 if (seek_increment
> 0) {
216 if (file_seek(wth
->fh
, seek_increment
, SEEK_CUR
, err
) == -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
);
225 *err
= WTAP_ERR_SHORT_READ
;
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
);
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
);
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)
260 init_gmt_to_localtime_offset();
265 /* Reads the next packet. */
266 static gboolean
observer_read(wtap
*wth
, int *err
, gchar
**err_info
,
269 int header_bytes_consumed
;
270 int data_bytes_consumed
;
271 packet_entry_header packet_header
;
273 /* skip records other than data records */
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
,
280 if (header_bytes_consumed
<= 0)
281 return FALSE
; /* EOF or error */
283 if (packet_header
.packet_type
== PACKET_TYPE_DATA_PACKET
)
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
))
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) {
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
)) {
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
;
321 int data_bytes_consumed
;
323 if (file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
) == -1)
326 /* process the packet header, including TLVs */
327 offset
= read_packet_header(wth
->random_fh
, pseudo_header
, &packet_header
, err
,
330 return FALSE
; /* EOF or error */
332 if (!process_packet_header(wth
, &packet_header
, phdr
, err
, err_info
))
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) {
346 read_packet_header(FILE_T fh
, union wtap_pseudo_header
*pseudo_header
,
347 packet_entry_header
*packet_header
, int *err
, gchar
**err_info
)
354 tlv_wireless_info wireless_header
;
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
);
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)
383 if (i
== sizeof *packet_header
) {
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
);
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
);
401 *err
= WTAP_ERR_SHORT_READ
;
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
);
414 /* process (or skip over) the current TLV */
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
);
421 *err
= WTAP_ERR_SHORT_READ
;
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
;
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)
440 offset
+= seek_increment
;
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
;
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
);
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
;
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;
521 case WTAP_ENCAP_IEEE_802_11_WITH_RADIO
:
522 /* Updated in read_packet_header */
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
)
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
);
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) {
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
))
559 bytes_consumed
+= length
;
561 return bytes_consumed
;
565 skip_to_next_packet(wtap
*wth
, int offset_to_next_packet
, int current_offset_from_packet_header
, int *err
,
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
);
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)
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
;
602 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
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
;
612 size_t comment_length
;
613 struct tm
* current_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 */
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
)) {
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
)) {
672 wdh
->bytes_dumped
+= sizeof(comment_header
);
674 if (!wtap_dump_file_write(wdh
, &comment
, comment_length
, err
)) {
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
)) {
686 wdh
->bytes_dumped
+= sizeof(time_header
);
689 init_gmt_to_localtime_offset();
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
,
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
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
;
710 seconds_since_2000
= (time_t) 0;
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
)) {
742 wdh
->bytes_dumped
+= sizeof(packet_header
);
744 /* write the packet data */
745 if (!wtap_dump_file_write(wdh
, pd
, phdr
->caplen
, err
)) {
748 wdh
->bytes_dumped
+= phdr
->caplen
;
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
)
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
;