diff --git a/.gitattributes b/.gitattributes index 9aed5309f5..4ef4821ad8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ corpus.tar.gz filter=lfs diff=lfs merge=lfs -text *.ebpf filter=lfs diff=lfs merge=lfs -text +*.pcapng filter=lfs diff=lfs merge=lfs -text diff --git a/.github/config/typos.toml b/.github/config/typos.toml index f33aad60a7..f17e1ab037 100644 --- a/.github/config/typos.toml +++ b/.github/config/typos.toml @@ -25,5 +25,5 @@ extend-exclude = [ "*.der", "*.pem", "**/specs/**/*", - "common/duvet/www/public/script.js", + "**/wireshark_sys*", ] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bbedb61c4d..a9897fe661 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -821,3 +821,45 @@ jobs: RUST_LOG: trace run: cargo +stable xtask ci + dc-wireshark: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macOS-latest] + steps: + - uses: actions/checkout@v4 + with: + lfs: true + + - name: Install rust toolchain + run: | + rustup toolchain install stable --profile minimal --component clippy,rustfmt + rustup override set stable + + - uses: camshaft/install@v1 + with: + crate: bindgen-cli + bins: bindgen + + - uses: camshaft/rust-cache@v1 + + - name: Generate bindings + working-directory: dc/wireshark + run: cargo xtask bindings + + - name: Run cargo fmt + working-directory: dc/wireshark + run: cargo fmt --all -- --check + + - name: Run clippy + working-directory: dc/wireshark + run: cargo clippy --tests + + - name: Run tests + working-directory: dc/wireshark + run: cargo xtask test + + - name: Run build + working-directory: dc/wireshark + run: cargo xtask build diff --git a/dc/wireshark/.cargo/config.toml b/dc/wireshark/.cargo/config.toml new file mode 100644 index 0000000000..35049cbcb1 --- /dev/null +++ b/dc/wireshark/.cargo/config.toml @@ -0,0 +1,2 @@ +[alias] +xtask = "run --package xtask --" diff --git a/dc/wireshark/.clippy.toml b/dc/wireshark/.clippy.toml new file mode 100644 index 0000000000..118bbe28e9 --- /dev/null +++ b/dc/wireshark/.clippy.toml @@ -0,0 +1 @@ +msrv = "1.77.0" diff --git a/dc/wireshark/.gitignore b/dc/wireshark/.gitignore new file mode 100644 index 0000000000..9aa68c9eb2 --- /dev/null +++ b/dc/wireshark/.gitignore @@ -0,0 +1,2 @@ +*.pcap +*.pcapng diff --git a/dc/wireshark/Cargo.toml b/dc/wireshark/Cargo.toml new file mode 100644 index 0000000000..cb0581bbb1 --- /dev/null +++ b/dc/wireshark/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "wireshark_dcquic" +version = "0.0.0" +edition = "2021" +publish = false +rust-version = "1.77" + +[lib] +crate-type = ["rlib", "cdylib"] + +[dependencies] +s2n-codec = { path = "../../common/s2n-codec" } +s2n-quic-core = { path = "../../quic/s2n-quic-core" } +s2n-quic-dc = { path = "../s2n-quic-dc" } + +[dev-dependencies] +bolero = "0.11" +s2n-quic-core = { path = "../../quic/s2n-quic-core", features = ["testing", "generator"] } +s2n-quic-dc = { path = "../s2n-quic-dc", features = ["testing"] } + +[workspace] +members = [".", "xtask"] + +[profile.fuzz] +inherits = "dev" +opt-level = 3 +incremental = false +codegen-units = 1 + +# this is to avoid conflicts with already installed plugins +[profile.release-test] +inherits = "release" diff --git a/dc/wireshark/README.md b/dc/wireshark/README.md new file mode 100644 index 0000000000..db3c76a113 --- /dev/null +++ b/dc/wireshark/README.md @@ -0,0 +1,61 @@ +# dcQUIC Wireshark integration + +This directory contains a Rust plugin for Wireshark, which supports dissecting +dcQUIC Datagram, Stream, Control, and Secret Control packets over UDP, and +Stream packets over TCP. (This is currently full support for what we send in +current versions of dcQUIC). + +The plugin supports heuristic dissection, and will incrementally mark/record +fields in Wireshark even if the full packet does not parse as we expect. The +plugin does not currently support making use of any secret material to decrypt +payloads or verify authentication tags. + +## Usage + +The plugin is built against Wireshark version 4.2.5 headers. It's likely that a +new set of bindgen bindings are needed for other versions, and Wireshark will +refuse to load the plugin outside of the 4.2.x series (without code changes to +increment the supported minor version). + +To install the plugin for the current machine, use the following command: + +``` +cargo xtask install +``` + +Once this is done, Wireshark should load the plugin successfully on startup. +You can check (even without a pcap) by (a) not seeing an error message and (b) +typing `dcquic` into the search bar, which should get auto-completed and +highlighted green as a valid search. + +You can also use the plugin from the command line via `tshark`, for example: + +``` +tshark -r stream-request-response.pcap -O dcquic 'dcquic && not tcp' +``` + +## Contributing changes + +If you need access to more Wireshark APIs that currently don't have bindings in +`src/wireshark_sys`, you can re-generate that file with +`./generate-bindings.sh`. + +https://www.wireshark.org/docs/wsdg_html/#ChapterDissection is a good starting +point for understanding the basics of the Wireshark interface. + +The tests are runnable without a Wireshark installation and are fairly good at +catching bugs unrelated to the specifics of Wireshark FFI (e.g., parser bugs +should be caught). We rely primarily on fuzz-style testing, both of valid +packets (to test fields are properly decoded) and of random packets (to ensure +lack of panics). + +### Why a Rust plugin? + +Wireshark supports Lua plugins, but they are comparatively much slower. In our +testing, a native plugin is 3.3x faster at performing the same body of work as +a Lua plugin. This cost adds up quickly, especially as we expect to frequently +work with fairly coarse packet captures that may contain millions of packets. + +A Rust plugin also allows for direct interop with our existing code, both for +help in parsing (e.g., VarInt decoding) and in testing. These are obviously +possible to integrate into Lua, but would take extra dependencies and work. diff --git a/dc/wireshark/build.rs b/dc/wireshark/build.rs new file mode 100644 index 0000000000..6189b63d51 --- /dev/null +++ b/dc/wireshark/build.rs @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +fn main() { + let plugin_name = option_env("PLUGIN_NAME").unwrap_or_else(|| "dcQUIC".to_string()); + println!("cargo:rustc-env=PLUGIN_NAME={plugin_name}"); + println!( + "cargo:rustc-env=PLUGIN_NAME_LOWER={}", + plugin_name.to_lowercase() + ); + + // don't link any libraries and prefer pulling symbols from the wireshark/tshark binary + if env("TARGET").contains("darwin") { + println!("cargo:rustc-link-arg=-Wl,-undefined,dynamic_lookup"); + } else { + println!("cargo:rustc-link-arg=-U"); + println!("cargo:rustc-link-arg=-shared"); + } +} + +fn env>(name: N) -> String { + let name = name.as_ref(); + option_env(name).unwrap_or_else(|| panic!("missing env {name}")) +} + +fn option_env>(name: N) -> Option { + let name = name.as_ref(); + println!("cargo:rerun-if-env-changed={}", name); + std::env::var(name).ok() +} diff --git a/dc/wireshark/generate-bindings.sh b/dc/wireshark/generate-bindings.sh new file mode 100755 index 0000000000..f6fc92b948 --- /dev/null +++ b/dc/wireshark/generate-bindings.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash + +set -xeuo pipefail + +VERSION="4.2.5" +BRANCH="wireshark-$VERSION" +PKG_CONFIG_PATH="${PKG_CONFIG_PATH:-}" + +# Install bindgen... +if ! command -v bindgen &> /dev/null; then + cargo +stable install bindgen-cli +fi + +INCLUDES=() + +nixpath() { + nix-shell --packages $1 --run 'echo -n $buildInputs' +} + +# add nix-specific paths +if command -v nix-shell &> /dev/null; then + PKG_CONFIG_PATH="$(nixpath wireshark.dev)/lib/pkgconfig:$(nixpath glib.dev)/lib/pkgconfig:$PKG_CONFIG_PATH" +elif command -v brew &> /dev/null; then + brew install pkg-config wireshark +elif command -v apt-get &> /dev/null; then + sudo add-apt-repository ppa:wireshark-dev/stable + sudo apt-get update + sudo apt-get install pkg-config wireshark-dev tshark -y +fi + +INCLUDES=( + "$(PKG_CONFIG_PATH="$PKG_CONFIG_PATH" pkg-config --cflags-only-I glib-2.0 wireshark)" +) + +OPTIONS=( + --allowlist-type 'gint' + --allowlist-type 'guint' + --allowlist-type 'guint16' + --allowlist-type 'guint32' + --allowlist-type 'gboolean' + --allowlist-type 'nstime_t' + --allowlist-type '_packet_info' + --allowlist-type '_header_field_info' + --opaque-type 'frame_data' + --opaque-type '_proto_node' + --allowlist-type 'frame_data' + --allowlist-type '_proto_node' + --allowlist-type 'proto_plugin' + --opaque-type 'epan_column_info' + --allowlist-type 'epan_column_info' + --opaque-type 'tvbuff' + --allowlist-type 'tvbuff' + --opaque-type 'tvbuff_t' + --allowlist-type 'tvbuff_t' + --opaque-type 'address' + --allowlist-type 'address' + --opaque-type 'port_type' + --allowlist-type 'port_type' + --opaque-type 'GSList' + --allowlist-type 'GSList' + --opaque-type 'GHashTable' + --allowlist-type 'GHashTable' + --opaque-type 'wtap_pseudo_header' + --allowlist-type 'wtap_pseudo_header' + --opaque-type 'wtap_rec' + --allowlist-type 'wtap_rec' + --opaque-type 'conversation_addr_port_endpoints' + --allowlist-type 'conversation_addr_port_endpoints' + --opaque-type 'conversation_element' + --allowlist-type 'conversation_element' + --allowlist-type 'dissector_handle_t' + --allowlist-type 'ftenum_t' + --allowlist-type 'field_display_e' + --allowlist-var 'COL_PROTOCOL' + --allowlist-var 'ENC_BIG_ENDIAN' + --allowlist-var 'DESEGMENT_ONE_MORE_SEGMENT' + --allowlist-var 'DESEGMENT_UNTIL_FIN' +) + +mkdir -p src/wireshark_sys/ + +# This list is filtered to roughly what our current usage requires. +# It's possible there's a better way to do this -- some of the Wireshark +# headers end up pulling in C++ so we do need some filtering. +bindgen \ + --raw-line '// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.' \ + --raw-line '// SPDX-License-Identifier: Apache-2.0' \ + ${OPTIONS[@]} \ + wrapper.h \ + -o src/wireshark_sys/minimal.rs \ + -- ${INCLUDES[@]} + +bindgen \ + --raw-line '// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.' \ + --raw-line '// SPDX-License-Identifier: Apache-2.0' \ + ${OPTIONS[@]} \ + --allowlist-function 'proto_register_.*' \ + --allowlist-function 'proto_tree_.*' \ + --allowlist-function 'proto_item_.*' \ + --allowlist-function 'tvb_memcpy' \ + --allowlist-function 'tvb_reported_length' \ + --allowlist-function 'tvb_reported_length' \ + --allowlist-function 'heuristic_.*' \ + --allowlist-function 'heur.*' \ + --allowlist-function 'create_dissector_handle_with_name_and_description' \ + --allowlist-function 'col_set_str' \ + --allowlist-function 'col_append_str' \ + --allowlist-function 'col_clear' \ + --allowlist-function 'find_or_create_conversation' \ + --allowlist-function 'conversation_set_dissector' \ + wrapper.h \ + -o src/wireshark_sys/full.rs \ + -- ${INCLUDES[@]} diff --git a/dc/wireshark/pcaps/dcquic-stream-tcp.pcapng b/dc/wireshark/pcaps/dcquic-stream-tcp.pcapng new file mode 100644 index 0000000000..bd93c3f37c --- /dev/null +++ b/dc/wireshark/pcaps/dcquic-stream-tcp.pcapng @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8518092c61ab2f91d41773341138089a95e9e5e6f14a3bbfec6723bedcf0af02 +size 28549304 diff --git a/dc/wireshark/pcaps/dcquic-stream-udp.pcapng b/dc/wireshark/pcaps/dcquic-stream-udp.pcapng new file mode 100644 index 0000000000..ba6d94af73 --- /dev/null +++ b/dc/wireshark/pcaps/dcquic-stream-udp.pcapng @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:54f38b9e09206425d5ff025722bb0f505bf2f3ae1aadf45299af421c35f7a007 +size 31807484 diff --git a/dc/wireshark/rust-toolchain b/dc/wireshark/rust-toolchain new file mode 100644 index 0000000000..e074a365cb --- /dev/null +++ b/dc/wireshark/rust-toolchain @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.77.0" +components = [ "rustc", "clippy", "rustfmt" ] diff --git a/dc/wireshark/src/bin/generate-pcap.rs b/dc/wireshark/src/bin/generate-pcap.rs new file mode 100644 index 0000000000..0a4922413c --- /dev/null +++ b/dc/wireshark/src/bin/generate-pcap.rs @@ -0,0 +1,281 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use s2n_codec::{EncoderBuffer, EncoderValue}; +use std::{io::Write, net::Ipv4Addr, path::Path}; + +const MAGIC_NUMBER: u32 = 0xa1b2c3d4; + +fn main() { + // https://wiki.wireshark.org/Development/LibpcapFileFormat#overview + let out_dir = std::env::args().nth(1).unwrap_or_default(); + + let output = Path::new(&out_dir).join("datagram.pcap"); + + let mut output = std::io::BufWriter::new(std::fs::File::create(output).unwrap()); + + output.write_all(&MAGIC_NUMBER.to_ne_bytes()).unwrap(); + + // version major.minor + output.write_all(&2u16.to_ne_bytes()).unwrap(); + output.write_all(&4u16.to_ne_bytes()).unwrap(); + + // GMT/local timezone conversion + output.write_all(&0i32.to_ne_bytes()).unwrap(); + + // Sigfigs. Wireshark says this should always be zero. + output.write_all(&0u32.to_ne_bytes()).unwrap(); + + let max_length = 500u32; + // Snaplen, maximum capture length. + output.write_all(&max_length.to_ne_bytes()).unwrap(); + + // Network kind. We're writing ethernet packets. + output.write_all(&1u32.to_ne_bytes()).unwrap(); + + let timestamp_start = 1716923147u32; + for idx in 0..100_000 { + output.write_all(×tamp_start.to_ne_bytes()).unwrap(); + // micros -- we always have zeros for this field. + output.write_all(&0u32.to_ne_bytes()).unwrap(); + + // Non-fragmented packet. + let mut packet = Packet::new(); + + packet.add_ethernet(); + packet.add_ip(None); + packet.add_udp(); + packet.add_dcquic(idx as u64); + + packet.ip_fill_length(); + packet.udp_fill_length(); + + assert!(packet.buffer.len() <= max_length as usize); + + // Captured length. + output + .write_all(&u32::try_from(packet.buffer.len()).unwrap().to_ne_bytes()) + .unwrap(); + // Real length. + output + .write_all(&u32::try_from(packet.buffer.len()).unwrap().to_ne_bytes()) + .unwrap(); + + output.write_all(&packet.buffer).unwrap(); + + output.write_all(×tamp_start.to_ne_bytes()).unwrap(); + // micros -- we always have zeros for this field. + output.write_all(&0u32.to_ne_bytes()).unwrap(); + + // Then write the same packet split into two parts. + let mut packet = Packet::new(); + + packet.add_ethernet(); + packet.add_ip(Some((0, true))); + packet.add_udp(); + packet.add_dcquic((1 << 15) | idx as u64); + + // UDP length must be filled before splitting as the UDP length includes both payloads. + packet.udp_fill_length(); + + let tail = packet.buffer.split_off(packet.udp_start.unwrap() + 16); + + packet.ip_fill_length(); + + assert!(packet.buffer.len() <= max_length as usize); + + // Captured length. + output + .write_all(&u32::try_from(packet.buffer.len()).unwrap().to_ne_bytes()) + .unwrap(); + // Real length. + output + .write_all(&u32::try_from(packet.buffer.len()).unwrap().to_ne_bytes()) + .unwrap(); + + output.write_all(&packet.buffer).unwrap(); + + output.write_all(×tamp_start.to_ne_bytes()).unwrap(); + // micros -- we always have zeros for this field. + output.write_all(&0u32.to_ne_bytes()).unwrap(); + + let mut packet = Packet::new(); + + packet.add_ethernet(); + packet.add_ip(Some((16, false))); + packet.buffer.extend(tail); + + packet.ip_fill_length(); + + assert!(packet.buffer.len() <= max_length as usize); + + // Captured length. + output + .write_all(&u32::try_from(packet.buffer.len()).unwrap().to_ne_bytes()) + .unwrap(); + // Real length. + output + .write_all(&u32::try_from(packet.buffer.len()).unwrap().to_ne_bytes()) + .unwrap(); + + output.write_all(&packet.buffer).unwrap(); + } +} + +struct Packet { + buffer: Vec, + + ip_start: Option, + ip_length_field: Option, + + udp_start: Option, + udp_length_field: Option, +} + +impl Packet { + fn new() -> Packet { + Packet { + buffer: Vec::with_capacity(500), + ip_start: None, + ip_length_field: None, + udp_start: None, + udp_length_field: None, + } + } + + fn add_ethernet(&mut self) { + // Ethernet and IP headers. + self.buffer.write_all(&[0; 6]).unwrap(); + self.buffer.write_all(&[0; 6]).unwrap(); + // Ipv4 + self.buffer.write_all(&[0x08, 0x00]).unwrap(); + } + + // fragment is a (offset, more fragments) tuple. + fn add_ip(&mut self, fragment: Option<(usize, bool)>) { + self.ip_start = Some(self.buffer.len()); + + // 0x05 = 20 byte header. + self.buffer.write_all(&[0x45]).unwrap(); + + // No DSCP or ECN flags. + self.buffer.write_all(&[0x0]).unwrap(); + + self.ip_length_field = Some(self.buffer.len()); + + // Total length + self.buffer.write_all(&0u16.to_be_bytes()).unwrap(); + + // Identification field. + self.buffer.write_all(&0u16.to_be_bytes()).unwrap(); + + if let Some((offset, more)) = fragment { + // Needs to fit into 13 bits. + assert!(offset < (1 << 13)); + let mut offset = offset as u16; + + // Fragment offsets are specified in multiples of 8. + assert!(offset % 8 == 0); + offset /= 8; + + // set more fragments bit if we expect there to be further packets. + if more { + offset |= 1 << 13; + } + + // DF bit is set. + self.buffer.write_all(&offset.to_be_bytes()).unwrap(); + } else { + // DF bit is set. + self.buffer.write_all(&[0x40, 0x0]).unwrap(); + } + + // TTL. + self.buffer.write_all(&[200]).unwrap(); + + // Protocol is UDP. + self.buffer.write_all(&[17]).unwrap(); + + // Omit the packet-level checksum. + self.buffer.write_all(&0u16.to_be_bytes()).unwrap(); + + // src, dst addresses + self.buffer + .write_all(&Ipv4Addr::LOCALHOST.octets()) + .unwrap(); + self.buffer + .write_all(&Ipv4Addr::LOCALHOST.octets()) + .unwrap(); + } + + fn ip_fill_length(&mut self) { + let start = self.ip_start.unwrap(); + let len_idx = self.ip_length_field.unwrap(); + + let len = u16::try_from(self.buffer.len() - start) + .unwrap() + .to_be_bytes(); + self.buffer[len_idx..len_idx + 2].copy_from_slice(&len); + } + + fn add_udp(&mut self) { + self.udp_start = Some(self.buffer.len()); + + // src, dst port + self.buffer.write_all(&3433u16.to_be_bytes()).unwrap(); + self.buffer.write_all(&3433u16.to_be_bytes()).unwrap(); + + self.udp_length_field = Some(self.buffer.len()); + + // Length of UDP header + data. + self.buffer.write_all(&0u16.to_be_bytes()).unwrap(); + + // Skip checksum. + self.buffer.write_all(&0u16.to_be_bytes()).unwrap(); + } + + fn add_dcquic(&mut self, packet_idx: u64) { + // dcQUIC datagram. + self.buffer.write_all(&[0x46]).unwrap(); + // Path secret ID + self.buffer.write_all(&[0x43; 16]).unwrap(); + // Key ID + encode_varint(&mut self.buffer, packet_idx); + + // Source control port. + self.buffer.write_all(&3443u16.to_be_bytes()).unwrap(); + + // Packet number. + encode_varint(&mut self.buffer, 0); + + let payload_len = 110; + + // Payload length. + encode_varint(&mut self.buffer, payload_len); + + for _ in 0..payload_len { + self.buffer.push(0x55); + } + + // Auth tag. + self.buffer.write_all(&[1; 16]).unwrap(); + } + + fn udp_fill_length(&mut self) { + let start = self.udp_start.unwrap(); + let len_idx = self.udp_length_field.unwrap(); + + let len = u16::try_from(self.buffer.len() - start) + .unwrap() + .to_be_bytes(); + self.buffer[len_idx..len_idx + 2].copy_from_slice(&len); + } +} + +fn encode_varint(output: &mut Vec, input: u64) { + let varint = s2n_quic_core::varint::VarInt::try_from(input).unwrap(); + let mut buffer = [0; 8]; + let mut buffer = EncoderBuffer::new(&mut buffer); + varint.encode(&mut buffer); + output.extend_from_slice(buffer.as_mut_slice()); +} diff --git a/dc/wireshark/src/buffer.rs b/dc/wireshark/src/buffer.rs new file mode 100644 index 0000000000..2419efbda8 --- /dev/null +++ b/dc/wireshark/src/buffer.rs @@ -0,0 +1,58 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![cfg_attr(test, allow(dead_code))] + +use crate::{value::Parsed, wireshark_sys::tvbuff_t}; +use s2n_codec::{DecoderBuffer, DecoderValue}; + +pub struct Buffer<'a> { + pub offset: usize, + pub tvb: *mut tvbuff_t, + pub packet: &'a [u8], +} + +impl<'a> Buffer<'a> { + // SAFETY: packet must come from `tvb`. + pub unsafe fn new(tvb: *mut tvbuff_t, packet: &'a [u8]) -> Buffer<'a> { + Buffer { + offset: 0, + tvb, + packet, + } + } + + pub fn is_empty(&self) -> bool { + self.offset == self.packet.len() + } + + pub fn consume<'t, T: DecoderValue<'t>>(&'t mut self) -> Option> { + let start = self.offset; + let decoder = DecoderBuffer::new(self.packet.get(self.offset..)?); + + let before = decoder.len(); + let (value, tail) = decoder.decode::().ok()?; + let after = tail.len(); + let len = before - after; + + self.offset += len; + Some(Parsed { + offset: start, + len, + value, + }) + } + + pub fn consume_bytes>(&mut self, len: L) -> Option> { + let len = len.try_into().ok()?; + let start = self.offset; + let bytes = self.packet.get(self.offset..)?.get(..len)?; + self.offset += len; + debug_assert_eq!(len, bytes.len()); + Some(Parsed { + offset: start, + len, + value: bytes, + }) + } +} diff --git a/dc/wireshark/src/dissect.rs b/dc/wireshark/src/dissect.rs new file mode 100644 index 0000000000..b04c056d73 --- /dev/null +++ b/dc/wireshark/src/dissect.rs @@ -0,0 +1,526 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use crate::{ + buffer::Buffer, + field::Registration, + value::Parsed, + wireshark::{Info, Item, Node}, +}; +use s2n_codec::DecoderBufferMut; +use s2n_quic_core::{frame::FrameMut, varint::VarInt}; +use s2n_quic_dc::packet::{self, stream}; + +pub fn udp_segment( + tree: &mut T, + root: &mut impl Item, + fields: &Registration, + ptag: Parsed, + buffer: &mut Buffer, + info: &mut impl Info, +) -> Option<()> { + match ptag.value { + packet::Tag::Stream(tag) => { + root.append_text(c" Stream"); + let tag = ptag.map(|_| tag); + stream(tree, fields, tag, buffer, info) + } + packet::Tag::Control(tag) => { + root.append_text(c" Control"); + let tag = ptag.map(|_| tag); + control(tree, fields, tag, buffer, info) + } + packet::Tag::Datagram(tag) => { + root.append_text(c" Datagram"); + let tag = ptag.map(|_| tag); + datagram(tree, fields, tag, buffer, info) + } + _ => { + root.append_text(c" Secret Control"); + secret_control(tree, fields, ptag, buffer, info) + } + } +} + +pub fn stream( + tree: &mut T, + fields: &Registration, + tag: Parsed, + buffer: &mut Buffer, + info: &mut impl Info, +) -> Option<()> { + let tag_item = tag.record(buffer, tree, fields.tag); + + let mut tag_tree = tree.add_subtree(tag_item, fields.tag_subtree); + for field in [ + fields.has_source_stream_port, + fields.is_recovery_packet, + fields.has_control_data, + fields.has_final_offset, + fields.has_application_header, + ] { + tag_tree.add_boolean(buffer, field, tag); + } + + let tag = tag.value; + + let path_secret_id = buffer.consume_bytes(16)?; + path_secret_id.record(buffer, tree, fields.path_secret_id); + + let key_id = buffer.consume::()?; + key_id.record(buffer, tree, fields.key_id); + + let source_control_port = buffer.consume::()?; + source_control_port.record(buffer, tree, fields.source_control_port); + + if tag.has_source_stream_port() { + let source_stream_port = buffer.consume::()?; + source_stream_port.record(buffer, tree, fields.source_stream_port); + } + + let stream_id = buffer.consume()?; + let stream_id = record_stream_id(tree, fields, buffer, stream_id); + + let packet_number = buffer.consume::()?; + packet_number.record(buffer, tree, fields.packet_number); + + // FIXME: Actually decode the 32 bit value? + if stream_id.is_reliable { + let relative_packet_number = buffer.consume::()?; + relative_packet_number.record(buffer, tree, fields.relative_packet_number); + } + + let next_expected_control_packet = buffer.consume::()?; + next_expected_control_packet.record(buffer, tree, fields.next_expected_control_packet); + + let stream_offset = buffer.consume::()?; + stream_offset.record(buffer, tree, fields.stream_offset); + + if tag.has_final_offset() { + let final_offset = buffer.consume::()?; + final_offset.record(buffer, tree, fields.final_offset); + } + + let control_data_len = if tag.has_control_data() { + let control_data_len = buffer.consume::()?; + control_data_len.record(buffer, tree, fields.control_data_len); + Some(control_data_len.value) + } else { + None + }; + + let payload_len = buffer.consume::()?; + payload_len.record(buffer, tree, fields.payload_len); + + if tag.has_application_header() { + let application_header_len = buffer.consume::()?; + application_header_len.record(buffer, tree, fields.application_header_len); + + let application_header = buffer.consume_bytes(application_header_len.value)?; + + application_header.record(buffer, tree, fields.application_header); + } + + let mut control_info = String::new(); + if let Some(control_data_len) = control_data_len { + let control_data = buffer.consume_bytes(control_data_len)?; + control_frames(tree, fields, buffer, control_data, &mut control_info); + } + + let payload = buffer.consume_bytes(payload_len.value)?; + payload.record_hidden(buffer, tree, fields.payload); + + let auth_tag = buffer.consume_bytes(16)?; + auth_tag.record(buffer, tree, fields.auth_tag); + + info.append_delim(" "); + info.append(format_args!( + "Stream(ID={}, PN={},{control_info} LEN={})", + key_id.value, packet_number.value, payload.len + )); + + Some(()) +} + +pub fn control( + tree: &mut T, + fields: &Registration, + tag: Parsed, + buffer: &mut Buffer, + info: &mut impl Info, +) -> Option<()> { + let tag_item = tag.record(buffer, tree, fields.tag); + + let mut tag_tree = tree.add_subtree(tag_item, fields.tag_subtree); + for field in [fields.is_stream, fields.has_application_header] { + tag_tree.add_boolean(buffer, field, tag); + } + + let tag = tag.value; + + let path_secret_id = buffer.consume_bytes(16)?; + path_secret_id.record(buffer, tree, fields.path_secret_id); + + let key_id = buffer.consume::()?; + key_id.record(buffer, tree, fields.key_id); + + let source_control_port = buffer.consume::()?; + source_control_port.record(buffer, tree, fields.source_control_port); + + if tag.is_stream() { + let stream_id = buffer.consume()?; + record_stream_id(tree, fields, buffer, stream_id); + } + + let packet_number = buffer.consume::()?; + packet_number.record(buffer, tree, fields.packet_number); + + let control_data_len = buffer.consume::()?; + control_data_len.record(buffer, tree, fields.control_data_len); + + if tag.has_application_header() { + let application_header_len = buffer.consume::()?; + application_header_len.record(buffer, tree, fields.application_header_len); + + let application_header = buffer.consume_bytes(application_header_len.value)?; + + application_header.record(buffer, tree, fields.application_header); + } + + let control_data = buffer.consume_bytes(control_data_len.value)?; + let mut control_info = String::new(); + control_frames(tree, fields, buffer, control_data, &mut control_info); + + let auth_tag = buffer.consume_bytes(16)?; + auth_tag.record(buffer, tree, fields.auth_tag); + + info.append_delim(" "); + info.append(format_args!( + "Control(ID={}, PN={},{control_info})", + key_id.value, packet_number.value + )); + + Some(()) +} + +pub fn control_frames( + tree: &mut T, + fields: &Registration, + buffer: &mut Buffer, + control_data: Parsed<&[u8]>, + info: &mut impl Info, +) { + let control_item = control_data.record_hidden(buffer, tree, fields.control_data); + let mut tree = tree.add_subtree(control_item, fields.control_data_subtree); + let tree = &mut tree; + let mut control_data_owned = control_data.value.to_vec(); + + let mut has_ack = false; + let mut has_max_data = false; + let mut has_close = false; + + let mut offset = 0; + let mut decoder = DecoderBufferMut::new(&mut control_data_owned); + while !decoder.is_empty() { + let before = decoder.len(); + let Ok((frame, remaining)) = decoder.decode::() else { + break; + }; + let after = remaining.len(); + let len = before - after; + decoder = remaining; + + // create a placeholder parsed value + let parsed = Parsed { + offset, + len, + value: (), + }; + offset += len; + + match frame { + FrameMut::Padding(_) => { + // do nothing + } + FrameMut::Ping(_) => { + // do nothing + } + FrameMut::Ack(ack) => { + // TODO fix the tests to not assume a single occurrence of each field + if cfg!(test) && has_ack { + continue; + } + + has_ack = true; + parsed + .with(ack.ack_delay()) + .record(buffer, tree, fields.ack_delay); + + // FIXME: Look into using FT_FRAMENUM, but that is limited to 32-bit numbers, so + // maybe too small? + let ranges = ack.ack_ranges(); + + // TODO fix the tests to not assume a single occurrence of each field + #[cfg(test)] + let ranges = ranges.take(1); + + for range in ranges { + let start = parsed.with(range.start().as_u64()); + let end = parsed.with(range.end().as_u64()); + + let range = end.record(buffer, tree, fields.ackd_packet); + let mut range_tree = tree.add_subtree(range, fields.ack_range_subtree); + start.record(buffer, &mut range_tree, fields.ack_range_min); + end.record(buffer, &mut range_tree, fields.ack_range_max); + } + + if let Some(ecn) = ack.ecn_counts { + parsed + .with(ecn.ect_0_count) + .record(buffer, tree, fields.ect_0_count); + parsed + .with(ecn.ect_1_count) + .record(buffer, tree, fields.ect_1_count); + parsed + .with(ecn.ce_count) + .record(buffer, tree, fields.ce_count); + } + } + FrameMut::MaxData(frame) => { + // TODO fix the tests to not assume a single occurrence of each field + if cfg!(test) && has_max_data { + continue; + } + + has_max_data = true; + parsed + .with(frame.maximum_data) + .record(buffer, tree, fields.max_data); + } + FrameMut::ConnectionClose(frame) => { + // TODO fix the tests to not assume a single occurrence of each field + if cfg!(test) && has_close { + continue; + } + + has_close = true; + parsed + .with(frame.error_code) + .record(buffer, tree, fields.close_error_code); + if let Some(frame_type) = frame.frame_type { + parsed + .with(frame_type) + .record(buffer, tree, fields.close_frame_type); + } + if let Some(reason) = frame.reason { + parsed + .with(reason) + .record(buffer, tree, fields.close_reason); + } + } + // FIXME: add "other" handling + _ => continue, + } + } + + for (was_observed, label) in [ + (has_ack, "ACK"), + (has_max_data, "MAX_DATA"), + (has_close, "CONNECTION_CLOSE"), + ] { + if was_observed { + if info.is_empty() { + info.append_str(" "); + } else { + info.append_str(", "); + } + info.append_str(label); + } + } +} + +fn record_stream_id( + tree: &mut T, + fields: &Registration, + buffer: &mut Buffer, + stream_id: Parsed, +) -> stream::Id { + stream_id + .map(|v| v.key_id) + .record(buffer, tree, fields.stream_id); + let id = stream_id.value; + + tree.add_boolean( + buffer, + fields.is_reliable, + Parsed { + offset: stream_id.offset + stream_id.len - 1, + len: 1, + // needs to match the bitmask to show up properly + value: if id.is_reliable { 0b10 } else { 0 }, + }, + ); + tree.add_boolean( + buffer, + fields.is_bidirectional, + Parsed { + offset: stream_id.offset + stream_id.len - 1, + len: 1, + value: id.is_bidirectional as u8, + }, + ); + + id +} + +pub fn datagram( + tree: &mut T, + fields: &Registration, + tag: Parsed, + buffer: &mut Buffer, + info: &mut impl Info, +) -> Option<()> { + let tag_item = tag.record(buffer, tree, fields.tag); + + let mut tag_tree = tree.add_subtree(tag_item, fields.tag_subtree); + for field in [ + fields.is_ack_eliciting, + fields.is_connected, + fields.has_application_header, + ] { + tag_tree.add_boolean(buffer, field, tag); + } + + let tag = tag.value; + + let path_secret_id = buffer.consume_bytes(16)?; + path_secret_id.record(buffer, tree, fields.path_secret_id); + + let key_id = buffer.consume::()?; + key_id.record(buffer, tree, fields.key_id); + + let source_control_port = buffer.consume::()?; + source_control_port.record(buffer, tree, fields.source_control_port); + + let packet_number = if tag.is_connected() || tag.ack_eliciting() { + let packet_number = buffer.consume::()?; + packet_number.record(buffer, tree, fields.packet_number); + Some(packet_number.value) + } else { + None + }; + + let payload_len = buffer.consume::()?; + payload_len.record(buffer, tree, fields.payload_len); + let payload_len = payload_len.value; + + if tag.ack_eliciting() { + let next_expected_control_packet = buffer.consume::()?; + next_expected_control_packet.record(buffer, tree, fields.next_expected_control_packet); + } + + let control_data_len = if tag.ack_eliciting() { + let control_data_len = buffer.consume::()?; + control_data_len.record(buffer, tree, fields.control_data_len); + Some(control_data_len.value) + } else { + None + }; + + if tag.has_application_header() { + let application_header_len = buffer.consume::()?; + application_header_len.record(buffer, tree, fields.application_header_len); + + let application_header = buffer.consume_bytes(application_header_len.value)?; + + application_header.record(buffer, tree, fields.application_header); + } + + if let Some(control_data_len) = control_data_len { + let control_data = buffer.consume_bytes(control_data_len)?; + control_data.record(buffer, tree, fields.control_data); + } + + let payload = buffer.consume_bytes(payload_len)?; + payload.record(buffer, tree, fields.payload); + + let auth_tag = buffer.consume_bytes(16)?; + auth_tag.record(buffer, tree, fields.auth_tag); + + info.append_delim(" "); + if let Some(pn) = packet_number { + info.append(format_args!( + "Datagram(ID={}, PN={pn}, LEN={payload_len})", + key_id.value + )); + } else { + info.append(format_args!( + "Datagram(ID={}, LEN={payload_len})", + key_id.value + )); + } + + Some(()) +} + +pub fn secret_control( + tree: &mut T, + fields: &Registration, + tag: Parsed, + buffer: &mut Buffer, + info: &mut impl Info, +) -> Option<()> { + let mut item = tag.record(buffer, tree, fields.tag); + + match tag.value { + packet::Tag::UnknownPathSecret(_) => { + item.append_text(c"UnknownPathSecret"); + + let path_secret_id = buffer.consume_bytes(16)?; + path_secret_id.record(buffer, tree, fields.path_secret_id); + + let auth_tag = buffer.consume_bytes(16)?; + auth_tag.record(buffer, tree, fields.auth_tag); + + info.append_delim(" "); + info.append_str("UnknownPathSecret"); + + Some(()) + } + packet::Tag::StaleKey(_) => { + item.append_text(c"StaleKey"); + + let path_secret_id = buffer.consume_bytes(16)?; + path_secret_id.record(buffer, tree, fields.path_secret_id); + + let min_key_id = buffer.consume::()?; + min_key_id.record(buffer, tree, fields.min_key_id); + + let auth_tag = buffer.consume_bytes(16)?; + auth_tag.record(buffer, tree, fields.auth_tag); + + info.append_delim(" "); + info.append_str("StaleKey"); + + Some(()) + } + packet::Tag::ReplayDetected(_) => { + item.append_text(c"ReplayDetected"); + + let path_secret_id = buffer.consume_bytes(16)?; + path_secret_id.record(buffer, tree, fields.path_secret_id); + + let rejected_key_id = buffer.consume::()?; + rejected_key_id.record(buffer, tree, fields.rejected_key_id); + + let auth_tag = buffer.consume_bytes(16)?; + auth_tag.record(buffer, tree, fields.auth_tag); + + info.append_delim(" "); + info.append_str("ReplayDetected"); + + Some(()) + } + _ => None, + } +} diff --git a/dc/wireshark/src/field.rs b/dc/wireshark/src/field.rs new file mode 100644 index 0000000000..a4616ac28f --- /dev/null +++ b/dc/wireshark/src/field.rs @@ -0,0 +1,558 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use crate::wireshark_sys; +use core::{ffi::CStr, ptr}; +use std::sync::OnceLock; + +static REGISTRATION: OnceLock = OnceLock::new(); + +#[allow(dead_code)] +pub unsafe extern "C" fn proto_register() { + let _ = get(); +} + +#[derive(Debug)] +pub struct Registration { + pub protocol: i32, + pub all_subtree: i32, + pub tag_subtree: i32, + pub control_data_subtree: i32, + + pub ack_range_subtree: i32, + pub ack_range_min: i32, + pub ack_range_max: i32, + + pub tag: i32, + pub is_ack_eliciting: i32, + pub is_connected: i32, + pub has_application_header: i32, + pub has_source_stream_port: i32, + pub is_recovery_packet: i32, + pub has_control_data: i32, + pub has_final_offset: i32, + pub path_secret_id: i32, + pub key_id: i32, + pub source_control_port: i32, + pub source_stream_port: i32, + pub packet_number: i32, + pub payload_len: i32, + pub next_expected_control_packet: i32, + pub control_data_len: i32, + pub application_header_len: i32, + pub application_header: i32, + pub control_data: i32, + pub payload: i32, + pub auth_tag: i32, + + pub is_bidirectional: i32, + pub is_reliable: i32, + pub stream_id: i32, + pub relative_packet_number: i32, + pub stream_offset: i32, + pub final_offset: i32, + + pub is_stream: i32, + pub ack_delay: i32, + pub ackd_packet: i32, + pub ect_0_count: i32, + pub ect_1_count: i32, + pub ce_count: i32, + pub max_data: i32, + + pub close_error_code: i32, + pub close_frame_type: i32, + pub close_reason: i32, + + pub min_key_id: i32, + pub rejected_key_id: i32, +} + +#[cfg_attr(test, allow(unused))] +fn register_field(protocol: Protocol, field: Field) -> i32 { + let protocol = protocol.0; + let hfinfo = field.info; + + #[cfg(test)] + static FIELD_ID: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0); + + #[cfg(not(test))] + unsafe { + let id = Box::leak(Box::new(0i32)); + let registration_array = Box::into_raw(Box::new(wireshark_sys::hf_register_info { + p_id: id as *mut _, + hfinfo, + })); + crate::wireshark_sys::proto_register_field_array(protocol, registration_array, 1); + *id + } + + #[cfg(test)] + { + FIELD_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed) as i32 + } +} + +#[must_use] +struct Field { + protocol: Protocol, + info: wireshark_sys::_header_field_info, +} + +impl Field { + fn with_mask(mut self, mask: u64) -> Self { + self.info.bitmask = mask; + self + } + + fn register(self) -> i32 { + register_field(self.protocol, self) + } +} + +fn register_subtree() -> i32 { + let id = Box::leak(Box::new(-1i32)); + #[cfg(not(test))] + unsafe { + crate::wireshark_sys::proto_register_subtree_array(&(id as *mut i32), 1); + } + *id +} + +#[derive(Clone, Copy)] +struct Protocol(i32); + +impl Protocol { + fn field( + self, + name: &'static CStr, + abbrev: &'static CStr, + type_: wireshark_sys::ftenum_t, + display: wireshark_sys::field_display_e, + blurb: &'static CStr, + ) -> Field { + Field { + protocol: self, + info: wireshark_sys::_header_field_info { + name: name.as_ptr(), + abbrev: abbrev.as_ptr(), + type_, + display: display as _, + strings: ptr::null(), + bitmask: 0, + blurb: blurb.as_ptr(), + + // Following fields are filled/used by Wireshark internally. + + // -1, 0, HF_REF_TYPE_NONE, -1, NULL + id: -1, + parent: 0, + ref_type: wireshark_sys::hf_ref_type_HF_REF_TYPE_NONE, + same_name_prev_id: -1, + same_name_next: ptr::null_mut(), + }, + } + } +} + +#[cfg(test)] +fn register_protocol() -> Protocol { + Protocol(10101) +} + +#[cfg(not(test))] +fn register_protocol() -> Protocol { + let name = concat!(env!("PLUGIN_NAME"), "\0"); + let lower = concat!(env!("PLUGIN_NAME_LOWER"), "\0"); + Protocol(unsafe { + wireshark_sys::proto_register_protocol( + name.as_ptr() as *const _, + name.as_ptr() as *const _, + lower.as_ptr() as *const _, + ) + }) +} + +pub fn get() -> &'static Registration { + REGISTRATION.get_or_init(init) +} + +fn init() -> Registration { + use wireshark_sys::{ + field_display_e_BASE_DEC as BASE_DEC, field_display_e_BASE_HEX as BASE_HEX, + field_display_e_BASE_NONE as BASE_NONE, field_display_e_SEP_DOT as SEP_DOT, + ftenum_FT_BOOLEAN as BOOLEAN, ftenum_FT_BYTES as BYTES, + ftenum_FT_RELATIVE_TIME as RELATIVE_TIME, ftenum_FT_STRING as STRING, + ftenum_FT_UINT16 as UINT16, ftenum_FT_UINT32 as UINT32, ftenum_FT_UINT64 as UINT64, + ftenum_FT_UINT8 as UINT8, + }; + + let protocol = register_protocol(); + + Registration { + protocol: protocol.0, + all_subtree: register_subtree(), + tag_subtree: register_subtree(), + control_data_subtree: register_subtree(), + ack_range_subtree: register_subtree(), + tag: protocol + .field(c"Tag", c"dcquic.tag", UINT8, BASE_HEX, c"dcQUIC packet tag") + .register(), + is_ack_eliciting: protocol + .field( + c"Is ack eliciting?", + c"dcquic.tag.is_ack_eliciting", + BOOLEAN, + SEP_DOT, + c"Will packet elicit acknowledgements?", + ) + .with_mask(masks::ACK_ELICITING) + .register(), + is_connected: protocol + .field( + c"Is connected?", + c"dcquic.tag.is_connected", + BOOLEAN, + SEP_DOT, + c"Is the application using a connected dcQUIC client?", + ) + .with_mask(masks::IS_CONNECTED) + .register(), + has_application_header: protocol + .field( + c"Has application header?", + c"dcquic.tag.has_application_header", + BOOLEAN, + SEP_DOT, + c"Does the packet contain an authenticated plaintext application-provided header?", + ) + .with_mask(masks::HAS_APPLICATION_HEADER) + .register(), + has_source_stream_port: protocol + .field( + c"Has source stream port?", + c"dcquic.tag.has_source_stream_port", + BOOLEAN, + SEP_DOT, + c"", + ) + .with_mask(masks::HAS_SOURCE_STREAM_PORT) + .register(), + is_recovery_packet: protocol + .field( + c"Is recovery packet?", + c"dcquic.tag.is_recovery_packet", + BOOLEAN, + SEP_DOT, + c"", + ) + .with_mask(masks::IS_RECOVERY_PACKET) + .register(), + has_control_data: protocol + .field( + c"Has control data?", + c"dcquic.tag.has_control_data", + BOOLEAN, + SEP_DOT, + c"", + ) + .with_mask(masks::HAS_CONTROL_DATA) + .register(), + has_final_offset: protocol + .field( + c"Has final offset?", + c"dcquic.tag.has_final_offset", + BOOLEAN, + SEP_DOT, + c"", + ) + .with_mask(masks::HAS_FINAL_OFFSET) + .register(), + path_secret_id: protocol + .field( + c"Path Secret ID", + c"dcquic.path_secret_id", + BYTES, + BASE_NONE, + c"dcQUIC path secret id", + ) + .register(), + key_id: protocol + .field( + c"Key ID", + c"dcquic.key_id", + UINT64, + BASE_DEC, + c"dcQUIC key ID", + ) + .register(), + source_control_port: protocol + .field( + c"Source Control Port", + c"dcquic.source_control_port", + UINT16, + BASE_DEC, + c"source control port", + ) + .register(), + source_stream_port: protocol + .field( + c"Source Stream Port", + c"dcquic.source_stream_port", + UINT16, + BASE_DEC, + c"", + ) + .register(), + packet_number: protocol + .field( + c"Packet Number", + c"dcquic.packet_number", + UINT64, + BASE_DEC, + c"packet number", + ) + .register(), + payload_len: protocol + .field( + c"Payload length", + c"dcquic.payload_len", + UINT64, + BASE_DEC, + c"payload length", + ) + .register(), + next_expected_control_packet: protocol + .field( + c"Next expected control packet", + c"dcquic.next_expected_control_packet", + UINT64, + BASE_DEC, + c"", + ) + .register(), + control_data_len: protocol + .field( + c"Control Data length", + c"dcquic.control_data_len", + UINT64, + BASE_DEC, + c"", + ) + .register(), + application_header_len: protocol + .field( + c"Application Header length", + c"dcquic.application_header_len", + UINT64, + BASE_DEC, + c"", + ) + .register(), + application_header: protocol + .field( + c"Application Header", + c"dcquic.application_header", + BYTES, + BASE_NONE, + c"", + ) + .register(), + control_data: protocol + .field( + c"Control Data", + c"dcquic.control_data", + BYTES, + BASE_NONE, + c"", + ) + .register(), + payload: protocol + .field(c"Payload", c"dcquic.payload", BYTES, BASE_NONE, c"") + .register(), + auth_tag: protocol + .field( + c"Authentication tag", + c"dcquic.auth_tag", + BYTES, + BASE_NONE, + c"", + ) + .register(), + is_bidirectional: protocol + .field( + c"Is bidirectional?", + c"dcquic.is_bidirectional", + BOOLEAN, + SEP_DOT, + c"", + ) + .with_mask(0x1) + .register(), + is_reliable: protocol + .field( + c"Is reliable?", + c"dcquic.is_reliable", + BOOLEAN, + SEP_DOT, + c"", + ) + .with_mask(0x2) + .register(), + stream_id: protocol + .field(c"Stream ID", c"dcquic.stream_id", UINT64, BASE_DEC, c"") + .register(), + relative_packet_number: protocol + .field( + c"Relative Packet Number", + c"dcquic.relative_packet_number", + UINT32, + BASE_DEC, + c"", + ) + .register(), + stream_offset: protocol + .field( + c"Stream Payload Offset", + c"dcquic.stream_payload_offset", + UINT64, + BASE_DEC, + c"", + ) + .register(), + final_offset: protocol + .field( + c"Stream Final Payload Length", + c"dcquic.stream_final_offset", + UINT64, + BASE_DEC, + c"", + ) + .register(), + is_stream: protocol + .field( + c"Is stream control packet?", + c"dcquic.is_stream_control", + BOOLEAN, + SEP_DOT, + c"", + ) + .with_mask(masks::IS_STREAM) + .register(), + ack_delay: protocol + .field( + c"Ack delay", + c"dcquic.control.ack_delay", + RELATIVE_TIME, + BASE_NONE, + c"", + ) + .register(), + ackd_packet: protocol + .field(c"Ack Range", c"dcquic.control.ack", UINT64, BASE_DEC, c"") + .register(), + ack_range_min: protocol + .field(c"Min", c"dcquic.control.ack.min", UINT64, BASE_DEC, c"") + .register(), + ack_range_max: protocol + .field(c"Max", c"dcquic.control.ack.min", UINT64, BASE_DEC, c"") + .register(), + ect_0_count: protocol + .field( + c"ECT(0) count", + c"dcquic.control.ect0", + UINT64, + BASE_DEC, + c"", + ) + .register(), + ect_1_count: protocol + .field( + c"ECT(1) count", + c"dcquic.control.ect1", + UINT64, + BASE_DEC, + c"", + ) + .register(), + ce_count: protocol + .field(c"CE count", c"dcquic.control.ce", UINT64, BASE_DEC, c"") + .register(), + max_data: protocol + .field( + c"Max Data", + c"dcquic.control.max_data", + UINT64, + BASE_DEC, + c"", + ) + .register(), + close_error_code: protocol + .field( + c"Close Error Code", + c"dcquic.control.close_error_code", + UINT64, + BASE_DEC, + c"", + ) + .register(), + close_frame_type: protocol + .field( + c"Close Frame Type", + c"dcquic.control.close_frame_type", + UINT64, + BASE_DEC, + c"", + ) + .register(), + close_reason: protocol + .field( + c"Close Reason", + c"dcquic.control.close_reason", + STRING, + BASE_NONE, + c"", + ) + .register(), + min_key_id: protocol + .field( + c"Min KeyId", + c"dcquic.secret.min_key_id", + UINT64, + BASE_DEC, + c"Minimum not-yet-seen key ID (at the time of this packets sending)", + ) + .register(), + rejected_key_id: protocol + .field( + c"Rejected KeyId", + c"dcquic.secret.rejected_key_id", + UINT64, + BASE_DEC, + c"KeyId rejected due to definitively observing replay", + ) + .register(), + } +} + +mod masks { + use s2n_quic_dc::packet::{control, datagram, stream}; + + pub const IS_STREAM: u64 = control::Tag::IS_STREAM_MASK as _; + pub const ACK_ELICITING: u64 = datagram::Tag::ACK_ELICITING_MASK as _; + pub const IS_CONNECTED: u64 = datagram::Tag::IS_CONNECTED_MASK as _; + pub const HAS_SOURCE_STREAM_PORT: u64 = stream::Tag::HAS_SOURCE_STREAM_PORT as _; + pub const IS_RECOVERY_PACKET: u64 = stream::Tag::IS_RECOVERY_PACKET as _; + pub const HAS_CONTROL_DATA: u64 = stream::Tag::HAS_CONTROL_DATA_MASK as _; + pub const HAS_FINAL_OFFSET: u64 = stream::Tag::HAS_FINAL_OFFSET_MASK as _; + + pub const HAS_APPLICATION_HEADER: u64 = { + // Statically assert that the masks line up between all three packets. + const _: [(); stream::Tag::HAS_APPLICATION_HEADER_MASK as usize] = + [(); datagram::Tag::HAS_APPLICATION_HEADER_MASK as usize]; + const _: [(); stream::Tag::HAS_APPLICATION_HEADER_MASK as usize] = + [(); control::Tag::HAS_APPLICATION_HEADER_MASK as usize]; + + datagram::Tag::HAS_APPLICATION_HEADER_MASK as _ + }; +} diff --git a/dc/wireshark/src/lib.rs b/dc/wireshark/src/lib.rs new file mode 100644 index 0000000000..861209224b --- /dev/null +++ b/dc/wireshark/src/lib.rs @@ -0,0 +1,32 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +mod buffer; +mod dissect; +mod field; +#[cfg(not(test))] +mod plugin; +mod value; +/// This wraps the underlying sys APIs in structures that support a cfg(test) mode that doesn't rely on Wireshark. +mod wireshark; + +/// These are bindgen-generated bindings from bindgen 4.2.5. +/// Allow warnings since we don't control the bindgen generation process enough for warnings to be worthwhile to fix. +#[allow(warnings)] +mod wireshark_sys { + // when we're running tests, we just want to pull in types without any `extern fn` so we don't + // end up with undefined symbols. + + #[cfg(test)] + #[path = "minimal.rs"] + mod sys_impl; + + #[cfg(not(test))] + #[path = "full.rs"] + mod sys_impl; + + pub use sys_impl::*; +} + +#[cfg(test)] +mod test; diff --git a/dc/wireshark/src/plugin.rs b/dc/wireshark/src/plugin.rs new file mode 100644 index 0000000000..a671c808a6 --- /dev/null +++ b/dc/wireshark/src/plugin.rs @@ -0,0 +1,215 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use crate::{buffer::Buffer, dissect, field, field::Registration, wireshark::Item, wireshark_sys}; +use std::{ffi::CStr, sync::OnceLock}; + +#[no_mangle] +#[used] +static plugin_version: [std::ffi::c_char; 4] = [b'0' as _, b'.' as _, b'1' as _, b'\0' as _]; + +// When bumping, make sure that the bindgen bindings are updated to the new version. +#[no_mangle] +#[used] +static plugin_want_major: std::ffi::c_int = 4; + +// When bumping, make sure that the bindgen bindings are updated to the new version. +#[no_mangle] +#[used] +static plugin_want_minor: std::ffi::c_int = 2; + +#[no_mangle] +pub extern "C" fn plugin_register() { + static PLUGIN: wireshark_sys::proto_plugin = wireshark_sys::proto_plugin { + register_protoinfo: Some(field::proto_register), + register_handoff: Some(proto_reg_handoff), + }; + + unsafe { + wireshark_sys::proto_register_plugin(&PLUGIN); + } +} + +static STREAM_DISSECTOR: OnceLock = OnceLock::new(); + +struct DissectorHandle(wireshark_sys::dissector_handle_t); + +// Probably a lie, but just an opaque ID anyway. +// Wireshark owns all the threading for the plugin so this is hopefully OK. +unsafe impl Send for DissectorHandle {} +unsafe impl Sync for DissectorHandle {} + +unsafe extern "C" fn proto_reg_handoff() { + wireshark_sys::heur_dissector_add( + c"udp".as_ptr(), + Some(dissect_heur_udp), + c"dcQUIC over UDP".as_ptr(), + concat!(env!("PLUGIN_NAME_LOWER"), "\0").as_ptr() as *const _, + field::get().protocol, + wireshark_sys::heuristic_enable_e_HEURISTIC_ENABLE, + ); + + wireshark_sys::heur_dissector_add( + c"tcp".as_ptr(), + Some(dissect_heur_tcp), + c"dcQUIC over TCP".as_ptr(), + concat!(env!("PLUGIN_NAME_LOWER"), "_tcp\0").as_ptr() as *const _, + field::get().protocol, + wireshark_sys::heuristic_enable_e_HEURISTIC_ENABLE, + ); + + STREAM_DISSECTOR.get_or_init(|| { + DissectorHandle( + wireshark_sys::create_dissector_handle_with_name_and_description( + Some(dissect_heur_tcp), + field::get().protocol, + concat!(env!("PLUGIN_NAME_LOWER"), "_tcp_stream\0").as_ptr() as *const _, + c"dcQUIC stream".as_ptr(), + ), + ) + }); +} + +// tvb may not actually be contiguous so copy it into an owned buffer +pub fn copy_to_rust(tvb: *mut wireshark_sys::tvbuff_t) -> Vec { + let len = unsafe { wireshark_sys::tvb_reported_length(tvb) as usize }; + let mut buffer: Vec = vec![0; len]; + unsafe { + wireshark_sys::tvb_memcpy(tvb, buffer.as_mut_ptr() as *mut std::ffi::c_void, 0, len); + } + buffer +} + +unsafe extern "C" fn dissect_heur_udp( + tvb: *mut wireshark_sys::tvbuff_t, + mut pinfo: *mut wireshark_sys::_packet_info, + proto: *mut wireshark_sys::_proto_node, + _: *mut std::ffi::c_void, +) -> i32 { + let fields = field::get(); + + let packet = copy_to_rust(tvb); + let mut buffer = Buffer::new(tvb, &packet); + + let mut accepted_offset = 0; + let mut info = vec![]; + + while !buffer.is_empty() { + let Some(tag) = buffer.consume() else { + break; + }; + let (mut tree, mut root) = register_root_node(proto, &buffer, fields); + let Some(()) = + dissect::udp_segment(&mut tree, &mut root, fields, tag, &mut buffer, &mut info) + else { + break; + }; + + accepted_offset = buffer.offset; + } + + // Didn't look like a dcQUIC packet. + if accepted_offset == 0 { + return 0; + } + + if !info.is_empty() { + // add a NULL byte + info.push(0); + clear_info(pinfo); + pinfo.append_text(CStr::from_ptr(info.as_ptr() as *const _)); + } + + set_protocol(pinfo, c"dcQUIC"); + + accepted_offset as _ +} + +unsafe extern "C" fn dissect_heur_tcp( + tvb: *mut wireshark_sys::tvbuff_t, + mut pinfo: *mut wireshark_sys::_packet_info, + proto: *mut wireshark_sys::_proto_node, + _: *mut std::ffi::c_void, +) -> i32 { + let fields = field::get(); + + let packet = copy_to_rust(tvb); + let mut buffer = Buffer::new(tvb, &packet); + + let mut accepted_offset = 0; + let mut info = vec![]; + + while !buffer.is_empty() { + let stream_frame_start = buffer.offset; + let Some(tag) = buffer.consume() else { + break; + }; + + let (mut tree, mut root) = register_root_node(proto, &buffer, fields); + root.append_text(c" Stream"); + let parse_res = dissect::stream(&mut tree, fields, tag, &mut buffer, &mut info); + wireshark_sys::proto_item_set_len(root, (buffer.offset - stream_frame_start) as i32); + if parse_res.is_none() { + // Start parsing again from the head of this stream... + (*pinfo).desegment_offset = stream_frame_start as _; + (*pinfo).desegment_len = wireshark_sys::DESEGMENT_ONE_MORE_SEGMENT; + break; + } + + accepted_offset = buffer.offset; + + // If we successfully parsed, then mark this conversation as being dissected by us + // going forward. + let conversation = wireshark_sys::find_or_create_conversation(pinfo); + wireshark_sys::conversation_set_dissector(conversation, STREAM_DISSECTOR.get().unwrap().0); + } + + // Didn't look like a dcQUIC segment. + if accepted_offset == 0 { + return 0; + } + + if !info.is_empty() { + // add a NULL byte + info.push(0); + clear_info(pinfo); + pinfo.append_text(CStr::from_ptr(info.as_ptr() as *const _)); + } + + set_protocol(pinfo, c"TCP/dcQUIC"); + + accepted_offset as _ +} + +unsafe fn register_root_node( + proto: *mut wireshark_sys::_proto_node, + buffer: &Buffer, + fields: &Registration, +) -> ( + *mut wireshark_sys::_proto_node, + *mut wireshark_sys::_proto_node, +) { + let ti = wireshark_sys::proto_tree_add_item( + proto, + fields.protocol, + buffer.tvb, + 0, + buffer.packet.len() as _, + wireshark_sys::ENC_BIG_ENDIAN, + ); + let tree = wireshark_sys::proto_item_add_subtree(ti, fields.all_subtree); + (tree, ti) +} + +unsafe fn set_protocol(pinfo: *mut wireshark_sys::_packet_info, protocol: &'static CStr) { + // set_str doesn't copy out protocol so it must be static + wireshark_sys::col_set_str( + (*pinfo).cinfo, + wireshark_sys::COL_PROTOCOL as _, + protocol.as_ptr(), + ); +} + +unsafe fn clear_info(pinfo: *mut wireshark_sys::_packet_info) { + wireshark_sys::col_clear((*pinfo).cinfo, wireshark_sys::COL_INFO as _); +} diff --git a/dc/wireshark/src/test.rs b/dc/wireshark/src/test.rs new file mode 100644 index 0000000000..5223195b51 --- /dev/null +++ b/dc/wireshark/src/test.rs @@ -0,0 +1,688 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use crate::{buffer::Buffer, dissect, value::Parsed}; +use s2n_codec::EncoderBuffer; +use s2n_quic_core::{ + buffer::{reader::Storage, Reader}, + stream::testing::Data, + varint::VarInt, +}; +use s2n_quic_dc::{ + credentials::{self, Credentials}, + packet::{self, stream}, +}; +use std::{collections::HashMap, num::NonZeroU16, ptr, time::Duration}; + +#[derive(Clone, Debug, bolero::TypeGenerator)] +struct StreamPacket { + credentials: s2n_quic_dc::credentials::Credentials, + source_control_port: NonZeroU16, + source_stream_port: Option, + stream_id: stream::Id, + packet_space: stream::PacketSpace, + packet_number: VarInt, + next_expected_control_packet: VarInt, + application_header: Data, + payload: Data, +} + +#[test] +fn check_stream_parse() { + // Initialize field IDs. + let _ = crate::field::get(); + + bolero::check!() + .with_type() + .for_each(|packet: &StreamPacket| { + let mut packet = packet.clone(); + let key = s2n_quic_dc::crypto::testing::Key::new(packet.credentials); + let sent_payload = packet.payload; + let sent_app_header_len = packet.application_header.buffered_len(); + let mut buffer = vec![ + 0; + sent_payload.buffered_len() + + sent_app_header_len + + s2n_quic_dc::packet::stream::encoder::MAX_HEADER_LEN + + s2n_quic_dc::packet::stream::encoder::MAX_RETRANSMISSION_HEADER_LEN + ]; + let length = s2n_quic_dc::packet::stream::encoder::encode( + EncoderBuffer::new(&mut buffer), + NonZeroU16::get(packet.source_control_port), + packet.source_stream_port.map(NonZeroU16::get), + packet.stream_id, + packet.packet_space, + packet.packet_number, + packet.next_expected_control_packet, + VarInt::new(packet.application_header.buffered_len() as u64).unwrap(), + &mut packet.application_header, + // FIXME: Consider populating control data? Not sent by current impl. + VarInt::ZERO, + &(), + &mut packet.payload, + &key, + ); + + let fields = crate::field::get(); + let mut tracker = Tracker::default(); + + let mut buffer = unsafe { Buffer::new(ptr::null_mut(), &buffer[..length]) }; + let tag: Parsed = buffer.consume().unwrap(); + assert!(dissect::stream(&mut tracker, fields, tag, &mut buffer, &mut ()).is_some()); + let tag: Parsed = tag.map(|v| v.into()); + + assert_eq!(tracker.remove(fields.tag), Field::Integer(tag.value as u64)); + assert_eq!( + tracker.remove(fields.path_secret_id), + Field::Slice(packet.credentials.id.to_vec()) + ); + assert_eq!( + tracker.remove(fields.key_id), + Field::Integer(packet.credentials.key_id.into()) + ); + assert_eq!( + tracker.remove(fields.source_control_port), + Field::Integer(packet.source_control_port.get() as u64) + ); + assert_eq!( + tracker.take(fields.source_stream_port), + packet + .source_stream_port + .map(|v| Field::Integer(v.get() as u64)) + ); + assert_eq!( + tracker.remove(fields.stream_id), + Field::Integer(u64::from(packet.stream_id.key_id)) + ); + assert_eq!( + tracker.remove(fields.is_reliable), + Field::Integer(if packet.stream_id.is_reliable { + stream::id::IS_RELIABLE_MASK + } else { + 0 + }) + ); + assert_eq!( + tracker.remove(fields.is_bidirectional), + Field::Integer(if packet.stream_id.is_bidirectional { + stream::id::IS_BIDIRECTIONAL_MASK + } else { + 0 + }) + ); + assert_eq!( + tracker.remove(fields.packet_number), + Field::Integer(u64::from(packet.packet_number)) + ); + assert_eq!( + tracker.remove(fields.next_expected_control_packet), + Field::Integer(u64::from(packet.next_expected_control_packet)) + ); + + // Tag fields all store the tag value itself. + for field in [ + fields.has_source_stream_port, + fields.is_recovery_packet, + fields.has_control_data, + fields.has_final_offset, + fields.has_application_header, + ] { + assert_eq!(tracker.remove(field), Field::Integer(tag.value as u64)); + } + + assert_eq!( + tracker.remove(fields.payload_len), + Field::Integer(sent_payload.buffered_len() as u64) + ); + + // FIXME: Deeper check? + assert!(tracker.take(fields.payload).is_some()); + + // FIXME: Deeper check? + assert!(tracker.take(fields.auth_tag).is_some()); + + assert_eq!( + tracker.take(fields.final_offset), + sent_payload + .final_offset() + .map(|v| Field::Integer(v.as_u64())), + ); + + assert_eq!( + tracker.remove(fields.stream_offset), + Field::Integer(sent_payload.current_offset().as_u64()) + ); + + // FIXME: Figure out how to best test this - right now this is filled in as part of + // *decoding* since we store the encrypted payloads. + if packet.stream_id.is_reliable { + assert_eq!( + tracker.remove(fields.relative_packet_number), + Field::Integer(0) + ); + } + + if sent_app_header_len > 0 { + assert_eq!( + tracker.remove(fields.application_header).slice_len(), + sent_app_header_len + ); + assert_eq!( + tracker.remove(fields.application_header_len), + Field::Integer(sent_app_header_len as u64) + ); + } + + assert_eq!( + tracker.seen_fields.borrow().len(), + 0, + "{:?}, remaining: {:?}", + fields, + tracker.seen_fields + ); + }); +} + +#[derive(Clone, Debug, bolero::TypeGenerator)] +struct DatagramPacket { + credentials: s2n_quic_dc::credentials::Credentials, + source_control_port: NonZeroU16, + // If None then not connected. + packet_number: Option, + next_expected_control_packet: Option, + application_header: Data, + payload: Data, +} + +#[test] +fn check_datagram_parse() { + // Initialize field IDs. + let _ = crate::field::get(); + + bolero::check!() + .with_type() + .for_each(|packet: &DatagramPacket| { + let mut packet = packet.clone(); + if packet.next_expected_control_packet.is_some() && packet.packet_number.is_none() { + packet.packet_number = Some(Default::default()); + } + let key = s2n_quic_dc::crypto::testing::Key::new(packet.credentials); + let sent_payload = packet.payload; + let sent_app_header_len = packet.application_header.buffered_len(); + let mut buffer = vec![ + 0; + sent_payload.buffered_len() + + sent_app_header_len + + s2n_quic_dc::packet::stream::encoder::MAX_HEADER_LEN + + s2n_quic_dc::packet::stream::encoder::MAX_RETRANSMISSION_HEADER_LEN + ]; + let length = s2n_quic_dc::packet::datagram::encoder::encode( + EncoderBuffer::new(&mut buffer), + packet.source_control_port.get(), + packet.packet_number, + packet.next_expected_control_packet, + VarInt::new(packet.application_header.buffered_len() as u64).unwrap(), + &mut packet.application_header, + // FIXME: Encode real control data. + &(), + VarInt::new(packet.payload.buffered_len() as u64).unwrap(), + &mut packet.payload, + &key, + ); + + let fields = crate::field::get(); + let mut tracker = Tracker::default(); + + let mut buffer = unsafe { Buffer::new(ptr::null_mut(), &buffer[..length]) }; + let tag: Parsed = buffer.consume().unwrap(); + assert!(dissect::datagram(&mut tracker, fields, tag, &mut buffer, &mut ()).is_some()); + let tag: Parsed = tag.map(|v| v.into()); + + assert_eq!(tracker.remove(fields.tag), Field::Integer(tag.value as u64)); + assert_eq!( + tracker.remove(fields.path_secret_id), + Field::Slice(packet.credentials.id.to_vec()) + ); + assert_eq!( + tracker.remove(fields.key_id), + Field::Integer(packet.credentials.key_id.into()) + ); + assert_eq!( + tracker.remove(fields.source_control_port), + Field::Integer(packet.source_control_port.get() as u64) + ); + assert_eq!( + tracker.take(fields.packet_number), + packet.packet_number.map(|v| Field::Integer(u64::from(v))) + ); + assert_eq!( + tracker.take(fields.next_expected_control_packet), + packet + .next_expected_control_packet + .map(|v| Field::Integer(u64::from(v))) + ); + + // Tag fields all store the tag value itself. + for field in [ + fields.is_ack_eliciting, + fields.has_application_header, + fields.is_connected, + ] { + assert_eq!(tracker.remove(field), Field::Integer(tag.value as u64)); + } + + assert_eq!( + tracker.remove(fields.payload_len), + Field::Integer(sent_payload.buffered_len() as u64) + ); + + // FIXME: Deeper check? + assert!(tracker.take(fields.payload).is_some()); + + // FIXME: Deeper check? + assert!(tracker.take(fields.auth_tag).is_some()); + + if sent_app_header_len > 0 { + assert_eq!( + tracker.remove(fields.application_header).slice_len(), + sent_app_header_len + ); + assert_eq!( + tracker.remove(fields.application_header_len), + Field::Integer(sent_app_header_len as u64) + ); + } + + // Is ack-eliciting? + // + // For now no control data is encoded, but we should still find the fields. + if packet.next_expected_control_packet.is_some() { + assert_eq!(tracker.remove(fields.control_data).slice_len(), 0); + assert_eq!(tracker.remove(fields.control_data_len), Field::Integer(0)); + } + + assert_eq!( + tracker.seen_fields.borrow().len(), + 0, + "{:?}, remaining: {:?}", + fields, + tracker.seen_fields + ); + }); +} + +#[derive(Clone, Debug, bolero::TypeGenerator)] +struct ControlPacket { + credentials: s2n_quic_dc::credentials::Credentials, + source_control_port: NonZeroU16, + stream_id: Option, + packet_number: VarInt, + next_expected_control_packet: Option, + application_header: Data, + control_data: Data, +} + +#[test] +fn check_control_parse() { + // Initialize field IDs. + let _ = crate::field::get(); + + bolero::check!() + .with_type() + .for_each(|packet: &ControlPacket| { + let mut packet = packet.clone(); + let key = s2n_quic_dc::crypto::testing::Key::new(packet.credentials); + let sent_app_header_len = packet.application_header.buffered_len(); + let mut buffer = vec![ + 0; + packet.control_data.buffered_len() + + sent_app_header_len + + s2n_quic_dc::packet::stream::encoder::MAX_HEADER_LEN + + s2n_quic_dc::packet::stream::encoder::MAX_RETRANSMISSION_HEADER_LEN + ]; + let length = s2n_quic_dc::packet::control::encoder::encode( + EncoderBuffer::new(&mut buffer), + packet.source_control_port.get(), + packet.stream_id, + packet.packet_number, + VarInt::new(packet.application_header.buffered_len() as u64).unwrap(), + &mut packet.application_header, + VarInt::new(packet.control_data.buffered_len() as u64).unwrap(), + // FIXME: Encode *real* control data, not random garbage. + &&packet.control_data.read_chunk(usize::MAX).unwrap()[..], + &key, + ); + + let fields = crate::field::get(); + let mut tracker = Tracker::default(); + + let mut buffer = unsafe { Buffer::new(ptr::null_mut(), &buffer[..length]) }; + let tag: Parsed = buffer.consume().unwrap(); + assert!(dissect::control(&mut tracker, fields, tag, &mut buffer, &mut ()).is_some()); + let tag: Parsed = tag.map(|v| v.into()); + + assert_eq!(tracker.remove(fields.tag), Field::Integer(tag.value as u64)); + assert_eq!( + tracker.remove(fields.path_secret_id), + Field::Slice(packet.credentials.id.to_vec()) + ); + assert_eq!( + tracker.remove(fields.key_id), + Field::Integer(packet.credentials.key_id.into()) + ); + assert_eq!( + tracker.remove(fields.source_control_port), + Field::Integer(packet.source_control_port.get() as u64) + ); + assert_eq!( + tracker.remove(fields.packet_number), + Field::Integer(packet.packet_number.as_u64()) + ); + + // FIXME: Deeper check? + assert!(tracker.take(fields.auth_tag).is_some()); + + if sent_app_header_len > 0 { + assert_eq!( + tracker.remove(fields.application_header).slice_len(), + sent_app_header_len + ); + assert_eq!( + tracker.remove(fields.application_header_len), + Field::Integer(sent_app_header_len as u64) + ); + } + + // FIXME: In order to make any assertion here we'd need to not encode random data into + // control packets. So skip it for now. + // assert_eq!( + // tracker.seen_fields.borrow().len(), + // 0, + // "{:?}, remaining: {:?}", + // fields, + // tracker.seen_fields + // ); + }); +} + +#[derive(Clone, Debug, bolero::TypeGenerator)] +enum SecretControlPacket { + UnknownPathSecret { + id: credentials::Id, + auth_tag: [u8; 16], + }, + StaleKey { + id: credentials::Id, + key_id: VarInt, + }, + ReplayDetected { + id: credentials::Id, + key_id: VarInt, + }, +} + +#[test] +fn check_secret_control_parse() { + // Initialize field IDs. + let _ = crate::field::get(); + + bolero::check!() + .with_type() + .for_each(|packet: &SecretControlPacket| { + // Use a fixed key, we don't change key IDs per control packet anyway. + let key = s2n_quic_dc::crypto::testing::Key::new(Credentials { + id: [0; 16].into(), + key_id: VarInt::ZERO, + }); + let mut buffer = vec![0; s2n_quic_dc::packet::secret_control::MAX_PACKET_SIZE]; + let length = match packet { + SecretControlPacket::UnknownPathSecret { id, auth_tag } => { + s2n_quic_dc::packet::secret_control::UnknownPathSecret { credential_id: *id } + .encode(EncoderBuffer::new(&mut buffer), auth_tag) + } + SecretControlPacket::StaleKey { id, key_id } => { + s2n_quic_dc::packet::secret_control::StaleKey { + credential_id: *id, + min_key_id: *key_id, + } + .encode(EncoderBuffer::new(&mut buffer), &key) + } + SecretControlPacket::ReplayDetected { id, key_id } => { + s2n_quic_dc::packet::secret_control::ReplayDetected { + credential_id: *id, + rejected_key_id: *key_id, + } + .encode(EncoderBuffer::new(&mut buffer), &key) + } + }; + + let fields = crate::field::get(); + let mut tracker = Tracker::default(); + + let mut buffer = unsafe { Buffer::new(ptr::null_mut(), &buffer[..length]) }; + let tag = buffer.consume().unwrap(); + assert!( + dissect::secret_control(&mut tracker, fields, tag, &mut buffer, &mut ()).is_some() + ); + + match packet { + SecretControlPacket::UnknownPathSecret { id, auth_tag } => { + assert_eq!(tracker.remove(fields.tag), Field::Integer(0b0110_0000)); + assert_eq!( + tracker.remove(fields.path_secret_id), + Field::Slice(id.to_vec()) + ); + assert_eq!( + tracker.remove(fields.auth_tag), + Field::Slice(auth_tag.to_vec()) + ); + } + SecretControlPacket::StaleKey { id, key_id } => { + assert_eq!(tracker.remove(fields.tag), Field::Integer(0b0110_0001)); + assert_eq!( + tracker.remove(fields.path_secret_id), + Field::Slice(id.to_vec()) + ); + assert_eq!( + tracker.remove(fields.min_key_id), + Field::Integer(key_id.as_u64()) + ); + // FIXME: Deeper check? + assert!(tracker.take(fields.auth_tag).is_some()); + } + SecretControlPacket::ReplayDetected { id, key_id } => { + assert_eq!(tracker.remove(fields.tag), Field::Integer(0b0110_0010)); + assert_eq!( + tracker.remove(fields.path_secret_id), + Field::Slice(id.to_vec()) + ); + assert_eq!( + tracker.remove(fields.rejected_key_id), + Field::Integer(key_id.as_u64()) + ); + // FIXME: Deeper check? + assert!(tracker.take(fields.auth_tag).is_some()); + } + }; + + assert_eq!( + tracker.seen_fields.borrow().len(), + 0, + "{:?}, remaining: {:?}", + fields, + tracker.seen_fields + ); + }); +} + +#[test] +fn random_stream_packets() { + // Initialize field IDs. + let _ = crate::field::get(); + + bolero::check!().for_each(|packet: &[u8]| { + let fields = crate::field::get(); + let mut tracker = Tracker::default(); + let mut buffer = unsafe { Buffer::new(ptr::null_mut(), packet) }; + let Some(tag) = buffer.consume() else { + return; + }; + // May fail to parse, but shouldn't panic. + let _ = dissect::stream(&mut tracker, fields, tag, &mut buffer, &mut ()); + }); +} + +#[test] +fn random_udp_packets() { + // Initialize field IDs. + let _ = crate::field::get(); + + bolero::check!().for_each(|packet: &[u8]| { + let fields = crate::field::get(); + let mut tracker = Tracker::default(); + let mut buffer = unsafe { Buffer::new(ptr::null_mut(), packet) }; + let Some(tag) = buffer.consume() else { + return; + }; + // May fail to parse, but shouldn't panic. + let _ = dissect::udp_segment(&mut tracker, &mut (), fields, tag, &mut buffer, &mut ()); + }); +} + +#[test] +fn random_datagram_packets() { + // Initialize field IDs. + let _ = crate::field::get(); + + bolero::check!().for_each(|packet: &[u8]| { + let fields = crate::field::get(); + let mut tracker = Tracker::default(); + let mut buffer = unsafe { Buffer::new(ptr::null_mut(), packet) }; + let Some(tag) = buffer.consume() else { + return; + }; + // May fail to parse, but shouldn't panic. + let _ = dissect::datagram(&mut tracker, fields, tag, &mut buffer, &mut ()); + }); +} + +#[test] +fn random_control_packets() { + // Initialize field IDs. + let _ = crate::field::get(); + + bolero::check!().for_each(|packet: &[u8]| { + let fields = crate::field::get(); + let mut tracker = Tracker::default(); + let mut buffer = unsafe { Buffer::new(ptr::null_mut(), packet) }; + let Some(tag) = buffer.consume() else { + return; + }; + // May fail to parse, but shouldn't panic. + let _ = dissect::control(&mut tracker, fields, tag, &mut buffer, &mut ()); + }); +} + +#[derive(Default, Clone)] +struct Tracker { + seen_fields: std::rc::Rc>>, +} + +impl Tracker { + fn put(&mut self, id: i32, field: Field) { + assert!(self.seen_fields.borrow_mut().insert(id, field).is_none()); + } + + #[track_caller] + fn remove(&mut self, id: i32) -> Field { + self.seen_fields.borrow_mut().remove(&id).unwrap() + } + + fn take(&mut self, id: i32) -> Option { + self.seen_fields.borrow_mut().remove(&id) + } +} + +#[derive(Debug, PartialEq, Eq)] +enum Field { + Integer(u64), + Slice(Vec), + Duration(Duration), +} + +impl Field { + #[track_caller] + fn slice_len(&self) -> usize { + match self { + Field::Slice(s) => s.len(), + Field::Integer(_) => panic!("expecting slice found integer"), + Field::Duration(_) => panic!("expecting slice found duration"), + } + } +} + +impl crate::wireshark::Node for Tracker { + type AddedItem = (); + + fn add_slice( + &mut self, + _buffer: &Buffer, + field: i32, + parsed: Parsed<&[u8]>, + ) -> Self::AddedItem { + self.put(field, Field::Slice(parsed.value.to_vec())); + } + + fn add_slice_hidden( + &mut self, + _buffer: &Buffer, + field: i32, + parsed: Parsed<&[u8]>, + ) -> Self::AddedItem { + self.put(field, Field::Slice(parsed.value.to_vec())); + } + + fn add_u64(&mut self, _buffer: &Buffer, field: i32, parsed: Parsed) -> Self::AddedItem { + self.put(field, Field::Integer(parsed.value)); + } + + fn add_u32(&mut self, _buffer: &Buffer, field: i32, parsed: Parsed) -> Self::AddedItem { + self.put(field, Field::Integer(parsed.value as u64)); + } + + fn add_u16(&mut self, _buffer: &Buffer, field: i32, parsed: Parsed) -> Self::AddedItem { + self.put(field, Field::Integer(parsed.value as u64)); + } + + fn add_u8(&mut self, _buffer: &Buffer, field: i32, parsed: Parsed) -> Self::AddedItem { + self.put(field, Field::Integer(parsed.value as u64)); + } + + fn add_boolean>( + &mut self, + _buffer: &Buffer, + field: i32, + parsed: Parsed, + ) -> Self::AddedItem { + self.put(field, Field::Integer(parsed.value.into() as u64)); + } + + fn add_duration( + &mut self, + _buffer: &Buffer, + field: i32, + parsed: Parsed, + ) -> Self::AddedItem { + self.put(field, Field::Duration(parsed.value)); + } + + fn add_subtree(&mut self, _: Self::AddedItem, _: i32) -> Self { + self.clone() + } +} + +impl crate::wireshark::Item for () { + fn append_text(&mut self, _: &'static std::ffi::CStr) { + // no-op + } +} diff --git a/dc/wireshark/src/value.rs b/dc/wireshark/src/value.rs new file mode 100644 index 0000000000..b0e8dd0fe2 --- /dev/null +++ b/dc/wireshark/src/value.rs @@ -0,0 +1,98 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use crate::{buffer::Buffer, wireshark::Node}; +use s2n_quic_core::varint::VarInt; +use s2n_quic_dc::packet; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct Parsed { + // offset and length inside `tvb` + pub offset: usize, + pub len: usize, + pub value: T, +} + +impl Parsed { + pub fn map(self, map: impl FnOnce(T) -> U) -> Parsed { + let value = map(self.value); + Parsed { + offset: self.offset, + len: self.len, + value, + } + } + + pub fn with(self, value: U) -> Parsed { + self.map(|_| value) + } +} + +impl Parsed { + pub fn record(&self, buffer: &Buffer, tree: &mut T, field: i32) -> T::AddedItem { + tree.add_u8(buffer, field, self.map(|v| v.into())) + } +} + +impl Parsed { + pub fn record(&self, buffer: &Buffer, tree: &mut T, field: i32) -> T::AddedItem { + tree.add_u8(buffer, field, self.map(|v| v.into())) + } +} + +impl Parsed { + pub fn record(&self, buffer: &Buffer, tree: &mut T, field: i32) -> T::AddedItem { + tree.add_u8(buffer, field, self.map(|v| v.into())) + } +} + +impl Parsed { + pub fn record(&self, buffer: &Buffer, tree: &mut T, field: i32) -> T::AddedItem { + tree.add_u8(buffer, field, self.map(|v| v.into())) + } +} + +impl Parsed { + pub fn record(&self, buffer: &Buffer, tree: &mut T, field: i32) -> T::AddedItem { + tree.add_u64(buffer, field, *self) + } +} + +impl Parsed { + pub fn record(&self, buffer: &Buffer, tree: &mut T, field: i32) -> T::AddedItem { + tree.add_u64(buffer, field, self.map(|v| v.as_u64())) + } +} + +impl Parsed { + pub fn record(&self, buffer: &Buffer, tree: &mut T, field: i32) -> T::AddedItem { + tree.add_u32(buffer, field, *self) + } +} + +impl Parsed { + pub fn record(&self, buffer: &Buffer, tree: &mut T, field: i32) -> T::AddedItem { + tree.add_u16(buffer, field, *self) + } +} + +impl Parsed { + pub fn record(&self, buffer: &Buffer, tree: &mut T, field: i32) -> T::AddedItem { + tree.add_duration(buffer, field, *self) + } +} + +impl Parsed<&'_ [u8]> { + pub fn record(&self, buffer: &Buffer, tree: &mut T, field: i32) -> T::AddedItem { + tree.add_slice(buffer, field, *self) + } + + pub fn record_hidden( + &self, + buffer: &Buffer, + tree: &mut T, + field: i32, + ) -> T::AddedItem { + tree.add_slice_hidden(buffer, field, *self) + } +} diff --git a/dc/wireshark/src/wireshark.rs b/dc/wireshark/src/wireshark.rs new file mode 100644 index 0000000000..30a473c8f7 --- /dev/null +++ b/dc/wireshark/src/wireshark.rs @@ -0,0 +1,259 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use crate::{buffer::Buffer, value::Parsed}; +use std::{ffi::CStr, time::Duration}; + +pub(crate) trait Info { + fn is_empty(&self) -> bool; + fn append(&mut self, v: T); + fn append_str(&mut self, v: &str); + fn append_delim(&mut self, v: &str) { + if !self.is_empty() { + self.append_str(v); + } + } +} + +impl Info for () { + fn is_empty(&self) -> bool { + true + } + + fn append(&mut self, v: T) { + let _ = v; + } + + fn append_str(&mut self, v: &str) { + let _ = v; + } +} + +impl Info for Vec { + fn is_empty(&self) -> bool { + (*self).is_empty() + } + + fn append(&mut self, v: T) { + use std::io::Write; + let _ = write!(self, "{}", v); + } + + fn append_str(&mut self, v: &str) { + self.extend_from_slice(v.as_bytes()); + } +} + +impl Info for String { + fn is_empty(&self) -> bool { + (*self).is_empty() + } + + fn append(&mut self, v: T) { + use std::fmt::Write; + let _ = write!(self, "{}", v); + } + + fn append_str(&mut self, v: &str) { + *self += v; + } +} + +pub(crate) trait Item { + fn append_text(&mut self, text: &'static CStr); +} + +pub(crate) trait Node { + type AddedItem: Item; + fn add_slice(&mut self, buffer: &Buffer, field: i32, parsed: Parsed<&[u8]>) -> Self::AddedItem; + fn add_slice_hidden( + &mut self, + buffer: &Buffer, + field: i32, + parsed: Parsed<&[u8]>, + ) -> Self::AddedItem; + fn add_u64(&mut self, buffer: &Buffer, field: i32, parsed: Parsed) -> Self::AddedItem; + fn add_u32(&mut self, buffer: &Buffer, field: i32, parsed: Parsed) -> Self::AddedItem; + fn add_u16(&mut self, buffer: &Buffer, field: i32, parsed: Parsed) -> Self::AddedItem; + fn add_u8(&mut self, buffer: &Buffer, field: i32, parsed: Parsed) -> Self::AddedItem; + // This takes a `u8` because it's typically used with a bitmask pointing at a specific bit. + fn add_boolean>( + &mut self, + buffer: &Buffer, + field: i32, + parsed: Parsed, + ) -> Self::AddedItem; + fn add_duration( + &mut self, + buffer: &Buffer, + field: i32, + parsed: Parsed, + ) -> Self::AddedItem; + + fn add_subtree(&mut self, item: Self::AddedItem, id: i32) -> Self; +} + +#[cfg(not(test))] +mod wireshark_sys_impl { + use super::*; + use crate::wireshark_sys; + + impl Item for *mut wireshark_sys::proto_item { + fn append_text(&mut self, text: &'static CStr) { + unsafe { + wireshark_sys::proto_item_append_text(*self, c"%s".as_ptr(), text.as_ptr()); + } + } + } + + impl Item for *mut wireshark_sys::_packet_info { + fn append_text(&mut self, text: &CStr) { + unsafe { + wireshark_sys::col_append_str( + (**self).cinfo, + wireshark_sys::COL_INFO as _, + text.as_ptr(), + ); + } + } + } + + impl Node for *mut wireshark_sys::_proto_node { + type AddedItem = *mut wireshark_sys::proto_item; + + fn add_u64(&mut self, buffer: &Buffer, field: i32, parsed: Parsed) -> Self::AddedItem { + unsafe { + wireshark_sys::proto_tree_add_uint64( + *self, + field, + buffer.tvb, + parsed.offset as _, + parsed.len as _, + parsed.value, + ) + } + } + + fn add_u32(&mut self, buffer: &Buffer, field: i32, parsed: Parsed) -> Self::AddedItem { + unsafe { + wireshark_sys::proto_tree_add_uint( + *self, + field, + buffer.tvb, + parsed.offset as _, + parsed.len as _, + parsed.value, + ) + } + } + + fn add_u16(&mut self, buffer: &Buffer, field: i32, parsed: Parsed) -> Self::AddedItem { + unsafe { + wireshark_sys::proto_tree_add_uint( + *self, + field, + buffer.tvb, + parsed.offset as _, + parsed.len as _, + parsed.value as u32, + ) + } + } + + fn add_u8(&mut self, buffer: &Buffer, field: i32, parsed: Parsed) -> Self::AddedItem { + unsafe { + wireshark_sys::proto_tree_add_uint( + *self, + field, + buffer.tvb, + parsed.offset as _, + parsed.len as _, + parsed.value as u32, + ) + } + } + + fn add_boolean>( + &mut self, + buffer: &Buffer, + field: i32, + parsed: Parsed, + ) -> Self::AddedItem { + unsafe { + wireshark_sys::proto_tree_add_boolean( + *self, + field, + buffer.tvb, + parsed.offset as _, + parsed.len as _, + parsed.value.into() as u32, + ) + } + } + + fn add_slice( + &mut self, + buffer: &Buffer, + field: i32, + parsed: Parsed<&[u8]>, + ) -> Self::AddedItem { + unsafe { + wireshark_sys::proto_tree_add_bytes_with_length( + *self, + field, + buffer.tvb, + parsed.offset as _, + parsed.len as _, + parsed.value.as_ptr(), + parsed.value.len() as _, + ) + } + } + + fn add_slice_hidden( + &mut self, + buffer: &Buffer, + field: i32, + parsed: Parsed<&[u8]>, + ) -> Self::AddedItem { + let fmt = format!("({} bytes)\0", parsed.len); + unsafe { + wireshark_sys::proto_tree_add_bytes_format_value( + *self, + field, + buffer.tvb, + parsed.offset as _, + parsed.len as _, + parsed.value.as_ptr(), + fmt.as_ptr() as *const _, + ) + } + } + + fn add_duration( + &mut self, + buffer: &Buffer, + field: i32, + parsed: Parsed, + ) -> Self::AddedItem { + let time = wireshark_sys::nstime_t { + secs: parsed.value.as_secs() as i64, + nsecs: parsed.value.subsec_nanos() as i32, + }; + unsafe { + wireshark_sys::proto_tree_add_time( + *self, + field, + buffer.tvb, + parsed.offset as _, + parsed.len as _, + &time, + ) + } + } + + fn add_subtree(&mut self, item: Self::AddedItem, id: i32) -> Self { + unsafe { wireshark_sys::proto_item_add_subtree(item, id) } + } + } +} diff --git a/dc/wireshark/src/wireshark_sys/full.rs b/dc/wireshark/src/wireshark_sys/full.rs new file mode 100644 index 0000000000..74dc1a6328 --- /dev/null +++ b/dc/wireshark/src/wireshark_sys/full.rs @@ -0,0 +1,3910 @@ +/* automatically generated by rust-bindgen 0.69.4 */ + +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct __BindgenBitfieldUnit { + storage: Storage, +} +impl __BindgenBitfieldUnit { + #[inline] + pub const fn new(storage: Storage) -> Self { + Self { storage } + } +} +impl __BindgenBitfieldUnit +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + #[inline] + pub fn get_bit(&self, index: usize) -> bool { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = self.storage.as_ref()[byte_index]; + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + byte & mask == mask + } + #[inline] + pub fn set_bit(&mut self, index: usize, val: bool) { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = &mut self.storage.as_mut()[byte_index]; + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + if val { + *byte |= mask; + } else { + *byte &= !mask; + } + } + #[inline] + pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + let mut val = 0; + for i in 0..(bit_width as usize) { + if self.get_bit(i + bit_offset) { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + val + } + #[inline] + pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + for i in 0..(bit_width as usize) { + let mask = 1 << i; + let val_bit_is_set = val & mask == mask; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + self.set_bit(index + bit_offset, val_bit_is_set); + } + } +} +pub const DESEGMENT_ONE_MORE_SEGMENT: u32 = 268435455; +pub const DESEGMENT_UNTIL_FIN: u32 = 268435454; +pub const ENC_BIG_ENDIAN: u32 = 0; +pub type __time_t = ::std::os::raw::c_long; +pub type guint8 = ::std::os::raw::c_uchar; +pub type gint16 = ::std::os::raw::c_short; +pub type guint16 = ::std::os::raw::c_ushort; +pub type gint32 = ::std::os::raw::c_int; +pub type guint32 = ::std::os::raw::c_uint; +pub type gint64 = ::std::os::raw::c_long; +pub type guint64 = ::std::os::raw::c_ulong; +pub type time_t = __time_t; +pub type gchar = ::std::os::raw::c_char; +pub type gint = ::std::os::raw::c_int; +pub type gboolean = gint; +pub type guint = ::std::os::raw::c_uint; +pub type gfloat = f32; +pub type gdouble = f64; +pub type gpointer = *mut ::std::os::raw::c_void; +pub type GByteArray = _GByteArray; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _GByteArray { + pub data: *mut guint8, + pub len: guint, +} +#[test] +fn bindgen_test_layout__GByteArray() { + const UNINIT: ::std::mem::MaybeUninit<_GByteArray> = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<_GByteArray>(), + 16usize, + concat!("Size of: ", stringify!(_GByteArray)) + ); + assert_eq!( + ::std::mem::align_of::<_GByteArray>(), + 8usize, + concat!("Alignment of ", stringify!(_GByteArray)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_GByteArray), + "::", + stringify!(data) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_GByteArray), + "::", + stringify!(len) + ) + ); +} +pub type va_list = __builtin_va_list; +pub type GHashTable = u8; +pub type GSList = [u64; 2usize]; +#[doc = " @defgroup wmem Wireshark Memory Manager\n\n Wmem is a memory management framework for Wireshark that makes it simple to\n write dissectors (and other 'user-space' code) that doesn't leak memory. The\n core module provides basic functions like malloc, realloc and free, but\n many other functions are available (see the \"Modules\" list at the top of\n the generated doxygen HTML).\n\n Any wmem functions which allocate memory are guaranteed to either succeed or\n abort the program. However, they *can* still legally return NULL when the\n amount of requested memory is zero.\n\n @{"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _wmem_allocator_t { + _unused: [u8; 0], +} +#[doc = " A public opaque type representing one wmem allocation pool."] +pub type wmem_allocator_t = _wmem_allocator_t; +#[doc = " @addtogroup wmem\n @{\n @defgroup wmem-list Doubly-Linked List\n\n A doubly-linked list implementation on top of wmem.\n\n @{"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _wmem_list_t { + _unused: [u8; 0], +} +pub type wmem_list_t = _wmem_list_t; +#[doc = " @addtogroup wmem\n @{\n @defgroup wmem-map Hash Map\n\n A hash map implementation on top of wmem. Provides insertion, deletion and\n lookup in expected amortized constant time. Uses universal hashing to map\n keys into buckets, and provides a generic strong hash function that makes\n it secure against algorithmic complexity attacks, and suitable for use\n even with untrusted data.\n\n @{"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _wmem_map_t { + _unused: [u8; 0], +} +pub type wmem_map_t = _wmem_map_t; +#[doc = " @addtogroup wmem\n @{\n @defgroup wmem-tree Red/Black Tree\n\n Binary trees are a well-known and popular device in computer science to\n handle storage of objects based on a search key or identity. The\n particular binary tree style implemented here is the red/black tree, which\n has the nice property of being self-balancing. This guarantees O(log(n))\n time for lookups, compared to linked lists that are O(n). This means\n red/black trees scale very well when many objects are being stored.\n\n @{"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _wmem_tree_t { + _unused: [u8; 0], +} +pub type wmem_tree_t = _wmem_tree_t; +#[doc = " data structure to hold time values with nanosecond resolution"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nstime_t { + pub secs: time_t, + pub nsecs: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_nstime_t() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(nstime_t)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(nstime_t)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).secs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(nstime_t), + "::", + stringify!(secs) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).nsecs) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(nstime_t), + "::", + stringify!(nsecs) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct wtap_rec { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct epan_session { + _unused: [u8; 0], +} +pub type frame_data = [u64; 13usize]; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _e_guid_t { + pub data1: guint32, + pub data2: guint16, + pub data3: guint16, + pub data4: [guint8; 8usize], +} +#[test] +fn bindgen_test_layout__e_guid_t() { + const UNINIT: ::std::mem::MaybeUninit<_e_guid_t> = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<_e_guid_t>(), + 16usize, + concat!("Size of: ", stringify!(_e_guid_t)) + ); + assert_eq!( + ::std::mem::align_of::<_e_guid_t>(), + 4usize, + concat!("Alignment of ", stringify!(_e_guid_t)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data1) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_e_guid_t), + "::", + stringify!(data1) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data2) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_e_guid_t), + "::", + stringify!(data2) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data3) as usize - ptr as usize }, + 6usize, + concat!( + "Offset of field: ", + stringify!(_e_guid_t), + "::", + stringify!(data3) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data4) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_e_guid_t), + "::", + stringify!(data4) + ) + ); +} +pub type e_guid_t = _e_guid_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct e_in6_addr { + pub bytes: [u8; 16usize], +} +#[test] +fn bindgen_test_layout_e_in6_addr() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(e_in6_addr)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(e_in6_addr)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).bytes) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(e_in6_addr), + "::", + stringify!(bytes) + ) + ); +} +pub type ws_in6_addr = e_in6_addr; +#[doc = " \"testy, virtual(-izable) buffer\". They are testy in that they get mad when\n an attempt is made to access data beyond the bounds of their array. In that\n case, they throw an exception.\n\n They are virtualizable in that new tvbuff's can be made from other tvbuffs,\n while only the original tvbuff may have data. That is, the new tvbuff has\n virtual data."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct tvbuff { + _unused: [u8; 0], +} +pub type tvbuff_t = u8; +extern "C" { + pub fn tvb_reported_length(tvb: *const tvbuff_t) -> guint; +} +extern "C" { + #[doc = " Returns target for convenience. Does not suffer from possible\n expense of tvb_get_ptr(), since this routine is smart enough\n to copy data in chunks if the request range actually exists in\n different \"real\" tvbuffs. This function assumes that the target\n memory is already allocated; it does not allocate or free the\n target memory."] + pub fn tvb_memcpy( + tvb: *mut tvbuff_t, + target: *mut ::std::os::raw::c_void, + offset: gint, + length: usize, + ) -> *mut ::std::os::raw::c_void; +} +pub type address = [u64; 3usize]; +pub const port_type_PT_NONE: port_type = 0; +pub const port_type_PT_SCTP: port_type = 1; +pub const port_type_PT_TCP: port_type = 2; +pub const port_type_PT_UDP: port_type = 3; +pub const port_type_PT_DCCP: port_type = 4; +pub const port_type_PT_IPX: port_type = 5; +pub const port_type_PT_DDP: port_type = 6; +pub const port_type_PT_IDP: port_type = 7; +pub const port_type_PT_USB: port_type = 8; +pub const port_type_PT_I2C: port_type = 9; +pub const port_type_PT_IBQP: port_type = 10; +pub const port_type_PT_BLUETOOTH: port_type = 11; +pub const port_type_PT_IWARP_MPA: port_type = 12; +pub const port_type_PT_MCTP: port_type = 13; +pub type port_type = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _packet_info { + #[doc = "< name of protocol currently being dissected"] + pub current_proto: *const ::std::os::raw::c_char, + #[doc = "< Column formatting information"] + pub cinfo: *mut epan_column_info, + #[doc = "< Presence flags for some items"] + pub presence_flags: guint32, + #[doc = "< Frame number"] + pub num: guint32, + #[doc = "< Packet absolute time stamp"] + pub abs_ts: nstime_t, + #[doc = "< Relative timestamp (yes, it can be negative)"] + pub rel_ts: nstime_t, + #[doc = "< Relative timestamp from capture start (might be negative for broken files)"] + pub rel_cap_ts: nstime_t, + #[doc = "< Relative timestamp from capture start valid"] + pub rel_cap_ts_present: gboolean, + pub fd: *mut frame_data, + pub pseudo_header: *mut wtap_pseudo_header, + #[doc = "< Record metadata"] + pub rec: *mut wtap_rec, + #[doc = "< Frame data sources"] + pub data_src: *mut GSList, + #[doc = "< link-layer source address"] + pub dl_src: address, + #[doc = "< link-layer destination address"] + pub dl_dst: address, + #[doc = "< network-layer source address"] + pub net_src: address, + #[doc = "< network-layer destination address"] + pub net_dst: address, + #[doc = "< source address (net if present, DL otherwise )"] + pub src: address, + #[doc = "< destination address (net if present, DL otherwise )"] + pub dst: address, + #[doc = "< First encountered VLAN Id if present otherwise 0"] + pub vlan_id: guint32, + #[doc = "< reason why reassembly wasn't done, if any"] + pub noreassembly_reason: *const ::std::os::raw::c_char, + #[doc = "< TRUE if the protocol is only a fragment"] + pub fragmented: gboolean, + pub flags: _packet_info__bindgen_ty_1, + #[doc = "< type of the following two port numbers"] + pub ptype: port_type, + #[doc = "< source port"] + pub srcport: guint32, + #[doc = "< destination port"] + pub destport: guint32, + #[doc = "< matched uint for calling subdissector from table"] + pub match_uint: guint32, + #[doc = "< matched string for calling subdissector from table"] + pub match_string: *const ::std::os::raw::c_char, + #[doc = "< TRUE if address/port endpoints member should be used for conversations"] + pub use_conv_addr_port_endpoints: gboolean, + #[doc = "< Data that can be used for address+port conversations, including wildcarding"] + pub conv_addr_port_endpoints: *mut conversation_addr_port_endpoints, + #[doc = "< Arbritrary conversation identifier; can't be wildcarded"] + pub conv_elements: *mut conversation_element, + #[doc = "< >0 if this segment could be desegmented.\nA dissector that can offer this API (e.g.\nTCP) sets can_desegment=2, then\ncan_desegment is decremented by 1 each time\nwe pass to the next subdissector. Thus only\nthe dissector immediately above the\nprotocol which sets the flag can use it"] + pub can_desegment: guint16, + #[doc = "< Value of can_desegment before current\ndissector was called. Supplied so that\ndissectors for proxy protocols such as\nSOCKS can restore it, allowing the\ndissectors that they call to use the\nTCP dissector's desegmentation (SOCKS\njust retransmits TCP segments once it's\nfinished setting things up, so the TCP\ndesegmentor can desegment its payload)."] + pub saved_can_desegment: guint16, + #[doc = "< offset to stuff needing desegmentation"] + pub desegment_offset: ::std::os::raw::c_int, + #[doc = "< requested desegmentation additional length\nor\nDESEGMENT_ONE_MORE_SEGMENT:\nDesegment one more full segment\n(warning! only partially implemented)\nDESEGMENT_UNTIL_FIN:\nDesgment all data for this tcp session\nuntil the FIN segment."] + pub desegment_len: guint32, + #[doc = "< >0 if the subdissector has specified\na value in 'bytes_until_next_pdu'.\nWhen a dissector detects that the next PDU\nwill start beyond the start of the next\nsegment, it can set this value to 2\nand 'bytes_until_next_pdu' to the number of\nbytes beyond the next segment where the\nnext PDU starts.\n\nIf the protocol dissector below this\none is capable of PDU tracking it can\nuse this hint to detect PDUs that starts\nunaligned to the segment boundaries.\nThe TCP dissector is using this hint from\n(some) protocols to detect when a new PDU\nstarts in the middle of a tcp segment.\n\nThere is intelligence in the glue between\ndissector layers to make sure that this\nrequest is only passed down to the protocol\nimmediately below the current one and not\nany further."] + pub want_pdu_tracking: guint16, + pub bytes_until_next_pdu: guint32, + #[doc = "< Packet was captured as an\noutbound (P2P_DIR_SENT)\ninbound (P2P_DIR_RECV)\nunknown (P2P_DIR_UNKNOWN)"] + pub p2p_dir: ::std::os::raw::c_int, + #[doc = "< a hash table passed from one dissector to another"] + pub private_table: *mut GHashTable, + #[doc = "< layers of each protocol"] + pub layers: *mut wmem_list_t, + pub proto_layers: *mut wmem_map_t, + #[doc = "< The current \"depth\" or layer number in the current frame"] + pub curr_layer_num: guint8, + #[doc = "< The current \"depth\" or layer number for this dissector in the current frame"] + pub curr_proto_layer_num: guint8, + pub link_number: guint16, + #[doc = "< clnp/cotp source reference (can't use srcport, this would confuse tpkt)"] + pub clnp_srcref: guint16, + #[doc = "< clnp/cotp destination reference (can't use dstport, this would confuse tpkt)"] + pub clnp_dstref: guint16, + #[doc = "< 3GPP messages are sometime different UP link(UL) or Downlink(DL)"] + pub link_dir: ::std::os::raw::c_int, + #[doc = "< Rcv.Wind.Shift src applies when sending segments; -1 unknown; -2 disabled"] + pub src_win_scale: gint16, + #[doc = "< Rcv.Wind.Shift dst applies when sending segments; -1 unknown; -2 disabled"] + pub dst_win_scale: gint16, + #[doc = "< Per packet proto data"] + pub proto_data: *mut GSList, + pub frame_end_routines: *mut GSList, + #[doc = "< Memory pool scoped to the pinfo struct"] + pub pool: *mut wmem_allocator_t, + pub epan: *mut epan_session, + #[doc = "< name of heur list if this packet is being heuristically dissected"] + pub heur_list_name: *const gchar, + #[doc = "< The current \"depth\" or layer number in the current frame"] + pub dissection_depth: ::std::os::raw::c_int, +} +#[repr(C)] +#[repr(align(4))] +#[derive(Debug, Copy, Clone)] +pub struct _packet_info__bindgen_ty_1 { + pub _bitfield_align_1: [u8; 0], + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, + pub __bindgen_padding_0: [u8; 3usize], +} +#[test] +fn bindgen_test_layout__packet_info__bindgen_ty_1() { + assert_eq!( + ::std::mem::size_of::<_packet_info__bindgen_ty_1>(), + 4usize, + concat!("Size of: ", stringify!(_packet_info__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::<_packet_info__bindgen_ty_1>(), + 4usize, + concat!("Alignment of ", stringify!(_packet_info__bindgen_ty_1)) + ); +} +impl _packet_info__bindgen_ty_1 { + #[inline] + pub fn in_error_pkt(&self) -> guint32 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u32) } + } + #[inline] + pub fn set_in_error_pkt(&mut self, val: guint32) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 1u8, val as u64) + } + } + #[inline] + pub fn in_gre_pkt(&self) -> guint32 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(1usize, 1u8) as u32) } + } + #[inline] + pub fn set_in_gre_pkt(&mut self, val: guint32) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(1usize, 1u8, val as u64) + } + } + #[inline] + pub fn new_bitfield_1( + in_error_pkt: guint32, + in_gre_pkt: guint32, + ) -> __BindgenBitfieldUnit<[u8; 1usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = Default::default(); + __bindgen_bitfield_unit.set(0usize, 1u8, { + let in_error_pkt: u32 = unsafe { ::std::mem::transmute(in_error_pkt) }; + in_error_pkt as u64 + }); + __bindgen_bitfield_unit.set(1usize, 1u8, { + let in_gre_pkt: u32 = unsafe { ::std::mem::transmute(in_gre_pkt) }; + in_gre_pkt as u64 + }); + __bindgen_bitfield_unit + } +} +#[test] +fn bindgen_test_layout__packet_info() { + const UNINIT: ::std::mem::MaybeUninit<_packet_info> = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<_packet_info>(), + 440usize, + concat!("Size of: ", stringify!(_packet_info)) + ); + assert_eq!( + ::std::mem::align_of::<_packet_info>(), + 8usize, + concat!("Alignment of ", stringify!(_packet_info)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).current_proto) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(current_proto) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).cinfo) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(cinfo) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).presence_flags) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(presence_flags) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).num) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(num) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).abs_ts) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(abs_ts) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rel_ts) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(rel_ts) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rel_cap_ts) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(rel_cap_ts) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rel_cap_ts_present) as usize - ptr as usize }, + 72usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(rel_cap_ts_present) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, + 80usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(fd) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).pseudo_header) as usize - ptr as usize }, + 88usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(pseudo_header) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rec) as usize - ptr as usize }, + 96usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(rec) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data_src) as usize - ptr as usize }, + 104usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(data_src) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).dl_src) as usize - ptr as usize }, + 112usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(dl_src) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).dl_dst) as usize - ptr as usize }, + 136usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(dl_dst) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).net_src) as usize - ptr as usize }, + 160usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(net_src) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).net_dst) as usize - ptr as usize }, + 184usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(net_dst) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).src) as usize - ptr as usize }, + 208usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(src) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).dst) as usize - ptr as usize }, + 232usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(dst) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).vlan_id) as usize - ptr as usize }, + 256usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(vlan_id) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).noreassembly_reason) as usize - ptr as usize }, + 264usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(noreassembly_reason) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).fragmented) as usize - ptr as usize }, + 272usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(fragmented) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 276usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(flags) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).ptype) as usize - ptr as usize }, + 280usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(ptype) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).srcport) as usize - ptr as usize }, + 284usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(srcport) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).destport) as usize - ptr as usize }, + 288usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(destport) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).match_uint) as usize - ptr as usize }, + 292usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(match_uint) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).match_string) as usize - ptr as usize }, + 296usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(match_string) + ) + ); + assert_eq!( + unsafe { + ::std::ptr::addr_of!((*ptr).use_conv_addr_port_endpoints) as usize - ptr as usize + }, + 304usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(use_conv_addr_port_endpoints) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).conv_addr_port_endpoints) as usize - ptr as usize }, + 312usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(conv_addr_port_endpoints) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).conv_elements) as usize - ptr as usize }, + 320usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(conv_elements) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).can_desegment) as usize - ptr as usize }, + 328usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(can_desegment) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).saved_can_desegment) as usize - ptr as usize }, + 330usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(saved_can_desegment) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).desegment_offset) as usize - ptr as usize }, + 332usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(desegment_offset) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).desegment_len) as usize - ptr as usize }, + 336usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(desegment_len) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).want_pdu_tracking) as usize - ptr as usize }, + 340usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(want_pdu_tracking) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).bytes_until_next_pdu) as usize - ptr as usize }, + 344usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(bytes_until_next_pdu) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).p2p_dir) as usize - ptr as usize }, + 348usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(p2p_dir) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).private_table) as usize - ptr as usize }, + 352usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(private_table) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).layers) as usize - ptr as usize }, + 360usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(layers) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).proto_layers) as usize - ptr as usize }, + 368usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(proto_layers) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).curr_layer_num) as usize - ptr as usize }, + 376usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(curr_layer_num) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).curr_proto_layer_num) as usize - ptr as usize }, + 377usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(curr_proto_layer_num) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).link_number) as usize - ptr as usize }, + 378usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(link_number) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).clnp_srcref) as usize - ptr as usize }, + 380usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(clnp_srcref) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).clnp_dstref) as usize - ptr as usize }, + 382usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(clnp_dstref) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).link_dir) as usize - ptr as usize }, + 384usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(link_dir) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).src_win_scale) as usize - ptr as usize }, + 388usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(src_win_scale) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).dst_win_scale) as usize - ptr as usize }, + 390usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(dst_win_scale) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).proto_data) as usize - ptr as usize }, + 392usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(proto_data) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).frame_end_routines) as usize - ptr as usize }, + 400usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(frame_end_routines) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).pool) as usize - ptr as usize }, + 408usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(pool) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).epan) as usize - ptr as usize }, + 416usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(epan) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).heur_list_name) as usize - ptr as usize }, + 424usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(heur_list_name) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).dissection_depth) as usize - ptr as usize }, + 432usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(dissection_depth) + ) + ); +} +pub type packet_info = _packet_info; +pub type ws_in4_addr = u32; +pub const ftenum_FT_NONE: ftenum = 0; +pub const ftenum_FT_PROTOCOL: ftenum = 1; +pub const ftenum_FT_BOOLEAN: ftenum = 2; +pub const ftenum_FT_CHAR: ftenum = 3; +pub const ftenum_FT_UINT8: ftenum = 4; +pub const ftenum_FT_UINT16: ftenum = 5; +pub const ftenum_FT_UINT24: ftenum = 6; +pub const ftenum_FT_UINT32: ftenum = 7; +pub const ftenum_FT_UINT40: ftenum = 8; +pub const ftenum_FT_UINT48: ftenum = 9; +pub const ftenum_FT_UINT56: ftenum = 10; +pub const ftenum_FT_UINT64: ftenum = 11; +pub const ftenum_FT_INT8: ftenum = 12; +pub const ftenum_FT_INT16: ftenum = 13; +pub const ftenum_FT_INT24: ftenum = 14; +pub const ftenum_FT_INT32: ftenum = 15; +pub const ftenum_FT_INT40: ftenum = 16; +pub const ftenum_FT_INT48: ftenum = 17; +pub const ftenum_FT_INT56: ftenum = 18; +pub const ftenum_FT_INT64: ftenum = 19; +pub const ftenum_FT_IEEE_11073_SFLOAT: ftenum = 20; +pub const ftenum_FT_IEEE_11073_FLOAT: ftenum = 21; +pub const ftenum_FT_FLOAT: ftenum = 22; +pub const ftenum_FT_DOUBLE: ftenum = 23; +pub const ftenum_FT_ABSOLUTE_TIME: ftenum = 24; +pub const ftenum_FT_RELATIVE_TIME: ftenum = 25; +pub const ftenum_FT_STRING: ftenum = 26; +pub const ftenum_FT_STRINGZ: ftenum = 27; +pub const ftenum_FT_UINT_STRING: ftenum = 28; +pub const ftenum_FT_ETHER: ftenum = 29; +pub const ftenum_FT_BYTES: ftenum = 30; +pub const ftenum_FT_UINT_BYTES: ftenum = 31; +pub const ftenum_FT_IPv4: ftenum = 32; +pub const ftenum_FT_IPv6: ftenum = 33; +pub const ftenum_FT_IPXNET: ftenum = 34; +pub const ftenum_FT_FRAMENUM: ftenum = 35; +pub const ftenum_FT_GUID: ftenum = 36; +pub const ftenum_FT_OID: ftenum = 37; +pub const ftenum_FT_EUI64: ftenum = 38; +pub const ftenum_FT_AX25: ftenum = 39; +pub const ftenum_FT_VINES: ftenum = 40; +pub const ftenum_FT_REL_OID: ftenum = 41; +pub const ftenum_FT_SYSTEM_ID: ftenum = 42; +pub const ftenum_FT_STRINGZPAD: ftenum = 43; +pub const ftenum_FT_FCWWN: ftenum = 44; +pub const ftenum_FT_STRINGZTRUNC: ftenum = 45; +pub const ftenum_FT_NUM_TYPES: ftenum = 46; +pub type ftenum = ::std::os::raw::c_uint; +pub use self::ftenum as ftenum_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _fvalue_t { + _unused: [u8; 0], +} +pub type fvalue_t = _fvalue_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct expert_field { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _protocol { + _unused: [u8; 0], +} +#[doc = " Structure for information about a protocol"] +pub type protocol_t = _protocol; +#[doc = "< none"] +pub const field_display_e_BASE_NONE: field_display_e = 0; +#[doc = "< decimal [integer, float]"] +pub const field_display_e_BASE_DEC: field_display_e = 1; +#[doc = "< hexadecimal [integer, float]"] +pub const field_display_e_BASE_HEX: field_display_e = 2; +#[doc = "< octal [integer]"] +pub const field_display_e_BASE_OCT: field_display_e = 3; +#[doc = "< decimal (hexadecimal) [integer]"] +pub const field_display_e_BASE_DEC_HEX: field_display_e = 4; +#[doc = "< hexadecimal (decimal) [integer]"] +pub const field_display_e_BASE_HEX_DEC: field_display_e = 5; +#[doc = "< call custom routine to format [integer, float]"] +pub const field_display_e_BASE_CUSTOM: field_display_e = 6; +#[doc = "< exponential [float]"] +pub const field_display_e_BASE_EXP: field_display_e = 7; +#[doc = "< hexadecimal bytes with a period (.) between each byte"] +pub const field_display_e_SEP_DOT: field_display_e = 8; +#[doc = "< hexadecimal bytes with a dash (-) between each byte"] +pub const field_display_e_SEP_DASH: field_display_e = 9; +#[doc = "< hexadecimal bytes with a colon (:) between each byte"] +pub const field_display_e_SEP_COLON: field_display_e = 10; +#[doc = "< hexadecimal bytes with a space between each byte"] +pub const field_display_e_SEP_SPACE: field_display_e = 11; +#[doc = "< Used for IPv4 address that shouldn't be resolved (like for netmasks)"] +pub const field_display_e_BASE_NETMASK: field_display_e = 12; +#[doc = "< UDP port"] +pub const field_display_e_BASE_PT_UDP: field_display_e = 13; +#[doc = "< TCP port"] +pub const field_display_e_BASE_PT_TCP: field_display_e = 14; +#[doc = "< DCCP port"] +pub const field_display_e_BASE_PT_DCCP: field_display_e = 15; +#[doc = "< SCTP port"] +pub const field_display_e_BASE_PT_SCTP: field_display_e = 16; +#[doc = "< OUI resolution"] +pub const field_display_e_BASE_OUI: field_display_e = 17; +#[doc = "< local time in our time zone, with month and day"] +pub const field_display_e_ABSOLUTE_TIME_LOCAL: field_display_e = 18; +#[doc = "< UTC, with month and day"] +pub const field_display_e_ABSOLUTE_TIME_UTC: field_display_e = 19; +#[doc = "< UTC, with 1-origin day-of-year"] +pub const field_display_e_ABSOLUTE_TIME_DOY_UTC: field_display_e = 20; +#[doc = "< UTC, with \"NULL\" when timestamp is all zeros"] +pub const field_display_e_ABSOLUTE_TIME_NTP_UTC: field_display_e = 21; +#[doc = "< Unix time"] +pub const field_display_e_ABSOLUTE_TIME_UNIX: field_display_e = 22; +#[doc = "< Replace all whitespace characters (newline, formfeed, etc) with \"space\"."] +pub const field_display_e_BASE_STR_WSP: field_display_e = 23; +pub type field_display_e = ::std::os::raw::c_uint; +#[doc = "< Field is not referenced"] +pub const hf_ref_type_HF_REF_TYPE_NONE: hf_ref_type = 0; +#[doc = "< Field is indirectly referenced (only applicable for FT_PROTOCOL) via. its child"] +pub const hf_ref_type_HF_REF_TYPE_INDIRECT: hf_ref_type = 1; +#[doc = "< Field is directly referenced"] +pub const hf_ref_type_HF_REF_TYPE_DIRECT: hf_ref_type = 2; +pub type hf_ref_type = ::std::os::raw::c_uint; +#[doc = " information describing a header field"] +pub type header_field_info = _header_field_info; +#[doc = " information describing a header field"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _header_field_info { + #[doc = "< [FIELDNAME] full name of this field"] + pub name: *const ::std::os::raw::c_char, + #[doc = "< [FIELDFILTERNAME] filter name of this field"] + pub abbrev: *const ::std::os::raw::c_char, + #[doc = "< [FIELDTYPE] field type, one of FT_ (from ftypes.h)"] + pub type_: ftenum, + #[doc = "< [FIELDDISPLAY] one of BASE_, or field bit-width if FT_BOOLEAN and non-zero bitmask"] + pub display: ::std::os::raw::c_int, + #[doc = "< [FIELDCONVERT] value_string, val64_string, range_string or true_false_string,\ntypically converted by VALS(), RVALS() or TFS().\nIf this is an FT_PROTOCOL or BASE_PROTOCOL_INFO then it points to the\nassociated protocol_t structure"] + pub strings: *const ::std::os::raw::c_void, + #[doc = "< [BITMASK] bitmask of interesting bits"] + pub bitmask: guint64, + #[doc = "< [FIELDDESCR] Brief description of field"] + pub blurb: *const ::std::os::raw::c_char, + #[doc = "< Field ID"] + pub id: ::std::os::raw::c_int, + #[doc = "< parent protocol tree"] + pub parent: ::std::os::raw::c_int, + #[doc = "< is this field referenced by a filter"] + pub ref_type: hf_ref_type, + #[doc = "< ID of previous hfinfo with same abbrev"] + pub same_name_prev_id: ::std::os::raw::c_int, + #[doc = "< Link to next hfinfo with same abbrev"] + pub same_name_next: *mut header_field_info, +} +#[test] +fn bindgen_test_layout__header_field_info() { + const UNINIT: ::std::mem::MaybeUninit<_header_field_info> = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<_header_field_info>(), + 72usize, + concat!("Size of: ", stringify!(_header_field_info)) + ); + assert_eq!( + ::std::mem::align_of::<_header_field_info>(), + 8usize, + concat!("Alignment of ", stringify!(_header_field_info)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).name) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(name) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).abbrev) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(abbrev) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(type_) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).display) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(display) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).strings) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(strings) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).bitmask) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(bitmask) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).blurb) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(blurb) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).id) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(id) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).parent) as usize - ptr as usize }, + 52usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(parent) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).ref_type) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(ref_type) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).same_name_prev_id) as usize - ptr as usize }, + 60usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(same_name_prev_id) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).same_name_next) as usize - ptr as usize }, + 64usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(same_name_next) + ) + ); +} +#[doc = " Used when registering many fields at once, using proto_register_field_array()"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct hf_register_info { + #[doc = "< written to by register() function"] + pub p_id: *mut ::std::os::raw::c_int, + #[doc = "< the field info to be registered"] + pub hfinfo: header_field_info, +} +#[test] +fn bindgen_test_layout_hf_register_info() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 80usize, + concat!("Size of: ", stringify!(hf_register_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(hf_register_info)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).p_id) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(hf_register_info), + "::", + stringify!(p_id) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).hfinfo) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(hf_register_info), + "::", + stringify!(hfinfo) + ) + ); +} +#[doc = " string representation, if one of the proto_tree_add_..._format() functions used"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _item_label_t { + pub representation: [::std::os::raw::c_char; 240usize], +} +#[test] +fn bindgen_test_layout__item_label_t() { + const UNINIT: ::std::mem::MaybeUninit<_item_label_t> = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<_item_label_t>(), + 240usize, + concat!("Size of: ", stringify!(_item_label_t)) + ); + assert_eq!( + ::std::mem::align_of::<_item_label_t>(), + 1usize, + concat!("Alignment of ", stringify!(_item_label_t)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).representation) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_item_label_t), + "::", + stringify!(representation) + ) + ); +} +#[doc = " string representation, if one of the proto_tree_add_..._format() functions used"] +pub type item_label_t = _item_label_t; +#[doc = " Contains the field information for the proto_item."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct field_info { + #[doc = "< pointer to registered field information"] + pub hfinfo: *mut header_field_info, + #[doc = "< current start of data in field_info.ds_tvb"] + pub start: gint, + #[doc = "< current data length of item in field_info.ds_tvb"] + pub length: gint, + #[doc = "< start of appendix data"] + pub appendix_start: gint, + #[doc = "< length of appendix data"] + pub appendix_length: gint, + #[doc = "< one of ETT_ or -1"] + pub tree_type: gint, + #[doc = "< bitfield like FI_GENERATED, ..."] + pub flags: guint32, + #[doc = "< string for GUI tree"] + pub rep: *mut item_label_t, + #[doc = "< data source tvbuff"] + pub ds_tvb: *mut tvbuff_t, + pub value: *mut fvalue_t, + #[doc = "< Hierarchical layer number, for all protocols in the tree."] + pub total_layer_num: ::std::os::raw::c_int, + #[doc = "< Protocol layer number, so 1st, 2nd, 3rd, ... for protocol X."] + pub proto_layer_num: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_field_info() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 64usize, + concat!("Size of: ", stringify!(field_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(field_info)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).hfinfo) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(field_info), + "::", + stringify!(hfinfo) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).start) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(field_info), + "::", + stringify!(start) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).length) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(field_info), + "::", + stringify!(length) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).appendix_start) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(field_info), + "::", + stringify!(appendix_start) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).appendix_length) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(field_info), + "::", + stringify!(appendix_length) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).tree_type) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(field_info), + "::", + stringify!(tree_type) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(field_info), + "::", + stringify!(flags) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rep) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(field_info), + "::", + stringify!(rep) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).ds_tvb) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(field_info), + "::", + stringify!(ds_tvb) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).value) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(field_info), + "::", + stringify!(value) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).total_layer_num) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(field_info), + "::", + stringify!(total_layer_num) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).proto_layer_num) as usize - ptr as usize }, + 60usize, + concat!( + "Offset of field: ", + stringify!(field_info), + "::", + stringify!(proto_layer_num) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct crumb_spec_t { + pub crumb_bit_offset: guint, + pub crumb_bit_length: guint8, +} +#[test] +fn bindgen_test_layout_crumb_spec_t() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(crumb_spec_t)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(crumb_spec_t)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).crumb_bit_offset) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(crumb_spec_t), + "::", + stringify!(crumb_bit_offset) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).crumb_bit_length) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(crumb_spec_t), + "::", + stringify!(crumb_bit_length) + ) + ); +} +#[doc = " Each proto_tree, proto_item is one of these."] +#[repr(C)] +#[repr(align(8))] +#[derive(Debug, Copy, Clone)] +pub struct _proto_node { + pub _bindgen_opaque_blob: [u64; 6usize], +} +#[test] +fn bindgen_test_layout__proto_node() { + assert_eq!( + ::std::mem::size_of::<_proto_node>(), + 48usize, + concat!("Size of: ", stringify!(_proto_node)) + ); + assert_eq!( + ::std::mem::align_of::<_proto_node>(), + 8usize, + concat!("Alignment of ", stringify!(_proto_node)) + ); +} +#[doc = " Each proto_tree, proto_item is one of these."] +pub type proto_node = _proto_node; +#[doc = " A protocol tree element."] +pub type proto_tree = proto_node; +#[doc = " A protocol item element."] +pub type proto_item = proto_node; +pub type proto_tree_foreach_func = + ::std::option::Option; +extern "C" { + pub fn proto_tree_children_foreach( + tree: *mut proto_tree, + func: proto_tree_foreach_func, + data: gpointer, + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct proto_plugin { + pub register_protoinfo: ::std::option::Option, + pub register_handoff: ::std::option::Option, +} +#[test] +fn bindgen_test_layout_proto_plugin() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(proto_plugin)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(proto_plugin)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).register_protoinfo) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(proto_plugin), + "::", + stringify!(register_protoinfo) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).register_handoff) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(proto_plugin), + "::", + stringify!(register_handoff) + ) + ); +} +extern "C" { + #[doc = " Register dissector plugin with the plugin system."] + pub fn proto_register_plugin(plugin: *const proto_plugin); +} +extern "C" { + #[doc = " Create a subtree under an existing item.\n@param pi the parent item of the new subtree\n@param idx one of the ett_ array elements registered with proto_register_subtree_array()\n@return the new subtree"] + pub fn proto_item_add_subtree(pi: *mut proto_item, idx: gint) -> *mut proto_tree; +} +extern "C" { + #[doc = " Get an existing subtree under an item.\n@param pi the parent item of the subtree\n@return the subtree or NULL"] + pub fn proto_item_get_subtree(pi: *mut proto_item) -> *mut proto_tree; +} +extern "C" { + #[doc = " Get the parent of a subtree item.\n@param pi the child item in the subtree\n@return parent item or NULL"] + pub fn proto_item_get_parent(pi: *const proto_item) -> *mut proto_item; +} +extern "C" { + #[doc = " Get Nth generation parent item.\n@param pi the child item in the subtree\n@param gen the generation to get (using 1 here is the same as using proto_item_get_parent())\n@return parent item"] + pub fn proto_item_get_parent_nth( + pi: *mut proto_item, + gen: ::std::os::raw::c_int, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Replace text of item after it already has been created.\n@param pi the item to set the text\n@param format printf like format string\n@param ... printf like parameters"] + pub fn proto_item_set_text(pi: *mut proto_item, format: *const ::std::os::raw::c_char, ...); +} +extern "C" { + #[doc = " Append to text of item after it has already been created.\n@param pi the item to append the text to\n@param format printf like format string\n@param ... printf like parameters"] + pub fn proto_item_append_text(pi: *mut proto_item, format: *const ::std::os::raw::c_char, ...); +} +extern "C" { + #[doc = " Prepend to text of item after it has already been created.\n@param pi the item to prepend the text to\n@param format printf like format string\n@param ... printf like parameters"] + pub fn proto_item_prepend_text(pi: *mut proto_item, format: *const ::std::os::raw::c_char, ...); +} +extern "C" { + #[doc = " Set proto_item's length inside tvb, after it has already been created.\n@param pi the item to set the length\n@param length the new length of the item"] + pub fn proto_item_set_len(pi: *mut proto_item, length: gint); +} +extern "C" { + #[doc = " Sets the length of the item based on its start and on the specified\n offset, which is the offset past the end of the item; as the start\n in the item is relative to the beginning of the data source tvbuff,\n we need to pass in a tvbuff.\n\n Given an item created as:\n ti = proto_tree_add_item(*, *, tvb, offset, -1, *);\n then\n proto_item_set_end(ti, tvb, end);\n is equivalent to\n proto_item_set_len(ti, end - offset);\n\n@param pi the item to set the length\n@param tvb end is relative to this tvbuff\n@param end this end offset is relative to the beginning of tvb\n@todo make usage clearer, I don't understand it!"] + pub fn proto_item_set_end(pi: *mut proto_item, tvb: *mut tvbuff_t, end: gint); +} +extern "C" { + #[doc = " Get length of a proto_item. Useful after using proto_tree_add_item()\n to add a variable-length field (e.g., FT_UINT_STRING).\n@param pi the item to get the length from\n@return the current length"] + pub fn proto_item_get_len(pi: *const proto_item) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Set the bit offset and length for the specified proto_item.\n @param ti The item to set.\n @param bits_offset The number of bits from the beginning of the field.\n @param bits_len The new length in bits."] + pub fn proto_item_set_bits_offset_len( + ti: *mut proto_item, + bits_offset: ::std::os::raw::c_int, + bits_len: ::std::os::raw::c_int, + ); +} +extern "C" { + #[doc = " Get the display representation of a proto_item.\n Can be used, for example, to append that to the parent item of\n that item.\n@param scope the wmem scope to use to allocate the string\n@param pi the item from which to get the display representation\n@return the display representation"] + pub fn proto_item_get_display_repr( + scope: *mut wmem_allocator_t, + pi: *mut proto_item, + ) -> *mut ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Creates a new proto_tree root.\n@return the new tree root"] + pub fn proto_tree_create_root(pinfo: *mut _packet_info) -> *mut proto_tree; +} +extern "C" { + pub fn proto_tree_reset(tree: *mut proto_tree); +} +extern "C" { + #[doc = " Clear memory for entry proto_tree. Clears proto_tree struct also.\n@param tree the tree to free"] + pub fn proto_tree_free(tree: *mut proto_tree); +} +extern "C" { + #[doc = " Set the tree visible or invisible.\nIs the parsing being done for a visible proto_tree or an invisible one?\nBy setting this correctly, the proto_tree creation is sped up by not\nhaving to call vsnprintf and copy strings around.\n@param tree the tree to be set\n@param visible ... or not\n@return the old value"] + pub fn proto_tree_set_visible(tree: *mut proto_tree, visible: gboolean) -> gboolean; +} +extern "C" { + #[doc = " Indicate whether we should fake protocols during dissection (default = TRUE)\n@param tree the tree to be set\n@param fake_protocols TRUE if we should fake protocols"] + pub fn proto_tree_set_fake_protocols(tree: *mut proto_tree, fake_protocols: gboolean); +} +extern "C" { + #[doc = " Mark a field/protocol ID as \"interesting\".\n@param tree the tree to be set (currently ignored)\n@param hfid the interesting field id\n@todo what *does* interesting mean?"] + pub fn proto_tree_prime_with_hfid(tree: *mut proto_tree, hfid: ::std::os::raw::c_int); +} +extern "C" { + #[doc = " Get a parent item of a subtree.\n@param tree the tree to get the parent from\n@return parent item"] + pub fn proto_tree_get_parent(tree: *mut proto_tree) -> *mut proto_item; +} +extern "C" { + #[doc = " Get the parent tree of a subtree.\n@param tree the tree to get the parent from\n@return parent tree"] + pub fn proto_tree_get_parent_tree(tree: *mut proto_tree) -> *mut proto_tree; +} +extern "C" { + #[doc = " Get the root tree from any subtree.\n@param tree the tree to get the root from\n@return root tree"] + pub fn proto_tree_get_root(tree: *mut proto_tree) -> *mut proto_tree; +} +extern "C" { + #[doc = " Move an existing item behind another existing item.\n@param tree the tree to which both items belong\n@param fixed_item the item which keeps its position\n@param item_to_move the item which will be moved"] + pub fn proto_tree_move_item( + tree: *mut proto_tree, + fixed_item: *mut proto_item, + item_to_move: *mut proto_item, + ); +} +extern "C" { + #[doc = " Set start and length of an appendix for a proto_tree.\n@param tree the tree to set the appendix start and length\n@param tvb the tv buffer of the current data\n@param start the start offset of the appendix\n@param length the length of the appendix"] + pub fn proto_tree_set_appendix( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + ); +} +extern "C" { + #[doc = " Add an item to a proto_tree, using the text label registered to that item.\nThe item is extracted from the tvbuff handed to it.\n@param tree the tree to append this item to\n@param hfinfo field\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param encoding data encoding\n@return the newly created item"] + pub fn proto_tree_add_item_new( + tree: *mut proto_tree, + hfinfo: *mut header_field_info, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + ) -> *mut proto_item; +} +extern "C" { + pub fn proto_tree_add_item( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add an item to a proto_tree, using the text label registered to that item.\nThe item is extracted from the tvbuff handed to it.\n\nReturn the length of the item through the pointer.\n@param tree the tree to append this item to\n@param hfinfo field\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param encoding data encoding\n@param[out] lenretval points to a gint that will be set to the item length\n@return the newly created item, and *lenretval is set to the item length"] + pub fn proto_tree_add_item_new_ret_length( + tree: *mut proto_tree, + hfinfo: *mut header_field_info, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + lenretval: *mut gint, + ) -> *mut proto_item; +} +extern "C" { + pub fn proto_tree_add_item_ret_length( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + lenretval: *mut gint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add an integer data item to a proto_tree, using the text label registered to that item.\nThe item is extracted from the tvbuff handed to it, and the retrieved\nvalue is also set to *retval so the caller gets it back for other uses.\n\nThis function retrieves the value even if the passed-in tree param is NULL,\nso that it can be used by dissectors at all times to both get the value\nand set the tree item to it.\n\nLike other proto_tree_add functions, if there is a tree and the value cannot\nbe decoded from the tvbuff, then an expert info error is reported.\n\nThis function accepts ENC_LITTLE_ENDIAN and ENC_BIG_ENDIAN for native number\nencoding in the tvbuff\n\nThe length argument must\nbe set to the appropriate size of the native type as in other proto_add routines.\n\nIntegers of 8, 16, 24 and 32 bits can be retrieved with the _ret_int and\nret_uint functions; integers of 40, 48, 56, and 64 bits can be retrieved\nwith the _ret_uint64 function; Boolean values of 8, 16, 24, 32, 40, 48,\n56, and 64 bits can be retrieved with the _ret_boolean function.\n\n@param tree the tree to append this item to\n@param hfindex field\n@param tvb the tv buffer of the current data\n@param start start of data in tvb (cannot be negative)\n@param length length of data in tvb (for strings can be -1 for remaining)\n@param encoding data encoding (e.g, ENC_LITTLE_ENDIAN, ENC_BIG_ENDIAN, ENC_ASCII|ENC_STRING, etc.)\n@param[out] retval points to a gint32 or guint32 which will be set to the value\n@return the newly created item, and *retval is set to the decoded value masked/shifted according to bitmask"] + pub fn proto_tree_add_item_ret_int( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + retval: *mut gint32, + ) -> *mut proto_item; +} +extern "C" { + pub fn proto_tree_add_item_ret_int64( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + retval: *mut gint64, + ) -> *mut proto_item; +} +extern "C" { + pub fn proto_tree_add_item_ret_uint( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + retval: *mut guint32, + ) -> *mut proto_item; +} +extern "C" { + pub fn proto_tree_add_item_ret_uint64( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + retval: *mut guint64, + ) -> *mut proto_item; +} +extern "C" { + pub fn proto_tree_add_item_ret_varint( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + retval: *mut guint64, + lenretval: *mut gint, + ) -> *mut proto_item; +} +extern "C" { + pub fn proto_tree_add_item_ret_boolean( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + retval: *mut gboolean, + ) -> *mut proto_item; +} +extern "C" { + pub fn proto_tree_add_item_ret_ipv4( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + retval: *mut ws_in4_addr, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " @brief Parse an ipv6 address from the buffer and add it to the tree,\n writing the value to the pointer specified by the caller. The pointer\n must not be null.\n\n @param tree the tree\n @param hfindex the field\n @param tvb the tv buffer\n @param start the start index of data in tvb\n @param length the length of data. calls REPORT_DISSECTOR_BUG if not equal to FT_IPv6_LEN\n @param encoding encodings not yet supported. calls REPORT_DISSECTOR_BUG if not equal to 0\n @param retval where the address should be written, must not be null\n @return the newly created item"] + pub fn proto_tree_add_item_ret_ipv6( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + retval: *mut ws_in6_addr, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " @brief Parse an ethernet address from the buffer and add it to the tree,\n writing the value to the pointer specified by the caller. The pointer\n must not be null.\n\n @param tree the tree\n @param hfindex the field\n @param tvb the tv buffer\n @param start the start index of data in tvb\n @param length the length of data. calls REPORT_DISSECTOR_BUG if not equal to FT_ETHER_LEN\n @param encoding encodings not yet supported. calls REPORT_DISSECTOR_BUG if not equal to 0\n @param retval a buffer of at least FT_ETHER_LEN bytes for the address, must not be null\n @return the newly created item"] + pub fn proto_tree_add_item_ret_ether( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + retval: *mut guint8, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " @brief Parse a float from the buffer and add it to the tree,\n returning the item added and the parsed value via retval.\n\n @param tree the tree\n @param hfindex the field\n @param tvb the tv buffer\n @param start start index of data in tvb\n @param length the length of data. calls REPORT_DISSECTOR_BUG if not equal to 4\n @param encoding ENC_LITTLE_ENDIAN or ENC_BIG_ENDIAN\n @param[out] retval for the decoded value\n @return the newly created item"] + pub fn proto_tree_add_item_ret_float( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + retval: *mut gfloat, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " @brief Parse a double from the buffer and add it to the tree,\n returning the item added and the parsed value via retval\n\n @param tree the tree\n @param hfindex the field\n @param tvb the tv buffer\n @param start start index of data in tvb\n @param length length of data. calls REPORT_DISSECTOR_BUG if not equal to 8\n @param encoding ENC_LITTLE_ENDIAN or ENC_BIG_ENDIAN\n @param[out] retval for the decoded value\n @return the newly created item and retval is set to the decoded value"] + pub fn proto_tree_add_item_ret_double( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + retval: *mut gdouble, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add an string item to a proto_tree, using the text label registered to\nthat item.\n\nThe item is extracted from the tvbuff handed to it, and the retrieved\nvalue and its length are returned through pointers so the caller can use\nthem. The value is allocated using the wmem scope passed in.\n\nThis function retrieves the value and length even if the passed-in tree\nparam is NULL, so that then can be used by dissectors at all times to\nboth get the value and set the tree item to it.\n\nLike other proto_tree_add functions, if there is a tree and the value cannot\nbe decoded from the tvbuff, then an expert info error is reported.\n\nThis function accepts string encodings.\n\n@param scope the wmem scope to use to allocate the string\n@param tree the tree to append this item to\n@param hfindex field\n@param tvb the tv buffer of the current data\n@param start start of data in tvb (cannot be negative)\n@param length length of data in tvb (for strings can be -1 for remaining)\n@param encoding data encoding (e.g, ENC_ASCII, ENC_UTF_8, etc.)\n@param[out] retval points to a guint8 * that will be set to point to the\nstring value\n@param[out] lenretval points to a gint that will be set to the item length\n@return the newly created item, *retval is set to the decoded value,\nand *lenretval is set to the item length"] + pub fn proto_tree_add_item_ret_string_and_length( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + scope: *mut wmem_allocator_t, + retval: *mut *const guint8, + lenretval: *mut gint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add an string item to a proto_tree, using the text label registered to\nthat item.\n\nThe item is extracted from the tvbuff handed to it, and the retrieved\nvalue is returned through a pointer so the caller can use it. The value\nis allocated using the wmem scope passed in.\n\nThis function retrieves the value even if the passed-in tree param is NULL,\nso that it can be used by dissectors at all times to both get the value\nand set the tree item to it.\n\nLike other proto_tree_add functions, if there is a tree and the value cannot\nbe decoded from the tvbuff, then an expert info error is reported.\n\nThis function accepts string encodings.\n\n@param scope the wmem scope to use to allocate the string\n@param tree the tree to append this item to\n@param hfindex field\n@param tvb the tv buffer of the current data\n@param start start of data in tvb (cannot be negative)\n@param length length of data in tvb (for strings can be -1 for remaining)\n@param encoding data encoding (e.g, ENC_ASCII, ENC_UTF_8, etc.)\n@param[out] retval points to a guint8 * that will be set to point to the\nstring value\n@return the newly created item, and *retval is set to the decoded value"] + pub fn proto_tree_add_item_ret_string( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + scope: *mut wmem_allocator_t, + retval: *mut *const guint8, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add an string or byte array item to a proto_tree, using the\ntext label registered to that item.\n\nThis provides a string that is a display representation of the value,\nand the length of the item, similar to what\nproto_tree_add_item_ret_string_and_length() does.\n\n@param scope the wmem scope to use to allocate the string\n@param tree the tree to append this item to\n@param hfindex field\n@param tvb the tv buffer of the current data\n@param start start of data in tvb (cannot be negative)\n@param length length of data in tvb (for strings can be -1 for remaining)\n@param encoding data encoding (e.g, ENC_ASCII, ENC_UTF_8, etc.)\n@param[out] retval points to a guint8 * that will be set to point to the\nstring value\n@param[out] lenretval points to a gint that will be set to the item length\n@return the newly created item, *retval is set to the display string,\nand *lenretval is set to the item length"] + pub fn proto_tree_add_item_ret_display_string_and_length( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + scope: *mut wmem_allocator_t, + retval: *mut *mut ::std::os::raw::c_char, + lenretval: *mut gint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add an string or byte array item to a proto_tree, using the\ntext label registered to that item.\n\nThis provides a string that is a display representation of the value,\nsimilar to what proto_tree_add_item_ret_string() does.\n\n@param tree the tree to append this item to\n@param hfindex field\n@param tvb the tv buffer of the current data\n@param start start of data in tvb (cannot be negative)\n@param length length of data in tvb (for strings can be -1 for remaining)\n@param encoding data encoding (e.g, ENC_ASCII, ENC_UTF_8, etc.)\n@param scope the wmem scope to use to allocate the string\n@param[out] retval points to a guint8 * that will be set to point to the\nstring value\n@return the newly created item, *retval is set to the display string"] + pub fn proto_tree_add_item_ret_display_string( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + scope: *mut wmem_allocator_t, + retval: *mut *mut ::std::os::raw::c_char, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a time item to a proto_tree, using thetext label registered to that item.\n\nThis provides a string that is a display representation of the time value\n\n@param tree the tree to append this item to\n@param hfindex field\n@param tvb the tv buffer of the current data\n@param start start of data in tvb (cannot be negative)\n@param length length of data in tvb (for strings can be -1 for remaining)\n@param encoding data encoding (e.g, ENC_ASCII, ENC_UTF_8, etc.)\n@param scope the wmem scope to use to allocate the string\n@param[out] retval points to a guint8 * that will be set to point to the\nstring value\n@return the newly created item, *retval is set to the display string"] + pub fn proto_tree_add_item_ret_time_string( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + scope: *mut wmem_allocator_t, + retval: *mut *mut ::std::os::raw::c_char, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " (INTERNAL USE ONLY) Add a text-only node to a proto_tree.\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_text_internal( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " (INTERNAL USE ONLY) Add a text-only node to a proto_tree using a variable argument list.\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param format printf like format string\n@param ap variable argument list\n@return the newly created item"] + pub fn proto_tree_add_text_valist_internal( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + format: *const ::std::os::raw::c_char, + ap: *mut __va_list_tag, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a text-only node that creates a subtree underneath.\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param idx one of the ett_ array elements registered with proto_register_subtree_array()\n@param tree_item item returned with tree creation. Can be NULL if going to be unused\n@param text label for the tree\n@return the newly created tree"] + pub fn proto_tree_add_subtree( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + idx: gint, + tree_item: *mut *mut proto_item, + text: *const ::std::os::raw::c_char, + ) -> *mut proto_tree; +} +extern "C" { + #[doc = " Add a text-only node that creates a subtree underneath.\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param idx one of the ett_ array elements registered with proto_register_subtree_array()\n@param tree_item item returned with tree creation. Can be NULL if going to be unused\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created tree"] + pub fn proto_tree_add_subtree_format( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + idx: gint, + tree_item: *mut *mut proto_item, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_tree; +} +extern "C" { + #[doc = " Add a text-only node to a proto_tree with tvb_format_text() string."] + pub fn proto_tree_add_format_text( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a text-only node to a proto_tree with tvb_format_text_wsp() string."] + pub fn proto_tree_add_format_wsp_text( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_NONE field to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_none_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_PROTOCOL to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_protocol_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_BYTES to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param start_ptr pointer to the data to display\n@return the newly created item"] + pub fn proto_tree_add_bytes( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + start_ptr: *const guint8, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_BYTES to a proto_tree like proto_tree_add_bytes,\nbut used when the tvb data length does not match the bytes length.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param start_ptr pointer to the data to display\n@param ptr_length length of data in start_ptr\n@return the newly created item"] + pub fn proto_tree_add_bytes_with_length( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + start_ptr: *const guint8, + ptr_length: gint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Get and add a byte-array-based FT_* to a proto_tree.\n\nSupported: FT_BYTES, FT_UINT_BYTES, FT_OID, FT_REL_OID, and FT_SYSTEM_ID.\n\nThe item is extracted from the tvbuff handed to it, based on the ENC_* passed\nin for the encoding, and the retrieved byte array is also set to *retval so the\ncaller gets it back for other uses.\n\nThis function retrieves the value even if the passed-in tree param is NULL,\nso that it can be used by dissectors at all times to both get the value\nand set the tree item to it.\n\nLike other proto_tree_add functions, if there is a tree and the value cannot\nbe decoded from the tvbuff, then an expert info error is reported. For string\nencoding, this means that a failure to decode the hex value from the string\nresults in an expert info error being added to the tree.\n\nIf encoding is string-based, it will convert using tvb_get_string_bytes(); see\nthat function's comments for details.\n\n@note The GByteArray retval must be pre-constructed using g_byte_array_new().\n\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param encoding data encoding (e.g, ENC_LITTLE_ENDIAN, or ENC_UTF_8|ENC_STR_HEX)\n@param[in,out] retval points to a GByteArray which will be set to the bytes from the Tvb.\n@param[in,out] endoff if not NULL, gets set to the character after those consumed.\n@param[in,out] err if not NULL, gets set to 0 if no failure, else the errno code (e.g., EINVAL).\n@return the newly created item, and retval is set to the decoded value"] + pub fn proto_tree_add_bytes_item( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + retval: *mut GByteArray, + endoff: *mut gint, + err: *mut gint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_BYTES to a proto_tree, with the format generating\nthe string for the value and with the field name being included\nautomatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param start_ptr pointer to the data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_bytes_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + start_ptr: *const guint8, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_BYTES to a proto_tree, with the format generating\nthe entire string for the entry, including any field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param start_ptr pointer to the data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_bytes_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + start_ptr: *const guint8, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value_ptr pointer to the data to display\n@return the newly created item"] + pub fn proto_tree_add_time( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value_ptr: *const nstime_t, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Get and add a FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree.\nThe item is extracted from the tvbuff handed to it, based on the ENC_* passed\nin for the encoding, and the retrieved value is also set to *retval so the\ncaller gets it back for other uses.\n\nThis function retrieves the value even if the passed-in tree param is NULL,\nso that it can be used by dissectors at all times to both get the value\nand set the tree item to it.\n\nLike other proto_tree_add functions, if there is a tree and the value cannot\nbe decoded from the tvbuff, then an expert info error is reported. For string\nencoding, this means that a failure to decode the time value from the string\nresults in an expert info error being added to the tree.\n\nIf encoding is string-based, it will convert using tvb_get_string_time(); see\nthat function's comments for details.\n\n@note The nstime_t *retval must be pre-allocated as a nstime_t.\n\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param encoding data encoding (e.g, ENC_LITTLE_ENDIAN, ENC_UTF_8|ENC_ISO_8601_DATE_TIME, etc.)\n@param[in,out] retval points to a nstime_t which will be set to the value\n@param[in,out] endoff if not NULL, gets set to the character after those consumed.\n@param[in,out] err if not NULL, gets set to 0 if no failure, else EINVAL.\n@return the newly created item, and retval is set to the decoded value"] + pub fn proto_tree_add_time_item( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + encoding: guint, + retval: *mut nstime_t, + endoff: *mut gint, + err: *mut gint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree, with\nthe format generating the string for the value and with the field name\nbeing included automatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value_ptr pointer to the data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_time_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value_ptr: *mut nstime_t, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree, with\nthe format generating the entire string for the entry, including any field\nname.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value_ptr pointer to the data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_time_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value_ptr: *mut nstime_t, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_IPXNET to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@return the newly created item"] + pub fn proto_tree_add_ipxnet( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint32, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_IPXNET to a proto_tree, with the format generating\nthe string for the value and with the field name being included\nautomatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_ipxnet_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint32, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_IPXNET to a proto_tree, with the format generating\nthe entire string for the entry, including any field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_ipxnet_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint32, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_IPv4 to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@return the newly created item"] + pub fn proto_tree_add_ipv4( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: ws_in4_addr, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_IPv4 to a proto_tree, with the format generating\nthe string for the value and with the field name being included\nautomatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_ipv4_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: ws_in4_addr, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_IPv4 to a proto_tree, with the format generating\nthe entire string for the entry, including any field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_ipv4_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: ws_in4_addr, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_IPv6 to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value_ptr data to display\n@return the newly created item"] + pub fn proto_tree_add_ipv6( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value_ptr: *const ws_in6_addr, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_IPv6 to a proto_tree, with the format generating\nthe string for the value and with the field name being included\nautomatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value_ptr data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_ipv6_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value_ptr: *const ws_in6_addr, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_IPv6 to a proto_tree, with the format generating\nthe entire string for the entry, including any field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value_ptr data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_ipv6_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value_ptr: *const ws_in6_addr, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_ETHER to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@return the newly created item"] + pub fn proto_tree_add_ether( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: *const guint8, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_ETHER to a proto_tree, with the format generating\nthe string for the value and with the field name being included\nautomatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_ether_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: *const guint8, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_ETHER to a proto_tree, with the format generating\nthe entire string for the entry, including any field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_ether_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: *const guint8, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_GUID to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value_ptr data to display\n@return the newly created item"] + pub fn proto_tree_add_guid( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value_ptr: *const e_guid_t, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_GUID to a proto_tree, with the format generating\nthe string for the value and with the field name being included\nautomatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value_ptr data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_guid_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value_ptr: *const e_guid_t, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_GUID to a proto_tree, with the format generating\nthe entire string for the entry, including any field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value_ptr data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_guid_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value_ptr: *const e_guid_t, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_OID to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value_ptr data to display\n@return the newly created item"] + pub fn proto_tree_add_oid( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value_ptr: *const guint8, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_OID to a proto_tree, with the format generating\nthe string for the value and with the field name being included\nautomatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value_ptr data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_oid_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value_ptr: *const guint8, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_OID to a proto_tree, with the format generating\nthe entire string for the entry, including any field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value_ptr data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_oid_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value_ptr: *const guint8, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add an FT_STRING, FT_STRINGZ, FT_STRINGZPAD, or FT_STRINGZTRUNC to a\nproto_tree. The value passed in should be a UTF-8 encoded null terminated\nstring, such as produced by tvb_get_string_enc(), regardless of the original\npacket data.\n\nThis function is used to add a custom string *value* to the protocol tree.\nDo not format the string value for display, for example by using format_text().\nThe input string represents packet data, not a display label. Formatting\nlabels is a concern of the UI. Doing that here would change the meaning of the packet\ndata, restrict the options for formatting later and make display filtering unintuitive\nfor whitespace and other special characters.\n\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@return the newly created item"] + pub fn proto_tree_add_string( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: *const ::std::os::raw::c_char, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_STRING, FT_STRINGZ, FT_STRINGZPAD, or FT_STRINGZTRUNC\nto a proto_tree, with the format generating the string for the value\nand with the field name being included automatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_string_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: *const ::std::os::raw::c_char, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_STRING, FT_STRINGZ, FT_STRINGZPAD, or FT_STRINGZTRUNC\nto a proto_tree, with the format generating the entire string for the\nentry, including any field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_string_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: *const ::std::os::raw::c_char, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_BOOLEAN to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@return the newly created item"] + pub fn proto_tree_add_boolean( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint32, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_BOOLEAN to a proto_tree, with the format generating\nthe string for the value and with the field name being included\nautomatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_boolean_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint32, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_BOOLEAN to a proto_tree, with the format generating\nthe entire string for the entry, including any field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_boolean_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint32, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_FLOAT to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@return the newly created item"] + pub fn proto_tree_add_float( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: f32, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_FLOAT to a proto_tree, with the format generating\nthe string for the value and with the field name being included\nautomatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_float_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: f32, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_FLOAT to a proto_tree, with the format generating\nthe entire string for the entry, including any field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_float_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: f32, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_DOUBLE to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@return the newly created item"] + pub fn proto_tree_add_double( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: f64, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_DOUBLE to a proto_tree, with the format generating\nthe string for the value and with the field name being included\nautomatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_double_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: f64, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_DOUBLE to a proto_tree, with the format generating\nthe entire string for the entry, including any field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_double_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: f64, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add one of FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@return the newly created item"] + pub fn proto_tree_add_uint( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint32, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree,\nwith the format generating the string for the value and with the field\nname being included automatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_uint_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint32, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree,\nwith the format generating the entire string for the entry, including any\nfield name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_uint_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint32, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add an FT_UINT64 to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@return the newly created item"] + pub fn proto_tree_add_uint64( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint64, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_UINT64 to a proto_tree, with the format generating\nthe string for the value and with the field name being included\nautomatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_uint64_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint64, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_UINT64 to a proto_tree, with the format generating\nthe entire string for the entry, including any field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_uint64_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint64, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add one of FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@return the newly created item"] + pub fn proto_tree_add_int( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: gint32, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree,\nwith the format generating the string for the value and with the field\nname being included automatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_int_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: gint32, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree,\nwith the format generating the entire string for the entry, including\nany field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_int_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: gint32, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add an FT_INT64 to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@return the newly created item"] + pub fn proto_tree_add_int64( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: gint64, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_INT64 to a proto_tree, with the format generating\nthe string for the value and with the field name being included\nautomatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_int64_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: gint64, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_INT64 to a proto_tree, with the format generating\nthe entire string for the entry, including any field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_int64_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: gint64, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_EUI64 to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@return the newly created item"] + pub fn proto_tree_add_eui64( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint64, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_EUI64 to a proto_tree, with the format generating\nthe string for the value and with the field name being included\nautomatically.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_eui64_format_value( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint64, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a formatted FT_EUI64 to a proto_tree, with the format generating\nthe entire string for the entry, including any field name.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param start start of data in tvb\n@param length length of data in tvb\n@param value data to display\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_eui64_format( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + start: gint, + length: gint, + value: guint64, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Useful for quick debugging. Also sends string to STDOUT, so don't\nleave call to this function in production code.\n@param tree the tree to append the text to\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_debug_text( + tree: *mut proto_tree, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Fill given label_str with a simple string representation of field.\n@param finfo the item to get the info from\n@param label_str the string to fill\n@todo think about changing the parameter profile"] + pub fn proto_item_fill_label(finfo: *mut field_info, label_str: *mut gchar); +} +extern "C" { + #[doc = " Fill the given display_label_str with the string representation of a field\n formatted according to its type and field display specifier.\n Used to display custom columns and packet diagram values.\n@param fi The item to get the info from\n@param display_label_str The string to fill\n@return The length of the label excluding the terminating '\\0'."] + pub fn proto_item_fill_display_label( + fi: *mut field_info, + display_label_str: *mut gchar, + label_str_size: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Register a new protocol.\n@param name the full name of the new protocol\n@param short_name abbreviated name of the new protocol\n@param filter_name protocol name used for a display filter string\n@return the new protocol handle"] + pub fn proto_register_protocol( + name: *const ::std::os::raw::c_char, + short_name: *const ::std::os::raw::c_char, + filter_name: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Register a \"helper\" protocol (pino - protocol in name only).\nThis is for dissectors that need distinguishing names and don't need the other\nfeatures (like enable/disable). One use case is a protocol with multiple dissection\nfunctions in a single dissector table needing unique \"dissector names\" to remove\nconfusion with Decode As dialog. Another use case is for a dissector table set\nup to handle TLVs within a single protocol (and allow \"external\" TLVs being\nregistered through the dissector table).\n@param name the full name of the new protocol\n@param short_name abbreviated name of the new protocol\n@param filter_name protocol name used for a display filter string\n@param parent_proto the \"real\" protocol for the helper. The parent decides enable/disable\n@param field_type FT_PROTOCOL or FT_BYTES. Allows removal of \"protocol highlighting\" (FT_BYTES)\nif pino is part of TLV.\n@return the new protocol handle"] + pub fn proto_register_protocol_in_name_only( + name: *const ::std::os::raw::c_char, + short_name: *const ::std::os::raw::c_char, + filter_name: *const ::std::os::raw::c_char, + parent_proto: ::std::os::raw::c_int, + field_type: ftenum, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Register a protocol alias.\nThis is for dissectors whose original name has changed, e.g. BOOTP to DHCP.\n@param proto_id protocol id returned by proto_register_protocol (0-indexed)\n@param alias_name alias for the protocol's filter name"] + pub fn proto_register_alias( + proto_id: ::std::os::raw::c_int, + alias_name: *const ::std::os::raw::c_char, + ); +} +#[doc = " This type of function can be registered to get called whenever\na given field was not found but a its prefix is matched;\nIt can be used to procrastinate the hf array registration.\n@param match what's being matched"] +pub type prefix_initializer_t = + ::std::option::Option; +extern "C" { + #[doc = " Register a new prefix for delayed initialization of field arrays\nNote that the initializer function MAY NOT be called before the dissector\nis first called. That is, dissectors using this function must be prepared\nto call the initializer before beginning dissection; they should do this by\ncalling proto_registrar_get_byname() on one of the dissector's field names.\n@param prefix the prefix for the new protocol\n@param initializer function that will initialize the field array for the given prefix"] + pub fn proto_register_prefix( + prefix: *const ::std::os::raw::c_char, + initializer: prefix_initializer_t, + ); +} +extern "C" { + #[doc = " Register a header_field array.\n@param parent the protocol handle from proto_register_protocol()\n@param hf the hf_register_info array\n@param num_records the number of records in hf"] + pub fn proto_register_field_array( + parent: ::std::os::raw::c_int, + hf: *mut hf_register_info, + num_records: ::std::os::raw::c_int, + ); +} +extern "C" { + #[doc = " Register a protocol subtree (ett) array.\n@param indices array of ett indices\n@param num_indices the number of records in indices"] + pub fn proto_register_subtree_array( + indices: *const *mut gint, + num_indices: ::std::os::raw::c_int, + ); +} +extern "C" { + #[doc = " This function will dissect a sequence of bytes that describe a bitmask.\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param offset start of data in tvb\n@param hf_hdr an 8/16/24/32/40/48/56/64 bit integer that describes the\nbitmask to be dissected.\nThis field will form an expansion under which the individual fields\nof the bitmask are dissected and displayed.\nThis field must be of the type FT_[U]INT{8|16|24|32|40|48|56|64}.\n@param ett subtree index\n@param fields an array of pointers to int that lists all the fields of the\nbitmask. These fields can be either of the type FT_BOOLEAN for flags\nor another integer of the same type/size as hf_hdr with a mask specified.\nThis array is terminated by a NULL entry.\nFT_BOOLEAN bits that are set to 1 will have the name added to the expansion.\nFT_integer fields that have a value_string attached will have the\nmatched string displayed on the expansion line.\n@param encoding big or little endian byte representation (ENC_BIG_ENDIAN/ENC_LITTLE_ENDIAN/ENC_HOST_ENDIAN)\n@return the newly created item"] + pub fn proto_tree_add_bitmask( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + offset: guint, + hf_hdr: ::std::os::raw::c_int, + ett: gint, + fields: *const *mut ::std::os::raw::c_int, + encoding: guint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " This function will dissect a sequence of bytes that describe a bitmask.\nThe value of the integer containing the bitmask is returned through\na pointer.\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param offset start of data in tvb\n@param hf_hdr an 8/16/24/32/40/48/56/64 bit integer that describes the\nbitmask to be dissected.\nThis field will form an expansion under which the individual fields\nof the bitmask are dissected and displayed.\nThis field must be of the type FT_[U]INT{8|16|24|32|40|48|56|64}.\n@param ett subtree index\n@param fields an array of pointers to int that lists all the fields of the\nbitmask. These fields can be either of the type FT_BOOLEAN for flags\nor another integer of the same type/size as hf_hdr with a mask specified.\nThis array is terminated by a NULL entry.\nFT_BOOLEAN bits that are set to 1 will have the name added to the expansion.\nFT_integer fields that have a value_string attached will have the\nmatched string displayed on the expansion line.\n@param encoding big or little endian byte representation (ENC_BIG_ENDIAN/ENC_LITTLE_ENDIAN/ENC_HOST_ENDIAN)\n@param[out] retval points to a guint64 which will be set\n@return the newly created item, and *retval is set to the decoded value masked/shifted according to bitmask"] + pub fn proto_tree_add_bitmask_ret_uint64( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + offset: guint, + hf_hdr: ::std::os::raw::c_int, + ett: gint, + fields: *const *mut ::std::os::raw::c_int, + encoding: guint, + retval: *mut guint64, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " This function will dissect a sequence of bytes that describe a bitmask.\nThis has \"filterable\" bitmask header functionality of proto_tree_add_bitmask\nwith the ability to control what data is appended to the header like\nproto_tree_add_bitmask_text\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param offset start of data in tvb\n@param hf_hdr an 8/16/24/32/40/48/56/64 bit integer that describes the\nbitmask to be dissected.\nThis field will form an expansion under which the individual fields\nof the bitmask are dissected and displayed.\nThis field must be of the type FT_[U]INT{8|16|24|32|40|48|56|64}.\n@param ett subtree index\n@param fields an array of pointers to int that lists all the fields of the\nbitmask. These fields can be either of the type FT_BOOLEAN for flags\nor another integer of the same type/size as hf_hdr with a mask specified.\nThis array is terminated by a NULL entry.\nFT_BOOLEAN bits that are set to 1 will have the name added to the expansion.\nFT_integer fields that have a value_string attached will have the\nmatched string displayed on the expansion line.\n@param encoding big or little endian byte representation (ENC_BIG_ENDIAN/ENC_LITTLE_ENDIAN/ENC_HOST_ENDIAN)\n@param flags bitmask field using BMT_NO_* flags to determine behavior\n@return the newly created item"] + pub fn proto_tree_add_bitmask_with_flags( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + offset: guint, + hf_hdr: ::std::os::raw::c_int, + ett: gint, + fields: *const *mut ::std::os::raw::c_int, + encoding: guint, + flags: ::std::os::raw::c_int, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " This function will dissect a sequence of bytes that describe a bitmask.\nThis has \"filterable\" bitmask header functionality of proto_tree_add_bitmask\nwith the ability to control what data is appended to the header like\nproto_tree_add_bitmask_text\nThe value of the integer containing the bitmask is returned through\na pointer.\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param offset start of data in tvb\n@param hf_hdr an 8/16/24/32/40/48/56/64 bit integer that describes the\nbitmask to be dissected.\nThis field will form an expansion under which the individual fields\nof the bitmask are dissected and displayed.\nThis field must be of the type FT_[U]INT{8|16|24|32|40|48|56|64}.\n@param ett subtree index\n@param fields an array of pointers to int that lists all the fields of the\nbitmask. These fields can be either of the type FT_BOOLEAN for flags\nor another integer of the same type/size as hf_hdr with a mask specified.\nThis array is terminated by a NULL entry.\nFT_BOOLEAN bits that are set to 1 will have the name added to the expansion.\nFT_integer fields that have a value_string attached will have the\nmatched string displayed on the expansion line.\n@param encoding big or little endian byte representation (ENC_BIG_ENDIAN/ENC_LITTLE_ENDIAN/ENC_HOST_ENDIAN)\n@param flags bitmask field using BMT_NO_* flags to determine behavior\n@param[out] retval points to a guint64 which will be set\n@return the newly created item, and *retval is set to the decoded value masked/shifted according to bitmask"] + pub fn proto_tree_add_bitmask_with_flags_ret_uint64( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + offset: guint, + hf_hdr: ::std::os::raw::c_int, + ett: gint, + fields: *const *mut ::std::os::raw::c_int, + encoding: guint, + flags: ::std::os::raw::c_int, + retval: *mut guint64, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " This function will dissect a value that describe a bitmask. Similar to proto_tree_add_bitmask(),\nbut with a passed in value (presumably because it can't be retrieved directly from tvb)\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param offset start of data in tvb\n@param hf_hdr an 8/16/24/32/64 bit integer that describes the bitmask to be dissected.\nThis field will form an expansion under which the individual fields of the\nbitmask is dissected and displayed.\nThis field must be of the type FT_[U]INT{8|16|24|32|64}.\n@param ett subtree index\n@param fields an array of pointers to int that lists all the fields of the\nbitmask. These fields can be either of the type FT_BOOLEAN for flags\nor another integer of the same type/size as hf_hdr with a mask specified.\nThis array is terminated by a NULL entry.\nFT_BOOLEAN bits that are set to 1 will have the name added to the expansion.\nFT_integer fields that have a value_string attached will have the\nmatched string displayed on the expansion line.\n@param value bitmask value\n@return the newly created item"] + pub fn proto_tree_add_bitmask_value( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + offset: guint, + hf_hdr: ::std::os::raw::c_int, + ett: gint, + fields: *const *mut ::std::os::raw::c_int, + value: guint64, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " This function will dissect a value that describe a bitmask. Similar to proto_tree_add_bitmask(),\nbut with a passed in value (presumably because it can't be retrieved directly from tvb)\nThis has \"filterable\" bitmask header functionality of proto_tree_add_bitmask_value\nwith the ability to control what data is appended to the header like\nproto_tree_add_bitmask_text\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param offset start of data in tvb\n@param hf_hdr an 8/16/24/32/64 bit integer that describes the bitmask to be dissected.\nThis field will form an expansion under which the individual fields of the\nbitmask is dissected and displayed.\nThis field must be of the type FT_[U]INT{8|16|24|32|64}.\n@param ett subtree index\n@param fields an array of pointers to int that lists all the fields of the\nbitmask. These fields can be either of the type FT_BOOLEAN for flags\nor another integer of the same type/size as hf_hdr with a mask specified.\nThis array is terminated by a NULL entry.\nFT_BOOLEAN bits that are set to 1 will have the name added to the expansion.\nFT_integer fields that have a value_string attached will have the\nmatched string displayed on the expansion line.\n@param value bitmask value\n@param flags bitmask field using BMT_NO_* flags to determine behavior\n@return the newly created item"] + pub fn proto_tree_add_bitmask_value_with_flags( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + offset: guint, + hf_hdr: ::std::os::raw::c_int, + ett: gint, + fields: *const *mut ::std::os::raw::c_int, + value: guint64, + flags: ::std::os::raw::c_int, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " This function will dissect a sequence of bytes that describe a bitmask. Similar\nto proto_tree_add_bitmask(), but with no \"header\" item to group all of the fields\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param offset start of data in tvb\n@param len number of bytes of data\n@param fields an array of pointers to int that lists all the fields of the\nbitmask. These fields can be either of the type FT_BOOLEAN for flags\nor another integer of the same type/size as hf_hdr with a mask specified.\nThis array is terminated by a NULL entry.\nFT_BOOLEAN bits that are set to 1 will have the name added to the expansion.\nFT_integer fields that have a value_string attached will have the\nmatched string displayed on the expansion line.\n@param encoding big or little endian byte representation (ENC_BIG_ENDIAN/ENC_LITTLE_ENDIAN/ENC_HOST_ENDIAN)"] + pub fn proto_tree_add_bitmask_list( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + offset: guint, + len: ::std::os::raw::c_int, + fields: *const *mut ::std::os::raw::c_int, + encoding: guint, + ); +} +extern "C" { + #[doc = " This function will dissect a value that describe a bitmask. Similar to proto_tree_add_bitmask_list(),\nbut with a return value\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param offset start of data in tvb\n@param len number of bytes of data\n@param fields an array of pointers to int that lists all the fields of the\nbitmask. These fields can be either of the type FT_BOOLEAN for flags\nor another integer of the same type/size as hf_hdr with a mask specified.\nThis array is terminated by a NULL entry.\nFT_BOOLEAN bits that are set to 1 will have the name added to the expansion.\nFT_integer fields that have a value_string attached will have the\nmatched string displayed on the expansion line.\n@param encoding big or little endian byte representation (ENC_BIG_ENDIAN/ENC_LITTLE_ENDIAN/ENC_HOST_ENDIAN)\n@param retval if a pointer is passed here the value is returned."] + pub fn proto_tree_add_bitmask_list_ret_uint64( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + offset: guint, + len: ::std::os::raw::c_int, + fields: *const *mut ::std::os::raw::c_int, + encoding: guint, + retval: *mut guint64, + ); +} +extern "C" { + #[doc = " This function will dissect a value that describe a bitmask. Similar to proto_tree_add_bitmask_list(),\nbut with a passed in value (presumably because it can't be retrieved directly from tvb)\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param offset start of data in tvb\n@param len number of bytes of data\n@param fields an array of pointers to int that lists all the fields of the\nbitmask. These fields can be either of the type FT_BOOLEAN for flags\nor another integer of the same type/size as hf_hdr with a mask specified.\nThis array is terminated by a NULL entry.\nFT_BOOLEAN bits that are set to 1 will have the name added to the expansion.\nFT_integer fields that have a value_string attached will have the\nmatched string displayed on the expansion line.\n@param value bitmask value"] + pub fn proto_tree_add_bitmask_list_value( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + offset: guint, + len: ::std::os::raw::c_int, + fields: *const *mut ::std::os::raw::c_int, + value: guint64, + ); +} +extern "C" { + #[doc = " This function will dissect a sequence of bytes that describe a bitmask.\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param offset start of data in tvb\n@param len number of bytes of data\n@param hf_hdr an 8/16/24/32 bit integer that describes the bitmask to be dissected.\nThis field will form an expansion under which the individual fields of the\nbitmask are dissected and displayed.\nThis field must be of the type FT_[U]INT{8|16|24|32}.\n@param ett subtree index\n@param fields an array of pointers to int that lists all the fields of the\nbitmask. These fields can be either of the type FT_BOOLEAN for flags\nor another integer with a mask specified.\nThis array is terminated by a NULL entry.\nFT_BOOLEAN bits that are set to 1 will have the name added to the expansion.\nFT_integer fields that have a value_string attached will have the\nmatched string displayed on the expansion line.\n@param exp expert info field used when decodable_len < len. This also means this function\nshould be called even when tree == NULL\n@param encoding big or little endian byte representation (ENC_BIG_ENDIAN/ENC_LITTLE_ENDIAN/ENC_HOST_ENDIAN)\n@return the newly created item"] + pub fn proto_tree_add_bitmask_len( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + offset: guint, + len: guint, + hf_hdr: ::std::os::raw::c_int, + ett: gint, + fields: *const *mut ::std::os::raw::c_int, + exp: *mut expert_field, + encoding: guint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a text with a subtree of bitfields.\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param offset start of data in tvb\n@param len length of the field name\n@param name field name (NULL if bitfield contents should be used)\n@param fallback field name if none of bitfields were usable\n@param ett subtree index\n@param fields NULL-terminated array of bitfield indexes\n@param encoding big or little endian byte representation (ENC_BIG_ENDIAN/ENC_LITTLE_ENDIAN/ENC_HOST_ENDIAN)\n@param flags bitmask field\n@return the newly created item"] + pub fn proto_tree_add_bitmask_text( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + offset: guint, + len: guint, + name: *const ::std::os::raw::c_char, + fallback: *const ::std::os::raw::c_char, + ett: gint, + fields: *const *mut ::std::os::raw::c_int, + encoding: guint, + flags: ::std::os::raw::c_int, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add bits to a proto_tree, using the text label registered to that item.\nThe item is extracted from the tvbuff handed to it.\n@param tree the tree to append this item to\n@param hf_index field index. Fields for use with this function should have bitmask==0.\n@param tvb the tv buffer of the current data\n@param bit_offset start of data in tvb expressed in bits\n@param no_of_bits length of data in tvb expressed in bits\n@param encoding data encoding\n@return the newly created item"] + pub fn proto_tree_add_bits_item( + tree: *mut proto_tree, + hf_index: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + bit_offset: guint, + no_of_bits: gint, + encoding: guint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add bits to a proto_tree, using the text label registered to that item.\n The item is extracted from the tvbuff handed to it as a set\n of crumbs (segments) of contiguous bits, specified by an\n array of crumb_spec elements. The crumbs are assembled to\n create the value. There may be any number of crumbs\n specifying up to a total of 64 bits which may occur anywhere\n within the tvb. If the span of the crumbs within the tvb is 4\n octets or less, a bitmap of the crumbs is produced.\n@param tree the tree to append this item to\n@param hf_index field index. Fields for use with this function should have bitmask==0.\n@param tvb the tv buffer of the current data\n@param bit_offset of the first crumb in tvb expressed in bits\n@param crumb_spec pointer to crumb_spec array\n@param return_value if a pointer is passed here the value is returned.\n@return the newly created item"] + pub fn proto_tree_add_split_bits_item_ret_val( + tree: *mut proto_tree, + hf_index: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + bit_offset: guint, + crumb_spec: *const crumb_spec_t, + return_value: *mut guint64, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add bitmap text for a split-bits crumb to a proto_tree,\n using the text label registered to an item. The bitmap is\n extracted from the tvbuff handed to it as a crumb (segment)\n of contiguous bits, specified by one of an array of\n crumb_spec elements. This function is normally called once\n per crumb, after the call to\nproto_tree_add_split_bits_item_ret_val\n@param tree the tree to append this item to\n@param hf_index field index. Fields for use with this function should have bitmask==0.\n@param tvb the tv buffer of the current data\n@param bit_offset of the first crumb in tvb expressed in bits\n@param crumb_spec pointer to crumb_spec array\n@param crumb_index into the crumb_spec array for this crumb"] + pub fn proto_tree_add_split_bits_crumb( + tree: *mut proto_tree, + hf_index: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + bit_offset: guint, + crumb_spec: *const crumb_spec_t, + crumb_index: guint16, + ); +} +extern "C" { + #[doc = " Add bits to a proto_tree, using the text label registered to that item.\nThe item is extracted from the tvbuff handed to it.\n@param tree the tree to append this item to\n@param hf_index field index. Fields for use with this function should have bitmask==0.\n@param tvb the tv buffer of the current data\n@param bit_offset start of data in tvb expressed in bits\n@param no_of_bits length of data in tvb expressed in bits\n@param return_value if a pointer is passed here the value is returned.\n@param encoding data encoding\n@return the newly created item"] + pub fn proto_tree_add_bits_ret_val( + tree: *mut proto_tree, + hf_index: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + bit_offset: guint, + no_of_bits: gint, + return_value: *mut guint64, + encoding: guint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add bits for a FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32\nheader field to a proto_tree, with the format generating the\nstring for the value and with the field name being included automatically.\n@param tree the tree to append this item to\n@param hf_index field index\n@param tvb the tv buffer of the current data\n@param bit_offset start of data in tvb expressed in bits\n@param no_of_bits length of data in tvb expressed in bit\n@param value data to display\n@param encoding data encoding\n@param format printf like format string\n@return the newly created item"] + pub fn proto_tree_add_uint_bits_format_value( + tree: *mut proto_tree, + hf_index: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + bit_offset: guint, + no_of_bits: gint, + value: guint32, + encoding: guint, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add bits for a FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32\nheader field to a proto_tree, with the format generating the\nstring for the value and with the field name being included automatically.\n@param tree the tree to append this item to\n@param hf_index field index\n@param tvb the tv buffer of the current data\n@param bit_offset start of data in tvb expressed in bits\n@param no_of_bits length of data in tvb expressed in bit\n@param value data to display\n@param encoding data encoding\n@param format printf like format string\n@return the newly created item"] + pub fn proto_tree_add_uint64_bits_format_value( + tree: *mut proto_tree, + hf_index: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + bit_offset: guint, + no_of_bits: gint, + value: guint64, + encoding: guint, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add bits for a FT_BOOLEAN header field to a proto_tree, with\nthe format generating the string for the value and with the field\nname being included automatically.\n@param tree the tree to append this item to\n@param hf_index field index\n@param tvb the tv buffer of the current data\n@param bit_offset start of data in tvb expressed in bits\n@param no_of_bits length of data in tvb expressed in bit\n@param value data to display\n@param encoding data encoding\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_boolean_bits_format_value( + tree: *mut proto_tree, + hf_index: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + bit_offset: guint, + no_of_bits: gint, + value: guint32, + encoding: guint, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add bits for a FT_BOOLEAN header field to a proto_tree, with\nthe format generating the string for the value and with the field\nname being included automatically.\n@param tree the tree to append this item to\n@param hf_index field index\n@param tvb the tv buffer of the current data\n@param bit_offset start of data in tvb expressed in bits\n@param no_of_bits length of data in tvb expressed in bit\n@param value data to display\n@param encoding data encoding\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_boolean_bits_format_value64( + tree: *mut proto_tree, + hf_index: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + bit_offset: guint, + no_of_bits: gint, + value: guint64, + encoding: guint, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add bits for a FT_INT8, FT_INT16, FT_INT24 or FT_INT32\nheader field to a proto_tree, with the format generating the\nstring for the value and with the field name being included automatically.\n@param tree the tree to append this item to\n@param hf_index field index\n@param tvb the tv buffer of the current data\n@param bit_offset start of data in tvb expressed in bits\n@param no_of_bits length of data in tvb expressed in bit\n@param value data to display\n@param encoding data encoding\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_int_bits_format_value( + tree: *mut proto_tree, + hf_index: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + bit_offset: guint, + no_of_bits: gint, + value: gint32, + encoding: guint, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add bits for a FT_INT8, FT_INT16, FT_INT24 or FT_INT32\nheader field to a proto_tree, with the format generating the\nstring for the value and with the field name being included automatically.\n@param tree the tree to append this item to\n@param hf_index field index\n@param tvb the tv buffer of the current data\n@param bit_offset start of data in tvb expressed in bits\n@param no_of_bits length of data in tvb expressed in bit\n@param value data to display\n@param encoding data encoding\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_int64_bits_format_value( + tree: *mut proto_tree, + hf_index: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + bit_offset: guint, + no_of_bits: gint, + value: gint64, + encoding: guint, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add bits for a FT_FLOAT header field to a proto_tree, with\nthe format generating the string for the value and with the field\nname being included automatically.\n@param tree the tree to append this item to\n@param hf_index field index\n@param tvb the tv buffer of the current data\n@param bit_offset start of data in tvb expressed in bits\n@param no_of_bits length of data in tvb expressed in bit\n@param value data to display\n@param encoding data encoding\n@param format printf like format string\n@param ... printf like parameters\n@return the newly created item"] + pub fn proto_tree_add_float_bits_format_value( + tree: *mut proto_tree, + hf_index: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + bit_offset: guint, + no_of_bits: gint, + value: f32, + encoding: guint, + format: *const ::std::os::raw::c_char, + ... + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_STRING with ENC_3GPP_TS_23_038_7BITS_PACKED encoding to a\nproto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param bit_offset start of data in tvb expressed in bits\n@param no_of_chars number of 7bits characters to display\n@return the newly created item"] + pub fn proto_tree_add_ts_23_038_7bits_packed_item( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + bit_offset: guint, + no_of_chars: gint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a FT_STRING with ENC_ASCII_7BITS encoding to a proto_tree.\n@param tree the tree to append this item to\n@param hfindex field index\n@param tvb the tv buffer of the current data\n@param bit_offset start of data in tvb expressed in bits\n@param no_of_chars number of 7bits characters to display\n@return the newly created item"] + pub fn proto_tree_add_ascii_7bits_item( + tree: *mut proto_tree, + hfindex: ::std::os::raw::c_int, + tvb: *mut tvbuff_t, + bit_offset: guint, + no_of_chars: gint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a checksum filed to a proto_tree.\nThis standardizes the display of a checksum field as well as any\nstatus and expert info supporting it.\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param offset start of data in tvb\n@param hf_checksum checksum field index\n@param hf_checksum_status optional checksum status field index. If none\nexists, just pass -1\n@param bad_checksum_expert optional expert info for a bad checksum. If\nnone exists, just pass NULL\n@param pinfo Packet info used for optional expert info. If unused, NULL can\nbe passed\n@param computed_checksum Checksum to verify against\n@param encoding data encoding of checksum from tvb\n@param flags bitmask field of PROTO_CHECKSUM_ options\n@return the newly created item"] + pub fn proto_tree_add_checksum( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + offset: guint, + hf_checksum: ::std::os::raw::c_int, + hf_checksum_status: ::std::os::raw::c_int, + bad_checksum_expert: *mut expert_field, + pinfo: *mut packet_info, + computed_checksum: guint32, + encoding: guint, + flags: guint, + ) -> *mut proto_item; +} +extern "C" { + #[doc = " Add a checksum bytes arry filed to a proto_tree.\nThis standardizes the display of a checksum field as well as any\nstatus and expert info supporting it.\n@param tree the tree to append this item to\n@param tvb the tv buffer of the current data\n@param offset start of data in tvb\n@param hf_checksum checksum field index\n@param hf_checksum_status optional checksum status field index. If none\nexists, just pass -1\n@param bad_checksum_expert optional expert info for a bad checksum. If\nnone exists, just pass NULL\n@param pinfo Packet info used for optional expert info. If unused, NULL can\nbe passed\n@param computed_checksum Checksum as bytes array to verify against\n@param checksum_len Checksum size in bytes\n@param flags bitmask field of PROTO_CHECKSUM_ options. PROTO_CHECKSUM_IN_CKSUM is ignored\n@return the newly created item"] + pub fn proto_tree_add_checksum_bytes( + tree: *mut proto_tree, + tvb: *mut tvbuff_t, + offset: guint, + hf_checksum: ::std::os::raw::c_int, + hf_checksum_status: ::std::os::raw::c_int, + bad_checksum_expert: *mut expert_field, + pinfo: *mut packet_info, + computed_checksum: *const u8, + checksum_len: usize, + flags: guint, + ) -> *mut proto_item; +} +#[doc = " Helper routines for column utility structures and routines."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct epan_column_info { + _unused: [u8; 0], +} +pub type column_info = epan_column_info; +#[doc = "< 0) Absolute date, as YYYY-MM-DD, and time"] +pub const COL_ABS_YMD_TIME: _bindgen_ty_21 = 0; +#[doc = "< 1) Absolute date, as YYYY/DOY, and time"] +pub const COL_ABS_YDOY_TIME: _bindgen_ty_21 = 1; +#[doc = "< 2) Absolute time"] +pub const COL_ABS_TIME: _bindgen_ty_21 = 2; +#[doc = "< 3) Cumulative number of bytes"] +pub const COL_CUMULATIVE_BYTES: _bindgen_ty_21 = 3; +#[doc = "< 4) Custom column (any filter name's contents)"] +pub const COL_CUSTOM: _bindgen_ty_21 = 4; +#[doc = "< 5) Delta time"] +pub const COL_DELTA_TIME: _bindgen_ty_21 = 5; +#[doc = "< 6) Delta time displayed"] +pub const COL_DELTA_TIME_DIS: _bindgen_ty_21 = 6; +#[doc = "< 7) Resolved dest"] +pub const COL_RES_DST: _bindgen_ty_21 = 7; +#[doc = "< 8) Unresolved dest"] +pub const COL_UNRES_DST: _bindgen_ty_21 = 8; +#[doc = "< 9) Resolved dest port"] +pub const COL_RES_DST_PORT: _bindgen_ty_21 = 9; +#[doc = "< 10) Unresolved dest port"] +pub const COL_UNRES_DST_PORT: _bindgen_ty_21 = 10; +#[doc = "< 11) Destination address"] +pub const COL_DEF_DST: _bindgen_ty_21 = 11; +#[doc = "< 12) Destination port"] +pub const COL_DEF_DST_PORT: _bindgen_ty_21 = 12; +#[doc = "< 13) Expert Info"] +pub const COL_EXPERT: _bindgen_ty_21 = 13; +#[doc = "< 14) FW-1 monitor interface/direction"] +pub const COL_IF_DIR: _bindgen_ty_21 = 14; +#[doc = "< 15) IEEE 802.11 (and WiMax?) - Channel"] +pub const COL_FREQ_CHAN: _bindgen_ty_21 = 15; +#[doc = "< 16) Data link layer dest address"] +pub const COL_DEF_DL_DST: _bindgen_ty_21 = 16; +#[doc = "< 17) Data link layer source address"] +pub const COL_DEF_DL_SRC: _bindgen_ty_21 = 17; +#[doc = "< 18) Resolved DL dest"] +pub const COL_RES_DL_DST: _bindgen_ty_21 = 18; +#[doc = "< 19) Unresolved DL dest"] +pub const COL_UNRES_DL_DST: _bindgen_ty_21 = 19; +#[doc = "< 20) Resolved DL source"] +pub const COL_RES_DL_SRC: _bindgen_ty_21 = 20; +#[doc = "< 21) Unresolved DL source"] +pub const COL_UNRES_DL_SRC: _bindgen_ty_21 = 21; +#[doc = "< 22) IEEE 802.11 - received signal strength"] +pub const COL_RSSI: _bindgen_ty_21 = 22; +#[doc = "< 23) IEEE 802.11 - TX rate in Mbps"] +pub const COL_TX_RATE: _bindgen_ty_21 = 23; +#[doc = "< 24) IP DSCP Value"] +pub const COL_DSCP_VALUE: _bindgen_ty_21 = 24; +#[doc = "< 25) Description"] +pub const COL_INFO: _bindgen_ty_21 = 25; +#[doc = "< 26) Resolved net dest"] +pub const COL_RES_NET_DST: _bindgen_ty_21 = 26; +#[doc = "< 27) Unresolved net dest"] +pub const COL_UNRES_NET_DST: _bindgen_ty_21 = 27; +#[doc = "< 28) Resolved net source"] +pub const COL_RES_NET_SRC: _bindgen_ty_21 = 28; +#[doc = "< 29) Unresolved net source"] +pub const COL_UNRES_NET_SRC: _bindgen_ty_21 = 29; +#[doc = "< 30) Network layer dest address"] +pub const COL_DEF_NET_DST: _bindgen_ty_21 = 30; +#[doc = "< 31) Network layer source address"] +pub const COL_DEF_NET_SRC: _bindgen_ty_21 = 31; +#[doc = "< 32) Packet list item number"] +pub const COL_NUMBER: _bindgen_ty_21 = 32; +#[doc = "< 33) Packet length in bytes"] +pub const COL_PACKET_LENGTH: _bindgen_ty_21 = 33; +#[doc = "< 34) Protocol"] +pub const COL_PROTOCOL: _bindgen_ty_21 = 34; +#[doc = "< 35) Relative time"] +pub const COL_REL_TIME: _bindgen_ty_21 = 35; +#[doc = "< 36) Source address"] +pub const COL_DEF_SRC: _bindgen_ty_21 = 36; +#[doc = "< 37) Source port"] +pub const COL_DEF_SRC_PORT: _bindgen_ty_21 = 37; +#[doc = "< 38) Resolved source"] +pub const COL_RES_SRC: _bindgen_ty_21 = 38; +#[doc = "< 39) Unresolved source"] +pub const COL_UNRES_SRC: _bindgen_ty_21 = 39; +#[doc = "< 40) Resolved source port"] +pub const COL_RES_SRC_PORT: _bindgen_ty_21 = 40; +#[doc = "< 41) Unresolved source port"] +pub const COL_UNRES_SRC_PORT: _bindgen_ty_21 = 41; +#[doc = "< 42) UTC date, as YYYY-MM-DD, and time"] +pub const COL_UTC_YMD_TIME: _bindgen_ty_21 = 42; +#[doc = "< 43) UTC date, as YYYY/DOY, and time"] +pub const COL_UTC_YDOY_TIME: _bindgen_ty_21 = 43; +#[doc = "< 44) UTC time"] +pub const COL_UTC_TIME: _bindgen_ty_21 = 44; +#[doc = "< 45) Command line-specified time (default relative)"] +pub const COL_CLS_TIME: _bindgen_ty_21 = 45; +#[doc = "< 46) Should always be last"] +pub const NUM_COL_FMTS: _bindgen_ty_21 = 46; +#[doc = " All of the possible columns in summary listing.\n\n NOTE1: The entries MUST remain in this order, or else you need to reorder\n the slist[] and dlist[] arrays in column.c to match!\n\n NOTE2: Please add the COL_XYZ entry in the appropriate spot, such that the\n dlist[] array remains in alphabetical order!"] +pub type _bindgen_ty_21 = ::std::os::raw::c_uint; +extern "C" { + #[doc = " Clears the text of a column element.\n\n @param cinfo the current packet row\n @param col the column to use, e.g. COL_INFO"] + pub fn col_clear(cinfo: *mut column_info, col: gint); +} +extern "C" { + #[doc = " Set (replace) the text of a column element, the text won't be formatted or copied.\n\n Use this for simple static strings like protocol names. Don't use for untrusted strings\n or strings that may contain unprintable characters.\n\n Usually used to set const strings!\n\n @param cinfo the current packet row\n @param col the column to use, e.g. COL_INFO\n @param str the string to set"] + pub fn col_set_str(cinfo: *mut column_info, col: gint, str_: *const gchar); +} +extern "C" { + #[doc = " Append the given text to a column element, the text will be formatted and copied.\n\n Unprintable characters according to isprint() are escaped.\n\n @param cinfo the current packet row\n @param col the column to use, e.g. COL_INFO\n @param str the string to append"] + pub fn col_append_str(cinfo: *mut column_info, col: gint, str_: *const gchar); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct dissector_handle { + _unused: [u8; 0], +} +pub type dissector_handle_t = *mut dissector_handle; +pub type dissector_t = ::std::option::Option< + unsafe extern "C" fn( + arg1: *mut tvbuff_t, + arg2: *mut packet_info, + arg3: *mut proto_tree, + arg4: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +#[doc = " Type of a heuristic dissector, used in heur_dissector_add().\n\n @param tvb the tvbuff with the (remaining) packet data\n @param pinfo the packet info of this packet (additional info)\n @param tree the protocol tree to be build or NULL\n @return TRUE if the packet was recognized by the sub-dissector (stop dissection here)"] +pub type heur_dissector_t = ::std::option::Option< + unsafe extern "C" fn( + tvb: *mut tvbuff_t, + pinfo: *mut packet_info, + tree: *mut proto_tree, + arg1: *mut ::std::os::raw::c_void, + ) -> gboolean, +>; +pub const heuristic_enable_e_HEURISTIC_DISABLE: heuristic_enable_e = 0; +pub const heuristic_enable_e_HEURISTIC_ENABLE: heuristic_enable_e = 1; +pub type heuristic_enable_e = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct heur_dtbl_entry { + pub dissector: heur_dissector_t, + pub protocol: *mut protocol_t, + pub list_name: *mut gchar, + pub display_name: *const gchar, + pub short_name: *mut gchar, + pub enabled: gboolean, + pub enabled_by_default: bool, +} +#[test] +fn bindgen_test_layout_heur_dtbl_entry() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 48usize, + concat!("Size of: ", stringify!(heur_dtbl_entry)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(heur_dtbl_entry)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).dissector) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(heur_dtbl_entry), + "::", + stringify!(dissector) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).protocol) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(heur_dtbl_entry), + "::", + stringify!(protocol) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).list_name) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(heur_dtbl_entry), + "::", + stringify!(list_name) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).display_name) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(heur_dtbl_entry), + "::", + stringify!(display_name) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).short_name) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(heur_dtbl_entry), + "::", + stringify!(short_name) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).enabled) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(heur_dtbl_entry), + "::", + stringify!(enabled) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).enabled_by_default) as usize - ptr as usize }, + 44usize, + concat!( + "Offset of field: ", + stringify!(heur_dtbl_entry), + "::", + stringify!(enabled_by_default) + ) + ); +} +pub type DATFunc_heur = ::std::option::Option< + unsafe extern "C" fn( + table_name: *const gchar, + entry: *mut heur_dtbl_entry, + user_data: gpointer, + ), +>; +extern "C" { + #[doc = " Iterate over heuristic dissectors in a table.\n\n Walk one heuristic dissector table's list calling a user supplied function\n on each entry.\n\n @param[in] table_name The name of the dissector table, e.g. \"tcp\".\n @param[in] func The function to call for each dissector.\n @param[in] user_data User data to pass to the function."] + pub fn heur_dissector_table_foreach( + table_name: *const ::std::os::raw::c_char, + func: DATFunc_heur, + user_data: gpointer, + ); +} +extern "C" { + #[doc = " Add a sub-dissector to a heuristic dissector list.\n Call this in the proto_handoff function of the sub-dissector.\n\n @param name the name of the heuristic dissector table into which to register the dissector, e.g. \"tcp\"\n @param dissector the sub-dissector to be registered\n @param display_name the string used to present heuristic to user, e.g. \"HTTP over TCP\"\n @param internal_name the string used for \"internal\" use to identify heuristic, e.g. \"http_tcp\"\n @param proto the protocol id of the sub-dissector\n @param enable initially enabled or not"] + pub fn heur_dissector_add( + name: *const ::std::os::raw::c_char, + dissector: heur_dissector_t, + display_name: *const ::std::os::raw::c_char, + internal_name: *const ::std::os::raw::c_char, + proto: ::std::os::raw::c_int, + enable: heuristic_enable_e, + ); +} +extern "C" { + #[doc = " Remove a sub-dissector from a heuristic dissector list.\n Call this in the prefs_reinit function of the sub-dissector.\n\n @param name the name of the \"parent\" protocol, e.g. \"tcp\"\n @param dissector the sub-dissector to be unregistered\n @param proto the protocol id of the sub-dissector"] + pub fn heur_dissector_delete( + name: *const ::std::os::raw::c_char, + dissector: heur_dissector_t, + proto: ::std::os::raw::c_int, + ); +} +extern "C" { + pub fn create_dissector_handle_with_name_and_description( + dissector: dissector_t, + proto: ::std::os::raw::c_int, + name: *const ::std::os::raw::c_char, + description: *const ::std::os::raw::c_char, + ) -> dissector_handle_t; +} +pub const conversation_type_CONVERSATION_NONE: conversation_type = 0; +pub const conversation_type_CONVERSATION_SCTP: conversation_type = 1; +pub const conversation_type_CONVERSATION_TCP: conversation_type = 2; +pub const conversation_type_CONVERSATION_UDP: conversation_type = 3; +pub const conversation_type_CONVERSATION_DCCP: conversation_type = 4; +pub const conversation_type_CONVERSATION_IPX: conversation_type = 5; +pub const conversation_type_CONVERSATION_NCP: conversation_type = 6; +pub const conversation_type_CONVERSATION_EXCHG: conversation_type = 7; +pub const conversation_type_CONVERSATION_DDP: conversation_type = 8; +pub const conversation_type_CONVERSATION_SBCCS: conversation_type = 9; +pub const conversation_type_CONVERSATION_IDP: conversation_type = 10; +pub const conversation_type_CONVERSATION_TIPC: conversation_type = 11; +pub const conversation_type_CONVERSATION_USB: conversation_type = 12; +pub const conversation_type_CONVERSATION_I2C: conversation_type = 13; +pub const conversation_type_CONVERSATION_IBQP: conversation_type = 14; +pub const conversation_type_CONVERSATION_BLUETOOTH: conversation_type = 15; +pub const conversation_type_CONVERSATION_TDMOP: conversation_type = 16; +pub const conversation_type_CONVERSATION_DVBCI: conversation_type = 17; +pub const conversation_type_CONVERSATION_ISO14443: conversation_type = 18; +pub const conversation_type_CONVERSATION_ISDN: conversation_type = 19; +pub const conversation_type_CONVERSATION_H223: conversation_type = 20; +pub const conversation_type_CONVERSATION_X25: conversation_type = 21; +pub const conversation_type_CONVERSATION_IAX2: conversation_type = 22; +pub const conversation_type_CONVERSATION_DLCI: conversation_type = 23; +pub const conversation_type_CONVERSATION_ISUP: conversation_type = 24; +pub const conversation_type_CONVERSATION_BICC: conversation_type = 25; +pub const conversation_type_CONVERSATION_GSMTAP: conversation_type = 26; +pub const conversation_type_CONVERSATION_IUUP: conversation_type = 27; +pub const conversation_type_CONVERSATION_DVBBBF: conversation_type = 28; +pub const conversation_type_CONVERSATION_IWARP_MPA: conversation_type = 29; +pub const conversation_type_CONVERSATION_BT_UTP: conversation_type = 30; +pub const conversation_type_CONVERSATION_LOG: conversation_type = 31; +pub const conversation_type_CONVERSATION_LTP: conversation_type = 32; +pub const conversation_type_CONVERSATION_MCTP: conversation_type = 33; +pub const conversation_type_CONVERSATION_NVME_MI: conversation_type = 34; +pub const conversation_type_CONVERSATION_BP: conversation_type = 35; +pub const conversation_type_CONVERSATION_SNMP: conversation_type = 36; +pub const conversation_type_CONVERSATION_QUIC: conversation_type = 37; +pub const conversation_type_CONVERSATION_IDN: conversation_type = 38; +pub type conversation_type = ::std::os::raw::c_uint; +#[doc = " Elements used to identify conversations for *_full routines and\n pinfo->conv_elements.\n Arrays must be terminated with an element .type set to CE_CONVERSATION_TYPE.\n\n This is currently set only by conversation_set_elements_by_id(); it\n is not set for conversations identified by address/port endpoints.\n\n In find_conversation_pinfo() and find_or_create_conversation(), if\n any dissector has set this, then, unless some dissector has set the\n pair of address/port endpoints (see below), the array of elements\n is used to look up or create the conversation. Otherwise, the\n current addresses and ports in the packet_info structure are used.\n\n XXX - is there any reason why we shouldn't use an array of conversation\n elements, with the appropriate addresses and ports, and set it for\n all protocols that use conversations specified by a pair of address/port\n endpoints? That might simplify find_conversation_pinfo() by having\n them always use the array of elements if it's present, and just fail if\n it's not."] +#[repr(C)] +#[repr(align(8))] +#[derive(Debug, Copy, Clone)] +pub struct conversation_element { + pub _bindgen_opaque_blob: [u64; 4usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union conversation_element__bindgen_ty_1 { + pub conversation_type_val: conversation_type, + pub addr_val: address, + pub port_val: ::std::os::raw::c_uint, + pub str_val: *const ::std::os::raw::c_char, + pub uint_val: ::std::os::raw::c_uint, + pub uint64_val: u64, + pub int_val: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_conversation_element__bindgen_ty_1() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 24usize, + concat!("Size of: ", stringify!(conversation_element__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!( + "Alignment of ", + stringify!(conversation_element__bindgen_ty_1) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).conversation_type_val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation_element__bindgen_ty_1), + "::", + stringify!(conversation_type_val) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).addr_val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation_element__bindgen_ty_1), + "::", + stringify!(addr_val) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).port_val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation_element__bindgen_ty_1), + "::", + stringify!(port_val) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).str_val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation_element__bindgen_ty_1), + "::", + stringify!(str_val) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).uint_val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation_element__bindgen_ty_1), + "::", + stringify!(uint_val) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).uint64_val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation_element__bindgen_ty_1), + "::", + stringify!(uint64_val) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).int_val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation_element__bindgen_ty_1), + "::", + stringify!(int_val) + ) + ); +} +#[test] +fn bindgen_test_layout_conversation_element() { + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(conversation_element)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(conversation_element)) + ); +} +#[doc = " Elements used to identify conversations for *_full routines and\n pinfo->conv_elements.\n Arrays must be terminated with an element .type set to CE_CONVERSATION_TYPE.\n\n This is currently set only by conversation_set_elements_by_id(); it\n is not set for conversations identified by address/port endpoints.\n\n In find_conversation_pinfo() and find_or_create_conversation(), if\n any dissector has set this, then, unless some dissector has set the\n pair of address/port endpoints (see below), the array of elements\n is used to look up or create the conversation. Otherwise, the\n current addresses and ports in the packet_info structure are used.\n\n XXX - is there any reason why we shouldn't use an array of conversation\n elements, with the appropriate addresses and ports, and set it for\n all protocols that use conversations specified by a pair of address/port\n endpoints? That might simplify find_conversation_pinfo() by having\n them always use the array of elements if it's present, and just fail if\n it's not."] +pub type conversation_element_t = conversation_element; +#[doc = " Data structure representing a conversation."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct conversation { + pub next: *mut conversation, + #[doc = " pointer to next conversation on hash chain"] + pub last: *mut conversation, + #[doc = " pointer to the last conversation on hash chain"] + pub latest_found: *mut conversation, + #[doc = " pointer to the last conversation on hash chain"] + pub conv_index: guint32, + #[doc = " unique ID for conversation"] + pub setup_frame: guint32, + #[doc = " frame number that setup this conversation"] + pub last_frame: guint32, + #[doc = " highest frame number in this conversation"] + pub data_list: *mut wmem_tree_t, + #[doc = " list of data associated with conversation"] + pub dissector_tree: *mut wmem_tree_t, + #[doc = " tree containing protocol dissector client associated with conversation"] + pub options: guint, + #[doc = " wildcard flags"] + pub key_ptr: *mut conversation_element_t, +} +#[test] +fn bindgen_test_layout_conversation() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 72usize, + concat!("Size of: ", stringify!(conversation)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(conversation)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).next) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation), + "::", + stringify!(next) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).last) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(conversation), + "::", + stringify!(last) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).latest_found) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(conversation), + "::", + stringify!(latest_found) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).conv_index) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(conversation), + "::", + stringify!(conv_index) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).setup_frame) as usize - ptr as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(conversation), + "::", + stringify!(setup_frame) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).last_frame) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(conversation), + "::", + stringify!(last_frame) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data_list) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(conversation), + "::", + stringify!(data_list) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).dissector_tree) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(conversation), + "::", + stringify!(dissector_tree) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).options) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(conversation), + "::", + stringify!(options) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).key_ptr) as usize - ptr as usize }, + 64usize, + concat!( + "Offset of field: ", + stringify!(conversation), + "::", + stringify!(key_ptr) + ) + ); +} +#[doc = " Data structure representing a conversation."] +pub type conversation_t = conversation; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct conversation_addr_port_endpoints { + _unused: [u8; 0], +} +extern "C" { + #[doc = " A helper function that calls find_conversation() and, if a conversation is\n not found, calls conversation_new().\n The frame number and addresses are taken from pinfo.\n No options are used, though we could extend this API to include an options\n parameter.\n\n @param pinfo Packet info.\n @return The existing or new conversation."] + pub fn find_or_create_conversation(pinfo: *mut packet_info) -> *mut conversation_t; +} +extern "C" { + pub fn conversation_set_dissector( + conversation: *mut conversation_t, + handle: dissector_handle_t, + ); +} +pub type __builtin_va_list = [__va_list_tag; 1usize]; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __va_list_tag { + pub gp_offset: ::std::os::raw::c_uint, + pub fp_offset: ::std::os::raw::c_uint, + pub overflow_arg_area: *mut ::std::os::raw::c_void, + pub reg_save_area: *mut ::std::os::raw::c_void, +} +#[test] +fn bindgen_test_layout___va_list_tag() { + const UNINIT: ::std::mem::MaybeUninit<__va_list_tag> = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<__va_list_tag>(), + 24usize, + concat!("Size of: ", stringify!(__va_list_tag)) + ); + assert_eq!( + ::std::mem::align_of::<__va_list_tag>(), + 8usize, + concat!("Alignment of ", stringify!(__va_list_tag)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).gp_offset) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__va_list_tag), + "::", + stringify!(gp_offset) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).fp_offset) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(__va_list_tag), + "::", + stringify!(fp_offset) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).overflow_arg_area) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__va_list_tag), + "::", + stringify!(overflow_arg_area) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).reg_save_area) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__va_list_tag), + "::", + stringify!(reg_save_area) + ) + ); +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union wtap_pseudo_header { + pub _address: u8, +} diff --git a/dc/wireshark/src/wireshark_sys/minimal.rs b/dc/wireshark/src/wireshark_sys/minimal.rs new file mode 100644 index 0000000000..3d394a9571 --- /dev/null +++ b/dc/wireshark/src/wireshark_sys/minimal.rs @@ -0,0 +1,1531 @@ +/* automatically generated by rust-bindgen 0.69.4 */ + +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct __BindgenBitfieldUnit { + storage: Storage, +} +impl __BindgenBitfieldUnit { + #[inline] + pub const fn new(storage: Storage) -> Self { + Self { storage } + } +} +impl __BindgenBitfieldUnit +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + #[inline] + pub fn get_bit(&self, index: usize) -> bool { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = self.storage.as_ref()[byte_index]; + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + byte & mask == mask + } + #[inline] + pub fn set_bit(&mut self, index: usize, val: bool) { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = &mut self.storage.as_mut()[byte_index]; + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + if val { + *byte |= mask; + } else { + *byte &= !mask; + } + } + #[inline] + pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + let mut val = 0; + for i in 0..(bit_width as usize) { + if self.get_bit(i + bit_offset) { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + val + } + #[inline] + pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + for i in 0..(bit_width as usize) { + let mask = 1 << i; + let val_bit_is_set = val & mask == mask; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + self.set_bit(index + bit_offset, val_bit_is_set); + } + } +} +pub const DESEGMENT_ONE_MORE_SEGMENT: u32 = 268435455; +pub const DESEGMENT_UNTIL_FIN: u32 = 268435454; +pub const ENC_BIG_ENDIAN: u32 = 0; +pub type __time_t = ::std::os::raw::c_long; +pub type guint8 = ::std::os::raw::c_uchar; +pub type gint16 = ::std::os::raw::c_short; +pub type guint16 = ::std::os::raw::c_ushort; +pub type guint32 = ::std::os::raw::c_uint; +pub type guint64 = ::std::os::raw::c_ulong; +pub type time_t = __time_t; +pub type gchar = ::std::os::raw::c_char; +pub type gint = ::std::os::raw::c_int; +pub type gboolean = gint; +pub type guint = ::std::os::raw::c_uint; +pub type GHashTable = u8; +pub type GSList = [u64; 2usize]; +#[doc = " @defgroup wmem Wireshark Memory Manager\n\n Wmem is a memory management framework for Wireshark that makes it simple to\n write dissectors (and other 'user-space' code) that doesn't leak memory. The\n core module provides basic functions like malloc, realloc and free, but\n many other functions are available (see the \"Modules\" list at the top of\n the generated doxygen HTML).\n\n Any wmem functions which allocate memory are guaranteed to either succeed or\n abort the program. However, they *can* still legally return NULL when the\n amount of requested memory is zero.\n\n @{"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _wmem_allocator_t { + _unused: [u8; 0], +} +#[doc = " A public opaque type representing one wmem allocation pool."] +pub type wmem_allocator_t = _wmem_allocator_t; +#[doc = " @addtogroup wmem\n @{\n @defgroup wmem-list Doubly-Linked List\n\n A doubly-linked list implementation on top of wmem.\n\n @{"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _wmem_list_t { + _unused: [u8; 0], +} +pub type wmem_list_t = _wmem_list_t; +#[doc = " @addtogroup wmem\n @{\n @defgroup wmem-map Hash Map\n\n A hash map implementation on top of wmem. Provides insertion, deletion and\n lookup in expected amortized constant time. Uses universal hashing to map\n keys into buckets, and provides a generic strong hash function that makes\n it secure against algorithmic complexity attacks, and suitable for use\n even with untrusted data.\n\n @{"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _wmem_map_t { + _unused: [u8; 0], +} +pub type wmem_map_t = _wmem_map_t; +#[doc = " data structure to hold time values with nanosecond resolution"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nstime_t { + pub secs: time_t, + pub nsecs: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_nstime_t() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(nstime_t)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(nstime_t)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).secs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(nstime_t), + "::", + stringify!(secs) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).nsecs) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(nstime_t), + "::", + stringify!(nsecs) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct wtap_rec { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct epan_session { + _unused: [u8; 0], +} +pub type frame_data = [u64; 13usize]; +#[doc = " \"testy, virtual(-izable) buffer\". They are testy in that they get mad when\n an attempt is made to access data beyond the bounds of their array. In that\n case, they throw an exception.\n\n They are virtualizable in that new tvbuff's can be made from other tvbuffs,\n while only the original tvbuff may have data. That is, the new tvbuff has\n virtual data."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct tvbuff { + _unused: [u8; 0], +} +pub type tvbuff_t = u8; +pub type address = [u64; 3usize]; +pub const port_type_PT_NONE: port_type = 0; +pub const port_type_PT_SCTP: port_type = 1; +pub const port_type_PT_TCP: port_type = 2; +pub const port_type_PT_UDP: port_type = 3; +pub const port_type_PT_DCCP: port_type = 4; +pub const port_type_PT_IPX: port_type = 5; +pub const port_type_PT_DDP: port_type = 6; +pub const port_type_PT_IDP: port_type = 7; +pub const port_type_PT_USB: port_type = 8; +pub const port_type_PT_I2C: port_type = 9; +pub const port_type_PT_IBQP: port_type = 10; +pub const port_type_PT_BLUETOOTH: port_type = 11; +pub const port_type_PT_IWARP_MPA: port_type = 12; +pub const port_type_PT_MCTP: port_type = 13; +pub type port_type = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _packet_info { + #[doc = "< name of protocol currently being dissected"] + pub current_proto: *const ::std::os::raw::c_char, + #[doc = "< Column formatting information"] + pub cinfo: *mut epan_column_info, + #[doc = "< Presence flags for some items"] + pub presence_flags: guint32, + #[doc = "< Frame number"] + pub num: guint32, + #[doc = "< Packet absolute time stamp"] + pub abs_ts: nstime_t, + #[doc = "< Relative timestamp (yes, it can be negative)"] + pub rel_ts: nstime_t, + #[doc = "< Relative timestamp from capture start (might be negative for broken files)"] + pub rel_cap_ts: nstime_t, + #[doc = "< Relative timestamp from capture start valid"] + pub rel_cap_ts_present: gboolean, + pub fd: *mut frame_data, + pub pseudo_header: *mut wtap_pseudo_header, + #[doc = "< Record metadata"] + pub rec: *mut wtap_rec, + #[doc = "< Frame data sources"] + pub data_src: *mut GSList, + #[doc = "< link-layer source address"] + pub dl_src: address, + #[doc = "< link-layer destination address"] + pub dl_dst: address, + #[doc = "< network-layer source address"] + pub net_src: address, + #[doc = "< network-layer destination address"] + pub net_dst: address, + #[doc = "< source address (net if present, DL otherwise )"] + pub src: address, + #[doc = "< destination address (net if present, DL otherwise )"] + pub dst: address, + #[doc = "< First encountered VLAN Id if present otherwise 0"] + pub vlan_id: guint32, + #[doc = "< reason why reassembly wasn't done, if any"] + pub noreassembly_reason: *const ::std::os::raw::c_char, + #[doc = "< TRUE if the protocol is only a fragment"] + pub fragmented: gboolean, + pub flags: _packet_info__bindgen_ty_1, + #[doc = "< type of the following two port numbers"] + pub ptype: port_type, + #[doc = "< source port"] + pub srcport: guint32, + #[doc = "< destination port"] + pub destport: guint32, + #[doc = "< matched uint for calling subdissector from table"] + pub match_uint: guint32, + #[doc = "< matched string for calling subdissector from table"] + pub match_string: *const ::std::os::raw::c_char, + #[doc = "< TRUE if address/port endpoints member should be used for conversations"] + pub use_conv_addr_port_endpoints: gboolean, + #[doc = "< Data that can be used for address+port conversations, including wildcarding"] + pub conv_addr_port_endpoints: *mut conversation_addr_port_endpoints, + #[doc = "< Arbritrary conversation identifier; can't be wildcarded"] + pub conv_elements: *mut conversation_element, + #[doc = "< >0 if this segment could be desegmented.\nA dissector that can offer this API (e.g.\nTCP) sets can_desegment=2, then\ncan_desegment is decremented by 1 each time\nwe pass to the next subdissector. Thus only\nthe dissector immediately above the\nprotocol which sets the flag can use it"] + pub can_desegment: guint16, + #[doc = "< Value of can_desegment before current\ndissector was called. Supplied so that\ndissectors for proxy protocols such as\nSOCKS can restore it, allowing the\ndissectors that they call to use the\nTCP dissector's desegmentation (SOCKS\njust retransmits TCP segments once it's\nfinished setting things up, so the TCP\ndesegmentor can desegment its payload)."] + pub saved_can_desegment: guint16, + #[doc = "< offset to stuff needing desegmentation"] + pub desegment_offset: ::std::os::raw::c_int, + #[doc = "< requested desegmentation additional length\nor\nDESEGMENT_ONE_MORE_SEGMENT:\nDesegment one more full segment\n(warning! only partially implemented)\nDESEGMENT_UNTIL_FIN:\nDesgment all data for this tcp session\nuntil the FIN segment."] + pub desegment_len: guint32, + #[doc = "< >0 if the subdissector has specified\na value in 'bytes_until_next_pdu'.\nWhen a dissector detects that the next PDU\nwill start beyond the start of the next\nsegment, it can set this value to 2\nand 'bytes_until_next_pdu' to the number of\nbytes beyond the next segment where the\nnext PDU starts.\n\nIf the protocol dissector below this\none is capable of PDU tracking it can\nuse this hint to detect PDUs that starts\nunaligned to the segment boundaries.\nThe TCP dissector is using this hint from\n(some) protocols to detect when a new PDU\nstarts in the middle of a tcp segment.\n\nThere is intelligence in the glue between\ndissector layers to make sure that this\nrequest is only passed down to the protocol\nimmediately below the current one and not\nany further."] + pub want_pdu_tracking: guint16, + pub bytes_until_next_pdu: guint32, + #[doc = "< Packet was captured as an\noutbound (P2P_DIR_SENT)\ninbound (P2P_DIR_RECV)\nunknown (P2P_DIR_UNKNOWN)"] + pub p2p_dir: ::std::os::raw::c_int, + #[doc = "< a hash table passed from one dissector to another"] + pub private_table: *mut GHashTable, + #[doc = "< layers of each protocol"] + pub layers: *mut wmem_list_t, + pub proto_layers: *mut wmem_map_t, + #[doc = "< The current \"depth\" or layer number in the current frame"] + pub curr_layer_num: guint8, + #[doc = "< The current \"depth\" or layer number for this dissector in the current frame"] + pub curr_proto_layer_num: guint8, + pub link_number: guint16, + #[doc = "< clnp/cotp source reference (can't use srcport, this would confuse tpkt)"] + pub clnp_srcref: guint16, + #[doc = "< clnp/cotp destination reference (can't use dstport, this would confuse tpkt)"] + pub clnp_dstref: guint16, + #[doc = "< 3GPP messages are sometime different UP link(UL) or Downlink(DL)"] + pub link_dir: ::std::os::raw::c_int, + #[doc = "< Rcv.Wind.Shift src applies when sending segments; -1 unknown; -2 disabled"] + pub src_win_scale: gint16, + #[doc = "< Rcv.Wind.Shift dst applies when sending segments; -1 unknown; -2 disabled"] + pub dst_win_scale: gint16, + #[doc = "< Per packet proto data"] + pub proto_data: *mut GSList, + pub frame_end_routines: *mut GSList, + #[doc = "< Memory pool scoped to the pinfo struct"] + pub pool: *mut wmem_allocator_t, + pub epan: *mut epan_session, + #[doc = "< name of heur list if this packet is being heuristically dissected"] + pub heur_list_name: *const gchar, + #[doc = "< The current \"depth\" or layer number in the current frame"] + pub dissection_depth: ::std::os::raw::c_int, +} +#[repr(C)] +#[repr(align(4))] +#[derive(Debug, Copy, Clone)] +pub struct _packet_info__bindgen_ty_1 { + pub _bitfield_align_1: [u8; 0], + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, + pub __bindgen_padding_0: [u8; 3usize], +} +#[test] +fn bindgen_test_layout__packet_info__bindgen_ty_1() { + assert_eq!( + ::std::mem::size_of::<_packet_info__bindgen_ty_1>(), + 4usize, + concat!("Size of: ", stringify!(_packet_info__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::<_packet_info__bindgen_ty_1>(), + 4usize, + concat!("Alignment of ", stringify!(_packet_info__bindgen_ty_1)) + ); +} +impl _packet_info__bindgen_ty_1 { + #[inline] + pub fn in_error_pkt(&self) -> guint32 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u32) } + } + #[inline] + pub fn set_in_error_pkt(&mut self, val: guint32) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 1u8, val as u64) + } + } + #[inline] + pub fn in_gre_pkt(&self) -> guint32 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(1usize, 1u8) as u32) } + } + #[inline] + pub fn set_in_gre_pkt(&mut self, val: guint32) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(1usize, 1u8, val as u64) + } + } + #[inline] + pub fn new_bitfield_1( + in_error_pkt: guint32, + in_gre_pkt: guint32, + ) -> __BindgenBitfieldUnit<[u8; 1usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = Default::default(); + __bindgen_bitfield_unit.set(0usize, 1u8, { + let in_error_pkt: u32 = unsafe { ::std::mem::transmute(in_error_pkt) }; + in_error_pkt as u64 + }); + __bindgen_bitfield_unit.set(1usize, 1u8, { + let in_gre_pkt: u32 = unsafe { ::std::mem::transmute(in_gre_pkt) }; + in_gre_pkt as u64 + }); + __bindgen_bitfield_unit + } +} +#[test] +fn bindgen_test_layout__packet_info() { + const UNINIT: ::std::mem::MaybeUninit<_packet_info> = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<_packet_info>(), + 440usize, + concat!("Size of: ", stringify!(_packet_info)) + ); + assert_eq!( + ::std::mem::align_of::<_packet_info>(), + 8usize, + concat!("Alignment of ", stringify!(_packet_info)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).current_proto) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(current_proto) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).cinfo) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(cinfo) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).presence_flags) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(presence_flags) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).num) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(num) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).abs_ts) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(abs_ts) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rel_ts) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(rel_ts) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rel_cap_ts) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(rel_cap_ts) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rel_cap_ts_present) as usize - ptr as usize }, + 72usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(rel_cap_ts_present) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, + 80usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(fd) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).pseudo_header) as usize - ptr as usize }, + 88usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(pseudo_header) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rec) as usize - ptr as usize }, + 96usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(rec) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data_src) as usize - ptr as usize }, + 104usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(data_src) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).dl_src) as usize - ptr as usize }, + 112usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(dl_src) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).dl_dst) as usize - ptr as usize }, + 136usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(dl_dst) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).net_src) as usize - ptr as usize }, + 160usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(net_src) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).net_dst) as usize - ptr as usize }, + 184usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(net_dst) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).src) as usize - ptr as usize }, + 208usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(src) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).dst) as usize - ptr as usize }, + 232usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(dst) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).vlan_id) as usize - ptr as usize }, + 256usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(vlan_id) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).noreassembly_reason) as usize - ptr as usize }, + 264usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(noreassembly_reason) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).fragmented) as usize - ptr as usize }, + 272usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(fragmented) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 276usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(flags) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).ptype) as usize - ptr as usize }, + 280usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(ptype) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).srcport) as usize - ptr as usize }, + 284usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(srcport) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).destport) as usize - ptr as usize }, + 288usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(destport) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).match_uint) as usize - ptr as usize }, + 292usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(match_uint) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).match_string) as usize - ptr as usize }, + 296usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(match_string) + ) + ); + assert_eq!( + unsafe { + ::std::ptr::addr_of!((*ptr).use_conv_addr_port_endpoints) as usize - ptr as usize + }, + 304usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(use_conv_addr_port_endpoints) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).conv_addr_port_endpoints) as usize - ptr as usize }, + 312usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(conv_addr_port_endpoints) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).conv_elements) as usize - ptr as usize }, + 320usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(conv_elements) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).can_desegment) as usize - ptr as usize }, + 328usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(can_desegment) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).saved_can_desegment) as usize - ptr as usize }, + 330usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(saved_can_desegment) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).desegment_offset) as usize - ptr as usize }, + 332usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(desegment_offset) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).desegment_len) as usize - ptr as usize }, + 336usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(desegment_len) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).want_pdu_tracking) as usize - ptr as usize }, + 340usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(want_pdu_tracking) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).bytes_until_next_pdu) as usize - ptr as usize }, + 344usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(bytes_until_next_pdu) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).p2p_dir) as usize - ptr as usize }, + 348usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(p2p_dir) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).private_table) as usize - ptr as usize }, + 352usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(private_table) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).layers) as usize - ptr as usize }, + 360usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(layers) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).proto_layers) as usize - ptr as usize }, + 368usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(proto_layers) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).curr_layer_num) as usize - ptr as usize }, + 376usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(curr_layer_num) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).curr_proto_layer_num) as usize - ptr as usize }, + 377usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(curr_proto_layer_num) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).link_number) as usize - ptr as usize }, + 378usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(link_number) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).clnp_srcref) as usize - ptr as usize }, + 380usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(clnp_srcref) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).clnp_dstref) as usize - ptr as usize }, + 382usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(clnp_dstref) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).link_dir) as usize - ptr as usize }, + 384usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(link_dir) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).src_win_scale) as usize - ptr as usize }, + 388usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(src_win_scale) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).dst_win_scale) as usize - ptr as usize }, + 390usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(dst_win_scale) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).proto_data) as usize - ptr as usize }, + 392usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(proto_data) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).frame_end_routines) as usize - ptr as usize }, + 400usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(frame_end_routines) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).pool) as usize - ptr as usize }, + 408usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(pool) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).epan) as usize - ptr as usize }, + 416usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(epan) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).heur_list_name) as usize - ptr as usize }, + 424usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(heur_list_name) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).dissection_depth) as usize - ptr as usize }, + 432usize, + concat!( + "Offset of field: ", + stringify!(_packet_info), + "::", + stringify!(dissection_depth) + ) + ); +} +pub const ftenum_FT_NONE: ftenum = 0; +pub const ftenum_FT_PROTOCOL: ftenum = 1; +pub const ftenum_FT_BOOLEAN: ftenum = 2; +pub const ftenum_FT_CHAR: ftenum = 3; +pub const ftenum_FT_UINT8: ftenum = 4; +pub const ftenum_FT_UINT16: ftenum = 5; +pub const ftenum_FT_UINT24: ftenum = 6; +pub const ftenum_FT_UINT32: ftenum = 7; +pub const ftenum_FT_UINT40: ftenum = 8; +pub const ftenum_FT_UINT48: ftenum = 9; +pub const ftenum_FT_UINT56: ftenum = 10; +pub const ftenum_FT_UINT64: ftenum = 11; +pub const ftenum_FT_INT8: ftenum = 12; +pub const ftenum_FT_INT16: ftenum = 13; +pub const ftenum_FT_INT24: ftenum = 14; +pub const ftenum_FT_INT32: ftenum = 15; +pub const ftenum_FT_INT40: ftenum = 16; +pub const ftenum_FT_INT48: ftenum = 17; +pub const ftenum_FT_INT56: ftenum = 18; +pub const ftenum_FT_INT64: ftenum = 19; +pub const ftenum_FT_IEEE_11073_SFLOAT: ftenum = 20; +pub const ftenum_FT_IEEE_11073_FLOAT: ftenum = 21; +pub const ftenum_FT_FLOAT: ftenum = 22; +pub const ftenum_FT_DOUBLE: ftenum = 23; +pub const ftenum_FT_ABSOLUTE_TIME: ftenum = 24; +pub const ftenum_FT_RELATIVE_TIME: ftenum = 25; +pub const ftenum_FT_STRING: ftenum = 26; +pub const ftenum_FT_STRINGZ: ftenum = 27; +pub const ftenum_FT_UINT_STRING: ftenum = 28; +pub const ftenum_FT_ETHER: ftenum = 29; +pub const ftenum_FT_BYTES: ftenum = 30; +pub const ftenum_FT_UINT_BYTES: ftenum = 31; +pub const ftenum_FT_IPv4: ftenum = 32; +pub const ftenum_FT_IPv6: ftenum = 33; +pub const ftenum_FT_IPXNET: ftenum = 34; +pub const ftenum_FT_FRAMENUM: ftenum = 35; +pub const ftenum_FT_GUID: ftenum = 36; +pub const ftenum_FT_OID: ftenum = 37; +pub const ftenum_FT_EUI64: ftenum = 38; +pub const ftenum_FT_AX25: ftenum = 39; +pub const ftenum_FT_VINES: ftenum = 40; +pub const ftenum_FT_REL_OID: ftenum = 41; +pub const ftenum_FT_SYSTEM_ID: ftenum = 42; +pub const ftenum_FT_STRINGZPAD: ftenum = 43; +pub const ftenum_FT_FCWWN: ftenum = 44; +pub const ftenum_FT_STRINGZTRUNC: ftenum = 45; +pub const ftenum_FT_NUM_TYPES: ftenum = 46; +pub type ftenum = ::std::os::raw::c_uint; +pub use self::ftenum as ftenum_t; +#[doc = "< none"] +pub const field_display_e_BASE_NONE: field_display_e = 0; +#[doc = "< decimal [integer, float]"] +pub const field_display_e_BASE_DEC: field_display_e = 1; +#[doc = "< hexadecimal [integer, float]"] +pub const field_display_e_BASE_HEX: field_display_e = 2; +#[doc = "< octal [integer]"] +pub const field_display_e_BASE_OCT: field_display_e = 3; +#[doc = "< decimal (hexadecimal) [integer]"] +pub const field_display_e_BASE_DEC_HEX: field_display_e = 4; +#[doc = "< hexadecimal (decimal) [integer]"] +pub const field_display_e_BASE_HEX_DEC: field_display_e = 5; +#[doc = "< call custom routine to format [integer, float]"] +pub const field_display_e_BASE_CUSTOM: field_display_e = 6; +#[doc = "< exponential [float]"] +pub const field_display_e_BASE_EXP: field_display_e = 7; +#[doc = "< hexadecimal bytes with a period (.) between each byte"] +pub const field_display_e_SEP_DOT: field_display_e = 8; +#[doc = "< hexadecimal bytes with a dash (-) between each byte"] +pub const field_display_e_SEP_DASH: field_display_e = 9; +#[doc = "< hexadecimal bytes with a colon (:) between each byte"] +pub const field_display_e_SEP_COLON: field_display_e = 10; +#[doc = "< hexadecimal bytes with a space between each byte"] +pub const field_display_e_SEP_SPACE: field_display_e = 11; +#[doc = "< Used for IPv4 address that shouldn't be resolved (like for netmasks)"] +pub const field_display_e_BASE_NETMASK: field_display_e = 12; +#[doc = "< UDP port"] +pub const field_display_e_BASE_PT_UDP: field_display_e = 13; +#[doc = "< TCP port"] +pub const field_display_e_BASE_PT_TCP: field_display_e = 14; +#[doc = "< DCCP port"] +pub const field_display_e_BASE_PT_DCCP: field_display_e = 15; +#[doc = "< SCTP port"] +pub const field_display_e_BASE_PT_SCTP: field_display_e = 16; +#[doc = "< OUI resolution"] +pub const field_display_e_BASE_OUI: field_display_e = 17; +#[doc = "< local time in our time zone, with month and day"] +pub const field_display_e_ABSOLUTE_TIME_LOCAL: field_display_e = 18; +#[doc = "< UTC, with month and day"] +pub const field_display_e_ABSOLUTE_TIME_UTC: field_display_e = 19; +#[doc = "< UTC, with 1-origin day-of-year"] +pub const field_display_e_ABSOLUTE_TIME_DOY_UTC: field_display_e = 20; +#[doc = "< UTC, with \"NULL\" when timestamp is all zeros"] +pub const field_display_e_ABSOLUTE_TIME_NTP_UTC: field_display_e = 21; +#[doc = "< Unix time"] +pub const field_display_e_ABSOLUTE_TIME_UNIX: field_display_e = 22; +#[doc = "< Replace all whitespace characters (newline, formfeed, etc) with \"space\"."] +pub const field_display_e_BASE_STR_WSP: field_display_e = 23; +pub type field_display_e = ::std::os::raw::c_uint; +#[doc = "< Field is not referenced"] +pub const hf_ref_type_HF_REF_TYPE_NONE: hf_ref_type = 0; +#[doc = "< Field is indirectly referenced (only applicable for FT_PROTOCOL) via. its child"] +pub const hf_ref_type_HF_REF_TYPE_INDIRECT: hf_ref_type = 1; +#[doc = "< Field is directly referenced"] +pub const hf_ref_type_HF_REF_TYPE_DIRECT: hf_ref_type = 2; +pub type hf_ref_type = ::std::os::raw::c_uint; +#[doc = " information describing a header field"] +pub type header_field_info = _header_field_info; +#[doc = " information describing a header field"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _header_field_info { + #[doc = "< [FIELDNAME] full name of this field"] + pub name: *const ::std::os::raw::c_char, + #[doc = "< [FIELDFILTERNAME] filter name of this field"] + pub abbrev: *const ::std::os::raw::c_char, + #[doc = "< [FIELDTYPE] field type, one of FT_ (from ftypes.h)"] + pub type_: ftenum, + #[doc = "< [FIELDDISPLAY] one of BASE_, or field bit-width if FT_BOOLEAN and non-zero bitmask"] + pub display: ::std::os::raw::c_int, + #[doc = "< [FIELDCONVERT] value_string, val64_string, range_string or true_false_string,\ntypically converted by VALS(), RVALS() or TFS().\nIf this is an FT_PROTOCOL or BASE_PROTOCOL_INFO then it points to the\nassociated protocol_t structure"] + pub strings: *const ::std::os::raw::c_void, + #[doc = "< [BITMASK] bitmask of interesting bits"] + pub bitmask: guint64, + #[doc = "< [FIELDDESCR] Brief description of field"] + pub blurb: *const ::std::os::raw::c_char, + #[doc = "< Field ID"] + pub id: ::std::os::raw::c_int, + #[doc = "< parent protocol tree"] + pub parent: ::std::os::raw::c_int, + #[doc = "< is this field referenced by a filter"] + pub ref_type: hf_ref_type, + #[doc = "< ID of previous hfinfo with same abbrev"] + pub same_name_prev_id: ::std::os::raw::c_int, + #[doc = "< Link to next hfinfo with same abbrev"] + pub same_name_next: *mut header_field_info, +} +#[test] +fn bindgen_test_layout__header_field_info() { + const UNINIT: ::std::mem::MaybeUninit<_header_field_info> = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::<_header_field_info>(), + 72usize, + concat!("Size of: ", stringify!(_header_field_info)) + ); + assert_eq!( + ::std::mem::align_of::<_header_field_info>(), + 8usize, + concat!("Alignment of ", stringify!(_header_field_info)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).name) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(name) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).abbrev) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(abbrev) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(type_) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).display) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(display) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).strings) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(strings) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).bitmask) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(bitmask) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).blurb) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(blurb) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).id) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(id) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).parent) as usize - ptr as usize }, + 52usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(parent) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).ref_type) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(ref_type) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).same_name_prev_id) as usize - ptr as usize }, + 60usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(same_name_prev_id) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).same_name_next) as usize - ptr as usize }, + 64usize, + concat!( + "Offset of field: ", + stringify!(_header_field_info), + "::", + stringify!(same_name_next) + ) + ); +} +#[doc = " Each proto_tree, proto_item is one of these."] +#[repr(C)] +#[repr(align(8))] +#[derive(Debug, Copy, Clone)] +pub struct _proto_node { + pub _bindgen_opaque_blob: [u64; 6usize], +} +#[test] +fn bindgen_test_layout__proto_node() { + assert_eq!( + ::std::mem::size_of::<_proto_node>(), + 48usize, + concat!("Size of: ", stringify!(_proto_node)) + ); + assert_eq!( + ::std::mem::align_of::<_proto_node>(), + 8usize, + concat!("Alignment of ", stringify!(_proto_node)) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct proto_plugin { + pub register_protoinfo: ::std::option::Option, + pub register_handoff: ::std::option::Option, +} +#[test] +fn bindgen_test_layout_proto_plugin() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(proto_plugin)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(proto_plugin)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).register_protoinfo) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(proto_plugin), + "::", + stringify!(register_protoinfo) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).register_handoff) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(proto_plugin), + "::", + stringify!(register_handoff) + ) + ); +} +#[doc = " Helper routines for column utility structures and routines."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct epan_column_info { + _unused: [u8; 0], +} +#[doc = "< 0) Absolute date, as YYYY-MM-DD, and time"] +pub const COL_ABS_YMD_TIME: _bindgen_ty_21 = 0; +#[doc = "< 1) Absolute date, as YYYY/DOY, and time"] +pub const COL_ABS_YDOY_TIME: _bindgen_ty_21 = 1; +#[doc = "< 2) Absolute time"] +pub const COL_ABS_TIME: _bindgen_ty_21 = 2; +#[doc = "< 3) Cumulative number of bytes"] +pub const COL_CUMULATIVE_BYTES: _bindgen_ty_21 = 3; +#[doc = "< 4) Custom column (any filter name's contents)"] +pub const COL_CUSTOM: _bindgen_ty_21 = 4; +#[doc = "< 5) Delta time"] +pub const COL_DELTA_TIME: _bindgen_ty_21 = 5; +#[doc = "< 6) Delta time displayed"] +pub const COL_DELTA_TIME_DIS: _bindgen_ty_21 = 6; +#[doc = "< 7) Resolved dest"] +pub const COL_RES_DST: _bindgen_ty_21 = 7; +#[doc = "< 8) Unresolved dest"] +pub const COL_UNRES_DST: _bindgen_ty_21 = 8; +#[doc = "< 9) Resolved dest port"] +pub const COL_RES_DST_PORT: _bindgen_ty_21 = 9; +#[doc = "< 10) Unresolved dest port"] +pub const COL_UNRES_DST_PORT: _bindgen_ty_21 = 10; +#[doc = "< 11) Destination address"] +pub const COL_DEF_DST: _bindgen_ty_21 = 11; +#[doc = "< 12) Destination port"] +pub const COL_DEF_DST_PORT: _bindgen_ty_21 = 12; +#[doc = "< 13) Expert Info"] +pub const COL_EXPERT: _bindgen_ty_21 = 13; +#[doc = "< 14) FW-1 monitor interface/direction"] +pub const COL_IF_DIR: _bindgen_ty_21 = 14; +#[doc = "< 15) IEEE 802.11 (and WiMax?) - Channel"] +pub const COL_FREQ_CHAN: _bindgen_ty_21 = 15; +#[doc = "< 16) Data link layer dest address"] +pub const COL_DEF_DL_DST: _bindgen_ty_21 = 16; +#[doc = "< 17) Data link layer source address"] +pub const COL_DEF_DL_SRC: _bindgen_ty_21 = 17; +#[doc = "< 18) Resolved DL dest"] +pub const COL_RES_DL_DST: _bindgen_ty_21 = 18; +#[doc = "< 19) Unresolved DL dest"] +pub const COL_UNRES_DL_DST: _bindgen_ty_21 = 19; +#[doc = "< 20) Resolved DL source"] +pub const COL_RES_DL_SRC: _bindgen_ty_21 = 20; +#[doc = "< 21) Unresolved DL source"] +pub const COL_UNRES_DL_SRC: _bindgen_ty_21 = 21; +#[doc = "< 22) IEEE 802.11 - received signal strength"] +pub const COL_RSSI: _bindgen_ty_21 = 22; +#[doc = "< 23) IEEE 802.11 - TX rate in Mbps"] +pub const COL_TX_RATE: _bindgen_ty_21 = 23; +#[doc = "< 24) IP DSCP Value"] +pub const COL_DSCP_VALUE: _bindgen_ty_21 = 24; +#[doc = "< 25) Description"] +pub const COL_INFO: _bindgen_ty_21 = 25; +#[doc = "< 26) Resolved net dest"] +pub const COL_RES_NET_DST: _bindgen_ty_21 = 26; +#[doc = "< 27) Unresolved net dest"] +pub const COL_UNRES_NET_DST: _bindgen_ty_21 = 27; +#[doc = "< 28) Resolved net source"] +pub const COL_RES_NET_SRC: _bindgen_ty_21 = 28; +#[doc = "< 29) Unresolved net source"] +pub const COL_UNRES_NET_SRC: _bindgen_ty_21 = 29; +#[doc = "< 30) Network layer dest address"] +pub const COL_DEF_NET_DST: _bindgen_ty_21 = 30; +#[doc = "< 31) Network layer source address"] +pub const COL_DEF_NET_SRC: _bindgen_ty_21 = 31; +#[doc = "< 32) Packet list item number"] +pub const COL_NUMBER: _bindgen_ty_21 = 32; +#[doc = "< 33) Packet length in bytes"] +pub const COL_PACKET_LENGTH: _bindgen_ty_21 = 33; +#[doc = "< 34) Protocol"] +pub const COL_PROTOCOL: _bindgen_ty_21 = 34; +#[doc = "< 35) Relative time"] +pub const COL_REL_TIME: _bindgen_ty_21 = 35; +#[doc = "< 36) Source address"] +pub const COL_DEF_SRC: _bindgen_ty_21 = 36; +#[doc = "< 37) Source port"] +pub const COL_DEF_SRC_PORT: _bindgen_ty_21 = 37; +#[doc = "< 38) Resolved source"] +pub const COL_RES_SRC: _bindgen_ty_21 = 38; +#[doc = "< 39) Unresolved source"] +pub const COL_UNRES_SRC: _bindgen_ty_21 = 39; +#[doc = "< 40) Resolved source port"] +pub const COL_RES_SRC_PORT: _bindgen_ty_21 = 40; +#[doc = "< 41) Unresolved source port"] +pub const COL_UNRES_SRC_PORT: _bindgen_ty_21 = 41; +#[doc = "< 42) UTC date, as YYYY-MM-DD, and time"] +pub const COL_UTC_YMD_TIME: _bindgen_ty_21 = 42; +#[doc = "< 43) UTC date, as YYYY/DOY, and time"] +pub const COL_UTC_YDOY_TIME: _bindgen_ty_21 = 43; +#[doc = "< 44) UTC time"] +pub const COL_UTC_TIME: _bindgen_ty_21 = 44; +#[doc = "< 45) Command line-specified time (default relative)"] +pub const COL_CLS_TIME: _bindgen_ty_21 = 45; +#[doc = "< 46) Should always be last"] +pub const NUM_COL_FMTS: _bindgen_ty_21 = 46; +#[doc = " All of the possible columns in summary listing.\n\n NOTE1: The entries MUST remain in this order, or else you need to reorder\n the slist[] and dlist[] arrays in column.c to match!\n\n NOTE2: Please add the COL_XYZ entry in the appropriate spot, such that the\n dlist[] array remains in alphabetical order!"] +pub type _bindgen_ty_21 = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct dissector_handle { + _unused: [u8; 0], +} +pub type dissector_handle_t = *mut dissector_handle; +pub const conversation_type_CONVERSATION_NONE: conversation_type = 0; +pub const conversation_type_CONVERSATION_SCTP: conversation_type = 1; +pub const conversation_type_CONVERSATION_TCP: conversation_type = 2; +pub const conversation_type_CONVERSATION_UDP: conversation_type = 3; +pub const conversation_type_CONVERSATION_DCCP: conversation_type = 4; +pub const conversation_type_CONVERSATION_IPX: conversation_type = 5; +pub const conversation_type_CONVERSATION_NCP: conversation_type = 6; +pub const conversation_type_CONVERSATION_EXCHG: conversation_type = 7; +pub const conversation_type_CONVERSATION_DDP: conversation_type = 8; +pub const conversation_type_CONVERSATION_SBCCS: conversation_type = 9; +pub const conversation_type_CONVERSATION_IDP: conversation_type = 10; +pub const conversation_type_CONVERSATION_TIPC: conversation_type = 11; +pub const conversation_type_CONVERSATION_USB: conversation_type = 12; +pub const conversation_type_CONVERSATION_I2C: conversation_type = 13; +pub const conversation_type_CONVERSATION_IBQP: conversation_type = 14; +pub const conversation_type_CONVERSATION_BLUETOOTH: conversation_type = 15; +pub const conversation_type_CONVERSATION_TDMOP: conversation_type = 16; +pub const conversation_type_CONVERSATION_DVBCI: conversation_type = 17; +pub const conversation_type_CONVERSATION_ISO14443: conversation_type = 18; +pub const conversation_type_CONVERSATION_ISDN: conversation_type = 19; +pub const conversation_type_CONVERSATION_H223: conversation_type = 20; +pub const conversation_type_CONVERSATION_X25: conversation_type = 21; +pub const conversation_type_CONVERSATION_IAX2: conversation_type = 22; +pub const conversation_type_CONVERSATION_DLCI: conversation_type = 23; +pub const conversation_type_CONVERSATION_ISUP: conversation_type = 24; +pub const conversation_type_CONVERSATION_BICC: conversation_type = 25; +pub const conversation_type_CONVERSATION_GSMTAP: conversation_type = 26; +pub const conversation_type_CONVERSATION_IUUP: conversation_type = 27; +pub const conversation_type_CONVERSATION_DVBBBF: conversation_type = 28; +pub const conversation_type_CONVERSATION_IWARP_MPA: conversation_type = 29; +pub const conversation_type_CONVERSATION_BT_UTP: conversation_type = 30; +pub const conversation_type_CONVERSATION_LOG: conversation_type = 31; +pub const conversation_type_CONVERSATION_LTP: conversation_type = 32; +pub const conversation_type_CONVERSATION_MCTP: conversation_type = 33; +pub const conversation_type_CONVERSATION_NVME_MI: conversation_type = 34; +pub const conversation_type_CONVERSATION_BP: conversation_type = 35; +pub const conversation_type_CONVERSATION_SNMP: conversation_type = 36; +pub const conversation_type_CONVERSATION_QUIC: conversation_type = 37; +pub const conversation_type_CONVERSATION_IDN: conversation_type = 38; +pub type conversation_type = ::std::os::raw::c_uint; +#[doc = " Elements used to identify conversations for *_full routines and\n pinfo->conv_elements.\n Arrays must be terminated with an element .type set to CE_CONVERSATION_TYPE.\n\n This is currently set only by conversation_set_elements_by_id(); it\n is not set for conversations identified by address/port endpoints.\n\n In find_conversation_pinfo() and find_or_create_conversation(), if\n any dissector has set this, then, unless some dissector has set the\n pair of address/port endpoints (see below), the array of elements\n is used to look up or create the conversation. Otherwise, the\n current addresses and ports in the packet_info structure are used.\n\n XXX - is there any reason why we shouldn't use an array of conversation\n elements, with the appropriate addresses and ports, and set it for\n all protocols that use conversations specified by a pair of address/port\n endpoints? That might simplify find_conversation_pinfo() by having\n them always use the array of elements if it's present, and just fail if\n it's not."] +#[repr(C)] +#[repr(align(8))] +#[derive(Debug, Copy, Clone)] +pub struct conversation_element { + pub _bindgen_opaque_blob: [u64; 4usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union conversation_element__bindgen_ty_1 { + pub conversation_type_val: conversation_type, + pub addr_val: address, + pub port_val: ::std::os::raw::c_uint, + pub str_val: *const ::std::os::raw::c_char, + pub uint_val: ::std::os::raw::c_uint, + pub uint64_val: u64, + pub int_val: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_conversation_element__bindgen_ty_1() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 24usize, + concat!("Size of: ", stringify!(conversation_element__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!( + "Alignment of ", + stringify!(conversation_element__bindgen_ty_1) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).conversation_type_val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation_element__bindgen_ty_1), + "::", + stringify!(conversation_type_val) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).addr_val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation_element__bindgen_ty_1), + "::", + stringify!(addr_val) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).port_val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation_element__bindgen_ty_1), + "::", + stringify!(port_val) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).str_val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation_element__bindgen_ty_1), + "::", + stringify!(str_val) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).uint_val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation_element__bindgen_ty_1), + "::", + stringify!(uint_val) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).uint64_val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation_element__bindgen_ty_1), + "::", + stringify!(uint64_val) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).int_val) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(conversation_element__bindgen_ty_1), + "::", + stringify!(int_val) + ) + ); +} +#[test] +fn bindgen_test_layout_conversation_element() { + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(conversation_element)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(conversation_element)) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct conversation_addr_port_endpoints { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union wtap_pseudo_header { + pub _address: u8, +} diff --git a/dc/wireshark/wrapper.h b/dc/wireshark/wrapper.h new file mode 100644 index 0000000000..edb5ec6149 --- /dev/null +++ b/dc/wireshark/wrapper.h @@ -0,0 +1,2 @@ +#include "epan/packet_info.h" +#include "epan/conversation.h" diff --git a/dc/wireshark/xtask/Cargo.toml b/dc/wireshark/xtask/Cargo.toml new file mode 100644 index 0000000000..b0b5d40a1b --- /dev/null +++ b/dc/wireshark/xtask/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "xtask" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +clap = { version = "4", features = ["derive"] } +xshell = "0.2" diff --git a/dc/wireshark/xtask/src/main.rs b/dc/wireshark/xtask/src/main.rs new file mode 100644 index 0000000000..ad3e843adf --- /dev/null +++ b/dc/wireshark/xtask/src/main.rs @@ -0,0 +1,214 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use clap::Parser; +use xshell::{cmd, Shell}; + +type Error = Box; +type Result = core::result::Result; + +#[derive(Debug, Parser)] +enum Args { + Bindings(Bindings), + Build(Build), + Test(Test), + Install(Install), +} + +impl Args { + fn run(self) { + let sh = Shell::new().unwrap(); + match self { + Self::Bindings(v) => v.run(&sh), + Self::Build(v) => v.run(&sh), + Self::Test(v) => v.run(&sh), + Self::Install(v) => v.run(&sh), + } + .unwrap() + } +} + +#[derive(Debug, Parser)] +struct Bindings {} + +impl Bindings { + fn run(self, sh: &Shell) -> Result { + // TODO port this script to rust + cmd!(sh, "./generate-bindings.sh").run()?; + Ok(()) + } +} + +#[derive(Debug, Default, Parser)] +struct Build { + #[arg(long)] + profile: Option, + #[arg(long)] + target: Option, +} + +impl Build { + fn run(self, sh: &Shell) -> Result { + let target = if let Some(target) = self.target.as_ref() { + let _ = cmd!(sh, "rustup target add {target}").run(); + vec!["--target", target] + } else { + vec![] + }; + let profile = self.profile.as_deref().unwrap_or("release"); + cmd!(sh, "cargo build --profile {profile} {target...}").run()?; + Ok(()) + } +} + +#[derive(Debug, Parser)] +struct Test {} + +impl Test { + fn run(self, sh: &Shell) -> Result { + cmd!(sh, "cargo test").run()?; + let plugin_dir = plugin_dir(); + + sh.create_dir(format!("target/wireshark/{plugin_dir}"))?; + sh.create_dir("target/pcaps")?; + + // change the plugin name to avoid conflicts if it's already installed + let plugin_name = "dcQUIC__DEV"; + let plugin_name_lower = &plugin_name.to_lowercase(); + let _env = sh.push_env("PLUGIN_NAME", plugin_name); + + let profile = "release-test"; + + Build { + profile: Some(profile.into()), + ..Default::default() + } + .run(sh)?; + + let so = so(); + sh.copy_file( + format!("target/{profile}/libwireshark_dcquic.{so}"), + // wireshark always looks for `.so` regardless of platform + format!("target/wireshark/{plugin_dir}/lib{plugin_name_lower}.so"), + )?; + + cmd!( + sh, + "cargo run --release --bin generate-pcap -- target/pcaps/" + ) + .run()?; + + let _env = sh.push_env("WIRESHARK_PLUGIN_DIR", "target/wireshark/plugins"); + + let pcaps = [ + // TODO add more + "pcaps/dcquic-stream-tcp.pcapng", + "pcaps/dcquic-stream-udp.pcapng", + // TODO figure out why this isn't parsing as dcQUIC + // "target/pcaps/datagram.pcap", + ]; + + let tshark = tshark(sh)?; + + for pcap in pcaps { + assert!( + std::path::Path::new(pcap).exists(), + "{pcap} is missing - git LFS is required to clone pcaps" + ); + + let cmd = cmd!( + sh, + "{tshark} -r {pcap} -2 -O {plugin_name_lower} -R {plugin_name_lower}" + ); + + let Ok(out) = cmd.output() else { + // if the command failed then re-run it and print it to the console + cmd.run()?; + panic!("tshark did not exit successfully"); + }; + + let stdout = core::str::from_utf8(&out.stdout).unwrap(); + let stderr = core::str::from_utf8(&out.stderr).unwrap(); + + if !stderr.is_empty() { + eprintln!("{pcap} STDERR\n{stderr}"); + // TODO fix the TCP implementation + if !pcap.contains("tcp") { + panic!(); + } + } + + assert!(stdout.contains(plugin_name), "{pcap} STDOUT:\n{stdout}"); + } + + Ok(()) + } +} + +fn tshark(sh: &Shell) -> Result { + if let Ok(tshark) = cmd!(sh, "which tshark").read() { + return Ok(tshark.trim().into()); + } + + if cfg!(target_os = "macos") { + cmd!(sh, "brew install wireshark").run()?; + } else if cfg!(target_os = "linux") { + let is_nix = cmd!(sh, "which nix-shell").run().is_ok(); + if is_nix { + return Ok(cmd!(sh, "nix-shell --packages tshark --run 'which tshark'").read()?); + } + + let is_apt = cmd!(sh, "which apt-get").run().is_ok(); + + if is_apt { + cmd!(sh, "sudo apt-get install tshark -y").run()?; + } + } + + Ok("tshark".into()) +} + +fn so() -> &'static str { + if cfg!(target_os = "macos") { + "dylib" + } else { + "so" + } +} + +fn plugin_dir() -> &'static str { + if cfg!(target_os = "macos") { + "plugins/4-2/epan" + } else { + "plugins/4.2/epan" + } +} + +#[derive(Debug, Parser)] +struct Install {} + +impl Install { + fn run(self, sh: &Shell) -> Result { + Build::default().run(sh)?; + + let dir = if cfg!(unix) { + format!("~/.local/lib/wireshark/{}", plugin_dir()) + } else { + todo!("OS is currently unsupported") + }; + + sh.create_dir(&dir)?; + let so = so(); + sh.copy_file( + format!("target/release/libwireshark_dcquic.{so}"), + // wireshark always looks for `.so`, regardless of platform + format!("{dir}/libdcquic.so"), + )?; + + Ok(()) + } +} + +fn main() { + Args::parse().run(); +} diff --git a/quic/s2n-quic-core/src/stream/testing.rs b/quic/s2n-quic-core/src/stream/testing.rs index bf17228bfb..77afa7df8c 100644 --- a/quic/s2n-quic-core/src/stream/testing.rs +++ b/quic/s2n-quic-core/src/stream/testing.rs @@ -181,8 +181,14 @@ impl Data { /// Moves the current offset forward by the provided `len` pub fn seek_forward(&mut self, len: u64) { - self.offset += len; + let len = self.buffered_len.min(len); self.buffered_len -= len; + if let Some(new_offset) = self.offset.checked_add(len) { + self.offset = new_offset; + } else { + self.final_offset = Some(u64::MAX); + self.buffered_len = 0; + } } } diff --git a/quic/s2n-quic-platform/build.rs b/quic/s2n-quic-platform/build.rs index f6f7d8fd58..0da5fb1a46 100644 --- a/quic/s2n-quic-platform/build.rs +++ b/quic/s2n-quic-platform/build.rs @@ -100,6 +100,7 @@ struct Env { out_dir: String, target: String, target_os: String, + rustc_linker: Option, } impl Env { @@ -110,6 +111,7 @@ impl Env { out_dir: env("OUT_DIR"), target: env("TARGET"), target_os: env("CARGO_CFG_TARGET_OS"), + rustc_linker: option_env("RUSTC_LINKER"), } } @@ -128,6 +130,10 @@ impl Env { .arg("opt-level=0") .arg(path); + if let Some(linker) = self.rustc_linker.as_ref() { + command.arg(format!("-Clinker={linker}")); + } + for (key, _) in std::env::vars() { const CARGO_FEATURE: &str = "CARGO_FEATURE_"; if key.starts_with(CARGO_FEATURE) {