pespin submitted this change.
client: Support generation of pcapng file format
Support transmitting traffic recordings in pcapng towards
osmo-pca-server based on VTY config. Old libpcap's file format
(.pcap) is still left as default to to keep backward compatibility
towards older osmo-pcap-server instances still running. Furthermore,
.pcap support is more extended than .pcapng since it's way older.
When pcapng file format is selected, osmo-pcap-client will use the same
osmo-pcap protocol used in pcap mode, but the payloads encoded in
messages will be in pcapng file format instead of pcap.
This means, for LINK_HDR message type it will encode a file header with
a payload consisting of 1 SHB + N IDB blocks (one for each network
interface being monitored).
Upon each packet recording received from the monitoring interface, it
will encode a LINK_DATA message containing a payload with a encoded
pcapng block.
This works mostly transparetly on the osmo-pcap-server side, since in
general it handles those payloads mostly transparently. Only some sanity
checks will need to be updated and improve there to account for the new
pcapng blocks. This in turn requires identifying pcap vs pcapng format
being recieved from the client, and also placing the proper file suffix
when creating the file. This will be done in a follow-up patch modyfing
the server side.
Related: SYS#5822
Change-Id: I3c80518a1e53a1f77e1aca8dfa83f683f9516ad6
---
M doc/manuals/chapters/client.adoc
M include/osmo-pcap/osmo_pcap_client.h
M include/osmo-pcap/osmo_pcap_file.h
M src/osmo_client_core.c
M src/osmo_client_network.c
M src/osmo_client_vty.c
M src/osmo_pcap_file.c
7 files changed, 534 insertions(+), 10 deletions(-)
diff --git a/doc/manuals/chapters/client.adoc b/doc/manuals/chapters/client.adoc
index f6ceac5..1769b60 100644
--- a/doc/manuals/chapters/client.adoc
+++ b/doc/manuals/chapters/client.adoc
@@ -44,15 +44,28 @@
.osmo-pcap-client VTY configuration for packet capture
----
client
- pcap device eth0 <1>
- pcap filter udp port 23000 <2>
- pcap detect-loop 1 <3>
+ pcap file-format pcapng <1>
+ pcap device eth0 <2>
+ pcap device eth2 <3>
+ pcap filter udp port 23000 <4>
+ pcap detect-loop 1 <5>
----
-<1> the network device from which to obtain a capture
-<2> the libpcap filter string (`udp port 23000` in this example)
-<3> instruct osmo-pcap-client to automatically add a filter that prevents capturing
- the traffic between osmo-pcap-client and osmo-pcap-server, which would create a loop.
+<1> Prepare records in pcapng format.
+<2> The network device from which to obtain a capture.
+<3> Recording from multiple devices concurrently is supported.
+<4> The libpcap filter string (`udp port 23000` in this example).
+<5> Instruct osmo-pcap-client to automatically add a filter that prevents
+ capturing the traffic between osmo-pcap-client and osmo-pcap-server,
+ which would create a loop.
+Adding or removing new recording network devices during operation is not really
+supported, and a restart of osmo-pcap-client is expected for the new
+configuration to be properly set up.
+
+NOTE:: Recording from multiple network devices using old libpcap .pcap format is
+also supported, but since that file format doesn't allow storing per-interface
+information, it will end up stored in the server as if all came from the same
+interface.
=== Configuring the primary server
diff --git a/include/osmo-pcap/osmo_pcap_client.h b/include/osmo-pcap/osmo_pcap_client.h
index 470edb6..1b66488 100644
--- a/include/osmo-pcap/osmo_pcap_client.h
+++ b/include/osmo-pcap/osmo_pcap_client.h
@@ -31,6 +31,7 @@
#include <osmocom/core/write_queue.h>
#include <osmo-pcap/osmo_tls.h>
+#include <osmo-pcap/osmo_pcap_file.h>
#define WQUEUE_MAXLEN_DEFAULT 1000
@@ -115,6 +116,7 @@
int filter_itself;
int gprs_filtering;
int snaplen;
+ enum osmo_pcap_fmt pcap_fmt;
struct osmo_pcap_client_conn *conn;
struct llist_head conns;
diff --git a/include/osmo-pcap/osmo_pcap_file.h b/include/osmo-pcap/osmo_pcap_file.h
index 50a7706..705e6d2 100644
--- a/include/osmo-pcap/osmo_pcap_file.h
+++ b/include/osmo-pcap/osmo_pcap_file.h
@@ -24,6 +24,11 @@
#include <unistd.h>
#include <stdint.h>
+enum osmo_pcap_fmt {
+ OSMO_PCAP_FMT_PCAP = 0,
+ OSMO_PCAP_FMT_PCAPNG,
+};
+
/***********************************************************
* Libpcap File Format (.pcap)
* https://wiki.wireshark.org/Development/LibpcapFileFormat
@@ -35,3 +40,113 @@
unsigned int osmo_pcap_file_record_size(const struct pcap_pkthdr *in_hdr);
int osmo_pcap_file_msgb_append_record(struct msgb *msg, const struct pcap_pkthdr *in_hdr, const uint8_t *data);
+
+/***********************************************************
+ * PCAP Next Generation (pcapng) Capture File Format
+ * https://wiki.wireshark.org/Development/PcapNg
+ * https://ietf-opsawg-wg.github.io/draft-ietf-opsawg-pcap/draft-ietf-opsawg-pcapng.html
+ * Related: wireshark.git: wiretap/{pcapng.*, pcapio.c, pcapng_module.h}, wtap_opttypes.h, dumpcap.c
+ ***********************************************************/
+
+#define OSMO_PCAPNG_FILE_MAGIC 0x1A2B3C4D
+#define OSMO_PCAPNG_FILE_MAGIC_SWAPPED 0x4D3C2B1A
+
+#define BLOCK_TYPE_SHB 0x0A0D0D0A /* Section Header Block */
+#define BLOCK_TYPE_IDB 0x00000001 /* Interface Description Block */
+#define BLOCK_TYPE_PB 0x00000002 /* Packet Block (obsolete) */
+#define BLOCK_TYPE_SPB 0x00000003 /* Simple Packet Block */
+#define BLOCK_TYPE_EPB 0x00000006 /* Enhanced Packet Block */
+
+/* Options for all blocks */
+#define OPT_EOFOPT 0
+#define OPT_COMMENT 1
+/* Section Header block (SHB) */
+#define OPT_SHB_HARDWARE 2
+#define OPT_SHB_OS 3
+#define OPT_SHB_USERAPPL 4
+
+/* Interface Description block (IDB) */
+#define OPT_IDB_NAME 2
+#define OPT_IDB_DESCRIPTION 3
+#define OPT_IDB_IP4ADDR 4
+#define OPT_IDB_IP6ADDR 5
+#define OPT_IDB_MACADDR 6
+#define OPT_IDB_FILTER 11
+
+/* filter Option: */
+enum osmo_pcapng_file_if_filter_type {
+ IF_FILTER_CAP = 0, /* pcap filter string */
+ IF_FILTER_BPF = 1 /* BPF program */
+};
+
+/* pcapng: common block header file encoding for every block type */
+struct pcapng_block_header {
+ uint32_t block_type;
+ uint32_t block_total_length;
+ uint8_t block_body[0]; /* x bytes block_body */
+ /* uint32_t block_total_length */
+} __attribute__((packed));
+
+struct pcapng_option_header {
+ uint16_t type;
+ uint16_t value_length;
+} __attribute__((packed));
+
+/* pcapng: section header block file encoding */
+struct pcapng_section_header_block {
+ /* pcapng_block_header_t */
+ uint32_t magic;
+ uint16_t version_major;
+ uint16_t version_minor;
+ uint64_t section_length; /* might be -1 for unknown */
+ /* ... Options ... */
+} __attribute__((packed));
+
+/* pcapng: interface description block file encoding */
+struct pcapng_iface_descr_block {
+ uint16_t linktype;
+ uint16_t reserved;
+ uint32_t snaplen;
+ /* ... Options ... */
+} __attribute__((packed));
+
+/* pcapng: enhanced packet block file encoding */
+struct pcapng_enhanced_packet_block {
+ uint32_t interface_id;
+ uint32_t timestamp_high;
+ uint32_t timestamp_low;
+ uint32_t captured_len;
+ uint32_t packet_len;
+ uint8_t packet_data[0]; /* ... Packet Data ... */
+ /* ... Padding ... */
+ /* ... Options ... */
+} __attribute__((packed));
+
+/* Helper APIs to encode blocks: */
+
+struct osmo_pcapng_file_shb_pars {
+ const char *hardware;
+ const char *os;
+ const char *userappl;
+};
+unsigned int osmo_pcapng_file_shb_size(const struct osmo_pcapng_file_shb_pars *pars);
+int osmo_pcapng_file_msgb_append_shb(struct msgb *msg, const struct osmo_pcapng_file_shb_pars *pars);
+
+struct osmo_pcapng_file_idb_pars {
+ const char *name;
+ const char *filter;
+ int link_type;
+ int snap_len;
+};
+unsigned int osmo_pcapng_file_idb_size(const struct osmo_pcapng_file_idb_pars *pars);
+int osmo_pcapng_file_msgb_append_idb(struct msgb *msg, const struct osmo_pcapng_file_idb_pars *pars);
+
+struct osmo_pcapng_file_epb_pars {
+ uint64_t timestamp_usec;
+ uint32_t interface_id;
+ const uint8_t *captured_data;
+ uint32_t captured_len;
+ uint32_t packet_len;
+};
+unsigned int osmo_pcapng_file_epb_size(const struct osmo_pcapng_file_epb_pars *pars);
+int osmo_pcapng_file_msgb_append_epb(struct msgb *msg, const struct osmo_pcapng_file_epb_pars *pars);
diff --git a/src/osmo_client_core.c b/src/osmo_client_core.c
index 538b68a..dd16878 100644
--- a/src/osmo_client_core.c
+++ b/src/osmo_client_core.c
@@ -303,6 +303,7 @@
return NULL;
client->snaplen = DEFAULT_SNAPLEN;
+ client->pcap_fmt = OSMO_PCAP_FMT_PCAP;
INIT_LLIST_HEAD(&client->handles);
INIT_LLIST_HEAD(&client->conns);
diff --git a/src/osmo_client_network.c b/src/osmo_client_network.c
index e14f4ca..abdb7d3 100644
--- a/src/osmo_client_network.c
+++ b/src/osmo_client_network.c
@@ -187,6 +187,46 @@
return msg;
}
+static struct msgb *osmo_client_conn_prepare_msg_data_pcapng(struct osmo_pcap_client_conn *conn,
+ const struct osmo_pcap_handle *ph,
+ const struct pcap_pkthdr *pkthdr,
+ const uint8_t *data)
+{
+ struct osmo_pcap_data *om_hdr;
+ struct msgb *msg;
+ struct osmo_pcapng_file_epb_pars epb_pars;
+ unsigned int record_size;
+ int rc;
+
+ epb_pars = (struct osmo_pcapng_file_epb_pars){
+ .timestamp_usec = (pkthdr->ts.tv_sec * 1000 * 1000) + pkthdr->ts.tv_usec,
+ .interface_id = ph->idx,
+ .captured_data = data,
+ .captured_len = pkthdr->caplen,
+ .packet_len = pkthdr->len,
+ };
+
+ record_size = osmo_pcapng_file_epb_size(&epb_pars);
+
+ msg = msgb_alloc(sizeof(*om_hdr) + record_size, "pcap-data");
+ if (!msg) {
+ LOGCONN(conn, LOGL_ERROR, "Failed to allocate\n");
+ rate_ctr_inc2(conn->client->ctrg, CLIENT_CTR_NOMEM);
+ return NULL;
+ }
+
+ om_hdr = (struct osmo_pcap_data *) msgb_put(msg, sizeof(*om_hdr));
+ om_hdr->type = PKT_LINK_DATA;
+ om_hdr->len = htons(record_size);
+ rc = osmo_pcapng_file_msgb_append_epb(msg, &epb_pars);
+ if (rc < 0) {
+ msgb_free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
static struct msgb *osmo_client_conn_prepare_msg_ipip(struct osmo_pcap_client_conn *conn,
const struct osmo_pcap_handle *ph,
const struct pcap_pkthdr *pkthdr,
@@ -231,7 +271,16 @@
switch (conn->protocol) {
case PROTOCOL_OSMOPCAP:
- msg = osmo_client_conn_prepare_msg_data_pcap(conn, ph, pkthdr, data);
+ switch (client->pcap_fmt) {
+ case OSMO_PCAP_FMT_PCAP:
+ msg = osmo_client_conn_prepare_msg_data_pcap(conn, ph, pkthdr, data);
+ break;
+ case OSMO_PCAP_FMT_PCAPNG:
+ msg = osmo_client_conn_prepare_msg_data_pcapng(conn, ph, pkthdr, data);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
break;
case PROTOCOL_IPIP:
msg = osmo_client_conn_prepare_msg_ipip(conn, ph, pkthdr, data);
@@ -271,7 +320,7 @@
if (linktype != pcap_datalink(ph->handle)) {
LOGCONN(conn, LOGL_ERROR,
"File format 'pcap' doesn't support recording from multiple ifaces "
- "with different link types!\n");
+ "with different link types! Use VTY config 'pcap file-format pcapng'.\n");
return NULL;
}
}
@@ -298,6 +347,81 @@
return msg;
}
+struct osmo_pcapng_file_shb_pars shb_pars = {
+ .hardware = "osmo-pcap hw",
+ .os = "osmo-pcap os",
+ .userappl = "osmo-pcap userappl",
+};
+
+static int pcap_handle_prepare_pcapng_idb_pars(const struct osmo_pcap_handle *ph,
+ struct osmo_pcapng_file_idb_pars *pars)
+{
+ struct osmo_pcap_client *client = ph->client;
+ memset(pars, 0, sizeof(*pars));
+
+ pars->name = ph->devname;
+ pars->filter = client->filter_string;
+ pars->link_type = pcap_datalink(ph->handle);
+ pars->snap_len = client->snaplen;
+ return 0;
+}
+
+static struct msgb *osmo_client_conn_prepare_msg_link_pcapng(struct osmo_pcap_client_conn *conn)
+{
+ struct osmo_pcap_data *om_hdr;
+ struct msgb *msg;
+ struct osmo_pcap_handle *ph;
+ int rc;
+ uint32_t file_hdr_size = osmo_pcapng_file_shb_size(&shb_pars);
+
+ /* Calculate size: */
+ llist_for_each_entry(ph, &conn->client->handles, entry) {
+ struct osmo_pcapng_file_idb_pars idb_pars;
+ if (pcap_handle_prepare_pcapng_idb_pars(ph, &idb_pars) < 0) {
+ LOGPH(ph, LOGL_ERROR, "Failed preparing pcapng IDB from handle\n");
+ return NULL;
+ }
+ file_hdr_size += osmo_pcapng_file_idb_size(&idb_pars);
+ }
+
+ msg = msgb_alloc(sizeof(*om_hdr) + file_hdr_size, "link-data");
+ if (!msg) {
+ LOGCONN(conn, LOGL_ERROR, "Failed to allocate data\n");
+ return NULL;
+ }
+
+ om_hdr = (struct osmo_pcap_data *)msgb_put(msg, sizeof(*om_hdr));
+ om_hdr->type = PKT_LINK_HDR;
+
+ rc = osmo_pcapng_file_msgb_append_shb(msg, &shb_pars);
+ if (rc < 0) {
+ LOGCONN(conn, LOGL_ERROR, "Failed to create pcapng SHB\n");
+ msgb_free(msg);
+ return NULL;
+ }
+ om_hdr->len = rc;
+
+ llist_for_each_entry(ph, &conn->client->handles, entry) {
+ struct osmo_pcapng_file_idb_pars idb_pars;
+ if (pcap_handle_prepare_pcapng_idb_pars(ph, &idb_pars) < 0) {
+ LOGPH(ph, LOGL_ERROR, "Failed preparing pcapng IDB from handle\n");
+ msgb_free(msg);
+ return NULL;
+ }
+ rc = osmo_pcapng_file_msgb_append_idb(msg, &idb_pars);
+ if (rc < 0) {
+ LOGPH(ph, LOGL_ERROR, "Failed to append pcapng IDB to msgb\n");
+ msgb_free(msg);
+ return NULL;
+ }
+ om_hdr->len += rc;
+ }
+
+ OSMO_ASSERT(om_hdr->len == file_hdr_size);
+ om_hdr->len = htons(om_hdr->len);
+ return msg;
+}
+
void osmo_client_conn_send_link(struct osmo_pcap_client_conn *conn)
{
struct msgb *msg;
@@ -306,7 +430,17 @@
if (conn->protocol == PROTOCOL_IPIP)
return;
- msg = osmo_client_conn_prepare_msg_link_pcap(conn);
+ switch (conn->client->pcap_fmt) {
+ case OSMO_PCAP_FMT_PCAP:
+ msg = osmo_client_conn_prepare_msg_link_pcap(conn);
+ break;
+ case OSMO_PCAP_FMT_PCAPNG:
+ msg = osmo_client_conn_prepare_msg_link_pcapng(conn);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+
if (!msg)
return;
write_data(conn, msg);
diff --git a/src/osmo_client_vty.c b/src/osmo_client_vty.c
index 009c735..1824324 100644
--- a/src/osmo_client_vty.c
+++ b/src/osmo_client_vty.c
@@ -1,6 +1,7 @@
/*
* osmo-pcap-client code
*
+ * (C) 2025 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* (C) 2011-2016 by Holger Hans Peter Freyther <holger@moiji-mobile.com>
* (C) 2011 by On-Waves
* All Rights Reserved
@@ -130,6 +131,8 @@
vty_out(vty, "client%s", VTY_NEWLINE);
+ if (pcap_client->pcap_fmt != OSMO_PCAP_FMT_PCAP)
+ vty_out(vty, " pcap file-format pcapng%s", VTY_NEWLINE);
llist_for_each_entry(ph, &pcap_client->handles, entry) {
vty_out(vty, " pcap device %s%s",
ph->devname, VTY_NEWLINE);
@@ -150,6 +153,22 @@
return CMD_SUCCESS;
}
+DEFUN(cfg_client_pcap_file_format,
+ cfg_client_pcap_file_format_cmd,
+ "pcap file-format (pcap|pcapng)",
+ PCAP_STRING "The pcap file format to use\n"
+ "Libpcap Capture File Format (.pcap)\n"
+ "PCAP Next Generation Capture File Format (.pcapng)\n")
+{
+ if (strcmp(argv[0], "pcap") == 0)
+ pcap_client->pcap_fmt = OSMO_PCAP_FMT_PCAP;
+ else if (strcmp(argv[0], "pcapng") == 0)
+ pcap_client->pcap_fmt = OSMO_PCAP_FMT_PCAPNG;
+ else
+ return CMD_WARNING;
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_client_no_device,
cfg_client_no_device_cmd,
"no pcap device NAME",
@@ -559,6 +578,7 @@
install_node(&server_node, config_write_server);
+ install_element(CLIENT_NODE, &cfg_client_pcap_file_format_cmd);
install_element(CLIENT_NODE, &cfg_client_no_device_cmd);
install_element(CLIENT_NODE, &cfg_client_device_cmd);
install_element(CLIENT_NODE, &cfg_client_snaplen_cmd);
diff --git a/src/osmo_pcap_file.c b/src/osmo_pcap_file.c
index eb8cc23..4b8b114 100644
--- a/src/osmo_pcap_file.c
+++ b/src/osmo_pcap_file.c
@@ -76,3 +76,242 @@
return osmo_pcap_file_record_size(in_hdr);
}
+
+
+/***********************************************************
+ * PCAP Next Generation (pcapng) Capture File Format
+ * https://wiki.wireshark.org/Development/PcapNg
+ * https://ietf-opsawg-wg.github.io/draft-ietf-opsawg-pcap/draft-ietf-opsawg-pcapng.html
+ * Related: wireshark.git: wiretap/{pcapng.*, pcapio.c, pcapng_module.h}, wtap_opttypes.h, dumpcap.c
+ ***********************************************************/
+
+/* Get required length to store a string option */
+static unsigned int osmo_pcapng_file_opt_string_size(const char *str)
+{
+ size_t str_len = str ? strlen(str) : 0;
+ uint8_t pad = str_len % 4;
+ /* Each option is padded to 4 bytes: */
+ if (pad)
+ pad = 4 - pad;
+ return sizeof(struct pcapng_option_header) + str_len + pad;
+}
+
+/* Append a string option */
+static int osmo_pcapng_file_msgb_append_opt_string(struct msgb *msg, uint16_t type, const char *str)
+{
+ struct pcapng_option_header *opth;
+ size_t str_len = str ? strlen(str) : 0;
+
+ opth = (struct pcapng_option_header *)msgb_put(msg, sizeof(*opth));
+ opth->type = type;
+ opth->value_length = str_len;
+ if (str_len > 0)
+ memcpy(msgb_put(msg, str_len), str, str_len);
+
+ /* Each option is padded to 4 bytes: */
+ uint8_t pad = str_len % 4;
+ if (pad) {
+ pad = 4 - pad;
+ uint8_t *buf = (uint8_t *)msgb_put(msg, pad);
+ memset(buf, 0, pad);
+ }
+ return sizeof(*opth) + opth->value_length + pad;
+}
+
+/* Get required length to store a if_filter option.
+ * This is a 1 byte enum osmo_pcapng_file_if_filter_type + string */
+static unsigned int osmo_pcapng_file_opt_if_filter_string_size(const char *str)
+{
+ size_t str_len = str ? strlen(str) : 0;
+ size_t len = 1 + str_len;
+ uint8_t pad = len % 4;
+ /* Each option is padded to 4 bytes: */
+ if (pad)
+ pad = 4 - pad;
+ return sizeof(struct pcapng_option_header) + len + pad;
+}
+
+/* Append a if_filter option (OPT_IDB_FILTER). */
+static int osmo_pcapng_file_msgb_append_opt_if_filter_string(struct msgb *msg, uint16_t type, const char *str)
+{
+ struct pcapng_option_header *opth;
+ uint8_t if_filter_type = IF_FILTER_CAP;
+ size_t str_len = str ? strlen(str) : 0;
+
+ opth = (struct pcapng_option_header *)msgb_put(msg, sizeof(*opth));
+ opth->type = type;
+ opth->value_length = 1 + str_len;
+ msgb_put_u8(msg, if_filter_type);
+ if (str_len > 0)
+ memcpy(msgb_put(msg, str_len), str, str_len);
+
+ /* Each option is padded to 4 bytes: */
+ uint8_t pad = opth->value_length % 4;
+ if (pad) {
+ pad = 4 - pad;
+ uint8_t *buf = (uint8_t *)msgb_put(msg, pad);
+ memset(buf, 0, pad);
+ }
+ return sizeof(*opth) + opth->value_length + pad;
+}
+
+/* Get required length to store a OPT_EOFOPT option */
+static unsigned int osmo_pcapng_file_opt_eofopt_size(void)
+{
+ return sizeof(struct pcapng_option_header);
+}
+
+/* Append a OPT_EOFOPT option */
+static int osmo_pcapng_file_msgb_append_opt_eofopt(struct msgb *msg)
+{
+ struct pcapng_option_header *opth;
+
+ opth = (struct pcapng_option_header *)msgb_put(msg, sizeof(*opth));
+ opth->type = OPT_EOFOPT;
+ opth->value_length = 0;
+
+ return sizeof(*opth);
+}
+
+/* Get required length to store a given record (packet) */
+unsigned int osmo_pcapng_file_shb_size(const struct osmo_pcapng_file_shb_pars *pars)
+{
+ uint32_t block_total_len = sizeof(struct pcapng_block_header) +
+ sizeof(struct pcapng_section_header_block) +
+ sizeof(uint32_t);
+ block_total_len += osmo_pcapng_file_opt_string_size(pars->hardware);
+ block_total_len += osmo_pcapng_file_opt_string_size(pars->os);
+ block_total_len += osmo_pcapng_file_opt_string_size(pars->userappl);
+ block_total_len += osmo_pcapng_file_opt_eofopt_size();
+ return block_total_len;
+}
+
+/* Appends a Section Header Block (SHB) to msg
+ * returns number of bytes appended on success, negative on error */
+int osmo_pcapng_file_msgb_append_shb(struct msgb *msg, const struct osmo_pcapng_file_shb_pars *pars)
+{
+ struct pcapng_block_header *bh;
+ struct pcapng_section_header_block *shb;
+ uint8_t *footer_len;
+ uint32_t block_total_len = osmo_pcapng_file_shb_size(pars);
+
+ bh = (struct pcapng_block_header *)msgb_put(msg, sizeof(*bh));
+ bh->block_type = BLOCK_TYPE_SHB;
+ bh->block_total_length = block_total_len;
+
+ /* write block fixed content */
+ shb = (struct pcapng_section_header_block *)msgb_put(msg, sizeof(*shb));
+ shb->magic = 0x1A2B3C4D;
+ shb->version_major = 1;
+ shb->version_minor = 0;
+ shb->section_length = -1;
+
+ /* Options (variable) */
+ osmo_pcapng_file_msgb_append_opt_string(msg, OPT_SHB_HARDWARE, pars->hardware);
+ osmo_pcapng_file_msgb_append_opt_string(msg, OPT_SHB_OS, pars->os);
+ osmo_pcapng_file_msgb_append_opt_string(msg, OPT_SHB_USERAPPL, pars->userappl);
+ osmo_pcapng_file_msgb_append_opt_eofopt(msg);
+
+ /* SHB Block Total Length */
+ footer_len = (uint8_t *)msgb_put(msg, sizeof(uint32_t));
+ memcpy(footer_len, &block_total_len, sizeof(uint32_t));
+
+ return block_total_len;
+}
+
+unsigned int osmo_pcapng_file_idb_size(const struct osmo_pcapng_file_idb_pars *pars)
+{
+ uint32_t block_total_len = sizeof(struct pcapng_block_header) +
+ sizeof(struct pcapng_iface_descr_block) +
+ sizeof(uint32_t);
+ block_total_len += osmo_pcapng_file_opt_string_size(pars->name);
+ block_total_len += osmo_pcapng_file_opt_if_filter_string_size(pars->filter);
+ block_total_len += osmo_pcapng_file_opt_eofopt_size();
+ return block_total_len;
+}
+
+int osmo_pcapng_file_msgb_append_idb(struct msgb *msg, const struct osmo_pcapng_file_idb_pars *pars)
+{
+ struct pcapng_block_header *bh;
+ struct pcapng_iface_descr_block *idb;
+ uint8_t *footer_len;
+ uint32_t block_total_len = osmo_pcapng_file_idb_size(pars);
+
+ bh = (struct pcapng_block_header *)msgb_put(msg, sizeof(*bh));
+ bh->block_type = BLOCK_TYPE_IDB;
+ bh->block_total_length = block_total_len;
+
+ /* write block fixed content */
+ idb = (struct pcapng_iface_descr_block *)msgb_put(msg, sizeof(*idb));
+ idb->linktype = pars->link_type;
+ idb->reserved = 0;
+ idb->snaplen = pars->snap_len;
+
+ /* Options (variable) */
+ osmo_pcapng_file_msgb_append_opt_string(msg, OPT_IDB_NAME, pars->name);
+ osmo_pcapng_file_msgb_append_opt_if_filter_string(msg, OPT_IDB_FILTER, pars->filter);
+ osmo_pcapng_file_msgb_append_opt_eofopt(msg);
+
+ /* IDB Block Total Length */
+ footer_len = (uint8_t *)msgb_put(msg, sizeof(uint32_t));
+ memcpy(footer_len, &block_total_len, sizeof(uint32_t));
+
+ return block_total_len;
+}
+
+unsigned int osmo_pcapng_file_epb_size(const struct osmo_pcapng_file_epb_pars *pars)
+{
+ uint32_t block_total_len = sizeof(struct pcapng_block_header) +
+ sizeof(struct pcapng_enhanced_packet_block) +
+ pars->captured_len +
+ sizeof(uint32_t);
+ /* Packet data is padded to 4 bytes: */
+ uint8_t pad = pars->captured_len % 4;
+ if (pad)
+ block_total_len += (4 - pad);
+
+ /* TODO: other Options */
+ block_total_len += osmo_pcapng_file_opt_eofopt_size();
+ return block_total_len;
+}
+
+int osmo_pcapng_file_msgb_append_epb(struct msgb *msg, const struct osmo_pcapng_file_epb_pars *pars)
+{
+ struct pcapng_block_header *bh;
+ struct pcapng_enhanced_packet_block *epb;
+ uint8_t *footer_len;
+ uint32_t block_total_len = osmo_pcapng_file_epb_size(pars);
+
+ bh = (struct pcapng_block_header *)msgb_put(msg, sizeof(*bh));
+ bh->block_type = BLOCK_TYPE_EPB;
+ bh->block_total_length = block_total_len;
+
+ /* write block fixed content */
+ epb = (struct pcapng_enhanced_packet_block *)msgb_put(msg, sizeof(*epb));
+ epb->interface_id = pars->interface_id;
+ epb->timestamp_high = pars->timestamp_usec >> 32;
+ epb->timestamp_low = (uint32_t)(pars->timestamp_usec & 0xffffffff);
+ epb->captured_len = pars->captured_len;
+ epb->packet_len = pars->packet_len;
+
+ /* Packet Data */
+ if (pars->captured_len > 0)
+ memcpy(msgb_put(msg, pars->captured_len), pars->captured_data, pars->captured_len);
+
+ /* Each option is padded to 4 bytes: */
+ uint8_t pad = pars->captured_len % 4;
+ if (pad) {
+ pad = 4 - pad;
+ uint8_t *buf = (uint8_t *)msgb_put(msg, pad);
+ memset(buf, 0, pad);
+ }
+
+ /* Options (variable) */
+ osmo_pcapng_file_msgb_append_opt_eofopt(msg);
+
+ /* EPB Block Total Length */
+ footer_len = (uint8_t *)msgb_put(msg, sizeof(uint32_t));
+ memcpy(footer_len, &block_total_len, sizeof(uint32_t));
+
+ return block_total_len;
+}
To view, visit change 39265. To unsubscribe, or for help writing mail filters, visit settings.