1*92022041SSam Saccone #include <errno.h>
2*92022041SSam Saccone
3*92022041SSam Saccone #include "nl80211.h"
4*92022041SSam Saccone #include "iw.h"
5*92022041SSam Saccone
6*92022041SSam Saccone
parse_rate_chunk(const char * arg,__u8 * nss,__u16 * mcs,unsigned int mode)7*92022041SSam Saccone static int parse_rate_chunk(const char *arg, __u8 *nss, __u16 *mcs, unsigned int mode)
8*92022041SSam Saccone {
9*92022041SSam Saccone unsigned int count, i;
10*92022041SSam Saccone unsigned int inss, mcs_start, mcs_end, tab[12];
11*92022041SSam Saccone unsigned int max_mcs = 0, max_nss = 0;
12*92022041SSam Saccone
13*92022041SSam Saccone *nss = 0; *mcs = 0;
14*92022041SSam Saccone
15*92022041SSam Saccone if (mode == NL80211_TXRATE_HE) {
16*92022041SSam Saccone max_mcs = 11;
17*92022041SSam Saccone max_nss = NL80211_HE_NSS_MAX;
18*92022041SSam Saccone } else {
19*92022041SSam Saccone max_mcs = 9;
20*92022041SSam Saccone max_nss = NL80211_VHT_NSS_MAX;
21*92022041SSam Saccone }
22*92022041SSam Saccone
23*92022041SSam Saccone if (strchr(arg, '-')) {
24*92022041SSam Saccone /* Format: NSS:MCS_START-MCS_END */
25*92022041SSam Saccone count = sscanf(arg, "%u:%u-%u", &inss, &mcs_start, &mcs_end);
26*92022041SSam Saccone
27*92022041SSam Saccone if (count != 3)
28*92022041SSam Saccone return 0;
29*92022041SSam Saccone
30*92022041SSam Saccone if (inss < 1 || inss > max_nss)
31*92022041SSam Saccone return 0;
32*92022041SSam Saccone
33*92022041SSam Saccone if (mcs_start > mcs_end)
34*92022041SSam Saccone return 0;
35*92022041SSam Saccone
36*92022041SSam Saccone if (mcs_start > max_mcs || mcs_end > max_mcs)
37*92022041SSam Saccone return 0;
38*92022041SSam Saccone
39*92022041SSam Saccone *nss = inss;
40*92022041SSam Saccone for (i = mcs_start; i <= mcs_end; i++)
41*92022041SSam Saccone *mcs |= 1 << i;
42*92022041SSam Saccone
43*92022041SSam Saccone } else {
44*92022041SSam Saccone /* Format: NSS:MCSx,MCSy,... */
45*92022041SSam Saccone if (mode == NL80211_TXRATE_HE) {
46*92022041SSam Saccone count = sscanf(arg, "%u:%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
47*92022041SSam Saccone &inss, &tab[0], &tab[1], &tab[2], &tab[3],
48*92022041SSam Saccone &tab[4], &tab[5], &tab[6], &tab[7], &tab[8],
49*92022041SSam Saccone &tab[9], &tab[10], &tab[11]);
50*92022041SSam Saccone } else {
51*92022041SSam Saccone count = sscanf(arg, "%u:%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", &inss,
52*92022041SSam Saccone &tab[0], &tab[1], &tab[2], &tab[3], &tab[4],
53*92022041SSam Saccone &tab[5], &tab[6], &tab[7], &tab[8], &tab[9]);
54*92022041SSam Saccone }
55*92022041SSam Saccone
56*92022041SSam Saccone if (count < 2)
57*92022041SSam Saccone return 0;
58*92022041SSam Saccone
59*92022041SSam Saccone if (inss < 1 || inss > max_nss)
60*92022041SSam Saccone return 0;
61*92022041SSam Saccone
62*92022041SSam Saccone *nss = inss;
63*92022041SSam Saccone for (i = 0; i < count - 1; i++) {
64*92022041SSam Saccone if (tab[i] > max_mcs)
65*92022041SSam Saccone return 0;
66*92022041SSam Saccone *mcs |= 1 << tab[i];
67*92022041SSam Saccone }
68*92022041SSam Saccone }
69*92022041SSam Saccone
70*92022041SSam Saccone return 1;
71*92022041SSam Saccone }
72*92022041SSam Saccone
parse_vht_chunk(const char * arg,__u8 * nss,__u16 * mcs)73*92022041SSam Saccone static int parse_vht_chunk(const char *arg, __u8 *nss, __u16 *mcs)
74*92022041SSam Saccone {
75*92022041SSam Saccone return parse_rate_chunk(arg, nss, mcs, NL80211_TXRATE_VHT);
76*92022041SSam Saccone }
77*92022041SSam Saccone
parse_he_chunk(const char * arg,__u8 * nss,__u16 * mcs)78*92022041SSam Saccone static int parse_he_chunk(const char *arg, __u8 *nss, __u16 *mcs)
79*92022041SSam Saccone {
80*92022041SSam Saccone return parse_rate_chunk(arg, nss, mcs, NL80211_TXRATE_HE);
81*92022041SSam Saccone }
82*92022041SSam Saccone
setup_vht(struct nl80211_txrate_vht * txrate_vht,int argc,char ** argv)83*92022041SSam Saccone static int setup_vht(struct nl80211_txrate_vht *txrate_vht,
84*92022041SSam Saccone int argc, char **argv)
85*92022041SSam Saccone {
86*92022041SSam Saccone __u8 nss;
87*92022041SSam Saccone __u16 mcs;
88*92022041SSam Saccone int i;
89*92022041SSam Saccone
90*92022041SSam Saccone memset(txrate_vht, 0, sizeof(*txrate_vht));
91*92022041SSam Saccone
92*92022041SSam Saccone for (i = 0; i < argc; i++) {
93*92022041SSam Saccone if (!parse_vht_chunk(argv[i], &nss, &mcs))
94*92022041SSam Saccone return 0;
95*92022041SSam Saccone
96*92022041SSam Saccone nss--;
97*92022041SSam Saccone txrate_vht->mcs[nss] |= mcs;
98*92022041SSam Saccone }
99*92022041SSam Saccone
100*92022041SSam Saccone return 1;
101*92022041SSam Saccone }
102*92022041SSam Saccone
setup_he(struct nl80211_txrate_he * txrate_he,int argc,char ** argv)103*92022041SSam Saccone static int setup_he(struct nl80211_txrate_he *txrate_he,
104*92022041SSam Saccone int argc, char **argv)
105*92022041SSam Saccone {
106*92022041SSam Saccone __u8 nss;
107*92022041SSam Saccone __u16 mcs;
108*92022041SSam Saccone int i;
109*92022041SSam Saccone
110*92022041SSam Saccone memset(txrate_he, 0, sizeof(*txrate_he));
111*92022041SSam Saccone
112*92022041SSam Saccone for (i = 0; i < argc; i++) {
113*92022041SSam Saccone if (!parse_he_chunk(argv[i], &nss, &mcs))
114*92022041SSam Saccone return 0;
115*92022041SSam Saccone
116*92022041SSam Saccone nss--;
117*92022041SSam Saccone txrate_he->mcs[nss] |= mcs;
118*92022041SSam Saccone }
119*92022041SSam Saccone
120*92022041SSam Saccone return 1;
121*92022041SSam Saccone }
122*92022041SSam Saccone
123*92022041SSam Saccone #define HE_GI_STR_MAX 16
124*92022041SSam Saccone #define HE_GI_08_STR "0.8"
125*92022041SSam Saccone #define HE_GI_16_STR "1.6"
126*92022041SSam Saccone #define HE_GI_32_STR "3.2"
parse_he_gi(char * he_gi)127*92022041SSam Saccone static int parse_he_gi(char *he_gi)
128*92022041SSam Saccone {
129*92022041SSam Saccone if (he_gi == NULL)
130*92022041SSam Saccone return 0;
131*92022041SSam Saccone
132*92022041SSam Saccone if (!strncmp(he_gi, HE_GI_08_STR, sizeof(HE_GI_08_STR)))
133*92022041SSam Saccone return NL80211_RATE_INFO_HE_GI_0_8;
134*92022041SSam Saccone if (!strncmp(he_gi, HE_GI_16_STR, sizeof(HE_GI_16_STR)))
135*92022041SSam Saccone return NL80211_RATE_INFO_HE_GI_1_6;
136*92022041SSam Saccone if (!strncmp(he_gi, HE_GI_32_STR, sizeof(HE_GI_32_STR)))
137*92022041SSam Saccone return NL80211_RATE_INFO_HE_GI_3_2;
138*92022041SSam Saccone
139*92022041SSam Saccone return -1;
140*92022041SSam Saccone }
141*92022041SSam Saccone
142*92022041SSam Saccone #define VHT_ARGC_MAX 100
143*92022041SSam Saccone
set_bitrates(struct nl_msg * msg,int argc,char ** argv,enum nl80211_attrs attr)144*92022041SSam Saccone int set_bitrates(struct nl_msg *msg,
145*92022041SSam Saccone int argc, char **argv,
146*92022041SSam Saccone enum nl80211_attrs attr)
147*92022041SSam Saccone {
148*92022041SSam Saccone struct nlattr *nl_rates, *nl_band;
149*92022041SSam Saccone int i, ret = 0;
150*92022041SSam Saccone bool have_legacy_24 = false, have_legacy_5 = false;
151*92022041SSam Saccone uint8_t legacy_24[32], legacy_5[32];
152*92022041SSam Saccone int n_legacy_24 = 0, n_legacy_5 = 0;
153*92022041SSam Saccone uint8_t *legacy = NULL;
154*92022041SSam Saccone int *n_legacy = NULL;
155*92022041SSam Saccone bool have_ht_mcs_24 = false, have_ht_mcs_5 = false;
156*92022041SSam Saccone bool have_vht_mcs_24 = false, have_vht_mcs_5 = false;
157*92022041SSam Saccone bool have_he_mcs_24 = false, have_he_mcs_5 = false;
158*92022041SSam Saccone bool have_he_mcs_6 = false;
159*92022041SSam Saccone uint8_t ht_mcs_24[77], ht_mcs_5[77];
160*92022041SSam Saccone int n_ht_mcs_24 = 0, n_ht_mcs_5 = 0;
161*92022041SSam Saccone struct nl80211_txrate_vht txrate_vht_24 = {};
162*92022041SSam Saccone struct nl80211_txrate_vht txrate_vht_5 = {};
163*92022041SSam Saccone struct nl80211_txrate_he txrate_he_24 = {};
164*92022041SSam Saccone struct nl80211_txrate_he txrate_he_5 = {};
165*92022041SSam Saccone struct nl80211_txrate_he txrate_he_6 = {};
166*92022041SSam Saccone uint8_t *mcs = NULL;
167*92022041SSam Saccone int *n_mcs = NULL;
168*92022041SSam Saccone char *vht_argv_5[VHT_ARGC_MAX] = {}; char *vht_argv_24[VHT_ARGC_MAX] = {};
169*92022041SSam Saccone char *he_argv_5[VHT_ARGC_MAX] = {}; char *he_argv_24[VHT_ARGC_MAX] = {};
170*92022041SSam Saccone char *he_argv_6[VHT_ARGC_MAX] = {};
171*92022041SSam Saccone char **vht_argv = NULL, **he_argv = NULL;
172*92022041SSam Saccone int vht_argc_5 = 0; int vht_argc_24 = 0;
173*92022041SSam Saccone int he_argc_5 = 0; int he_argc_24 = 0;
174*92022041SSam Saccone int he_argc_6 = 0;
175*92022041SSam Saccone int *vht_argc = NULL, *he_argc = NULL;
176*92022041SSam Saccone int sgi_24 = 0, sgi_5 = 0, lgi_24 = 0, lgi_5 = 0;
177*92022041SSam Saccone int has_he_gi_24 = 0, has_he_gi_5 = 0, has_he_ltf_24 = 0, has_he_ltf_5 = 0;
178*92022041SSam Saccone int has_he_gi_6 = 0, has_he_ltf_6 = 0;
179*92022041SSam Saccone int he_gi = 0, he_ltf = 0;
180*92022041SSam Saccone char *he_gi_argv = NULL;
181*92022041SSam Saccone
182*92022041SSam Saccone enum {
183*92022041SSam Saccone S_NONE,
184*92022041SSam Saccone S_LEGACY,
185*92022041SSam Saccone S_HT,
186*92022041SSam Saccone S_VHT,
187*92022041SSam Saccone S_HE,
188*92022041SSam Saccone S_GI,
189*92022041SSam Saccone S_HE_GI,
190*92022041SSam Saccone S_HE_LTF,
191*92022041SSam Saccone } parser_state = S_NONE;
192*92022041SSam Saccone
193*92022041SSam Saccone for (i = 0; i < argc; i++) {
194*92022041SSam Saccone char *end;
195*92022041SSam Saccone double tmpd;
196*92022041SSam Saccone long tmpl;
197*92022041SSam Saccone
198*92022041SSam Saccone if (strcmp(argv[i], "legacy-2.4") == 0) {
199*92022041SSam Saccone if (have_legacy_24)
200*92022041SSam Saccone return 1;
201*92022041SSam Saccone parser_state = S_LEGACY;
202*92022041SSam Saccone legacy = legacy_24;
203*92022041SSam Saccone n_legacy = &n_legacy_24;
204*92022041SSam Saccone have_legacy_24 = true;
205*92022041SSam Saccone } else if (strcmp(argv[i], "legacy-5") == 0) {
206*92022041SSam Saccone if (have_legacy_5)
207*92022041SSam Saccone return 1;
208*92022041SSam Saccone parser_state = S_LEGACY;
209*92022041SSam Saccone legacy = legacy_5;
210*92022041SSam Saccone n_legacy = &n_legacy_5;
211*92022041SSam Saccone have_legacy_5 = true;
212*92022041SSam Saccone }
213*92022041SSam Saccone else if (strcmp(argv[i], "ht-mcs-2.4") == 0) {
214*92022041SSam Saccone if (have_ht_mcs_24)
215*92022041SSam Saccone return 1;
216*92022041SSam Saccone parser_state = S_HT;
217*92022041SSam Saccone mcs = ht_mcs_24;
218*92022041SSam Saccone n_mcs = &n_ht_mcs_24;
219*92022041SSam Saccone have_ht_mcs_24 = true;
220*92022041SSam Saccone } else if (strcmp(argv[i], "ht-mcs-5") == 0) {
221*92022041SSam Saccone if (have_ht_mcs_5)
222*92022041SSam Saccone return 1;
223*92022041SSam Saccone parser_state = S_HT;
224*92022041SSam Saccone mcs = ht_mcs_5;
225*92022041SSam Saccone n_mcs = &n_ht_mcs_5;
226*92022041SSam Saccone have_ht_mcs_5 = true;
227*92022041SSam Saccone } else if (strcmp(argv[i], "vht-mcs-2.4") == 0) {
228*92022041SSam Saccone if (have_vht_mcs_24)
229*92022041SSam Saccone return 1;
230*92022041SSam Saccone parser_state = S_VHT;
231*92022041SSam Saccone vht_argv = vht_argv_24;
232*92022041SSam Saccone vht_argc = &vht_argc_24;
233*92022041SSam Saccone have_vht_mcs_24 = true;
234*92022041SSam Saccone } else if (strcmp(argv[i], "vht-mcs-5") == 0) {
235*92022041SSam Saccone if (have_vht_mcs_5)
236*92022041SSam Saccone return 1;
237*92022041SSam Saccone parser_state = S_VHT;
238*92022041SSam Saccone vht_argv = vht_argv_5;
239*92022041SSam Saccone vht_argc = &vht_argc_5;
240*92022041SSam Saccone have_vht_mcs_5 = true;
241*92022041SSam Saccone } else if (strcmp(argv[i], "he-mcs-2.4") == 0) {
242*92022041SSam Saccone if (have_he_mcs_24)
243*92022041SSam Saccone return 1;
244*92022041SSam Saccone parser_state = S_HE;
245*92022041SSam Saccone he_argv = he_argv_24;
246*92022041SSam Saccone he_argc = &he_argc_24;
247*92022041SSam Saccone have_he_mcs_24 = true;
248*92022041SSam Saccone } else if (strcmp(argv[i], "he-mcs-5") == 0) {
249*92022041SSam Saccone if (have_he_mcs_5)
250*92022041SSam Saccone return 1;
251*92022041SSam Saccone parser_state = S_HE;
252*92022041SSam Saccone he_argv = he_argv_5;
253*92022041SSam Saccone he_argc = &he_argc_5;
254*92022041SSam Saccone have_he_mcs_5 = true;
255*92022041SSam Saccone } else if (strcmp(argv[i], "he-mcs-6") == 0) {
256*92022041SSam Saccone if (have_he_mcs_6)
257*92022041SSam Saccone return 1;
258*92022041SSam Saccone parser_state = S_HE;
259*92022041SSam Saccone he_argv = he_argv_6;
260*92022041SSam Saccone he_argc = &he_argc_6;
261*92022041SSam Saccone have_he_mcs_6 = true;
262*92022041SSam Saccone } else if (strcmp(argv[i], "sgi-2.4") == 0) {
263*92022041SSam Saccone sgi_24 = 1;
264*92022041SSam Saccone parser_state = S_GI;
265*92022041SSam Saccone } else if (strcmp(argv[i], "sgi-5") == 0) {
266*92022041SSam Saccone sgi_5 = 1;
267*92022041SSam Saccone parser_state = S_GI;
268*92022041SSam Saccone } else if (strcmp(argv[i], "lgi-2.4") == 0) {
269*92022041SSam Saccone lgi_24 = 1;
270*92022041SSam Saccone parser_state = S_GI;
271*92022041SSam Saccone } else if (strcmp(argv[i], "lgi-5") == 0) {
272*92022041SSam Saccone lgi_5 = 1;
273*92022041SSam Saccone parser_state = S_GI;
274*92022041SSam Saccone } else if (strcmp(argv[i], "he-gi-2.4") == 0) {
275*92022041SSam Saccone has_he_gi_24 = 1;
276*92022041SSam Saccone parser_state = S_HE_GI;
277*92022041SSam Saccone } else if (strcmp(argv[i], "he-gi-5") == 0) {
278*92022041SSam Saccone has_he_gi_5 = 1;
279*92022041SSam Saccone parser_state = S_HE_GI;
280*92022041SSam Saccone } else if (strcmp(argv[i], "he-gi-6") == 0) {
281*92022041SSam Saccone has_he_gi_6 = 1;
282*92022041SSam Saccone parser_state = S_HE_GI;
283*92022041SSam Saccone } else if (strcmp(argv[i], "he-ltf-2.4") == 0) {
284*92022041SSam Saccone has_he_ltf_24 = 1;
285*92022041SSam Saccone parser_state = S_HE_LTF;
286*92022041SSam Saccone } else if (strcmp(argv[i], "he-ltf-5") == 0) {
287*92022041SSam Saccone has_he_ltf_5 = 1;
288*92022041SSam Saccone parser_state = S_HE_LTF;
289*92022041SSam Saccone } else if (strcmp(argv[i], "he-ltf-6") == 0) {
290*92022041SSam Saccone has_he_ltf_6 = 1;
291*92022041SSam Saccone parser_state = S_HE_LTF;
292*92022041SSam Saccone } else switch (parser_state) {
293*92022041SSam Saccone case S_LEGACY:
294*92022041SSam Saccone tmpd = strtod(argv[i], &end);
295*92022041SSam Saccone if (*end != '\0')
296*92022041SSam Saccone return 1;
297*92022041SSam Saccone if (tmpd < 1 || tmpd > 255 * 2)
298*92022041SSam Saccone return 1;
299*92022041SSam Saccone legacy[(*n_legacy)++] = tmpd * 2;
300*92022041SSam Saccone break;
301*92022041SSam Saccone case S_HT:
302*92022041SSam Saccone tmpl = strtol(argv[i], &end, 0);
303*92022041SSam Saccone if (*end != '\0')
304*92022041SSam Saccone return 1;
305*92022041SSam Saccone if (tmpl < 0 || tmpl > 255)
306*92022041SSam Saccone return 1;
307*92022041SSam Saccone mcs[(*n_mcs)++] = tmpl;
308*92022041SSam Saccone break;
309*92022041SSam Saccone case S_VHT:
310*92022041SSam Saccone if (*vht_argc >= VHT_ARGC_MAX)
311*92022041SSam Saccone return 1;
312*92022041SSam Saccone vht_argv[(*vht_argc)++] = argv[i];
313*92022041SSam Saccone break;
314*92022041SSam Saccone case S_HE:
315*92022041SSam Saccone if (*he_argc >= VHT_ARGC_MAX)
316*92022041SSam Saccone return 1;
317*92022041SSam Saccone he_argv[(*he_argc)++] = argv[i];
318*92022041SSam Saccone break;
319*92022041SSam Saccone case S_GI:
320*92022041SSam Saccone break;
321*92022041SSam Saccone case S_HE_GI:
322*92022041SSam Saccone he_gi_argv = argv[i];
323*92022041SSam Saccone break;
324*92022041SSam Saccone case S_HE_LTF:
325*92022041SSam Saccone he_ltf = strtol(argv[i], &end, 0);
326*92022041SSam Saccone if (*end != '\0')
327*92022041SSam Saccone return 1;
328*92022041SSam Saccone if (he_ltf < 0 || he_ltf > 4)
329*92022041SSam Saccone return 1;
330*92022041SSam Saccone he_ltf = he_ltf >> 1;
331*92022041SSam Saccone break;
332*92022041SSam Saccone default:
333*92022041SSam Saccone if (attr != NL80211_ATTR_TX_RATES)
334*92022041SSam Saccone goto next;
335*92022041SSam Saccone return 1;
336*92022041SSam Saccone }
337*92022041SSam Saccone }
338*92022041SSam Saccone
339*92022041SSam Saccone next:
340*92022041SSam Saccone if (attr != NL80211_ATTR_TX_RATES)
341*92022041SSam Saccone ret = i;
342*92022041SSam Saccone
343*92022041SSam Saccone if (have_vht_mcs_24)
344*92022041SSam Saccone if (!setup_vht(&txrate_vht_24, vht_argc_24, vht_argv_24))
345*92022041SSam Saccone return -EINVAL;
346*92022041SSam Saccone
347*92022041SSam Saccone if (have_vht_mcs_5)
348*92022041SSam Saccone if (!setup_vht(&txrate_vht_5, vht_argc_5, vht_argv_5))
349*92022041SSam Saccone return -EINVAL;
350*92022041SSam Saccone
351*92022041SSam Saccone if (have_he_mcs_24)
352*92022041SSam Saccone if (!setup_he(&txrate_he_24, he_argc_24, he_argv_24))
353*92022041SSam Saccone return -EINVAL;
354*92022041SSam Saccone
355*92022041SSam Saccone if (have_he_mcs_5)
356*92022041SSam Saccone if (!setup_he(&txrate_he_5, he_argc_5, he_argv_5))
357*92022041SSam Saccone return -EINVAL;
358*92022041SSam Saccone
359*92022041SSam Saccone if (have_he_mcs_6)
360*92022041SSam Saccone if (!setup_he(&txrate_he_6, he_argc_6, he_argv_6))
361*92022041SSam Saccone return -EINVAL;
362*92022041SSam Saccone
363*92022041SSam Saccone if (sgi_5 && lgi_5)
364*92022041SSam Saccone return 1;
365*92022041SSam Saccone
366*92022041SSam Saccone if (sgi_24 && lgi_24)
367*92022041SSam Saccone return 1;
368*92022041SSam Saccone
369*92022041SSam Saccone if (he_gi_argv) {
370*92022041SSam Saccone he_gi = parse_he_gi(he_gi_argv);
371*92022041SSam Saccone if (he_gi < 0)
372*92022041SSam Saccone return 1;
373*92022041SSam Saccone }
374*92022041SSam Saccone
375*92022041SSam Saccone nl_rates = nla_nest_start(msg, attr);
376*92022041SSam Saccone if (!nl_rates)
377*92022041SSam Saccone goto nla_put_failure;
378*92022041SSam Saccone
379*92022041SSam Saccone if (have_legacy_24 || have_ht_mcs_24 || have_vht_mcs_24 || have_he_mcs_24 ||
380*92022041SSam Saccone sgi_24 || lgi_24 || has_he_gi_24 || has_he_ltf_24) {
381*92022041SSam Saccone nl_band = nla_nest_start(msg, NL80211_BAND_2GHZ);
382*92022041SSam Saccone if (!nl_band)
383*92022041SSam Saccone goto nla_put_failure;
384*92022041SSam Saccone if (have_legacy_24)
385*92022041SSam Saccone nla_put(msg, NL80211_TXRATE_LEGACY, n_legacy_24, legacy_24);
386*92022041SSam Saccone if (have_ht_mcs_24)
387*92022041SSam Saccone nla_put(msg, NL80211_TXRATE_HT, n_ht_mcs_24, ht_mcs_24);
388*92022041SSam Saccone if (have_vht_mcs_24)
389*92022041SSam Saccone nla_put(msg, NL80211_TXRATE_VHT, sizeof(txrate_vht_24), &txrate_vht_24);
390*92022041SSam Saccone if (have_he_mcs_24)
391*92022041SSam Saccone nla_put(msg, NL80211_TXRATE_HE, sizeof(txrate_he_24),
392*92022041SSam Saccone &txrate_he_24);
393*92022041SSam Saccone if (sgi_24)
394*92022041SSam Saccone nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_SGI);
395*92022041SSam Saccone if (lgi_24)
396*92022041SSam Saccone nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_LGI);
397*92022041SSam Saccone if (has_he_gi_24)
398*92022041SSam Saccone nla_put_u8(msg, NL80211_TXRATE_HE_GI, he_gi);
399*92022041SSam Saccone if (has_he_ltf_24)
400*92022041SSam Saccone nla_put_u8(msg, NL80211_TXRATE_HE_LTF, he_ltf);
401*92022041SSam Saccone nla_nest_end(msg, nl_band);
402*92022041SSam Saccone }
403*92022041SSam Saccone
404*92022041SSam Saccone if (have_legacy_5 || have_ht_mcs_5 || have_vht_mcs_5 || have_he_mcs_5 ||
405*92022041SSam Saccone sgi_5 || lgi_5 || has_he_gi_5 || has_he_ltf_5) {
406*92022041SSam Saccone nl_band = nla_nest_start(msg, NL80211_BAND_5GHZ);
407*92022041SSam Saccone if (!nl_band)
408*92022041SSam Saccone goto nla_put_failure;
409*92022041SSam Saccone if (have_legacy_5)
410*92022041SSam Saccone nla_put(msg, NL80211_TXRATE_LEGACY, n_legacy_5, legacy_5);
411*92022041SSam Saccone if (have_ht_mcs_5)
412*92022041SSam Saccone nla_put(msg, NL80211_TXRATE_HT, n_ht_mcs_5, ht_mcs_5);
413*92022041SSam Saccone if (have_vht_mcs_5)
414*92022041SSam Saccone nla_put(msg, NL80211_TXRATE_VHT, sizeof(txrate_vht_5), &txrate_vht_5);
415*92022041SSam Saccone if (have_he_mcs_5)
416*92022041SSam Saccone nla_put(msg, NL80211_TXRATE_HE, sizeof(txrate_he_5),
417*92022041SSam Saccone &txrate_he_5);
418*92022041SSam Saccone if (sgi_5)
419*92022041SSam Saccone nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_SGI);
420*92022041SSam Saccone if (lgi_5)
421*92022041SSam Saccone nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_LGI);
422*92022041SSam Saccone if (has_he_gi_5)
423*92022041SSam Saccone nla_put_u8(msg, NL80211_TXRATE_HE_GI, he_gi);
424*92022041SSam Saccone if (has_he_ltf_5)
425*92022041SSam Saccone nla_put_u8(msg, NL80211_TXRATE_HE_LTF, he_ltf);
426*92022041SSam Saccone nla_nest_end(msg, nl_band);
427*92022041SSam Saccone }
428*92022041SSam Saccone
429*92022041SSam Saccone if (have_he_mcs_6 || has_he_gi_6 || has_he_ltf_6) {
430*92022041SSam Saccone nl_band = nla_nest_start(msg, NL80211_BAND_6GHZ);
431*92022041SSam Saccone if (!nl_band)
432*92022041SSam Saccone goto nla_put_failure;
433*92022041SSam Saccone if (have_he_mcs_6)
434*92022041SSam Saccone nla_put(msg, NL80211_TXRATE_HE, sizeof(txrate_he_6),
435*92022041SSam Saccone &txrate_he_6);
436*92022041SSam Saccone if (has_he_gi_6)
437*92022041SSam Saccone nla_put_u8(msg, NL80211_TXRATE_HE_GI, he_gi);
438*92022041SSam Saccone if (has_he_ltf_6)
439*92022041SSam Saccone nla_put_u8(msg, NL80211_TXRATE_HE_LTF, he_ltf);
440*92022041SSam Saccone nla_nest_end(msg, nl_band);
441*92022041SSam Saccone }
442*92022041SSam Saccone
443*92022041SSam Saccone nla_nest_end(msg, nl_rates);
444*92022041SSam Saccone
445*92022041SSam Saccone return ret;
446*92022041SSam Saccone nla_put_failure:
447*92022041SSam Saccone return -ENOBUFS;
448*92022041SSam Saccone }
449*92022041SSam Saccone
handle_bitrates(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)450*92022041SSam Saccone static int handle_bitrates(struct nl80211_state *state,
451*92022041SSam Saccone struct nl_msg *msg,
452*92022041SSam Saccone int argc, char **argv,
453*92022041SSam Saccone enum id_input id)
454*92022041SSam Saccone {
455*92022041SSam Saccone return set_bitrates(msg, argc, argv, NL80211_ATTR_TX_RATES);
456*92022041SSam Saccone }
457*92022041SSam Saccone
458*92022041SSam Saccone #define DESCR_LEGACY "[legacy-<2.4|5> <legacy rate in Mbps>*]"
459*92022041SSam Saccone #define DESCR DESCR_LEGACY " [ht-mcs-<2.4|5> <MCS index>*] [vht-mcs-<2.4|5> [he-mcs-<2.4|5|6> <NSS:MCSx,MCSy... | NSS:MCSx-MCSy>*] [sgi-2.4|lgi-2.4] [sgi-5|lgi-5]"
460*92022041SSam Saccone
461*92022041SSam Saccone COMMAND(set, bitrates, "[legacy-<2.4|5> <legacy rate in Mbps>*] [ht-mcs-<2.4|5> <MCS index>*] [vht-mcs-<2.4|5> [he-mcs-<2.4|5|6> <NSS:MCSx,MCSy... | NSS:MCSx-MCSy>*] [sgi-2.4|lgi-2.4] [sgi-5|lgi-5] [he-gi-<2.4|5|6> <0.8|1.6|3.2>] [he-ltf-<2.4|5|6> <1|2|4>]",
462*92022041SSam Saccone NL80211_CMD_SET_TX_BITRATE_MASK, 0, CIB_NETDEV, handle_bitrates,
463*92022041SSam Saccone "Sets up the specified rate masks.\n"
464*92022041SSam Saccone "Not passing any arguments would clear the existing mask (if any).");
465