]> git.ipfire.org Git - thirdparty/iw.git/blame - bitrate.c
info: macro-ify ext_feat_print()
[thirdparty/iw.git] / bitrate.c
CommitLineData
942b5cd8
JB
1#include <errno.h>
2
3#include "nl80211.h"
4#include "iw.h"
5
6
118976b2
JD
7static int parse_vht_chunk(const char *arg, __u8 *nss, __u16 *mcs)
8{
0ee571d5 9 unsigned int count, i;
118976b2
JD
10 unsigned int inss, mcs_start, mcs_end, tab[10];
11
12 *nss = 0; *mcs = 0;
13
14 if (strchr(arg, '-')) {
15 /* Format: NSS:MCS_START-MCS_END */
16 count = sscanf(arg, "%u:%u-%u", &inss, &mcs_start, &mcs_end);
17
18 if (count != 3)
19 return 0;
20
21 if (inss < 1 || inss > NL80211_VHT_NSS_MAX)
22 return 0;
23
24 if (mcs_start > mcs_end)
25 return 0;
26
27 if (mcs_start > 9 || mcs_end > 9)
28 return 0;
29
30 *nss = inss;
31 for (i = mcs_start; i <= mcs_end; i++)
32 *mcs |= 1 << i;
33
34 } else {
35 /* Format: NSS:MCSx,MCSy,... */
36 count = sscanf(arg, "%u:%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", &inss,
37 &tab[0], &tab[1], &tab[2], &tab[3], &tab[4], &tab[5],
38 &tab[6], &tab[7], &tab[8], &tab[9]);
39
40 if (count < 2)
41 return 0;
42
43 if (inss < 1 || inss > NL80211_VHT_NSS_MAX)
44 return 0;
45
46 *nss = inss;
47 for (i = 0; i < count - 1; i++) {
48 if (tab[i] > 9)
49 return 0;
50 *mcs |= 1 << tab[i];
51 }
52 }
53
54 return 1;
55}
56
57static int setup_vht(struct nl80211_txrate_vht *txrate_vht,
58 int argc, char **argv)
59{
60 __u8 nss;
61 __u16 mcs;
62 int i;
63
64 memset(txrate_vht, 0, sizeof(*txrate_vht));
65
66 for (i = 0; i < argc; i++) {
67 if(!parse_vht_chunk(argv[i], &nss, &mcs))
68 return 0;
69
70 nss--;
71 txrate_vht->mcs[nss] |= mcs;
72 }
73
74 return 1;
75}
76
77#define VHT_ARGC_MAX 100
78
942b5cd8 79static int handle_bitrates(struct nl80211_state *state,
942b5cd8 80 struct nl_msg *msg,
05514f95
JB
81 int argc, char **argv,
82 enum id_input id)
942b5cd8
JB
83{
84 struct nlattr *nl_rates, *nl_band;
85 int i;
86 bool have_legacy_24 = false, have_legacy_5 = false;
87 uint8_t legacy_24[32], legacy_5[32];
88 int n_legacy_24 = 0, n_legacy_5 = 0;
89 uint8_t *legacy = NULL;
90 int *n_legacy = NULL;
118976b2
JD
91 bool have_ht_mcs_24 = false, have_ht_mcs_5 = false;
92 bool have_vht_mcs_24 = false, have_vht_mcs_5 = false;
93 uint8_t ht_mcs_24[77], ht_mcs_5[77];
94 int n_ht_mcs_24 = 0, n_ht_mcs_5 = 0;
95 struct nl80211_txrate_vht txrate_vht_24 = {};
96 struct nl80211_txrate_vht txrate_vht_5 = {};
942b5cd8
JB
97 uint8_t *mcs = NULL;
98 int *n_mcs = NULL;
118976b2
JD
99 char *vht_argv_5[VHT_ARGC_MAX] = {}; char *vht_argv_24[VHT_ARGC_MAX] = {};
100 char **vht_argv = NULL;
101 int vht_argc_5 = 0; int vht_argc_24 = 0;
102 int *vht_argc = NULL;
eaa16697 103 int sgi_24 = 0, sgi_5 = 0, lgi_24 = 0, lgi_5 = 0;
118976b2 104
942b5cd8
JB
105 enum {
106 S_NONE,
107 S_LEGACY,
118976b2
JD
108 S_HT,
109 S_VHT,
eaa16697 110 S_GI,
942b5cd8
JB
111 } parser_state = S_NONE;
112
113 for (i = 0; i < argc; i++) {
114 char *end;
bd0f464b 115 double tmpd;
942b5cd8 116 long tmpl;
942b5cd8
JB
117
118 if (strcmp(argv[i], "legacy-2.4") == 0) {
119 if (have_legacy_24)
120 return 1;
121 parser_state = S_LEGACY;
122 legacy = legacy_24;
123 n_legacy = &n_legacy_24;
124 have_legacy_24 = true;
125 } else if (strcmp(argv[i], "legacy-5") == 0) {
126 if (have_legacy_5)
127 return 1;
128 parser_state = S_LEGACY;
129 legacy = legacy_5;
130 n_legacy = &n_legacy_5;
131 have_legacy_5 = true;
132 }
118976b2
JD
133 else if (strcmp(argv[i], "ht-mcs-2.4") == 0) {
134 if (have_ht_mcs_24)
135 return 1;
136 parser_state = S_HT;
137 mcs = ht_mcs_24;
138 n_mcs = &n_ht_mcs_24;
139 have_ht_mcs_24 = true;
140 } else if (strcmp(argv[i], "ht-mcs-5") == 0) {
141 if (have_ht_mcs_5)
142 return 1;
143 parser_state = S_HT;
144 mcs = ht_mcs_5;
145 n_mcs = &n_ht_mcs_5;
146 have_ht_mcs_5 = true;
147 } else if (strcmp(argv[i], "vht-mcs-2.4") == 0) {
148 if (have_vht_mcs_24)
942b5cd8 149 return 1;
118976b2
JD
150 parser_state = S_VHT;
151 vht_argv = vht_argv_24;
152 vht_argc = &vht_argc_24;
153 have_vht_mcs_24 = true;
154 } else if (strcmp(argv[i], "vht-mcs-5") == 0) {
155 if (have_vht_mcs_5)
942b5cd8 156 return 1;
118976b2
JD
157 parser_state = S_VHT;
158 vht_argv = vht_argv_5;
159 vht_argc = &vht_argc_5;
160 have_vht_mcs_5 = true;
eaa16697
JD
161 } else if (strcmp(argv[i], "sgi-2.4") == 0) {
162 sgi_24 = 1;
163 parser_state = S_GI;
164 } else if (strcmp(argv[i], "sgi-5") == 0) {
165 sgi_5 = 1;
166 parser_state = S_GI;
167 } else if (strcmp(argv[i], "lgi-2.4") == 0) {
168 lgi_24 = 1;
169 parser_state = S_GI;
170 } else if (strcmp(argv[i], "lgi-5") == 0) {
171 lgi_5 = 1;
172 parser_state = S_GI;
173 } else switch (parser_state) {
942b5cd8 174 case S_LEGACY:
bd0f464b 175 tmpd = strtod(argv[i], &end);
942b5cd8
JB
176 if (*end != '\0')
177 return 1;
bd0f464b 178 if (tmpd < 1 || tmpd > 255 * 2)
942b5cd8 179 return 1;
bd0f464b 180 legacy[(*n_legacy)++] = tmpd * 2;
942b5cd8 181 break;
118976b2 182 case S_HT:
942b5cd8
JB
183 tmpl = strtol(argv[i], &end, 0);
184 if (*end != '\0')
185 return 1;
186 if (tmpl < 0 || tmpl > 255)
187 return 1;
188 mcs[(*n_mcs)++] = tmpl;
189 break;
118976b2
JD
190 case S_VHT:
191 if (*vht_argc >= VHT_ARGC_MAX)
192 return 1;
193 vht_argv[(*vht_argc)++] = argv[i];
194 break;
eaa16697
JD
195 case S_GI:
196 break;
942b5cd8
JB
197 default:
198 return 1;
199 }
200 }
201
118976b2
JD
202 if (have_vht_mcs_24)
203 if(!setup_vht(&txrate_vht_24, vht_argc_24, vht_argv_24))
204 return -EINVAL;
205
206 if (have_vht_mcs_5)
207 if(!setup_vht(&txrate_vht_5, vht_argc_5, vht_argv_5))
208 return -EINVAL;
209
eaa16697
JD
210 if (sgi_5 && lgi_5)
211 return 1;
212
213 if (sgi_24 && lgi_24)
214 return 1;
215
942b5cd8
JB
216 nl_rates = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
217 if (!nl_rates)
218 goto nla_put_failure;
219
eaa16697 220 if (have_legacy_24 || have_ht_mcs_24 || have_vht_mcs_24 || sgi_24 || lgi_24) {
942b5cd8
JB
221 nl_band = nla_nest_start(msg, NL80211_BAND_2GHZ);
222 if (!nl_band)
223 goto nla_put_failure;
224 if (have_legacy_24)
225 nla_put(msg, NL80211_TXRATE_LEGACY, n_legacy_24, legacy_24);
118976b2
JD
226 if (have_ht_mcs_24)
227 nla_put(msg, NL80211_TXRATE_HT, n_ht_mcs_24, ht_mcs_24);
228 if (have_vht_mcs_24)
229 nla_put(msg, NL80211_TXRATE_VHT, sizeof(txrate_vht_24), &txrate_vht_24);
eaa16697
JD
230 if (sgi_24)
231 nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_SGI);
232 if (lgi_24)
233 nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_LGI);
942b5cd8
JB
234 nla_nest_end(msg, nl_band);
235 }
236
eaa16697 237 if (have_legacy_5 || have_ht_mcs_5 || have_vht_mcs_5 || sgi_5 || lgi_5) {
942b5cd8
JB
238 nl_band = nla_nest_start(msg, NL80211_BAND_5GHZ);
239 if (!nl_band)
240 goto nla_put_failure;
241 if (have_legacy_5)
242 nla_put(msg, NL80211_TXRATE_LEGACY, n_legacy_5, legacy_5);
118976b2
JD
243 if (have_ht_mcs_5)
244 nla_put(msg, NL80211_TXRATE_HT, n_ht_mcs_5, ht_mcs_5);
245 if (have_vht_mcs_5)
246 nla_put(msg, NL80211_TXRATE_VHT, sizeof(txrate_vht_5), &txrate_vht_5);
eaa16697
JD
247 if (sgi_5)
248 nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_SGI);
249 if (lgi_5)
250 nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_LGI);
942b5cd8
JB
251 nla_nest_end(msg, nl_band);
252 }
253
254 nla_nest_end(msg, nl_rates);
255
256 return 0;
257 nla_put_failure:
258 return -ENOBUFS;
259}
260
261#define DESCR_LEGACY "[legacy-<2.4|5> <legacy rate in Mbps>*]"
eaa16697 262#define DESCR DESCR_LEGACY " [ht-mcs-<2.4|5> <MCS index>*] [vht-mcs-<2.4|5> <NSS:MCSx,MCSy... | NSS:MCSx-MCSy>*] [sgi-2.4|lgi-2.4] [sgi-5|lgi-5]"
942b5cd8 263
eaa16697 264COMMAND(set, bitrates, "[legacy-<2.4|5> <legacy rate in Mbps>*] [ht-mcs-<2.4|5> <MCS index>*] [vht-mcs-<2.4|5> <NSS:MCSx,MCSy... | NSS:MCSx-MCSy>*] [sgi-2.4|lgi-2.4] [sgi-5|lgi-5]",
135e65d6 265 NL80211_CMD_SET_TX_BITRATE_MASK, 0, CIB_NETDEV, handle_bitrates,
dce7b720
SM
266 "Sets up the specified rate masks.\n"
267 "Not passing any arguments would clear the existing mask (if any).");