Coverage Report

Created: 2026-06-30 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/wiretap/observer.c
Line
Count
Source
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
 ***************************************************************************/
8
9
/***************************************************************************
10
 *                                                                         *
11
 *  SPDX-License-Identifier: GPL-2.0-or-later                              *
12
 *                                                                         *
13
 ***************************************************************************/
14
15
#include "config.h"
16
#include "observer.h"
17
18
#include <stdlib.h>
19
#include <string.h>
20
#include "wtap_module.h"
21
#include "file_wrappers.h"
22
#include <wsutil/epochs.h>
23
#include <wsutil/802_11-utils.h>
24
25
static const char observer_magic[] = {"ObserverPktBufferVersion=15.00"};
26
static const int true_magic_length = 17;
27
28
static const uint32_t observer_packet_magic = 0x88888888;
29
30
/*
31
 * This structure is used to keep state when writing files. An instance is
32
 * allocated for each file, and its address is stored in the wtap_dumper.priv
33
 * pointer field.
34
 */
35
typedef struct {
36
    uint64_t packet_count;
37
    uint8_t network_type;
38
    uint32_t time_format;
39
} observer_dump_private_state;
40
41
/*
42
 * Some time offsets are calculated in advance here, when the first Observer
43
 * file is opened for reading or writing, and are then used to adjust frame
44
 * timestamps as they are read or written.
45
 *
46
 * The Wiretap API expects timestamps in nanoseconds relative to
47
 * January 1, 1970, 00:00:00 UTC (the UNIX/POSIX epoch).
48
 *
49
 * Observer versions before 13.10 encode frame timestamps in nanoseconds
50
 * relative to January 1, 2000, 00:00:00 local time (the Observer epoch).
51
 * Versions 13.10 and later switch over to UTC encoding. Which encoding was used
52
 * when saving the file is identified via the time format TLV following
53
 * the file header.
54
 *
55
 * Unfortunately, even though Observer versions before 13.10 saved in local
56
 * time, they didn't include the timezone from which the frames were captured,
57
 * so converting to UTC correctly from all timezones is impossible. So an
58
 * assumption is made that the file is being read from within the same timezone
59
 * that it was written.
60
 *
61
 * All code herein is normalized to versions 13.10 and later, special casing for
62
 * versions earlier. In other words, timestamps are worked with as if
63
 * they are UTC-encoded, and adjustments from local time are made only if
64
 * the source file warrants it.
65
 *
66
 * All destination files are saved in UTC format.
67
 */
68
static time_t gmt_to_localtime_offset = (time_t) -1;
69
70
static const char *init_gmt_to_localtime_offset(void)
71
0
{
72
0
    if (gmt_to_localtime_offset == (time_t) -1) {
73
0
        time_t time_t_epoch_plus_one_day = 86400;
74
0
        struct tm *tm;
75
0
        struct tm gmt_tm;
76
0
        struct tm local_tm;
77
78
        /*
79
         * Compute the local time zone offset as the number of seconds west
80
         * of UTC. There's no obvious cross-platform API for querying this
81
         * directly. As a workaround, UTC and local tm structures are populated
82
         * relative to the 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.
86
         */
87
0
        tm = gmtime(&time_t_epoch_plus_one_day);
88
0
        if (tm == NULL)
89
0
            return "gmtime(one day past the Epoch) fails (this \"shouldn't happen\")";
90
0
        gmt_tm = *tm;
91
0
        tm = localtime(&time_t_epoch_plus_one_day);
92
0
        if (tm == NULL)
93
0
            return "localtime(one day past the Epoch) fails (this \"shouldn't happen\")";
94
0
        local_tm = *tm;
95
0
        local_tm.tm_isdst = 0;
96
0
        gmt_to_localtime_offset = mktime(&gmt_tm) - mktime(&local_tm);
97
0
    }
98
0
    return NULL;
99
0
}
100
101
static bool observer_read(wtap *wth, wtap_rec *rec,
102
    int *err, char **err_info, int64_t *data_offset);
103
static bool observer_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec,
104
    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
    wtap_rec *rec, 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
    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);
118
119
static int observer_file_type_subtype = -1;
120
121
void register_observer(void);
122
123
wtap_open_return_val observer_open(wtap *wth, int *err, char **err_info)
124
0
{
125
0
    unsigned offset;
126
0
    capture_file_header file_header;
127
0
    unsigned header_offset;
128
0
    unsigned i;
129
0
    tlv_header tlvh;
130
0
    unsigned seek_increment;
131
0
    packet_entry_header packet_header;
132
0
    observer_dump_private_state * private_state = NULL;
133
0
    const char *err_str;
134
135
0
    offset = 0;
136
137
    /* read in the buffer file header */
138
0
    if (!wtap_read_bytes(wth->fh, &file_header, sizeof file_header,
139
0
                         err, err_info)) {
140
0
        if (*err != WTAP_ERR_SHORT_READ)
141
0
            return WTAP_OPEN_ERROR;
142
0
        return WTAP_OPEN_NOT_MINE;
143
0
    }
144
0
    offset += (unsigned)sizeof file_header;
145
0
    CAPTURE_FILE_HEADER_FROM_LE_IN_PLACE(file_header);
146
147
    /* check if version info is present */
148
0
    if (memcmp(file_header.observer_version, observer_magic, true_magic_length)!=0) {
149
0
        return WTAP_OPEN_NOT_MINE;
150
0
    }
151
152
    /* get the location of the first packet */
153
    /* v15 and newer uses high byte offset, in previous versions it will be 0 */
154
0
    header_offset = file_header.offset_to_first_packet + ((unsigned)(file_header.offset_to_first_packet_high_byte)<<16);
155
156
0
    if (offset > header_offset) {
157
        /*
158
         * The packet data begins before the file header ends.
159
         */
160
0
        *err = WTAP_ERR_BAD_FILE;
161
0
        *err_info = ws_strdup_printf("Observer: The first packet begins in the middle of the file header");
162
0
        return WTAP_OPEN_ERROR;
163
0
    }
164
165
    /* initialize the private state */
166
0
    private_state = g_new(observer_dump_private_state, 1);
167
0
    private_state->time_format = TIME_INFO_LOCAL;
168
0
    wth->priv = (void *) private_state;
169
170
    /* process extra information */
171
0
    for (i = 0; i < file_header.number_of_information_elements; i++) {
172
0
        unsigned tlv_data_length;
173
174
        /*
175
         * Make sure reading the TLV header won't put us in the middle
176
         * of the packet data.
177
         */
178
0
        if (offset + (unsigned)sizeof tlvh > header_offset) {
179
            /*
180
             * We're at or past the point where the packet data begins,
181
             * but we have the IE header to read.
182
             */
183
0
            *err = WTAP_ERR_BAD_FILE;
184
0
            *err_info = ws_strdup_printf("Observer: TLVs run into the first packet data");
185
0
            return WTAP_OPEN_ERROR;
186
0
        }
187
188
        /* read the TLV header */
189
0
        if (!wtap_read_bytes(wth->fh, &tlvh, sizeof tlvh, err, err_info))
190
0
            return WTAP_OPEN_ERROR;
191
0
        offset += (unsigned)sizeof tlvh;
192
0
        TLV_HEADER_FROM_LE_IN_PLACE(tlvh);
193
194
0
        if (tlvh.length < sizeof tlvh) {
195
0
            *err = WTAP_ERR_BAD_FILE;
196
0
            *err_info = ws_strdup_printf("Observer: bad record (TLV length %u < %zu)",
197
0
                tlvh.length, sizeof tlvh);
198
0
            return WTAP_OPEN_ERROR;
199
0
        }
200
201
0
        tlv_data_length = tlvh.length - (unsigned)sizeof tlvh;
202
        /*
203
         * Make sure reading the TLV data won't put us in the middle
204
         * of the packet data.
205
         */
206
0
        if (offset + tlv_data_length > header_offset) {
207
            /*
208
             * We're at or past the point where the packet data begins,
209
             * but we have the IE data to read.
210
             */
211
0
            *err = WTAP_ERR_BAD_FILE;
212
0
            *err_info = ws_strdup_printf("Observer: TLVs run into the first packet data");
213
0
            return WTAP_OPEN_ERROR;
214
0
        }
215
216
217
        /* process (or skip over) the current TLV */
218
0
        switch (tlvh.type) {
219
0
        case INFORMATION_TYPE_TIME_INFO:
220
0
            if (tlv_data_length != sizeof private_state->time_format) {
221
0
                *err = WTAP_ERR_BAD_FILE;
222
0
                *err_info = ws_strdup_printf("Observer: bad record (time information TLV length %u != %zu)",
223
0
                    tlvh.length,
224
0
                    sizeof tlvh + sizeof private_state->time_format);
225
0
                return WTAP_OPEN_ERROR;
226
0
            }
227
0
            if (!wtap_read_bytes(wth->fh, &private_state->time_format,
228
0
                                 sizeof private_state->time_format,
229
0
                                 err, err_info))
230
0
                return WTAP_OPEN_ERROR;
231
0
            private_state->time_format = GUINT32_FROM_LE(private_state->time_format);
232
0
            offset += (unsigned)sizeof private_state->time_format;
233
0
            break;
234
0
        default:
235
0
            if (tlv_data_length != 0) {
236
0
                if (!wtap_read_bytes(wth->fh, NULL, tlv_data_length, err, err_info))
237
0
                    return WTAP_OPEN_ERROR;
238
0
            }
239
0
            offset += tlv_data_length;
240
0
        }
241
0
    }
242
243
    /* get to the first packet */
244
0
    seek_increment = header_offset - offset;
245
0
    if (seek_increment != 0) {
246
0
        if (!wtap_read_bytes(wth->fh, NULL, seek_increment, err, err_info))
247
0
            return WTAP_OPEN_ERROR;
248
0
    }
249
250
    /*
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.
255
     *
256
     * If that's *not* the case, we need to use WTAP_ENCAP_PER_PACKET.
257
     *
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.
262
     */
263
0
    if (!wtap_read_bytes_or_eof(wth->fh, &packet_header, sizeof packet_header,
264
0
                                err, err_info)) {
265
0
        if (*err == 0) {
266
            /*
267
             * EOF, so there *are* no records.
268
             */
269
0
            *err = WTAP_ERR_BAD_FILE;
270
0
            *err_info = ws_strdup_printf("Observer: No records in the file, so we can't determine the link-layer type");
271
0
        }
272
0
        return WTAP_OPEN_ERROR;
273
0
    }
274
0
    PACKET_ENTRY_HEADER_FROM_LE_IN_PLACE(packet_header);
275
276
    /* check the packet's magic number */
277
0
    if (packet_header.packet_magic != observer_packet_magic) {
278
0
        *err = WTAP_ERR_UNSUPPORTED;
279
0
        *err_info = ws_strdup_printf("Observer: unsupported packet version %ul", packet_header.packet_magic);
280
0
        return WTAP_OPEN_ERROR;
281
0
    }
282
283
    /* check the data link type */
284
0
    if (observer_to_wtap_encap(packet_header.network_type) == WTAP_ENCAP_UNKNOWN) {
285
0
        *err = WTAP_ERR_UNSUPPORTED;
286
0
        *err_info = ws_strdup_printf("Observer: network type %u unknown or unsupported", packet_header.network_type);
287
0
        return WTAP_OPEN_ERROR;
288
0
    }
289
0
    wth->file_encap = observer_to_wtap_encap(packet_header.network_type);
290
291
    /* set up the rest of the capture parameters */
292
0
    private_state->packet_count = 0;
293
0
    private_state->network_type = wtap_to_observer_encap(wth->file_encap);
294
0
    wth->subtype_read = observer_read;
295
0
    wth->subtype_seek_read = observer_seek_read;
296
0
    wth->subtype_close = NULL;
297
0
    wth->subtype_sequential_close = NULL;
298
0
    wth->snapshot_length = 0;    /* not available in header */
299
0
    wth->file_tsprec = WTAP_TSPREC_NSEC;
300
0
    wth->file_type_subtype = observer_file_type_subtype;
301
302
    /* reset the pointer to the first packet */
303
0
    if (file_seek(wth->fh, header_offset, SEEK_SET, err) == -1)
304
0
        return WTAP_OPEN_ERROR;
305
306
0
    err_str = init_gmt_to_localtime_offset();
307
0
    if (err_str != NULL) {
308
0
        *err = WTAP_ERR_INTERNAL;
309
0
        *err_info = ws_strdup_printf("observer: %s", err_str);
310
0
        return WTAP_OPEN_ERROR;
311
0
    }
312
313
    /*
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.
318
     */
319
0
    wtap_add_generated_idb(wth);
320
321
0
    return WTAP_OPEN_MINE;
322
0
}
323
324
/* Reads the next packet. */
325
static bool observer_read(wtap *wth, wtap_rec *rec,
326
    int *err, char **err_info, int64_t *data_offset)
327
0
{
328
0
    int header_bytes_consumed;
329
0
    int data_bytes_consumed;
330
0
    packet_entry_header packet_header;
331
332
    /* skip records other than data records */
333
0
    for (;;) {
334
0
        *data_offset = file_tell(wth->fh);
335
336
        /* process the packet header, including TLVs */
337
0
        header_bytes_consumed = read_packet_header(wth, wth->fh, &rec->rec_header.packet_header.pseudo_header, &packet_header, err,
338
0
            err_info);
339
0
        if (header_bytes_consumed <= 0)
340
0
            return false;    /* EOF or error */
341
342
0
        if (packet_header.packet_type == PACKET_TYPE_DATA_PACKET)
343
0
            break;
344
345
        /* skip to next packet */
346
0
        if (!skip_to_next_packet(wth, packet_header.offset_to_next_packet,
347
0
                header_bytes_consumed, err, err_info)) {
348
0
            return false;    /* EOF or error */
349
0
        }
350
0
    }
351
352
0
    if (!process_packet_header(wth, &packet_header, rec, err, err_info))
353
0
        return false;
354
355
    /* read the frame data */
356
0
    data_bytes_consumed = read_packet_data(wth->fh, packet_header.offset_to_frame,
357
0
            header_bytes_consumed, rec, err, err_info);
358
0
    if (data_bytes_consumed < 0) {
359
0
        return false;
360
0
    }
361
362
    /* skip over any extra bytes following the frame data */
363
0
    if (!skip_to_next_packet(wth, packet_header.offset_to_next_packet,
364
0
            header_bytes_consumed + data_bytes_consumed, err, err_info)) {
365
0
        return false;
366
0
    }
367
368
0
    return true;
369
0
}
370
371
/* Reads a packet at an offset. */
372
static bool observer_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec,
373
    int *err, char **err_info)
374
0
{
375
0
    union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header;
376
0
    packet_entry_header packet_header;
377
0
    int offset;
378
0
    int data_bytes_consumed;
379
380
0
    if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
381
0
        return false;
382
383
    /* process the packet header, including TLVs */
384
0
    offset = read_packet_header(wth, wth->random_fh, pseudo_header, &packet_header, err,
385
0
        err_info);
386
0
    if (offset <= 0)
387
0
        return false;    /* EOF or error */
388
389
0
    if (!process_packet_header(wth, &packet_header, rec, err, err_info))
390
0
        return false;
391
392
    /* read the frame data */
393
0
    data_bytes_consumed = read_packet_data(wth->random_fh, packet_header.offset_to_frame,
394
0
        offset, rec, err, err_info);
395
0
    if (data_bytes_consumed < 0) {
396
0
        return false;
397
0
    }
398
399
0
    return true;
400
0
}
401
402
static int
403
read_packet_header(wtap *wth, FILE_T fh, union wtap_pseudo_header *pseudo_header,
404
    packet_entry_header *packet_header, int *err, char **err_info)
405
0
{
406
0
    int offset;
407
0
    unsigned i;
408
0
    tlv_header tlvh;
409
0
    tlv_wireless_info wireless_header;
410
411
0
    offset = 0;
412
413
    /* pull off the packet header */
414
0
    if (!wtap_read_bytes_or_eof(fh, packet_header, sizeof *packet_header,
415
0
                                err, err_info)) {
416
0
        if (*err != 0)
417
0
            return -1;
418
0
        return 0;    /* EOF */
419
0
    }
420
0
    offset += (int)sizeof *packet_header;
421
0
    PACKET_ENTRY_HEADER_FROM_LE_IN_PLACE(*packet_header);
422
423
    /* check the packet's magic number */
424
0
    if (packet_header->packet_magic != observer_packet_magic) {
425
426
        /*
427
         * Some files are zero-padded at the end. There is no warning of this
428
         * in the previous packet header information, such as setting
429
         * offset_to_next_packet to zero. So detect this situation by treating
430
         * an all-zero header as a sentinel. Return EOF when it is encountered,
431
         * rather than treat it as a bad record.
432
         */
433
0
        for (i = 0; i < sizeof *packet_header; i++) {
434
0
            if (((uint8_t*) packet_header)[i] != 0)
435
0
                break;
436
0
        }
437
0
        if (i == sizeof *packet_header) {
438
0
            *err = 0;
439
0
            return 0;    /* EOF */
440
0
        }
441
442
0
        *err = WTAP_ERR_BAD_FILE;
443
0
        *err_info = ws_strdup_printf("Observer: bad record: Invalid magic number 0x%08x",
444
0
            packet_header->packet_magic);
445
0
        return -1;
446
0
    }
447
448
    /* initialize the pseudo header */
449
0
    switch (wth->file_encap) {
450
0
    case WTAP_ENCAP_ETHERNET:
451
        /* There is no FCS in the frame */
452
0
        pseudo_header->eth.fcs_len = 0;
453
0
        break;
454
0
    case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
455
0
        memset(&pseudo_header->ieee_802_11, 0, sizeof(pseudo_header->ieee_802_11));
456
0
        pseudo_header->ieee_802_11.fcs_len = 0;
457
0
        pseudo_header->ieee_802_11.decrypted = false;
458
0
        pseudo_header->ieee_802_11.datapad = false;
459
0
        pseudo_header->ieee_802_11.phy = PHDR_802_11_PHY_UNKNOWN;
460
        /* Updated below */
461
0
        break;
462
0
    }
463
464
    /* process extra information */
465
0
    for (i = 0; i < packet_header->number_of_information_elements; i++) {
466
0
        unsigned tlv_data_length;
467
468
        /* read the TLV header */
469
0
        if (!wtap_read_bytes(fh, &tlvh, sizeof tlvh, err, err_info))
470
0
            return -1;
471
0
        offset += (int)sizeof tlvh;
472
0
        TLV_HEADER_FROM_LE_IN_PLACE(tlvh);
473
474
0
        if (tlvh.length < sizeof tlvh) {
475
0
            *err = WTAP_ERR_BAD_FILE;
476
0
            *err_info = ws_strdup_printf("Observer: bad record (TLV length %u < %zu)",
477
0
                tlvh.length, sizeof tlvh);
478
0
            return -1;
479
0
        }
480
0
        tlv_data_length = tlvh.length - (unsigned)sizeof tlvh;
481
482
        /* process (or skip over) the current TLV */
483
0
        switch (tlvh.type) {
484
0
        case INFORMATION_TYPE_WIRELESS:
485
0
            if (tlv_data_length != sizeof wireless_header) {
486
0
                *err = WTAP_ERR_BAD_FILE;
487
0
                *err_info = ws_strdup_printf("Observer: bad record (wireless TLV length %u != %zu)",
488
0
                    tlvh.length, sizeof tlvh + sizeof wireless_header);
489
0
                return -1;
490
0
            }
491
0
            if (!wtap_read_bytes(fh, &wireless_header, sizeof wireless_header,
492
0
                                 err, err_info))
493
0
                return -1;
494
            /* set decryption status */
495
            /* XXX - what other bits are there in conditions? */
496
0
            pseudo_header->ieee_802_11.decrypted = (wireless_header.conditions & WIRELESS_WEP_SUCCESS) != 0;
497
0
            pseudo_header->ieee_802_11.has_channel = true;
498
0
            pseudo_header->ieee_802_11.channel = wireless_header.frequency;
499
0
            pseudo_header->ieee_802_11.has_data_rate = true;
500
0
            pseudo_header->ieee_802_11.data_rate = wireless_header.rate;
501
0
            pseudo_header->ieee_802_11.has_signal_percent = true;
502
0
            pseudo_header->ieee_802_11.signal_percent = wireless_header.strengthPercent;
503
504
            /*
505
             * We don't know they PHY, but we do have the data rate;
506
             * try to guess the PHY based on the data rate and channel.
507
             */
508
0
            if (RATE_IS_DSSS(pseudo_header->ieee_802_11.data_rate)) {
509
                /* 11b */
510
0
                pseudo_header->ieee_802_11.phy = PHDR_802_11_PHY_11B;
511
0
                pseudo_header->ieee_802_11.phy_info.info_11b.has_short_preamble = false;
512
0
            } else if (RATE_IS_OFDM(pseudo_header->ieee_802_11.data_rate)) {
513
                /* 11a or 11g, depending on the band. */
514
0
                if (CHAN_IS_BG(pseudo_header->ieee_802_11.channel)) {
515
                    /* 11g */
516
0
                    pseudo_header->ieee_802_11.phy = PHDR_802_11_PHY_11G;
517
0
                    pseudo_header->ieee_802_11.phy_info.info_11g.has_mode = false;
518
0
                } else {
519
                    /* 11a */
520
0
                    pseudo_header->ieee_802_11.phy = PHDR_802_11_PHY_11A;
521
0
                    pseudo_header->ieee_802_11.phy_info.info_11a.has_channel_type = false;
522
0
                    pseudo_header->ieee_802_11.phy_info.info_11a.has_turbo_type = false;
523
0
                }
524
0
            }
525
526
0
            offset += (int)sizeof wireless_header;
527
0
            break;
528
0
        default:
529
            /* skip the TLV data */
530
0
            if (tlv_data_length != 0) {
531
0
                if (!wtap_read_bytes(fh, NULL, tlv_data_length, err, err_info))
532
0
                    return -1;
533
0
            }
534
0
            offset += tlv_data_length;
535
0
        }
536
0
    }
537
538
0
    return offset;
539
0
}
540
541
static bool
542
process_packet_header(wtap *wth, packet_entry_header *packet_header,
543
    wtap_rec *rec, int *err, char **err_info)
544
0
{
545
    /*
546
     * Set the wiretap record metadata fields.
547
     *
548
     * XXX - the link=layer type is per-packet, as it's in the packet
549
     * header, but there's also a link-layer type in the file header,
550
     * from which we get the file's encapsulation.  What relationship
551
     * does the latter have to the former?  Do we ever need to make
552
     * the file's encapsulation WTAP_ENCAP_PER_PACKET?
553
     */
554
0
    wtap_setup_packet_rec(rec, observer_to_wtap_encap(packet_header->network_type));
555
0
    rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
556
0
    rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
557
0
    if(wth->file_encap == WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS) {
558
0
        rec->rec_header.packet_header.len = packet_header->network_size;
559
0
        rec->rec_header.packet_header.caplen = packet_header->captured_size;
560
0
    } else {
561
        /*
562
         * XXX - what are those 4 bytes?
563
         *
564
         * The comment in the code said "neglect frame markers for wiretap",
565
         * but in the captures I've seen, there's no actual data corresponding
566
         * to them that might be a "frame marker".
567
         *
568
         * Instead, the packets had a network_size 4 bytes larger than the
569
         * captured_size; does the network_size include the CRC, even
570
         * though it's not included in a capture?  If so, most other
571
         * network analyzers that have a "network size" and a "captured
572
         * size" don't include the CRC in the "network size" if they
573
         * don't include the CRC in a full-length captured packet; the
574
         * "captured size" is less than the "network size" only if a
575
         * user-specified "snapshot length" caused the packet to be
576
         * sliced at a particular point.
577
         *
578
         * That's the model that wiretap and Wireshark/TShark use, so
579
         * we implement that model here.
580
         */
581
0
        if (packet_header->network_size < 4) {
582
0
            *err = WTAP_ERR_BAD_FILE;
583
0
            *err_info = ws_strdup_printf("Observer: bad record: Packet length %u < 4",
584
0
                                        packet_header->network_size);
585
0
            return false;
586
0
        }
587
588
0
        rec->rec_header.packet_header.len = packet_header->network_size - 4;
589
0
        rec->rec_header.packet_header.caplen = MIN(packet_header->captured_size, rec->rec_header.packet_header.len);
590
0
    }
591
    /*
592
     * The maximum value of packet_header->captured_size is 65535, which
593
     * is less than WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need
594
     * to check it.
595
     */
596
597
    /* set the wiretap timestamp, assuming for the moment that Observer encoded it in UTC */
598
0
    rec->ts.secs = (time_t) ((packet_header->nano_seconds_since_2000 / 1000000000) + EPOCH_DELTA_2000_01_01_00_00_00_UTC);
599
0
    rec->ts.nsecs = (int) (packet_header->nano_seconds_since_2000 % 1000000000);
600
601
    /* adjust to local time, if necessary, also accounting for DST if the frame
602
       was captured while it was in effect */
603
0
    if (((observer_dump_private_state*)wth->priv)->time_format == TIME_INFO_LOCAL)
604
0
    {
605
0
        struct tm *tm;
606
0
        struct tm daylight_tm;
607
0
        struct tm standard_tm;
608
0
        time_t    dst_offset;
609
610
        /* the Observer timestamp was encoded as local time, so add a
611
           correction from local time to UTC */
612
0
        rec->ts.secs += gmt_to_localtime_offset;
613
614
        /* perform a DST adjustment if necessary */
615
0
        tm = localtime(&rec->ts.secs);
616
0
        if (tm != NULL) {
617
0
            standard_tm = *tm;
618
0
            if (standard_tm.tm_isdst > 0) {
619
0
                daylight_tm = standard_tm;
620
0
                standard_tm.tm_isdst = 0;
621
0
                dst_offset = mktime(&standard_tm) - mktime(&daylight_tm);
622
0
                 rec->ts.secs -= dst_offset;
623
0
            }
624
0
        }
625
0
    }
626
627
0
    return true;
628
0
}
629
630
static int
631
read_packet_data(FILE_T fh, int offset_to_frame, int current_offset_from_packet_header,
632
    wtap_rec *rec, int *err, char **err_info)
633
0
{
634
0
    int seek_increment;
635
0
    uint32_t bytes_consumed = 0;
636
637
    /* validate offsets */
638
0
    if (offset_to_frame < current_offset_from_packet_header) {
639
0
        *err = WTAP_ERR_BAD_FILE;
640
0
        *err_info = ws_strdup_printf("Observer: bad record (offset to packet data %d < %d)",
641
0
            offset_to_frame, current_offset_from_packet_header);
642
0
        return -1;
643
0
    }
644
645
    /* skip to the packet data */
646
0
    seek_increment = offset_to_frame - current_offset_from_packet_header;
647
0
    if (seek_increment > 0) {
648
0
        if (!wtap_read_bytes(fh, NULL, seek_increment, err, err_info)) {
649
0
            return -1;
650
0
        }
651
0
        bytes_consumed += seek_increment;
652
0
    }
653
654
    /* read in the packet data */
655
0
    if (!wtap_read_bytes_buffer(fh, &rec->data,
656
0
                                rec->rec_header.packet_header.caplen,
657
0
                                err, err_info))
658
0
        return false;
659
0
    bytes_consumed += rec->rec_header.packet_header.caplen;
660
661
0
    return bytes_consumed;
662
0
}
663
664
static bool
665
skip_to_next_packet(wtap *wth, int offset_to_next_packet, int current_offset_from_packet_header, int *err,
666
    char **err_info)
667
0
{
668
0
    int seek_increment;
669
670
    /* validate offsets */
671
0
    if (offset_to_next_packet < current_offset_from_packet_header) {
672
0
        *err = WTAP_ERR_BAD_FILE;
673
0
        *err_info = ws_strdup_printf("Observer: bad record (offset to next packet %d < %d)",
674
0
            offset_to_next_packet, current_offset_from_packet_header);
675
0
        return false;
676
0
    }
677
678
    /* skip to the next packet header */
679
0
    seek_increment = offset_to_next_packet - current_offset_from_packet_header;
680
0
    if (seek_increment > 0) {
681
0
        if (!wtap_read_bytes(wth->fh, NULL, seek_increment, err, err_info))
682
0
            return false;
683
0
    }
684
685
0
    return true;
686
0
}
687
688
/* Returns 0 if we could write the specified encapsulation type,
689
   an error indication otherwise. */
690
static int observer_dump_can_write_encap(int encap)
691
0
{
692
    /* per-packet encapsulations aren't supported */
693
0
    if (encap == WTAP_ENCAP_PER_PACKET)
694
0
        return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
695
696
0
    if (encap < 0 || (wtap_to_observer_encap(encap) == OBSERVER_UNDEFINED))
697
0
        return WTAP_ERR_UNWRITABLE_ENCAP;
698
699
0
    return 0;
700
0
}
701
702
/* Returns true on success, false on failure; sets "*err" to an error code on
703
   failure. */
704
static bool observer_dump_open(wtap_dumper *wdh, int *err,
705
    char **err_info)
706
0
{
707
0
    observer_dump_private_state * private_state = NULL;
708
0
    capture_file_header file_header;
709
0
    unsigned header_offset;
710
0
    const char *err_str;
711
0
    tlv_header comment_header;
712
0
    char comment[64];
713
0
    size_t comment_length;
714
0
    tlv_header time_info_header;
715
0
    tlv_time_info time_info;
716
0
    struct tm * current_time;
717
0
    time_t system_time;
718
719
    /* initialize the private state */
720
0
    private_state = g_new(observer_dump_private_state, 1);
721
0
    private_state->packet_count = 0;
722
0
    private_state->network_type = wtap_to_observer_encap(wdh->file_encap);
723
0
    private_state->time_format = TIME_INFO_GMT;
724
725
    /* populate the fields of wdh */
726
0
    wdh->priv = (void *) private_state;
727
0
    wdh->subtype_write = observer_dump;
728
729
    /* initialize the file header */
730
0
    memset(&file_header, 0x00, sizeof(file_header));
731
0
    (void) g_strlcpy(file_header.observer_version, observer_magic, 31);
732
0
    header_offset = (uint16_t)sizeof(file_header);
733
734
    /* create the file comment TLV */
735
0
    {
736
0
        time(&system_time);
737
0
        current_time = localtime(&system_time);
738
0
        memset(&comment, 0x00, sizeof(comment));
739
0
        if (current_time != NULL)
740
0
            snprintf(comment, 64, "This capture was saved from Wireshark on %s", asctime(current_time));
741
0
        else
742
0
            snprintf(comment, 64, "This capture was saved from Wireshark");
743
0
        comment_length = strlen(comment);
744
745
0
        comment_header.type = INFORMATION_TYPE_COMMENT;
746
0
        comment_header.length = (uint16_t) (sizeof(comment_header) + comment_length);
747
748
        /* update the file header to account for the comment TLV */
749
0
        file_header.number_of_information_elements++;
750
0
        header_offset += comment_header.length;
751
0
    }
752
753
    /* create the timestamp encoding TLV */
754
0
    {
755
0
        time_info_header.type = INFORMATION_TYPE_TIME_INFO;
756
0
        time_info_header.length = (uint16_t) (sizeof(time_info_header) + sizeof(time_info));
757
0
        time_info.time_format = TIME_INFO_GMT;
758
759
        /* update the file header to account for the timestamp encoding TLV */
760
0
        file_header.number_of_information_elements++;
761
0
        header_offset += time_info_header.length;
762
0
    }
763
764
    /* Store the offset to the first packet */
765
0
    file_header.offset_to_first_packet_high_byte = (header_offset >> 16);
766
0
    file_header.offset_to_first_packet = (header_offset & 0xFFFF);
767
768
    /* write the file header, swapping any multibyte fields first */
769
0
    CAPTURE_FILE_HEADER_TO_LE_IN_PLACE(file_header);
770
0
    if (!wtap_dump_file_write(wdh, &file_header, sizeof(file_header), err)) {
771
0
        return false;
772
0
    }
773
774
    /* write the comment TLV */
775
0
    {
776
0
        TLV_HEADER_TO_LE_IN_PLACE(comment_header);
777
0
        if (!wtap_dump_file_write(wdh, &comment_header, sizeof(comment_header), err)) {
778
0
            return false;
779
0
        }
780
781
0
        if (!wtap_dump_file_write(wdh, &comment, comment_length, err)) {
782
0
            return false;
783
0
        }
784
0
    }
785
786
    /* write the time info TLV */
787
0
    {
788
0
        TLV_HEADER_TO_LE_IN_PLACE(time_info_header);
789
0
        if (!wtap_dump_file_write(wdh, &time_info_header, sizeof(time_info_header), err)) {
790
0
            return false;
791
0
        }
792
793
0
        TLV_TIME_INFO_TO_LE_IN_PLACE(time_info);
794
0
        if (!wtap_dump_file_write(wdh, &time_info, sizeof(time_info), err)) {
795
0
            return false;
796
0
        }
797
0
    }
798
799
0
    err_str = init_gmt_to_localtime_offset();
800
0
    if (err_str != NULL) {
801
0
        *err = WTAP_ERR_INTERNAL;
802
0
        *err_info = ws_strdup_printf("observer: %s", err_str);
803
0
        return false;
804
0
    }
805
806
0
    return true;
807
0
}
808
809
/* Write a record for a packet to a dump file.
810
   Returns true on success, false on failure. */
811
static bool observer_dump(wtap_dumper *wdh, const wtap_rec *rec,
812
    int *err, char **err_info _U_)
813
0
{
814
0
    observer_dump_private_state * private_state = NULL;
815
0
    packet_entry_header           packet_header;
816
0
    uint64_t                      seconds_since_2000;
817
818
    /* We can only write packet records. */
819
0
    if (rec->rec_type != REC_TYPE_PACKET) {
820
0
        *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
821
0
        *err_info = wtap_unwritable_rec_type_err_string(rec);
822
0
        return false;
823
0
    }
824
825
    /*
826
     * Make sure this packet doesn't have a link-layer type that
827
     * differs from the one for the file.
828
     */
829
0
    if (wdh->file_encap != rec->rec_header.packet_header.pkt_encap) {
830
0
        *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
831
0
        return false;
832
0
    }
833
834
    /* The captured size field is 16 bits, so there's a hard limit of
835
       65535. */
836
0
    if (rec->rec_header.packet_header.caplen > 65535) {
837
0
        *err = WTAP_ERR_PACKET_TOO_LARGE;
838
0
        return false;
839
0
    }
840
841
    /* Convert the number of seconds since epoch from the time_t epoch
842
       to Observer's 2000-01-01 00:00:00 UTC epoch.
843
844
       The number of seconds since the Observer epoch must be non-negative,
845
       presumably because Observer treats it as such, and can't handle
846
       dates/times before its epoch. If the time stamp precedes the Observer
847
       epoch, just use the Observer epoch.
848
849
       We first check for negative time_t values, and then cast the
850
       known-to-be-nonnegative value to uint64_t and compare against
851
       the epoch, to avoid signed vs. unsigned comparison warnings.
852
       If we make the epoch offsets signed, we won't have to do this. */
853
0
    if (rec->ts.secs < 0 || (uint64_t)rec->ts.secs < EPOCH_DELTA_2000_01_01_00_00_00_UTC) {
854
0
        seconds_since_2000 = 0;
855
0
    } else {
856
0
        seconds_since_2000 = rec->ts.secs - EPOCH_DELTA_2000_01_01_00_00_00_UTC;
857
0
    }
858
859
    /* populate the fields of the packet header */
860
0
    private_state = (observer_dump_private_state *) wdh->priv;
861
862
0
    memset(&packet_header, 0x00, sizeof(packet_header));
863
0
    packet_header.packet_magic = observer_packet_magic;
864
0
    packet_header.network_speed = 1000000;
865
0
    packet_header.captured_size = (uint16_t) rec->rec_header.packet_header.caplen;
866
0
    packet_header.network_size = (uint16_t) (rec->rec_header.packet_header.len + 4);
867
0
    packet_header.offset_to_frame = sizeof(packet_header);
868
    /* XXX - what if this doesn't fit in 16 bits?  It's not guaranteed to... */
869
0
    packet_header.offset_to_next_packet = (uint16_t)sizeof(packet_header) + rec->rec_header.packet_header.caplen;
870
0
    packet_header.network_type = private_state->network_type;
871
0
    packet_header.flags = 0x00;
872
0
    packet_header.number_of_information_elements = 0;
873
0
    packet_header.packet_type = PACKET_TYPE_DATA_PACKET;
874
0
    packet_header.packet_number = private_state->packet_count;
875
0
    packet_header.original_packet_number = packet_header.packet_number;
876
0
    packet_header.nano_seconds_since_2000 = seconds_since_2000 * 1000000000 + rec->ts.nsecs;
877
878
0
    private_state->packet_count++;
879
880
    /* write the packet header */
881
0
    PACKET_ENTRY_HEADER_TO_LE_IN_PLACE(packet_header);
882
0
    if (!wtap_dump_file_write(wdh, &packet_header, sizeof(packet_header), err)) {
883
0
        return false;
884
0
    }
885
886
    /* write the packet data */
887
0
    if (!wtap_dump_file_write(wdh, ws_buffer_start_ptr(&rec->data), rec->rec_header.packet_header.caplen, err)) {
888
0
        return false;
889
0
    }
890
891
0
    return true;
892
0
}
893
894
static int observer_to_wtap_encap(int observer_encap)
895
0
{
896
0
    switch(observer_encap) {
897
0
    case OBSERVER_ETHERNET:
898
0
        return WTAP_ENCAP_ETHERNET;
899
0
    case OBSERVER_TOKENRING:
900
0
        return WTAP_ENCAP_TOKEN_RING;
901
0
    case OBSERVER_FIBRE_CHANNEL:
902
0
        return WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS;
903
0
    case OBSERVER_WIRELESS_802_11:
904
0
        return WTAP_ENCAP_IEEE_802_11_WITH_RADIO;
905
0
    case OBSERVER_UNDEFINED:
906
0
        return WTAP_ENCAP_UNKNOWN;
907
0
    }
908
0
    return WTAP_ENCAP_UNKNOWN;
909
0
}
910
911
static int wtap_to_observer_encap(int wtap_encap)
912
0
{
913
0
    switch(wtap_encap) {
914
0
    case WTAP_ENCAP_ETHERNET:
915
0
        return OBSERVER_ETHERNET;
916
0
    case WTAP_ENCAP_TOKEN_RING:
917
0
        return OBSERVER_TOKENRING;
918
0
    case WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS:
919
0
        return OBSERVER_FIBRE_CHANNEL;
920
0
    case WTAP_ENCAP_UNKNOWN:
921
0
        return OBSERVER_UNDEFINED;
922
0
    }
923
0
    return OBSERVER_UNDEFINED;
924
0
}
925
926
static const struct supported_block_type observer_blocks_supported[] = {
927
    /*
928
     * We support packet blocks, with no comments or other options.
929
     */
930
    { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
931
};
932
933
static const struct file_type_subtype_info observer_info = {
934
    "Viavi Observer", "observer", "bfr", NULL,
935
    false, BLOCKS_SUPPORTED(observer_blocks_supported),
936
    observer_dump_can_write_encap, observer_dump_open, NULL
937
};
938
939
void register_observer(void)
940
14
{
941
14
    observer_file_type_subtype = wtap_register_file_type_subtype(&observer_info);
942
943
    /*
944
     * We now call this file format just "observer", but we allow
945
     * it to be referred to as "niobserver" for backwards
946
     * compatibility.
947
     *
948
     * Register "niobserver" for that purpose.
949
     */
950
14
    wtap_register_compatibility_file_subtype_name("niobserver", "observer");
951
952
    /*
953
     * Register name for backwards compatibility with the
954
     * wtap_filetypes table in Lua.
955
     */
956
14
    wtap_register_backwards_compatibility_lua_name("NETWORK_INSTRUMENTS",
957
14
                                                   observer_file_type_subtype);
958
14
}
959
960
/*
961
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
962
 *
963
 * Local variables:
964
 * c-basic-offset: 4
965
 * tab-width: 8
966
 * indent-tabs-mode: nil
967
 * End:
968
 *
969
 * vi: set shiftwidth=4 tabstop=8 expandtab:
970
 * :indentSize=4:tabSize=8:noTabs=true:
971
 */