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