summaryrefslogtreecommitdiffstats
path: root/tools/radiotap-gen/radiotap-gen.c
blob: 3f319ab5df22b48a2e1459f1afe5837752ebbfe0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
 * A generic packet generator application for U-SIG radiotap packets.
 *
 * Copyright Richard Sharpe, 2022.
 *
 * You will need libpcap installed.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 *
 * A sample program showing how to create packets with radiotap headers. This
 * is mainly useful for those situations where you are adding a new radiotap
 * TLV but the drivers for the hardware is not ready yet and you need to
 * test your radiotap dissector.
 */

#include <errno.h>
#include <glib.h>
#include <pcap.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

struct u_sig_hdr {
	uint16_t type;
	uint16_t len;
	uint32_t common;
	uint32_t value;
	uint32_t mask;
} __attribute__((packed));

struct radiotap_hdr {
	uint8_t vers;
	uint8_t pad;
	uint16_t len;
	uint32_t presence_flags;
	uint32_t MAC_timestamp[2];
	uint8_t flags;
	uint8_t data_rate;
	uint16_t channel_freq;
	uint16_t pad2;
	uint16_t pad3;
	struct u_sig_hdr u_sig_hdr;
} __attribute__((packed));

struct complete_pkt {
	struct radiotap_hdr radiotap;
	uint8_t pkt_data[26];
} __attribute__((packed));

/* Some random 802.11 packet, an S1G beacon, I think */
uint8_t pkt_data[26] = { 0x1c, 0x0b, 0x00, 0x00, 0x02, 0x00, 0xeb, 0x4b,
			 0x02, 0x8b, 0x12, 0x52, 0xa7, 0x6b, 0x00, 0x62,
			 0x9c, 0x6b, 0x64, 0x4e, 0x35, 0xae, 0x05, 0x02,
			 0x00, 0x02 };

#define PHY_VERSION_ID_KNOWN 0x00000001
#define BW_KNOWN             0x00000002
#define UL_DL_KNOWN          0x00000004
#define BSS_COLOR_KNOWN      0x00000008
#define UL_DL                0x00040000

/*
 * Generate some u_sig packets.
 */
static void gen_u_sig_pkts(pcap_dumper_t *dumper)
{
	struct pcap_pkthdr hdr;
	struct complete_pkt pkt;
	struct timeval ts;
	/*
	 * Create the complete packet.
	 *
	 * 1. Set up the radiotap headers we need, including the TLVs.
	 */
	pkt.radiotap.vers = 0;
	pkt.radiotap.pad = 0;
	pkt.radiotap.len = sizeof(struct radiotap_hdr);
	pkt.radiotap.presence_flags = 0x1000000F;
	pkt.radiotap.MAC_timestamp[0] = 0x17860500;
	pkt.radiotap.MAC_timestamp[1] = 0x22ac9b1a;
	pkt.radiotap.flags = 0;
	pkt.radiotap.data_rate = 0x02;
	pkt.radiotap.channel_freq = 5600;
	pkt.radiotap.pad2 = 0x0100;
	pkt.radiotap.pad3 = 0x0000;
	pkt.radiotap.u_sig_hdr.type = 33;   /* The TLV we want U-SIG */
	pkt.radiotap.u_sig_hdr.len = 12;

	/* Set the BW to 80MHz for the moment */
	pkt.radiotap.u_sig_hdr.common = PHY_VERSION_ID_KNOWN | BW_KNOWN | \
					UL_DL_KNOWN | 0x00012000;
	/*
	 * The bits are:          U-SIG-1 B20-25: all 1s.
	 *               PPDU Type and Comp mode: 0
	 *                              Validate: 1
	 *         Punctured Channel Information: 0 (no puncturing)
	 *                              Validate: 1
	 *                           EHT SIG MCS: 0 (EHT-MCS 0)
	 */
	pkt.radiotap.u_sig_hdr.value = 0x0000413F;
	pkt.radiotap.u_sig_hdr.mask =  0x003fbec0;  /* The Intel value */

	/* Copy the packet data in */
	memcpy(pkt.pkt_data, pkt_data, sizeof(pkt.pkt_data));

	gettimeofday(&ts, NULL);
	hdr.ts.tv_sec = ts.tv_sec;
	hdr.ts.tv_usec = ts.tv_usec;
	hdr.caplen = sizeof(struct complete_pkt);
	hdr.len = sizeof(struct complete_pkt);

	pcap_dump((u_char *)dumper, &hdr, (u_char *)&pkt);

	/* Dump another with different 160MHz */
	/*
	 * The bits are:          U-SIG-1 B20-25: all 1s.
	 *               PPDU Type and Comp mode: 0
	 *                              Validate: 1
	 *         Punctured Channel Information: 1 ([x 1 1 1]puncturing)
	 *                              Validate: 1
	 *                           EHT SIG MCS: 1 (EHT-MCS 1)
	 */
	pkt.radiotap.u_sig_hdr.common = PHY_VERSION_ID_KNOWN | BW_KNOWN | \
					UL_DL_KNOWN | 0x00018000;;
	pkt.radiotap.u_sig_hdr.mask =  0x003fbec0;
	pkt.radiotap.u_sig_hdr.value = 0x0001183F;

	/* We should probably update the timestamp */
	pcap_dump((u_char *)dumper, &hdr, (u_char *)&pkt);

	/* Dump another with different 160MHz */
	/*
	 * The bits are:          U-SIG-1 B20-25: all 1s.
	 *               PPDU Type and Comp mode: 0
	 *                              Validate: 1
	 *         Punctured Channel Information: 1 ([x 1 1 1]puncturing)
	 *                              Validate: 1
	 *                           EHT SIG MCS: 1 (EHT-MCS 1)
	 */
	pkt.radiotap.u_sig_hdr.common = PHY_VERSION_ID_KNOWN | BW_KNOWN | \
					UL_DL_KNOWN | UL_DL | 0x00018000;
	pkt.radiotap.u_sig_hdr.mask =  0x003fbec0;
	pkt.radiotap.u_sig_hdr.value = 0x0001183F;

	pcap_dump((u_char *)dumper, &hdr, (u_char *)&pkt);
}

int main(int argc, char *argv[])
{
	int err = -1;
	pcap_t *pd = NULL;
	pcap_dumper_t *dumper = NULL;

	if (argc < 2) {
		printf("Usage: %s <pcap-file-name>\n", argv[0]);
		return 1;
	}

	pd = pcap_open_dead(DLT_IEEE802_11_RADIO, 65535);
	if (pd == NULL) {
		fprintf(stderr, "Unable to open pcap device: %s\n",
			g_strerror(errno));
		return -1;
	}

	dumper = pcap_dump_open(pd, argv[1]);
        if (dumper == NULL) {
		fprintf(stderr, "Unable to create dump file %s: %s\n",
			argv[1], pcap_geterr(pd));
		goto close_pd;
	}

	/*
	 * Add calls to any functions that generate packets.
	 */
	gen_u_sig_pkts(dumper);

	pcap_dump_close(dumper);
close_pd:
	pcap_close(pd);
	return err;
}