1 /***************************************************************************
2 network_instruments.c - description
4 begin : Wed Oct 29 2003
5 copyright : (C) 2003 by root
6 email : scotte[AT}netinst.com
7 ***************************************************************************/
9 /***************************************************************************
11 * SPDX-License-Identifier: GPL-2.0-or-later *
13 ***************************************************************************/
21 #include "file_wrappers.h"
22 #include "network_instruments.h"
24 static const char network_instruments_magic[] = {"ObserverPktBufferVersion=15.00"};
25 static const int true_magic_length = 17;
27 static const guint32 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
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
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;
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);
89 return "gmtime(one day past the Epoch) fails (this \"shouldn't happen\")";
91 tm = localtime(&ansi_epoch_plus_one_day);
93 return "localtime(one day past the Epoch) fails (this \"shouldn't happen\")";
95 local_tm.tm_isdst = 0;
96 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 wtap_rec *rec, Buffer *buf, int *err, gchar **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, gchar **err_info);
107 static gboolean process_packet_header(wtap *wth,
108 packet_entry_header *packet_header, wtap_rec *rec, int *err,
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 gboolean 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 gboolean observer_dump(wtap_dumper *wdh, const wtap_rec *rec,
115 const guint8 *pd, int *err, gchar **err_info);
116 static gint observer_to_wtap_encap(int observer_encap);
117 static gint wtap_to_observer_encap(int wtap_encap);
119 wtap_open_return_val network_instruments_open(wtap *wth, int *err, gchar **err_info)
122 capture_file_header file_header;
127 packet_entry_header packet_header;
128 observer_dump_private_state * private_state = NULL;
132 /* read in the buffer file header */
133 if (!wtap_read_bytes(wth->fh, &file_header, sizeof file_header,
135 if (*err != WTAP_ERR_SHORT_READ)
136 return WTAP_OPEN_ERROR;
137 return WTAP_OPEN_NOT_MINE;
139 offset += (int)sizeof file_header;
140 CAPTURE_FILE_HEADER_FROM_LE_IN_PLACE(file_header);
142 /* check if version info is present */
143 if (memcmp(file_header.observer_version, network_instruments_magic, true_magic_length)!=0) {
144 return WTAP_OPEN_NOT_MINE;
147 /* initialize the private state */
148 private_state = (observer_dump_private_state *) g_malloc(sizeof(observer_dump_private_state));
149 private_state->time_format = TIME_INFO_LOCAL;
150 wth->priv = (void *) private_state;
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 + ((int)(file_header.offset_to_first_packet_high_byte)<<16);
156 /* process extra information */
157 for (i = 0; i < file_header.number_of_information_elements; i++) {
158 /* for safety break if we've reached the first packet */
159 if (offset >= header_offset)
162 /* read the TLV header */
163 if (!wtap_read_bytes(wth->fh, &tlvh, sizeof tlvh, err, err_info))
164 return WTAP_OPEN_ERROR;
165 offset += (int)sizeof tlvh;
166 TLV_HEADER_FROM_LE_IN_PLACE(tlvh);
168 if (tlvh.length < sizeof tlvh) {
169 *err = WTAP_ERR_BAD_FILE;
170 *err_info = g_strdup_printf("Observer: bad record (TLV length %u < %lu)",
171 tlvh.length, (unsigned long)sizeof tlvh);
172 return WTAP_OPEN_ERROR;
175 /* process (or skip over) the current TLV */
177 case INFORMATION_TYPE_TIME_INFO:
178 /* XXX - what if tlvh.length != sizeof sizeof private_state->time_format? */
179 if (!wtap_read_bytes(wth->fh, &private_state->time_format,
180 sizeof private_state->time_format,
182 return WTAP_OPEN_ERROR;
183 private_state->time_format = GUINT32_FROM_LE(private_state->time_format);
184 offset += (int)sizeof private_state->time_format;
187 seek_increment = tlvh.length - (int)sizeof tlvh;
188 if (seek_increment > 0) {
189 if (!wtap_read_bytes(wth->fh, NULL, seek_increment, err, err_info))
190 return WTAP_OPEN_ERROR;
192 offset += seek_increment;
196 /* get to the first packet */
197 if (header_offset < offset) {
198 *err = WTAP_ERR_BAD_FILE;
199 *err_info = g_strdup_printf("Observer: bad record (offset to first packet %d < %d)",
200 header_offset, offset);
201 return WTAP_OPEN_ERROR;
203 seek_increment = header_offset - offset;
204 if (seek_increment > 0) {
205 if (!wtap_read_bytes(wth->fh, NULL, seek_increment, err, err_info))
206 return WTAP_OPEN_ERROR;
209 /* pull off the packet header */
210 if (!wtap_read_bytes(wth->fh, &packet_header, sizeof packet_header,
212 return WTAP_OPEN_ERROR;
213 PACKET_ENTRY_HEADER_FROM_LE_IN_PLACE(packet_header);
215 /* check the packet's magic number */
216 if (packet_header.packet_magic != observer_packet_magic) {
217 *err = WTAP_ERR_UNSUPPORTED;
218 *err_info = g_strdup_printf("Observer: unsupported packet version %ul", packet_header.packet_magic);
219 return WTAP_OPEN_ERROR;
222 /* check the data link type */
223 if (observer_to_wtap_encap(packet_header.network_type) == WTAP_ENCAP_UNKNOWN) {
224 *err = WTAP_ERR_UNSUPPORTED;
225 *err_info = g_strdup_printf("Observer: network type %u unknown or unsupported", packet_header.network_type);
226 return WTAP_OPEN_ERROR;
228 wth->file_encap = observer_to_wtap_encap(packet_header.network_type);
230 /* set up the rest of the capture parameters */
231 private_state->packet_count = 0;
232 private_state->network_type = wtap_to_observer_encap(wth->file_encap);
233 wth->subtype_read = observer_read;
234 wth->subtype_seek_read = observer_seek_read;
235 wth->subtype_close = NULL;
236 wth->subtype_sequential_close = NULL;
237 wth->snapshot_length = 0; /* not available in header */
238 wth->file_tsprec = WTAP_TSPREC_NSEC;
239 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_NETWORK_INSTRUMENTS;
241 /* reset the pointer to the first packet */
242 if (file_seek(wth->fh, header_offset, SEEK_SET, err) == -1)
243 return WTAP_OPEN_ERROR;
245 if (init_gmt_to_localtime_offset() != NULL) {
246 *err = WTAP_ERR_INTERNAL;
248 * XXX - we should return the error string, so the caller
249 * can report the details of the internal error, but that
250 * would require plugin file readers to do so for internal
251 * errors as well, which could break binary compatibility;
252 * we'll do that in the next release.
254 return WTAP_OPEN_ERROR;
257 return WTAP_OPEN_MINE;
260 /* Reads the next packet. */
261 static gboolean observer_read(wtap *wth, int *err, gchar **err_info,
264 int header_bytes_consumed;
265 int data_bytes_consumed;
266 packet_entry_header packet_header;
268 /* skip records other than data records */
270 *data_offset = file_tell(wth->fh);
272 /* process the packet header, including TLVs */
273 header_bytes_consumed = read_packet_header(wth, wth->fh, &wth->rec.rec_header.packet_header.pseudo_header, &packet_header, err,
275 if (header_bytes_consumed <= 0)
276 return FALSE; /* EOF or error */
278 if (packet_header.packet_type == PACKET_TYPE_DATA_PACKET)
281 /* skip to next packet */
282 if (!skip_to_next_packet(wth, packet_header.offset_to_next_packet,
283 header_bytes_consumed, err, err_info)) {
284 return FALSE; /* EOF or error */
288 if (!process_packet_header(wth, &packet_header, &wth->rec, err, err_info))
291 /* read the frame data */
292 data_bytes_consumed = read_packet_data(wth->fh, packet_header.offset_to_frame,
293 header_bytes_consumed, wth->rec_data,
294 wth->rec.rec_header.packet_header.caplen, err, err_info);
295 if (data_bytes_consumed < 0) {
299 /* skip over any extra bytes following the frame data */
300 if (!skip_to_next_packet(wth, packet_header.offset_to_next_packet,
301 header_bytes_consumed + data_bytes_consumed, err, err_info)) {
308 /* Reads a packet at an offset. */
309 static gboolean observer_seek_read(wtap *wth, gint64 seek_off,
310 wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
312 union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header;
313 packet_entry_header packet_header;
315 int data_bytes_consumed;
317 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
320 /* process the packet header, including TLVs */
321 offset = read_packet_header(wth, wth->random_fh, pseudo_header, &packet_header, err,
324 return FALSE; /* EOF or error */
326 if (!process_packet_header(wth, &packet_header, rec, err, err_info))
329 /* read the frame data */
330 data_bytes_consumed = read_packet_data(wth->random_fh, packet_header.offset_to_frame,
331 offset, buf, rec->rec_header.packet_header.caplen, err, err_info);
332 if (data_bytes_consumed < 0) {
340 read_packet_header(wtap *wth, FILE_T fh, union wtap_pseudo_header *pseudo_header,
341 packet_entry_header *packet_header, int *err, gchar **err_info)
347 tlv_wireless_info wireless_header;
351 /* pull off the packet header */
352 if (!wtap_read_bytes_or_eof(fh, packet_header, sizeof *packet_header,
358 offset += (int)sizeof *packet_header;
359 PACKET_ENTRY_HEADER_FROM_LE_IN_PLACE(*packet_header);
361 /* check the packet's magic number */
362 if (packet_header->packet_magic != observer_packet_magic) {
365 * Some files are zero-padded at the end. There is no warning of this
366 * in the previous packet header information, such as setting
367 * offset_to_next_packet to zero. So detect this situation by treating
368 * an all-zero header as a sentinel. Return EOF when it is encountered,
369 * rather than treat it as a bad record.
371 for (i = 0; i < sizeof *packet_header; i++) {
372 if (((guint8*) packet_header)[i] != 0)
375 if (i == sizeof *packet_header) {
380 *err = WTAP_ERR_BAD_FILE;
381 *err_info = g_strdup_printf("Observer: bad record: Invalid magic number 0x%08x",
382 packet_header->packet_magic);
386 /* initialize the pseudo header */
387 switch (wth->file_encap) {
388 case WTAP_ENCAP_ETHERNET:
389 /* There is no FCS in the frame */
390 pseudo_header->eth.fcs_len = 0;
392 case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
393 memset(&pseudo_header->ieee_802_11, 0, sizeof(pseudo_header->ieee_802_11));
394 pseudo_header->ieee_802_11.fcs_len = 0;
395 pseudo_header->ieee_802_11.decrypted = FALSE;
396 pseudo_header->ieee_802_11.datapad = FALSE;
397 pseudo_header->ieee_802_11.phy = PHDR_802_11_PHY_UNKNOWN;
402 /* process extra information */
403 for (i = 0; i < packet_header->number_of_information_elements; i++) {
404 /* read the TLV header */
405 if (!wtap_read_bytes(fh, &tlvh, sizeof tlvh, err, err_info))
407 offset += (int)sizeof tlvh;
408 TLV_HEADER_FROM_LE_IN_PLACE(tlvh);
410 if (tlvh.length < sizeof tlvh) {
411 *err = WTAP_ERR_BAD_FILE;
412 *err_info = g_strdup_printf("Observer: bad record (TLV length %u < %lu)",
413 tlvh.length, (unsigned long)sizeof tlvh);
417 /* process (or skip over) the current TLV */
419 case INFORMATION_TYPE_WIRELESS:
420 /* XXX - what if tlvh.length != sizeof wireless_header? */
421 if (!wtap_read_bytes(fh, &wireless_header, sizeof wireless_header,
424 /* set decryption status */
425 /* XXX - what other bits are there in conditions? */
426 pseudo_header->ieee_802_11.decrypted = (wireless_header.conditions & WIRELESS_WEP_SUCCESS) != 0;
427 pseudo_header->ieee_802_11.has_channel = TRUE;
428 pseudo_header->ieee_802_11.channel = wireless_header.frequency;
429 pseudo_header->ieee_802_11.has_data_rate = TRUE;
430 pseudo_header->ieee_802_11.data_rate = wireless_header.rate;
431 pseudo_header->ieee_802_11.has_signal_percent = TRUE;
432 pseudo_header->ieee_802_11.signal_percent = wireless_header.strengthPercent;
433 offset += (int)sizeof wireless_header;
436 /* skip the TLV data */
437 seek_increment = tlvh.length - (int)sizeof tlvh;
438 if (seek_increment > 0) {
439 if (!wtap_read_bytes(fh, NULL, seek_increment, err, err_info))
442 offset += seek_increment;
450 process_packet_header(wtap *wth, packet_entry_header *packet_header,
451 wtap_rec *rec, int *err, gchar **err_info)
453 /* set the wiretap record metadata fields */
454 rec->rec_type = REC_TYPE_PACKET;
455 rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
456 rec->rec_header.packet_header.pkt_encap = observer_to_wtap_encap(packet_header->network_type);
457 if(wth->file_encap == WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS) {
458 rec->rec_header.packet_header.len = packet_header->network_size;
459 rec->rec_header.packet_header.caplen = packet_header->captured_size;
462 * XXX - what are those 4 bytes?
464 * The comment in the code said "neglect frame markers for wiretap",
465 * but in the captures I've seen, there's no actual data corresponding
466 * to them that might be a "frame marker".
468 * Instead, the packets had a network_size 4 bytes larger than the
469 * captured_size; does the network_size include the CRC, even
470 * though it's not included in a capture? If so, most other
471 * network analyzers that have a "network size" and a "captured
472 * size" don't include the CRC in the "network size" if they
473 * don't include the CRC in a full-length captured packet; the
474 * "captured size" is less than the "network size" only if a
475 * user-specified "snapshot length" caused the packet to be
476 * sliced at a particular point.
478 * That's the model that wiretap and Wireshark/TShark use, so
479 * we implement that model here.
481 if (packet_header->network_size < 4) {
482 *err = WTAP_ERR_BAD_FILE;
483 *err_info = g_strdup_printf("Observer: bad record: Packet length %u < 4",
484 packet_header->network_size);
488 rec->rec_header.packet_header.len = packet_header->network_size - 4;
489 rec->rec_header.packet_header.caplen = MIN(packet_header->captured_size, rec->rec_header.packet_header.len);
492 * The maximum value of packet_header->captured_size is 65535, which
493 * is less than WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need
497 /* set the wiretap timestamp, assuming for the moment that Observer encoded it in GMT */
498 rec->ts.secs = (time_t) ((packet_header->nano_seconds_since_2000 / 1000000000) + ansi_to_observer_epoch_offset);
499 rec->ts.nsecs = (int) (packet_header->nano_seconds_since_2000 % 1000000000);
501 /* adjust to local time, if necessary, also accounting for DST if the frame
502 was captured while it was in effect */
503 if (((observer_dump_private_state*)wth->priv)->time_format == TIME_INFO_LOCAL)
506 struct tm daylight_tm;
507 struct tm standard_tm;
510 /* the Observer timestamp was encoded as local time, so add a
511 correction from local time to GMT */
512 rec->ts.secs += gmt_to_localtime_offset;
514 /* perform a DST adjustment if necessary */
515 tm = localtime(&rec->ts.secs);
518 if (standard_tm.tm_isdst > 0) {
519 daylight_tm = standard_tm;
520 standard_tm.tm_isdst = 0;
521 dst_offset = mktime(&standard_tm) - mktime(&daylight_tm);
522 rec->ts.secs -= dst_offset;
531 read_packet_data(FILE_T fh, int offset_to_frame, int current_offset_from_packet_header, Buffer *buf,
532 int length, int *err, char **err_info)
535 int bytes_consumed = 0;
537 /* validate offsets */
538 if (offset_to_frame < current_offset_from_packet_header) {
539 *err = WTAP_ERR_BAD_FILE;
540 *err_info = g_strdup_printf("Observer: bad record (offset to packet data %d < %d)",
541 offset_to_frame, current_offset_from_packet_header);
545 /* skip to the packet data */
546 seek_increment = offset_to_frame - current_offset_from_packet_header;
547 if (seek_increment > 0) {
548 if (!wtap_read_bytes(fh, NULL, seek_increment, err, err_info)) {
551 bytes_consumed += seek_increment;
554 /* read in the packet data */
555 if (!wtap_read_packet_bytes(fh, buf, length, err, err_info))
557 bytes_consumed += length;
559 return bytes_consumed;
563 skip_to_next_packet(wtap *wth, int offset_to_next_packet, int current_offset_from_packet_header, int *err,
568 /* validate offsets */
569 if (offset_to_next_packet < current_offset_from_packet_header) {
570 *err = WTAP_ERR_BAD_FILE;
571 *err_info = g_strdup_printf("Observer: bad record (offset to next packet %d < %d)",
572 offset_to_next_packet, current_offset_from_packet_header);
576 /* skip to the next packet header */
577 seek_increment = offset_to_next_packet - current_offset_from_packet_header;
578 if (seek_increment > 0) {
579 if (!wtap_read_bytes(wth->fh, NULL, seek_increment, err, err_info))
586 /* Returns 0 if we could write the specified encapsulation type,
587 an error indication otherwise. */
588 int network_instruments_dump_can_write_encap(int encap)
590 /* per-packet encapsulations aren't supported */
591 if (encap == WTAP_ENCAP_PER_PACKET)
592 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
594 if (encap < 0 || (wtap_to_observer_encap(encap) == OBSERVER_UNDEFINED))
595 return WTAP_ERR_UNWRITABLE_ENCAP;
600 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
602 gboolean network_instruments_dump_open(wtap_dumper *wdh, int *err)
604 observer_dump_private_state * private_state = NULL;
605 capture_file_header file_header;
607 tlv_header comment_header;
608 tlv_time_info time_header;
610 size_t comment_length;
611 struct tm * current_time;
614 /* initialize the private state */
615 private_state = (observer_dump_private_state *) g_malloc(sizeof(observer_dump_private_state));
616 private_state->packet_count = 0;
617 private_state->network_type = wtap_to_observer_encap(wdh->encap);
618 private_state->time_format = TIME_INFO_GMT;
620 /* populate the fields of wdh */
621 wdh->priv = (void *) private_state;
622 wdh->subtype_write = observer_dump;
624 /* initialize the file header */
625 memset(&file_header, 0x00, sizeof(file_header));
626 g_strlcpy(file_header.observer_version, network_instruments_magic, 31);
627 file_header.offset_to_first_packet = (guint16)sizeof(file_header);
628 file_header.offset_to_first_packet_high_byte = 0;
630 /* create the file comment TLV */
633 current_time = localtime(&system_time);
634 memset(&comment, 0x00, sizeof(comment));
635 if (current_time != NULL)
636 g_snprintf(comment, 64, "This capture was saved from Wireshark on %s", asctime(current_time));
638 g_snprintf(comment, 64, "This capture was saved from Wireshark");
639 comment_length = strlen(comment);
641 comment_header.type = INFORMATION_TYPE_COMMENT;
642 comment_header.length = (guint16) (sizeof(comment_header) + comment_length);
644 /* update the file header to account for the comment TLV */
645 file_header.number_of_information_elements++;
646 file_header.offset_to_first_packet += comment_header.length;
649 /* create the timestamp encoding TLV */
651 time_header.type = INFORMATION_TYPE_TIME_INFO;
652 time_header.length = (guint16) (sizeof(time_header));
653 time_header.time_format = TIME_INFO_GMT;
655 /* update the file header to account for the timestamp encoding TLV */
656 file_header.number_of_information_elements++;
657 file_header.offset_to_first_packet += time_header.length;
660 /* write the file header, swapping any multibyte fields first */
661 CAPTURE_FILE_HEADER_TO_LE_IN_PLACE(file_header);
662 if (!wtap_dump_file_write(wdh, &file_header, sizeof(file_header), err)) {
665 wdh->bytes_dumped += sizeof(file_header);
667 /* write the comment TLV */
669 TLV_HEADER_TO_LE_IN_PLACE(comment_header);
670 if (!wtap_dump_file_write(wdh, &comment_header, sizeof(comment_header), err)) {
673 wdh->bytes_dumped += sizeof(comment_header);
675 if (!wtap_dump_file_write(wdh, &comment, comment_length, err)) {
678 wdh->bytes_dumped += comment_length;
681 /* write the time info TLV */
683 TLV_TIME_INFO_TO_LE_IN_PLACE(time_header);
684 if (!wtap_dump_file_write(wdh, &time_header, sizeof(time_header), err)) {
687 wdh->bytes_dumped += sizeof(time_header);
690 init_gmt_to_localtime_offset();
695 /* Write a record for a packet to a dump file.
696 Returns TRUE on success, FALSE on failure. */
697 static gboolean observer_dump(wtap_dumper *wdh, const wtap_rec *rec,
699 int *err, gchar **err_info _U_)
701 observer_dump_private_state * private_state = NULL;
702 packet_entry_header packet_header;
703 guint64 seconds_since_2000;
705 /* We can only write packet records. */
706 if (rec->rec_type != REC_TYPE_PACKET) {
707 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
711 /* The captured size field is 16 bits, so there's a hard limit of
713 if (rec->rec_header.packet_header.caplen > 65535) {
714 *err = WTAP_ERR_PACKET_TOO_LARGE;
718 /* convert the number of seconds since epoch from ANSI-relative to
720 if (rec->ts.secs < ansi_to_observer_epoch_offset) {
721 if(rec->ts.secs > (time_t) 0) {
722 seconds_since_2000 = rec->ts.secs;
724 seconds_since_2000 = (time_t) 0;
727 seconds_since_2000 = rec->ts.secs - ansi_to_observer_epoch_offset;
730 /* populate the fields of the packet header */
731 private_state = (observer_dump_private_state *) wdh->priv;
733 memset(&packet_header, 0x00, sizeof(packet_header));
734 packet_header.packet_magic = observer_packet_magic;
735 packet_header.network_speed = 1000000;
736 packet_header.captured_size = (guint16) rec->rec_header.packet_header.caplen;
737 packet_header.network_size = (guint16) (rec->rec_header.packet_header.len + 4);
738 packet_header.offset_to_frame = sizeof(packet_header);
739 /* XXX - what if this doesn't fit in 16 bits? It's not guaranteed to... */
740 packet_header.offset_to_next_packet = (guint16)sizeof(packet_header) + rec->rec_header.packet_header.caplen;
741 packet_header.network_type = private_state->network_type;
742 packet_header.flags = 0x00;
743 packet_header.number_of_information_elements = 0;
744 packet_header.packet_type = PACKET_TYPE_DATA_PACKET;
745 packet_header.packet_number = private_state->packet_count;
746 packet_header.original_packet_number = packet_header.packet_number;
747 packet_header.nano_seconds_since_2000 = seconds_since_2000 * 1000000000 + rec->ts.nsecs;
749 private_state->packet_count++;
751 /* write the packet header */
752 PACKET_ENTRY_HEADER_TO_LE_IN_PLACE(packet_header);
753 if (!wtap_dump_file_write(wdh, &packet_header, sizeof(packet_header), err)) {
756 wdh->bytes_dumped += sizeof(packet_header);
758 /* write the packet data */
759 if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err)) {
762 wdh->bytes_dumped += rec->rec_header.packet_header.caplen;
767 static gint observer_to_wtap_encap(int observer_encap)
769 switch(observer_encap) {
770 case OBSERVER_ETHERNET:
771 return WTAP_ENCAP_ETHERNET;
772 case OBSERVER_TOKENRING:
773 return WTAP_ENCAP_TOKEN_RING;
774 case OBSERVER_FIBRE_CHANNEL:
775 return WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS;
776 case OBSERVER_WIRELESS_802_11:
777 return WTAP_ENCAP_IEEE_802_11_WITH_RADIO;
778 case OBSERVER_UNDEFINED:
779 return WTAP_ENCAP_UNKNOWN;
781 return WTAP_ENCAP_UNKNOWN;
784 static gint wtap_to_observer_encap(int wtap_encap)
787 case WTAP_ENCAP_ETHERNET:
788 return OBSERVER_ETHERNET;
789 case WTAP_ENCAP_TOKEN_RING:
790 return OBSERVER_TOKENRING;
791 case WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS:
792 return OBSERVER_FIBRE_CHANNEL;
793 case WTAP_ENCAP_UNKNOWN:
794 return OBSERVER_UNDEFINED;
796 return OBSERVER_UNDEFINED;
800 * Editor modelines - http://www.wireshark.org/tools/modelines.html
805 * indent-tabs-mode: nil
808 * vi: set shiftwidth=4 tabstop=8 expandtab:
809 * :indentSize=4:tabSize=8:noTabs=true: