blob: 316d754495c025f1b22f8a8732d817cde84a9140 [file] [log] [blame]
developer617abbd2024-04-23 14:50:01 +08001From a32046bcffcb766b4999e76399b755887d2d5d0b Mon Sep 17 00:00:00 2001
2From: Gilad Itzkovitch <gilad.itzkovitch@morsemicro.com>
3Date: Mon, 27 Feb 2023 15:05:29 +1300
4Subject: [PATCH 14/28] iw: S1G: add frequency set in kHz and offset options
5
6This change adds support to specify the set frequency in kHz for
7the set frequency command which include an offset whenever needed.
8Also, it adds S1G bandwidth options to the selected chandef.
9
10Signed-off-by: Gilad Itzkovitch <gilad.itzkovitch@morsemicro.com>
11Link: https://lore.kernel.org/r/20230227020529.504934-1-gilad.itzkovitch@virscient.com
12Signed-off-by: Johannes Berg <johannes.berg@intel.com>
13---
14 ap.c | 2 +-
15 ibss.c | 2 +-
16 interface.c | 2 +-
17 iw.h | 5 +++-
18 mesh.c | 2 +-
19 ocb.c | 2 +-
20 phy.c | 37 ++++++++++++++++++++++-----
21 util.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++-----
22 8 files changed, 106 insertions(+), 18 deletions(-)
23
24diff --git a/ap.c b/ap.c
25index db9efb7..748576d 100644
26--- a/ap.c
27+++ b/ap.c
28@@ -28,7 +28,7 @@ static int handle_start_ap(struct nl80211_state *state,
29 argc--;
30
31 /* chandef */
32- res = parse_freqchan(&chandef, false, argc, argv, &parsed);
33+ res = parse_freqchan(&chandef, false, argc, argv, &parsed, false);
34 if (res)
35 return res;
36 argc -= parsed;
37diff --git a/ibss.c b/ibss.c
38index f6cbc4c..6e6a835 100644
39--- a/ibss.c
40+++ b/ibss.c
41@@ -30,7 +30,7 @@ static int join_ibss(struct nl80211_state *state,
42 argv++;
43 argc--;
44
45- err = parse_freqchan(&chandef, false, argc, argv, &parsed);
46+ err = parse_freqchan(&chandef, false, argc, argv, &parsed, false);
47 if (err)
48 return err;
49
50diff --git a/interface.c b/interface.c
51index 7e1dd58..eeef496 100644
52--- a/interface.c
53+++ b/interface.c
54@@ -701,7 +701,7 @@ static int handle_chanfreq(struct nl80211_state *state, struct nl_msg *msg,
55 int parsed;
56 char *end;
57
58- res = parse_freqchan(&chandef, chan, argc, argv, &parsed);
59+ res = parse_freqchan(&chandef, chan, argc, argv, &parsed, false);
60 if (res)
61 return res;
62
63diff --git a/iw.h b/iw.h
64index 45e4fbe..19c76cf 100644
65--- a/iw.h
66+++ b/iw.h
67@@ -102,7 +102,9 @@ struct chandef {
68 enum nl80211_chan_width width;
69
70 unsigned int control_freq;
71+ unsigned int control_freq_offset;
72 unsigned int center_freq1;
73+ unsigned int center_freq1_offset;
74 unsigned int center_freq2;
75 };
76
77@@ -207,7 +209,8 @@ int parse_hex_mask(char *hexmask, unsigned char **result, size_t *result_len,
78 unsigned char *parse_hex(char *hex, size_t *outlen);
79
80 int parse_keys(struct nl_msg *msg, char **argv[], int *argc);
81-int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv, int *parsed);
82+int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv,
83+ int *parsed, bool freq_in_khz);
84 enum nl80211_chan_width str_to_bw(const char *str);
85 int parse_txq_stats(char *buf, int buflen, struct nlattr *tid_stats_attr, int header,
86 int tid, const char *indent);
87diff --git a/mesh.c b/mesh.c
88index 0fb98a3..40e5e5e 100644
89--- a/mesh.c
90+++ b/mesh.c
91@@ -485,7 +485,7 @@ static int join_mesh(struct nl80211_state *state,
92 int err, parsed;
93
94 err = parse_freqchan(&chandef, false, argc - 1, argv + 1,
95- &parsed);
96+ &parsed, false);
97 if (err)
98 return err;
99
100diff --git a/ocb.c b/ocb.c
101index fc9579b..ee0eedf 100644
102--- a/ocb.c
103+++ b/ocb.c
104@@ -16,7 +16,7 @@ static int join_ocb(struct nl80211_state *state,
105 if (argc < 2)
106 return 1;
107
108- err = parse_freqchan(&chandef, false, argc, argv, &parsed);
109+ err = parse_freqchan(&chandef, false, argc, argv, &parsed, false);
110
111 if (err)
112 return err;
113diff --git a/phy.c b/phy.c
114index 15cea32..4722125 100644
115--- a/phy.c
116+++ b/phy.c
117@@ -191,7 +191,7 @@ static int handle_freq(struct nl80211_state *state, struct nl_msg *msg,
118 struct chandef chandef;
119 int res;
120
121- res = parse_freqchan(&chandef, false, argc, argv, NULL);
122+ res = parse_freqchan(&chandef, false, argc, argv, NULL, false);
123 if (res)
124 return res;
125
126@@ -209,6 +209,31 @@ COMMAND(set, freq,
127 "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
128 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
129
130+static int handle_freq_khz(struct nl80211_state *state, struct nl_msg *msg,
131+ int argc, char **argv,
132+ enum id_input id)
133+{
134+ struct chandef chandef;
135+ int res;
136+
137+ res = parse_freqchan(&chandef, false, argc, argv, NULL, true);
138+ if (res)
139+ return res;
140+
141+ return put_chandef(msg, &chandef);
142+}
143+
144+COMMAND(set, freq_khz,
145+ "<freq> [1MHz|2MHz|4MHz|8MHz|16MHz]\n"
146+ "<control freq> [1|2|4|8|16] [<center1_freq> [<center2_freq>]]",
147+ NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq_khz,
148+ "Set frequency in kHz the hardware is using\n"
149+ "configuration.");
150+COMMAND(set, freq_khz,
151+ "<freq> [1MHz|2MHz|4MHz|8MHz|16MHz]\n"
152+ "<control freq> [1|2|4|8|16] [<center1_freq> [<center2_freq>]]",
153+ NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq_khz, NULL);
154+
155 static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
156 int argc, char **argv,
157 enum id_input id)
158@@ -216,7 +241,7 @@ static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
159 struct chandef chandef;
160 int res;
161
162- res = parse_freqchan(&chandef, true, argc, argv, NULL);
163+ res = parse_freqchan(&chandef, true, argc, argv, NULL, false);
164 if (res)
165 return res;
166
167@@ -288,9 +313,9 @@ static int handle_cac_trigger(struct nl80211_state *state,
168 return 1;
169
170 if (strcmp(argv[0], "channel") == 0) {
171- res = parse_freqchan(&chandef, true, argc - 1, argv + 1, NULL);
172+ res = parse_freqchan(&chandef, true, argc - 1, argv + 1, NULL, false);
173 } else if (strcmp(argv[0], "freq") == 0) {
174- res = parse_freqchan(&chandef, false, argc - 1, argv + 1, NULL);
175+ res = parse_freqchan(&chandef, false, argc - 1, argv + 1, NULL, false);
176 } else {
177 return 1;
178 }
179@@ -334,9 +359,9 @@ static int handle_cac(struct nl80211_state *state,
180 return 1;
181
182 if (strcmp(argv[2], "channel") == 0) {
183- err = parse_freqchan(&chandef, true, argc - 3, argv + 3, NULL);
184+ err = parse_freqchan(&chandef, true, argc - 3, argv + 3, NULL, false);
185 } else if (strcmp(argv[2], "freq") == 0) {
186- err = parse_freqchan(&chandef, false, argc - 3, argv + 3, NULL);
187+ err = parse_freqchan(&chandef, false, argc - 3, argv + 3, NULL, false);
188 } else {
189 err = 1;
190 }
191diff --git a/util.c b/util.c
192index 50e3fbc..eef0332 100644
193--- a/util.c
194+++ b/util.c
195@@ -484,7 +484,7 @@ enum nl80211_chan_width str_to_bw(const char *str)
196 }
197
198 static int parse_freqs(struct chandef *chandef, int argc, char **argv,
199- int *parsed)
200+ int *parsed, bool freq_in_khz)
201 {
202 uint32_t freq;
203 char *end;
204@@ -537,7 +537,13 @@ static int parse_freqs(struct chandef *chandef, int argc, char **argv,
205 return 1;
206 *parsed += 1;
207
208- chandef->center_freq1 = freq;
209+ if (freq_in_khz) {
210+ chandef->center_freq1 = freq / 1000;
211+ chandef->center_freq1_offset = freq % 1000;
212+ } else {
213+ chandef->center_freq1 = freq;
214+ chandef->center_freq1_offset = 0;
215+ }
216
217 if (!need_cf2)
218 return 0;
219@@ -551,7 +557,11 @@ static int parse_freqs(struct chandef *chandef, int argc, char **argv,
220 freq = strtoul(argv[2], &end, 10);
221 if (*end)
222 return 1;
223- chandef->center_freq2 = freq;
224+
225+ if (freq_in_khz)
226+ chandef->center_freq2 = freq / 1000;
227+ else
228+ chandef->center_freq2 = freq;
229
230 *parsed += 1;
231
232@@ -568,6 +578,7 @@ static int parse_freqs(struct chandef *chandef, int argc, char **argv,
233 * @argv: Array of string arguments
234 * @parsed: Pointer to return the number of used arguments, or NULL to error
235 * out if any argument is left unused.
236+ * @freq_in_khz: Boolean whether to parse the frequency in kHz or default as MHz
237 *
238 * The given chandef structure will be filled in from the command line
239 * arguments. argc/argv will be updated so that further arguments from the
240@@ -591,7 +602,7 @@ static int parse_freqs(struct chandef *chandef, int argc, char **argv,
241 * Return: Number of used arguments, zero or negative error number otherwise
242 */
243 int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv,
244- int *parsed)
245+ int *parsed, bool freq_in_khz)
246 {
247 char *end;
248 static const struct chanmode chanmode[] = {
249@@ -631,9 +642,30 @@ int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv,
250 .width = NL80211_CHAN_WIDTH_320,
251 .freq1_diff = 0,
252 .chantype = -1 },
253+ { .name = "1MHz",
254+ .width = NL80211_CHAN_WIDTH_1,
255+ .freq1_diff = 0,
256+ .chantype = -1 },
257+ { .name = "2MHz",
258+ .width = NL80211_CHAN_WIDTH_2,
259+ .freq1_diff = 0,
260+ .chantype = -1 },
261+ { .name = "4MHz",
262+ .width = NL80211_CHAN_WIDTH_4,
263+ .freq1_diff = 0,
264+ .chantype = -1 },
265+ { .name = "8MHz",
266+ .width = NL80211_CHAN_WIDTH_8,
267+ .freq1_diff = 0,
268+ .chantype = -1 },
269+ { .name = "16MHz",
270+ .width = NL80211_CHAN_WIDTH_16,
271+ .freq1_diff = 0,
272+ .chantype = -1 },
273+
274 };
275 const struct chanmode *chanmode_selected = NULL;
276- unsigned int freq;
277+ unsigned int freq, freq_offset = 0;
278 unsigned int i;
279 int _parsed = 0;
280 int res = 0;
281@@ -643,7 +675,14 @@ int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv,
282
283 if (!argv[0])
284 goto out;
285+
286 freq = strtoul(argv[0], &end, 10);
287+
288+ if (freq_in_khz) {
289+ freq_offset = freq % 1000;
290+ freq = freq / 1000;
291+ }
292+
293 if (*end) {
294 res = 1;
295 goto out;
296@@ -660,8 +699,10 @@ int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv,
297 freq = ieee80211_channel_to_frequency(freq, band);
298 }
299 chandef->control_freq = freq;
300+ chandef->control_freq_offset = freq_offset;
301 /* Assume 20MHz NOHT channel for now. */
302 chandef->center_freq1 = freq;
303+ chandef->center_freq1_offset = freq_offset;
304
305 /* Try to parse HT mode definitions */
306 if (argc > 1) {
307@@ -674,9 +715,20 @@ int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv,
308 }
309 }
310
311+ /* Set channel width's default value */
312+ if (chandef->control_freq < 1000)
313+ chandef->width = NL80211_CHAN_WIDTH_16;
314+ else
315+ chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
316+
317 /* channel mode given, use it and return. */
318 if (chanmode_selected) {
319 chandef->center_freq1 = get_cf1(chanmode_selected, freq);
320+
321+ /* For non-S1G frequency */
322+ if (chandef->center_freq1 > 1000)
323+ chandef->center_freq1_offset = 0;
324+
325 chandef->width = chanmode_selected->width;
326 goto out;
327 }
328@@ -685,7 +737,7 @@ int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv,
329 if (chan)
330 goto out;
331
332- res = parse_freqs(chandef, argc - 1, argv + 1, &_parsed);
333+ res = parse_freqs(chandef, argc - 1, argv + 1, &_parsed, freq_in_khz);
334
335 out:
336 /* Error out if parsed is NULL. */
337@@ -701,6 +753,9 @@ int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv,
338 int put_chandef(struct nl_msg *msg, struct chandef *chandef)
339 {
340 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, chandef->control_freq);
341+ NLA_PUT_U32(msg,
342+ NL80211_ATTR_WIPHY_FREQ_OFFSET,
343+ chandef->control_freq_offset);
344 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width);
345
346 switch (chandef->width) {
347@@ -733,6 +788,11 @@ int put_chandef(struct nl_msg *msg, struct chandef *chandef)
348 NL80211_ATTR_CENTER_FREQ1,
349 chandef->center_freq1);
350
351+ if (chandef->center_freq1_offset)
352+ NLA_PUT_U32(msg,
353+ NL80211_ATTR_CENTER_FREQ1_OFFSET,
354+ chandef->center_freq1_offset);
355+
356 if (chandef->center_freq2)
357 NLA_PUT_U32(msg,
358 NL80211_ATTR_CENTER_FREQ2,
359--
3602.39.2
361