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