2020-06-25 13:10:05

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 7/9] wmediumd: add the ability to write a pcapng file

From: Johannes Berg <[email protected]>

Add the ability to write a pcapng file containing all the data.
The radiotap header is currently very minimal with only the
frequency and the signal strength.

---
wmediumd/wmediumd.c | 119 +++++++++++++++++++++++++++++++++++++++++++-
wmediumd/wmediumd.h | 2 +
2 files changed, 120 insertions(+), 1 deletion(-)

diff --git a/wmediumd/wmediumd.c b/wmediumd/wmediumd.c
index afc4f16d9ae9..5304931fbf74 100644
--- a/wmediumd/wmediumd.c
+++ b/wmediumd/wmediumd.c
@@ -36,6 +36,7 @@
#include <limits.h>
#include <unistd.h>
#include <stdarg.h>
+#include <endian.h>
#include <usfstl/loop.h>
#include <usfstl/sched.h>
#include <usfstl/schedctrl.h>
@@ -309,6 +310,48 @@ static void wmediumd_notify_frame_start(struct usfstl_job *job)
}
}

+static void log2pcap(struct wmediumd *ctx, struct frame *frame, uint64_t ts)
+{
+ struct {
+ uint8_t it_version;
+ uint8_t it_pad;
+ uint16_t it_len;
+ uint32_t it_present;
+ struct {
+ uint16_t freq, flags;
+ } channel;
+ uint8_t signal;
+ } __attribute__((packed)) radiotap_hdr = {
+ .it_len = htole16(sizeof(radiotap_hdr)),
+ .it_present = htole32(1 << 3 /* channel */ |
+ 1 << 5 /* signal dBm */),
+ .channel.freq = htole16(frame->freq),
+ .signal = frame->signal,
+ };
+ struct {
+ uint32_t type, blocklen, ifidx, ts_hi, ts_lo, caplen, pktlen;
+ } __attribute__((packed)) blockhdr = {
+ .type = 6,
+ .ts_hi = ts / (1ULL << 32),
+ .ts_lo = ts,
+ .caplen = frame->data_len + sizeof(radiotap_hdr),
+ .pktlen = frame->data_len + sizeof(radiotap_hdr),
+ };
+ static const uint8_t pad[3];
+ uint32_t sz, align;
+
+ sz = blockhdr.caplen + sizeof(blockhdr) + sizeof(uint32_t);
+ blockhdr.blocklen = (sz + 3) & ~3;
+ align = blockhdr.blocklen - sz;
+
+ fwrite(&blockhdr, sizeof(blockhdr), 1, ctx->pcap_file);
+ fwrite(&radiotap_hdr, sizeof(radiotap_hdr), 1, ctx->pcap_file);
+ fwrite(frame->data, frame->data_len, 1, ctx->pcap_file);
+ fwrite(pad, align, 1, ctx->pcap_file);
+ fwrite(&blockhdr.blocklen, sizeof(blockhdr.blocklen), 1, ctx->pcap_file);
+ fflush(ctx->pcap_file);
+}
+
static void queue_frame(struct wmediumd *ctx, struct station *station,
struct frame *frame)
{
@@ -438,6 +481,29 @@ static void queue_frame(struct wmediumd *ctx, struct station *station,
}
}

+ if (ctx->pcap_file) {
+ log2pcap(ctx, frame, target);
+
+ if (is_acked && !noack) {
+ struct {
+ struct frame frame;
+ uint16_t fc;
+ uint16_t dur;
+ uint8_t ra[6];
+ } __attribute__((packed, aligned(8))) ack = {
+ .fc = htole16(0xd4),
+ .dur = htole16(ack_time_usec),
+ };
+
+ memcpy(&ack.frame, frame, sizeof(ack.frame));
+ ack.frame.data_len = 10;
+ memcpy(ack.ra, frame->data + 10, 6);
+
+ log2pcap(ctx, &ack.frame,
+ target + send_time - ack_time_usec);
+ }
+ }
+
target += send_time;

frame->duration = send_time;
@@ -1141,10 +1207,58 @@ static void print_help(int exval)
printf(" -u socket expose vhost-user socket, don't use netlink\n");
printf(" -a socket expose wmediumd API socket\n");
printf(" -n force netlink use even with vhost-user\n");
+ printf(" -p FILE log packets to pcapng file FILE\n");

exit(exval);
}

+static void init_pcapng(struct wmediumd *ctx, const char *filename)
+{
+ struct {
+ uint32_t type, blocklen, byte_order;
+ uint16_t ver_maj, ver_min;
+ uint64_t seclen;
+ uint32_t blocklen2;
+ } __attribute__((packed)) blockhdr = {
+ .type = 0x0A0D0D0A,
+ .blocklen = sizeof(blockhdr),
+ .byte_order = 0x1A2B3C4D,
+ .ver_maj = 1,
+ .ver_min = 0,
+ .seclen = -1,
+ .blocklen2 = sizeof(blockhdr),
+ };
+ struct {
+ uint32_t type, blocklen;
+ uint16_t linktype, reserved;
+ uint32_t snaplen;
+ struct {
+ uint16_t code, len;
+ uint8_t val, pad[3];
+ } opt_if_tsresol;
+ struct {
+ uint16_t code, len;
+ } opt_endofopt;
+ uint32_t blocklen2;
+ } __attribute__((packed)) idb = {
+ .type = 1,
+ .blocklen = sizeof(idb),
+ .linktype = 127, // radiotap
+ .snaplen = -1,
+ .opt_if_tsresol.code = 9,
+ .opt_if_tsresol.len = 1,
+ .opt_if_tsresol.val = 6, // usec
+ .blocklen2 = sizeof(idb),
+ };
+
+ if (!filename)
+ return;
+
+ ctx->pcap_file = fopen(filename, "w+");
+ fwrite(&blockhdr, sizeof(blockhdr), 1, ctx->pcap_file);
+ fwrite(&idb, sizeof(idb), 1, ctx->pcap_file);
+}
+
int main(int argc, char *argv[])
{
int opt;
@@ -1174,7 +1288,7 @@ int main(int argc, char *argv[])
unsigned long int parse_log_lvl;
char* parse_end_token;

- while ((opt = getopt(argc, argv, "hVc:l:x:t:u:a:n")) != -1) {
+ while ((opt = getopt(argc, argv, "hVc:l:x:t:u:a:np:")) != -1) {
switch (opt) {
case 'h':
print_help(EXIT_SUCCESS);
@@ -1218,6 +1332,9 @@ int main(int argc, char *argv[])
case 'n':
force_netlink = true;
break;
+ case 'p':
+ init_pcapng(&ctx, optarg);
+ break;
case '?':
printf("wmediumd: Error - No such option: "
"`%c'\n\n", optopt);
diff --git a/wmediumd/wmediumd.h b/wmediumd/wmediumd.h
index 6319bb70c8f6..8619e28cbe9a 100644
--- a/wmediumd/wmediumd.h
+++ b/wmediumd/wmediumd.h
@@ -227,6 +227,8 @@ struct wmediumd {
u8 log_lvl;

u32 need_start_notify;
+
+ FILE *pcap_file;
};

struct hwsim_tx_rate {
--
2.26.2


2020-06-26 04:48:00

by Bob Copeland

[permalink] [raw]
Subject: Re: [PATCH 7/9] wmediumd: add the ability to write a pcapng file

On Thu, Jun 25, 2020 at 03:08:42PM +0200, Johannes Berg wrote:
> From: Johannes Berg <[email protected]>
>
> Add the ability to write a pcapng file containing all the data.
> The radiotap header is currently very minimal with only the
> frequency and the signal strength.

> + if (!filename)
> + return;
> +
> + ctx->pcap_file = fopen(filename, "w+");

I know it doesn't actually matter, but would be nice to close this
somewhere.

--
Bob Copeland %% https://bobcopeland.com/

2020-06-26 08:14:17

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 7/9] wmediumd: add the ability to write a pcapng file

On Thu, 2020-06-25 at 23:10 -0400, Bob Copeland wrote:
> On Thu, Jun 25, 2020 at 03:08:42PM +0200, Johannes Berg wrote:
> > From: Johannes Berg <[email protected]>
> >
> > Add the ability to write a pcapng file containing all the data.
> > The radiotap header is currently very minimal with only the
> > frequency and the signal strength.
> > + if (!filename)
> > + return;
> > +
> > + ctx->pcap_file = fopen(filename, "w+");
>
> I know it doesn't actually matter, but would be nice to close this
> somewhere.

Hah, true.

I guess we could now add to the control socket a way to quit wediumd
that doesn't involve killing it, and then that starts being a bit more
relevant :)


johannes