Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / wiretap / observer.c
blob61cbec9c48229f78f09da5596328d4d0e12406a1
1 /***************************************************************************
2 observer.c - description
3 -------------------
4 begin : Wed Oct 29 2003
5 copyright : (C) 2003 by root
6 email : scotte[AT}netinst.com
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * SPDX-License-Identifier: GPL-2.0-or-later *
12 * *
13 ***************************************************************************/
15 #include "config.h"
16 #include "observer.h"
18 #include <stdlib.h>
19 #include <string.h>
20 #include "wtap-int.h"
21 #include "file_wrappers.h"
22 #include <wsutil/802_11-utils.h>
24 static const char observer_magic[] = {"ObserverPktBufferVersion=15.00"};
25 static const int true_magic_length = 17;
27 static const uint32_t observer_packet_magic = 0x88888888;
30 * This structure is used to keep state when writing files. An instance is
31 * allocated for each file, and its address is stored in the wtap_dumper.priv
32 * pointer field.
34 typedef struct {
35 uint64_t packet_count;
36 uint8_t network_type;
37 uint32_t time_format;
38 } observer_dump_private_state;
41 * Some time offsets are calculated in advance here, when the first Observer
42 * file is opened for reading or writing, and are then used to adjust frame
43 * timestamps as they are read or written.
45 * The Wiretap API expects timestamps in nanoseconds relative to
46 * January 1, 1970, 00:00:00 GMT (the Wiretap epoch).
48 * Observer versions before 13.10 encode frame timestamps in nanoseconds
49 * relative to January 1, 2000, 00:00:00 local time (the Observer epoch).
50 * Versions 13.10 and later switch over to GMT encoding. Which encoding was used
51 * when saving the file is identified via the time format TLV following
52 * the file header.
54 * Unfortunately, even though Observer versions before 13.10 saved in local
55 * time, they didn't include the timezone from which the frames were captured,
56 * so converting to GMT correctly from all timezones is impossible. So an
57 * assumption is made that the file is being read from within the same timezone
58 * that it was written.
60 * All code herein is normalized to versions 13.10 and later, special casing for
61 * versions earlier. In other words, timestamps are worked with as if
62 * they are GMT-encoded, and adjustments from local time are made only if
63 * the source file warrants it.
65 * All destination files are saved in GMT format.
67 static const time_t ansi_to_observer_epoch_offset = 946684800;
68 static time_t gmt_to_localtime_offset = (time_t) -1;
70 static const char *init_gmt_to_localtime_offset(void)
72 if (gmt_to_localtime_offset == (time_t) -1) {
73 time_t ansi_epoch_plus_one_day = 86400;
74 struct tm *tm;
75 struct tm gmt_tm;
76 struct tm local_tm;
79 * Compute the local time zone offset as the number of seconds west
80 * of GMT. There's no obvious cross-platform API for querying this
81 * directly. As a workaround, GMT and local tm structures are populated
82 * relative to the ANSI time_t epoch (plus one day to ensure that
83 * local time stays after 1970/1/1 00:00:00). They are then converted
84 * back to time_t as if they were both local times, resulting in the
85 * time zone offset being the difference between them.
87 tm = gmtime(&ansi_epoch_plus_one_day);
88 if (tm == NULL)
89 return "gmtime(one day past the Epoch) fails (this \"shouldn't happen\")";
90 gmt_tm = *tm;
91 tm = localtime(&ansi_epoch_plus_one_day);
92 if (tm == NULL)
93 return "localtime(one day past the Epoch) fails (this \"shouldn't happen\")";
94 local_tm = *tm;
95 local_tm.tm_isdst = 0;
96 gmt_to_localtime_offset = mktime(&gmt_tm) - mktime(&local_tm);
98 return NULL;
101 static bool observer_read(wtap *wth, wtap_rec *rec, Buffer *buf,
102 int *err, char **err_info, int64_t *data_offset);
103 static bool observer_seek_read(wtap *wth, int64_t seek_off,
104 wtap_rec *rec, Buffer *buf, int *err, char **err_info);
105 static int read_packet_header(wtap *wth, FILE_T fh, union wtap_pseudo_header *pseudo_header,
106 packet_entry_header *packet_header, int *err, char **err_info);
107 static bool process_packet_header(wtap *wth,
108 packet_entry_header *packet_header, wtap_rec *rec, int *err,
109 char **err_info);
110 static int read_packet_data(FILE_T fh, int offset_to_frame, int current_offset_from_packet_header,
111 Buffer *buf, int length, int *err, char **err_info);
112 static bool skip_to_next_packet(wtap *wth, int offset_to_next_packet,
113 int current_offset_from_packet_header, int *err, char **err_info);
114 static bool observer_dump(wtap_dumper *wdh, const wtap_rec *rec,
115 const uint8_t *pd, int *err, char **err_info);
116 static int observer_to_wtap_encap(int observer_encap);
117 static int wtap_to_observer_encap(int wtap_encap);
119 static int observer_file_type_subtype = -1;
121 void register_observer(void);
123 wtap_open_return_val observer_open(wtap *wth, int *err, char **err_info)
125 unsigned offset;
126 capture_file_header file_header;
127 unsigned header_offset;
128 unsigned i;
129 tlv_header tlvh;
130 unsigned seek_increment;
131 packet_entry_header packet_header;
132 observer_dump_private_state * private_state = NULL;
133 const char *err_str;
135 offset = 0;
137 /* read in the buffer file header */
138 if (!wtap_read_bytes(wth->fh, &file_header, sizeof file_header,
139 err, err_info)) {
140 if (*err != WTAP_ERR_SHORT_READ)
141 return WTAP_OPEN_ERROR;
142 return WTAP_OPEN_NOT_MINE;
144 offset += (unsigned)sizeof file_header;
145 CAPTURE_FILE_HEADER_FROM_LE_IN_PLACE(file_header);
147 /* check if version info is present */
148 if (memcmp(file_header.observer_version, observer_magic, true_magic_length)!=0) {
149 return WTAP_OPEN_NOT_MINE;
152 /* get the location of the first packet */
153 /* v15 and newer uses high byte offset, in previous versions it will be 0 */
154 header_offset = file_header.offset_to_first_packet + ((unsigned)(file_header.offset_to_first_packet_high_byte)<<16);
156 if (offset > header_offset) {
158 * The packet data begins before the file header ends.
160 *err = WTAP_ERR_BAD_FILE;
161 *err_info = ws_strdup_printf("Observer: The first packet begins in the middle of the file header");
162 return WTAP_OPEN_ERROR;
165 /* initialize the private state */
166 private_state = g_new(observer_dump_private_state, 1);
167 private_state->time_format = TIME_INFO_LOCAL;
168 wth->priv = (void *) private_state;
170 /* process extra information */
171 for (i = 0; i < file_header.number_of_information_elements; i++) {
172 unsigned tlv_data_length;
175 * Make sure reading the TLV header won't put us in the middle
176 * of the packet data.
178 if (offset + (unsigned)sizeof tlvh > header_offset) {
180 * We're at or past the point where the packet data begins,
181 * but we have the IE header to read.
183 *err = WTAP_ERR_BAD_FILE;
184 *err_info = ws_strdup_printf("Observer: TLVs run into the first packet data");
185 return WTAP_OPEN_ERROR;
188 /* read the TLV header */
189 if (!wtap_read_bytes(wth->fh, &tlvh, sizeof tlvh, err, err_info))
190 return WTAP_OPEN_ERROR;
191 offset += (unsigned)sizeof tlvh;
192 TLV_HEADER_FROM_LE_IN_PLACE(tlvh);
194 if (tlvh.length < sizeof tlvh) {
195 *err = WTAP_ERR_BAD_FILE;
196 *err_info = ws_strdup_printf("Observer: bad record (TLV length %u < %zu)",
197 tlvh.length, sizeof tlvh);
198 return WTAP_OPEN_ERROR;
201 tlv_data_length = tlvh.length - (unsigned)sizeof tlvh;
203 * Make sure reading the TLV data won't put us in the middle
204 * of the packet data.
206 if (offset + tlv_data_length > header_offset) {
208 * We're at or past the point where the packet data begins,
209 * but we have the IE data to read.
211 *err = WTAP_ERR_BAD_FILE;
212 *err_info = ws_strdup_printf("Observer: TLVs run into the first packet data");
213 return WTAP_OPEN_ERROR;
217 /* process (or skip over) the current TLV */
218 switch (tlvh.type) {
219 case INFORMATION_TYPE_TIME_INFO:
220 if (tlv_data_length != sizeof private_state->time_format) {
221 *err = WTAP_ERR_BAD_FILE;
222 *err_info = ws_strdup_printf("Observer: bad record (time information TLV length %u != %zu)",
223 tlvh.length,
224 sizeof tlvh + sizeof private_state->time_format);
225 return WTAP_OPEN_ERROR;
227 if (!wtap_read_bytes(wth->fh, &private_state->time_format,
228 sizeof private_state->time_format,
229 err, err_info))
230 return WTAP_OPEN_ERROR;
231 private_state->time_format = GUINT32_FROM_LE(private_state->time_format);
232 offset += (unsigned)sizeof private_state->time_format;
233 break;
234 default:
235 if (tlv_data_length != 0) {
236 if (!wtap_read_bytes(wth->fh, NULL, tlv_data_length, err, err_info))
237 return WTAP_OPEN_ERROR;
239 offset += tlv_data_length;
243 /* get to the first packet */
244 seek_increment = header_offset - offset;
245 if (seek_increment != 0) {
246 if (!wtap_read_bytes(wth->fh, NULL, seek_increment, err, err_info))
247 return WTAP_OPEN_ERROR;
251 * We assume that all packets in a file have the same network type,
252 * whether they're data or expert information packets, and thus
253 * we can attempt to determine the network type by reading the
254 * first packet.
256 * If that's *not* the case, we need to use WTAP_ENCAP_PER_PACKET.
258 * Read the packet header. Don't assume there *is* a packet;
259 * if there isn't, report that as a bad file. (If we use
260 * WTAP_ENCAP_PER_PACKET, we don't need to handle that case, as
261 * we don't need to read the first packet.
263 if (!wtap_read_bytes_or_eof(wth->fh, &packet_header, sizeof packet_header,
264 err, err_info)) {
265 if (*err == 0) {
267 * EOF, so there *are* no records.
269 *err = WTAP_ERR_BAD_FILE;
270 *err_info = ws_strdup_printf("Observer: No records in the file, so we can't determine the link-layer type");
272 return WTAP_OPEN_ERROR;
274 PACKET_ENTRY_HEADER_FROM_LE_IN_PLACE(packet_header);
276 /* check the packet's magic number */
277 if (packet_header.packet_magic != observer_packet_magic) {
278 *err = WTAP_ERR_UNSUPPORTED;
279 *err_info = ws_strdup_printf("Observer: unsupported packet version %ul", packet_header.packet_magic);
280 return WTAP_OPEN_ERROR;
283 /* check the data link type */
284 if (observer_to_wtap_encap(packet_header.network_type) == WTAP_ENCAP_UNKNOWN) {
285 *err = WTAP_ERR_UNSUPPORTED;
286 *err_info = ws_strdup_printf("Observer: network type %u unknown or unsupported", packet_header.network_type);
287 return WTAP_OPEN_ERROR;
289 wth->file_encap = observer_to_wtap_encap(packet_header.network_type);
291 /* set up the rest of the capture parameters */
292 private_state->packet_count = 0;
293 private_state->network_type = wtap_to_observer_encap(wth->file_encap);
294 wth->subtype_read = observer_read;
295 wth->subtype_seek_read = observer_seek_read;
296 wth->subtype_close = NULL;
297 wth->subtype_sequential_close = NULL;
298 wth->snapshot_length = 0; /* not available in header */
299 wth->file_tsprec = WTAP_TSPREC_NSEC;
300 wth->file_type_subtype = observer_file_type_subtype;
302 /* reset the pointer to the first packet */
303 if (file_seek(wth->fh, header_offset, SEEK_SET, err) == -1)
304 return WTAP_OPEN_ERROR;
306 err_str = init_gmt_to_localtime_offset();
307 if (err_str != NULL) {
308 *err = WTAP_ERR_INTERNAL;
309 *err_info = ws_strdup_printf("observer: %s", err_str);
310 return WTAP_OPEN_ERROR;
314 * Add an IDB; we don't know how many interfaces were
315 * involved, so we just say one interface, about which
316 * we only know the link-layer type, snapshot length,
317 * and time stamp resolution.
319 wtap_add_generated_idb(wth);
321 return WTAP_OPEN_MINE;
324 /* Reads the next packet. */
325 static bool observer_read(wtap *wth, wtap_rec *rec, Buffer *buf,
326 int *err, char **err_info, int64_t *data_offset)
328 int header_bytes_consumed;
329 int data_bytes_consumed;
330 packet_entry_header packet_header;
332 /* skip records other than data records */
333 for (;;) {
334 *data_offset = file_tell(wth->fh);
336 /* process the packet header, including TLVs */
337 header_bytes_consumed = read_packet_header(wth, wth->fh, &rec->rec_header.packet_header.pseudo_header, &packet_header, err,
338 err_info);
339 if (header_bytes_consumed <= 0)
340 return false; /* EOF or error */
342 if (packet_header.packet_type == PACKET_TYPE_DATA_PACKET)
343 break;
345 /* skip to next packet */
346 if (!skip_to_next_packet(wth, packet_header.offset_to_next_packet,
347 header_bytes_consumed, err, err_info)) {
348 return false; /* EOF or error */
352 if (!process_packet_header(wth, &packet_header, rec, err, err_info))
353 return false;
355 /* read the frame data */
356 data_bytes_consumed = read_packet_data(wth->fh, packet_header.offset_to_frame,
357 header_bytes_consumed, buf, rec->rec_header.packet_header.caplen,
358 err, err_info);
359 if (data_bytes_consumed < 0) {
360 return false;
363 /* skip over any extra bytes following the frame data */
364 if (!skip_to_next_packet(wth, packet_header.offset_to_next_packet,
365 header_bytes_consumed + data_bytes_consumed, err, err_info)) {
366 return false;
369 return true;
372 /* Reads a packet at an offset. */
373 static bool observer_seek_read(wtap *wth, int64_t seek_off,
374 wtap_rec *rec, Buffer *buf, int *err, char **err_info)
376 union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header;
377 packet_entry_header packet_header;
378 int offset;
379 int data_bytes_consumed;
381 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
382 return false;
384 /* process the packet header, including TLVs */
385 offset = read_packet_header(wth, wth->random_fh, pseudo_header, &packet_header, err,
386 err_info);
387 if (offset <= 0)
388 return false; /* EOF or error */
390 if (!process_packet_header(wth, &packet_header, rec, err, err_info))
391 return false;
393 /* read the frame data */
394 data_bytes_consumed = read_packet_data(wth->random_fh, packet_header.offset_to_frame,
395 offset, buf, rec->rec_header.packet_header.caplen, err, err_info);
396 if (data_bytes_consumed < 0) {
397 return false;
400 return true;
403 static int
404 read_packet_header(wtap *wth, FILE_T fh, union wtap_pseudo_header *pseudo_header,
405 packet_entry_header *packet_header, int *err, char **err_info)
407 int offset;
408 unsigned i;
409 tlv_header tlvh;
410 tlv_wireless_info wireless_header;
412 offset = 0;
414 /* pull off the packet header */
415 if (!wtap_read_bytes_or_eof(fh, packet_header, sizeof *packet_header,
416 err, err_info)) {
417 if (*err != 0)
418 return -1;
419 return 0; /* EOF */
421 offset += (int)sizeof *packet_header;
422 PACKET_ENTRY_HEADER_FROM_LE_IN_PLACE(*packet_header);
424 /* check the packet's magic number */
425 if (packet_header->packet_magic != observer_packet_magic) {
428 * Some files are zero-padded at the end. There is no warning of this
429 * in the previous packet header information, such as setting
430 * offset_to_next_packet to zero. So detect this situation by treating
431 * an all-zero header as a sentinel. Return EOF when it is encountered,
432 * rather than treat it as a bad record.
434 for (i = 0; i < sizeof *packet_header; i++) {
435 if (((uint8_t*) packet_header)[i] != 0)
436 break;
438 if (i == sizeof *packet_header) {
439 *err = 0;
440 return 0; /* EOF */
443 *err = WTAP_ERR_BAD_FILE;
444 *err_info = ws_strdup_printf("Observer: bad record: Invalid magic number 0x%08x",
445 packet_header->packet_magic);
446 return -1;
449 /* initialize the pseudo header */
450 switch (wth->file_encap) {
451 case WTAP_ENCAP_ETHERNET:
452 /* There is no FCS in the frame */
453 pseudo_header->eth.fcs_len = 0;
454 break;
455 case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
456 memset(&pseudo_header->ieee_802_11, 0, sizeof(pseudo_header->ieee_802_11));
457 pseudo_header->ieee_802_11.fcs_len = 0;
458 pseudo_header->ieee_802_11.decrypted = false;
459 pseudo_header->ieee_802_11.datapad = false;
460 pseudo_header->ieee_802_11.phy = PHDR_802_11_PHY_UNKNOWN;
461 /* Updated below */
462 break;
465 /* process extra information */
466 for (i = 0; i < packet_header->number_of_information_elements; i++) {
467 unsigned tlv_data_length;
469 /* read the TLV header */
470 if (!wtap_read_bytes(fh, &tlvh, sizeof tlvh, err, err_info))
471 return -1;
472 offset += (int)sizeof tlvh;
473 TLV_HEADER_FROM_LE_IN_PLACE(tlvh);
475 if (tlvh.length < sizeof tlvh) {
476 *err = WTAP_ERR_BAD_FILE;
477 *err_info = ws_strdup_printf("Observer: bad record (TLV length %u < %zu)",
478 tlvh.length, sizeof tlvh);
479 return -1;
481 tlv_data_length = tlvh.length - (unsigned)sizeof tlvh;
483 /* process (or skip over) the current TLV */
484 switch (tlvh.type) {
485 case INFORMATION_TYPE_WIRELESS:
486 if (tlv_data_length != sizeof wireless_header) {
487 *err = WTAP_ERR_BAD_FILE;
488 *err_info = ws_strdup_printf("Observer: bad record (wireless TLV length %u != %zu)",
489 tlvh.length, sizeof tlvh + sizeof wireless_header);
490 return -1;
492 if (!wtap_read_bytes(fh, &wireless_header, sizeof wireless_header,
493 err, err_info))
494 return -1;
495 /* set decryption status */
496 /* XXX - what other bits are there in conditions? */
497 pseudo_header->ieee_802_11.decrypted = (wireless_header.conditions & WIRELESS_WEP_SUCCESS) != 0;
498 pseudo_header->ieee_802_11.has_channel = true;
499 pseudo_header->ieee_802_11.channel = wireless_header.frequency;
500 pseudo_header->ieee_802_11.has_data_rate = true;
501 pseudo_header->ieee_802_11.data_rate = wireless_header.rate;
502 pseudo_header->ieee_802_11.has_signal_percent = true;
503 pseudo_header->ieee_802_11.signal_percent = wireless_header.strengthPercent;
506 * We don't know they PHY, but we do have the data rate;
507 * try to guess the PHY based on the data rate and channel.
509 if (RATE_IS_DSSS(pseudo_header->ieee_802_11.data_rate)) {
510 /* 11b */
511 pseudo_header->ieee_802_11.phy = PHDR_802_11_PHY_11B;
512 pseudo_header->ieee_802_11.phy_info.info_11b.has_short_preamble = false;
513 } else if (RATE_IS_OFDM(pseudo_header->ieee_802_11.data_rate)) {
514 /* 11a or 11g, depending on the band. */
515 if (CHAN_IS_BG(pseudo_header->ieee_802_11.channel)) {
516 /* 11g */
517 pseudo_header->ieee_802_11.phy = PHDR_802_11_PHY_11G;
518 pseudo_header->ieee_802_11.phy_info.info_11g.has_mode = false;
519 } else {
520 /* 11a */
521 pseudo_header->ieee_802_11.phy = PHDR_802_11_PHY_11A;
522 pseudo_header->ieee_802_11.phy_info.info_11a.has_channel_type = false;
523 pseudo_header->ieee_802_11.phy_info.info_11a.has_turbo_type = false;
527 offset += (int)sizeof wireless_header;
528 break;
529 default:
530 /* skip the TLV data */
531 if (tlv_data_length != 0) {
532 if (!wtap_read_bytes(fh, NULL, tlv_data_length, err, err_info))
533 return -1;
535 offset += tlv_data_length;
539 return offset;
542 static bool
543 process_packet_header(wtap *wth, packet_entry_header *packet_header,
544 wtap_rec *rec, int *err, char **err_info)
546 /* set the wiretap record metadata fields */
547 rec->rec_type = REC_TYPE_PACKET;
548 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
549 rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
550 rec->rec_header.packet_header.pkt_encap = observer_to_wtap_encap(packet_header->network_type);
551 if(wth->file_encap == WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS) {
552 rec->rec_header.packet_header.len = packet_header->network_size;
553 rec->rec_header.packet_header.caplen = packet_header->captured_size;
554 } else {
556 * XXX - what are those 4 bytes?
558 * The comment in the code said "neglect frame markers for wiretap",
559 * but in the captures I've seen, there's no actual data corresponding
560 * to them that might be a "frame marker".
562 * Instead, the packets had a network_size 4 bytes larger than the
563 * captured_size; does the network_size include the CRC, even
564 * though it's not included in a capture? If so, most other
565 * network analyzers that have a "network size" and a "captured
566 * size" don't include the CRC in the "network size" if they
567 * don't include the CRC in a full-length captured packet; the
568 * "captured size" is less than the "network size" only if a
569 * user-specified "snapshot length" caused the packet to be
570 * sliced at a particular point.
572 * That's the model that wiretap and Wireshark/TShark use, so
573 * we implement that model here.
575 if (packet_header->network_size < 4) {
576 *err = WTAP_ERR_BAD_FILE;
577 *err_info = ws_strdup_printf("Observer: bad record: Packet length %u < 4",
578 packet_header->network_size);
579 return false;
582 rec->rec_header.packet_header.len = packet_header->network_size - 4;
583 rec->rec_header.packet_header.caplen = MIN(packet_header->captured_size, rec->rec_header.packet_header.len);
586 * The maximum value of packet_header->captured_size is 65535, which
587 * is less than WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need
588 * to check it.
591 /* set the wiretap timestamp, assuming for the moment that Observer encoded it in GMT */
592 rec->ts.secs = (time_t) ((packet_header->nano_seconds_since_2000 / 1000000000) + ansi_to_observer_epoch_offset);
593 rec->ts.nsecs = (int) (packet_header->nano_seconds_since_2000 % 1000000000);
595 /* adjust to local time, if necessary, also accounting for DST if the frame
596 was captured while it was in effect */
597 if (((observer_dump_private_state*)wth->priv)->time_format == TIME_INFO_LOCAL)
599 struct tm *tm;
600 struct tm daylight_tm;
601 struct tm standard_tm;
602 time_t dst_offset;
604 /* the Observer timestamp was encoded as local time, so add a
605 correction from local time to GMT */
606 rec->ts.secs += gmt_to_localtime_offset;
608 /* perform a DST adjustment if necessary */
609 tm = localtime(&rec->ts.secs);
610 if (tm != NULL) {
611 standard_tm = *tm;
612 if (standard_tm.tm_isdst > 0) {
613 daylight_tm = standard_tm;
614 standard_tm.tm_isdst = 0;
615 dst_offset = mktime(&standard_tm) - mktime(&daylight_tm);
616 rec->ts.secs -= dst_offset;
621 return true;
624 static int
625 read_packet_data(FILE_T fh, int offset_to_frame, int current_offset_from_packet_header, Buffer *buf,
626 int length, int *err, char **err_info)
628 int seek_increment;
629 int bytes_consumed = 0;
631 /* validate offsets */
632 if (offset_to_frame < current_offset_from_packet_header) {
633 *err = WTAP_ERR_BAD_FILE;
634 *err_info = ws_strdup_printf("Observer: bad record (offset to packet data %d < %d)",
635 offset_to_frame, current_offset_from_packet_header);
636 return -1;
639 /* skip to the packet data */
640 seek_increment = offset_to_frame - current_offset_from_packet_header;
641 if (seek_increment > 0) {
642 if (!wtap_read_bytes(fh, NULL, seek_increment, err, err_info)) {
643 return -1;
645 bytes_consumed += seek_increment;
648 /* read in the packet data */
649 if (!wtap_read_packet_bytes(fh, buf, length, err, err_info))
650 return false;
651 bytes_consumed += length;
653 return bytes_consumed;
656 static bool
657 skip_to_next_packet(wtap *wth, int offset_to_next_packet, int current_offset_from_packet_header, int *err,
658 char **err_info)
660 int seek_increment;
662 /* validate offsets */
663 if (offset_to_next_packet < current_offset_from_packet_header) {
664 *err = WTAP_ERR_BAD_FILE;
665 *err_info = ws_strdup_printf("Observer: bad record (offset to next packet %d < %d)",
666 offset_to_next_packet, current_offset_from_packet_header);
667 return false;
670 /* skip to the next packet header */
671 seek_increment = offset_to_next_packet - current_offset_from_packet_header;
672 if (seek_increment > 0) {
673 if (!wtap_read_bytes(wth->fh, NULL, seek_increment, err, err_info))
674 return false;
677 return true;
680 /* Returns 0 if we could write the specified encapsulation type,
681 an error indication otherwise. */
682 static int observer_dump_can_write_encap(int encap)
684 /* per-packet encapsulations aren't supported */
685 if (encap == WTAP_ENCAP_PER_PACKET)
686 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
688 if (encap < 0 || (wtap_to_observer_encap(encap) == OBSERVER_UNDEFINED))
689 return WTAP_ERR_UNWRITABLE_ENCAP;
691 return 0;
694 /* Returns true on success, false on failure; sets "*err" to an error code on
695 failure. */
696 static bool observer_dump_open(wtap_dumper *wdh, int *err,
697 char **err_info)
699 observer_dump_private_state * private_state = NULL;
700 capture_file_header file_header;
701 unsigned header_offset;
702 const char *err_str;
703 tlv_header comment_header;
704 char comment[64];
705 size_t comment_length;
706 tlv_header time_info_header;
707 tlv_time_info time_info;
708 struct tm * current_time;
709 time_t system_time;
711 /* initialize the private state */
712 private_state = g_new(observer_dump_private_state, 1);
713 private_state->packet_count = 0;
714 private_state->network_type = wtap_to_observer_encap(wdh->file_encap);
715 private_state->time_format = TIME_INFO_GMT;
717 /* populate the fields of wdh */
718 wdh->priv = (void *) private_state;
719 wdh->subtype_write = observer_dump;
721 /* initialize the file header */
722 memset(&file_header, 0x00, sizeof(file_header));
723 (void) g_strlcpy(file_header.observer_version, observer_magic, 31);
724 header_offset = (uint16_t)sizeof(file_header);
726 /* create the file comment TLV */
728 time(&system_time);
729 current_time = localtime(&system_time);
730 memset(&comment, 0x00, sizeof(comment));
731 if (current_time != NULL)
732 snprintf(comment, 64, "This capture was saved from Wireshark on %s", asctime(current_time));
733 else
734 snprintf(comment, 64, "This capture was saved from Wireshark");
735 comment_length = strlen(comment);
737 comment_header.type = INFORMATION_TYPE_COMMENT;
738 comment_header.length = (uint16_t) (sizeof(comment_header) + comment_length);
740 /* update the file header to account for the comment TLV */
741 file_header.number_of_information_elements++;
742 header_offset += comment_header.length;
745 /* create the timestamp encoding TLV */
747 time_info_header.type = INFORMATION_TYPE_TIME_INFO;
748 time_info_header.length = (uint16_t) (sizeof(time_info_header) + sizeof(time_info));
749 time_info.time_format = TIME_INFO_GMT;
751 /* update the file header to account for the timestamp encoding TLV */
752 file_header.number_of_information_elements++;
753 header_offset += time_info_header.length;
756 /* Store the offset to the first packet */
757 file_header.offset_to_first_packet_high_byte = (header_offset >> 16);
758 file_header.offset_to_first_packet = (header_offset & 0xFFFF);
760 /* write the file header, swapping any multibyte fields first */
761 CAPTURE_FILE_HEADER_TO_LE_IN_PLACE(file_header);
762 if (!wtap_dump_file_write(wdh, &file_header, sizeof(file_header), err)) {
763 return false;
766 /* write the comment TLV */
768 TLV_HEADER_TO_LE_IN_PLACE(comment_header);
769 if (!wtap_dump_file_write(wdh, &comment_header, sizeof(comment_header), err)) {
770 return false;
773 if (!wtap_dump_file_write(wdh, &comment, comment_length, err)) {
774 return false;
778 /* write the time info TLV */
780 TLV_HEADER_TO_LE_IN_PLACE(time_info_header);
781 if (!wtap_dump_file_write(wdh, &time_info_header, sizeof(time_info_header), err)) {
782 return false;
785 TLV_TIME_INFO_TO_LE_IN_PLACE(time_info);
786 if (!wtap_dump_file_write(wdh, &time_info, sizeof(time_info), err)) {
787 return false;
791 err_str = init_gmt_to_localtime_offset();
792 if (err_str != NULL) {
793 *err = WTAP_ERR_INTERNAL;
794 *err_info = ws_strdup_printf("observer: %s", err_str);
795 return false;
798 return true;
801 /* Write a record for a packet to a dump file.
802 Returns true on success, false on failure. */
803 static bool observer_dump(wtap_dumper *wdh, const wtap_rec *rec,
804 const uint8_t *pd,
805 int *err, char **err_info _U_)
807 observer_dump_private_state * private_state = NULL;
808 packet_entry_header packet_header;
809 uint64_t seconds_since_2000;
811 /* We can only write packet records. */
812 if (rec->rec_type != REC_TYPE_PACKET) {
813 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
814 return false;
818 * Make sure this packet doesn't have a link-layer type that
819 * differs from the one for the file.
821 if (wdh->file_encap != rec->rec_header.packet_header.pkt_encap) {
822 *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
823 return false;
826 /* The captured size field is 16 bits, so there's a hard limit of
827 65535. */
828 if (rec->rec_header.packet_header.caplen > 65535) {
829 *err = WTAP_ERR_PACKET_TOO_LARGE;
830 return false;
833 /* convert the number of seconds since epoch from ANSI-relative to
834 Observer-relative */
835 if (rec->ts.secs < ansi_to_observer_epoch_offset) {
836 if(rec->ts.secs > (time_t) 0) {
837 seconds_since_2000 = rec->ts.secs;
838 } else {
839 seconds_since_2000 = (time_t) 0;
841 } else {
842 seconds_since_2000 = rec->ts.secs - ansi_to_observer_epoch_offset;
845 /* populate the fields of the packet header */
846 private_state = (observer_dump_private_state *) wdh->priv;
848 memset(&packet_header, 0x00, sizeof(packet_header));
849 packet_header.packet_magic = observer_packet_magic;
850 packet_header.network_speed = 1000000;
851 packet_header.captured_size = (uint16_t) rec->rec_header.packet_header.caplen;
852 packet_header.network_size = (uint16_t) (rec->rec_header.packet_header.len + 4);
853 packet_header.offset_to_frame = sizeof(packet_header);
854 /* XXX - what if this doesn't fit in 16 bits? It's not guaranteed to... */
855 packet_header.offset_to_next_packet = (uint16_t)sizeof(packet_header) + rec->rec_header.packet_header.caplen;
856 packet_header.network_type = private_state->network_type;
857 packet_header.flags = 0x00;
858 packet_header.number_of_information_elements = 0;
859 packet_header.packet_type = PACKET_TYPE_DATA_PACKET;
860 packet_header.packet_number = private_state->packet_count;
861 packet_header.original_packet_number = packet_header.packet_number;
862 packet_header.nano_seconds_since_2000 = seconds_since_2000 * 1000000000 + rec->ts.nsecs;
864 private_state->packet_count++;
866 /* write the packet header */
867 PACKET_ENTRY_HEADER_TO_LE_IN_PLACE(packet_header);
868 if (!wtap_dump_file_write(wdh, &packet_header, sizeof(packet_header), err)) {
869 return false;
872 /* write the packet data */
873 if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err)) {
874 return false;
877 return true;
880 static int observer_to_wtap_encap(int observer_encap)
882 switch(observer_encap) {
883 case OBSERVER_ETHERNET:
884 return WTAP_ENCAP_ETHERNET;
885 case OBSERVER_TOKENRING:
886 return WTAP_ENCAP_TOKEN_RING;
887 case OBSERVER_FIBRE_CHANNEL:
888 return WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS;
889 case OBSERVER_WIRELESS_802_11:
890 return WTAP_ENCAP_IEEE_802_11_WITH_RADIO;
891 case OBSERVER_UNDEFINED:
892 return WTAP_ENCAP_UNKNOWN;
894 return WTAP_ENCAP_UNKNOWN;
897 static int wtap_to_observer_encap(int wtap_encap)
899 switch(wtap_encap) {
900 case WTAP_ENCAP_ETHERNET:
901 return OBSERVER_ETHERNET;
902 case WTAP_ENCAP_TOKEN_RING:
903 return OBSERVER_TOKENRING;
904 case WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS:
905 return OBSERVER_FIBRE_CHANNEL;
906 case WTAP_ENCAP_UNKNOWN:
907 return OBSERVER_UNDEFINED;
909 return OBSERVER_UNDEFINED;
912 static const struct supported_block_type observer_blocks_supported[] = {
914 * We support packet blocks, with no comments or other options.
916 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
919 static const struct file_type_subtype_info observer_info = {
920 "Viavi Observer", "observer", "bfr", NULL,
921 false, BLOCKS_SUPPORTED(observer_blocks_supported),
922 observer_dump_can_write_encap, observer_dump_open, NULL
925 void register_observer(void)
927 observer_file_type_subtype = wtap_register_file_type_subtype(&observer_info);
930 * We now call this file format just "observer", but we allow
931 * it to be referred to as "niobserver" for backwards
932 * compatibility.
934 * Register "niobserver" for that purpose.
936 wtap_register_compatibility_file_subtype_name("niobserver", "observer");
939 * Register name for backwards compatibility with the
940 * wtap_filetypes table in Lua.
942 wtap_register_backwards_compatibility_lua_name("NETWORK_INSTRUMENTS",
943 observer_file_type_subtype);
947 * Editor modelines - https://www.wireshark.org/tools/modelines.html
949 * Local variables:
950 * c-basic-offset: 4
951 * tab-width: 8
952 * indent-tabs-mode: nil
953 * End:
955 * vi: set shiftwidth=4 tabstop=8 expandtab:
956 * :indentSize=4:tabSize=8:noTabs=true: