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