]> git.ipfire.org Git - thirdparty/iw.git/blob - bitrate.c
iw: add VHT MCS/NSS set support to set bitrates
[thirdparty/iw.git] / bitrate.c
1 #include <errno.h>
2
3 #include "nl80211.h"
4 #include "iw.h"
5
6
7 static int parse_vht_chunk(const char *arg, __u8 *nss, __u16 *mcs)
8 {
9 int count, i;
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
57 static 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
79 static int handle_bitrates(struct nl80211_state *state,
80 struct nl_cb *cb,
81 struct nl_msg *msg,
82 int argc, char **argv,
83 enum id_input id)
84 {
85 struct nlattr *nl_rates, *nl_band;
86 int i;
87 bool have_legacy_24 = false, have_legacy_5 = false;
88 uint8_t legacy_24[32], legacy_5[32];
89 int n_legacy_24 = 0, n_legacy_5 = 0;
90 uint8_t *legacy = NULL;
91 int *n_legacy = NULL;
92 bool have_ht_mcs_24 = false, have_ht_mcs_5 = false;
93 bool have_vht_mcs_24 = false, have_vht_mcs_5 = false;
94 uint8_t ht_mcs_24[77], ht_mcs_5[77];
95 int n_ht_mcs_24 = 0, n_ht_mcs_5 = 0;
96 struct nl80211_txrate_vht txrate_vht_24 = {};
97 struct nl80211_txrate_vht txrate_vht_5 = {};
98 uint8_t *mcs = NULL;
99 int *n_mcs = NULL;
100 char *vht_argv_5[VHT_ARGC_MAX] = {}; char *vht_argv_24[VHT_ARGC_MAX] = {};
101 char **vht_argv = NULL;
102 int vht_argc_5 = 0; int vht_argc_24 = 0;
103 int *vht_argc = NULL;
104
105 enum {
106 S_NONE,
107 S_LEGACY,
108 S_HT,
109 S_VHT,
110 } parser_state = S_NONE;
111
112 for (i = 0; i < argc; i++) {
113 char *end;
114 double tmpd;
115 long tmpl;
116
117 if (strcmp(argv[i], "legacy-2.4") == 0) {
118 if (have_legacy_24)
119 return 1;
120 parser_state = S_LEGACY;
121 legacy = legacy_24;
122 n_legacy = &n_legacy_24;
123 have_legacy_24 = true;
124 } else if (strcmp(argv[i], "legacy-5") == 0) {
125 if (have_legacy_5)
126 return 1;
127 parser_state = S_LEGACY;
128 legacy = legacy_5;
129 n_legacy = &n_legacy_5;
130 have_legacy_5 = true;
131 }
132 else if (strcmp(argv[i], "ht-mcs-2.4") == 0) {
133 if (have_ht_mcs_24)
134 return 1;
135 parser_state = S_HT;
136 mcs = ht_mcs_24;
137 n_mcs = &n_ht_mcs_24;
138 have_ht_mcs_24 = true;
139 } else if (strcmp(argv[i], "ht-mcs-5") == 0) {
140 if (have_ht_mcs_5)
141 return 1;
142 parser_state = S_HT;
143 mcs = ht_mcs_5;
144 n_mcs = &n_ht_mcs_5;
145 have_ht_mcs_5 = true;
146 } else if (strcmp(argv[i], "vht-mcs-2.4") == 0) {
147 if (have_vht_mcs_24)
148 return 1;
149 parser_state = S_VHT;
150 vht_argv = vht_argv_24;
151 vht_argc = &vht_argc_24;
152 have_vht_mcs_24 = true;
153 } else if (strcmp(argv[i], "vht-mcs-5") == 0) {
154 if (have_vht_mcs_5)
155 return 1;
156 parser_state = S_VHT;
157 vht_argv = vht_argv_5;
158 vht_argc = &vht_argc_5;
159 have_vht_mcs_5 = true;
160 }
161 else switch (parser_state) {
162 case S_LEGACY:
163 tmpd = strtod(argv[i], &end);
164 if (*end != '\0')
165 return 1;
166 if (tmpd < 1 || tmpd > 255 * 2)
167 return 1;
168 legacy[(*n_legacy)++] = tmpd * 2;
169 break;
170 case S_HT:
171 tmpl = strtol(argv[i], &end, 0);
172 if (*end != '\0')
173 return 1;
174 if (tmpl < 0 || tmpl > 255)
175 return 1;
176 mcs[(*n_mcs)++] = tmpl;
177 break;
178 case S_VHT:
179 if (*vht_argc >= VHT_ARGC_MAX)
180 return 1;
181 vht_argv[(*vht_argc)++] = argv[i];
182 break;
183 default:
184 return 1;
185 }
186 }
187
188 if (have_vht_mcs_24)
189 if(!setup_vht(&txrate_vht_24, vht_argc_24, vht_argv_24))
190 return -EINVAL;
191
192 if (have_vht_mcs_5)
193 if(!setup_vht(&txrate_vht_5, vht_argc_5, vht_argv_5))
194 return -EINVAL;
195
196 nl_rates = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
197 if (!nl_rates)
198 goto nla_put_failure;
199
200 if (have_legacy_24 || have_ht_mcs_24 || have_vht_mcs_24) {
201 nl_band = nla_nest_start(msg, NL80211_BAND_2GHZ);
202 if (!nl_band)
203 goto nla_put_failure;
204 if (have_legacy_24)
205 nla_put(msg, NL80211_TXRATE_LEGACY, n_legacy_24, legacy_24);
206 if (have_ht_mcs_24)
207 nla_put(msg, NL80211_TXRATE_HT, n_ht_mcs_24, ht_mcs_24);
208 if (have_vht_mcs_24)
209 nla_put(msg, NL80211_TXRATE_VHT, sizeof(txrate_vht_24), &txrate_vht_24);
210 nla_nest_end(msg, nl_band);
211 }
212
213 if (have_legacy_5 || have_ht_mcs_5 || have_vht_mcs_5) {
214 nl_band = nla_nest_start(msg, NL80211_BAND_5GHZ);
215 if (!nl_band)
216 goto nla_put_failure;
217 if (have_legacy_5)
218 nla_put(msg, NL80211_TXRATE_LEGACY, n_legacy_5, legacy_5);
219 if (have_ht_mcs_5)
220 nla_put(msg, NL80211_TXRATE_HT, n_ht_mcs_5, ht_mcs_5);
221 if (have_vht_mcs_5)
222 nla_put(msg, NL80211_TXRATE_VHT, sizeof(txrate_vht_5), &txrate_vht_5);
223 nla_nest_end(msg, nl_band);
224 }
225
226 nla_nest_end(msg, nl_rates);
227
228 return 0;
229 nla_put_failure:
230 return -ENOBUFS;
231 }
232
233 #define DESCR_LEGACY "[legacy-<2.4|5> <legacy rate in Mbps>*]"
234 #define DESCR DESCR_LEGACY " [ht-mcs-<2.4|5> <MCS index>*] [vht-mcs-<2.4|5> <NSS:MCSx,MCSy... | NSS:MCSx-MCSy>*]"
235
236 COMMAND(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>*]",
237 NL80211_CMD_SET_TX_BITRATE_MASK, 0, CIB_NETDEV, handle_bitrates,
238 "Sets up the specified rate masks.\n"
239 "Not passing any arguments would clear the existing mask (if any).");