7 static int parse_rate_chunk(const char *arg
, __u8
*nss
, __u16
*mcs
, unsigned int mode
)
10 unsigned int inss
, mcs_start
, mcs_end
, tab
[12];
11 unsigned int max_mcs
= 0, max_nss
= 0;
15 if (mode
== NL80211_TXRATE_HE
) {
17 max_nss
= NL80211_HE_NSS_MAX
;
20 max_nss
= NL80211_VHT_NSS_MAX
;
23 if (strchr(arg
, '-')) {
24 /* Format: NSS:MCS_START-MCS_END */
25 count
= sscanf(arg
, "%u:%u-%u", &inss
, &mcs_start
, &mcs_end
);
30 if (inss
< 1 || inss
> max_nss
)
33 if (mcs_start
> mcs_end
)
36 if (mcs_start
> max_mcs
|| mcs_end
> max_mcs
)
40 for (i
= mcs_start
; i
<= mcs_end
; i
++)
44 /* Format: NSS:MCSx,MCSy,... */
45 if (mode
== NL80211_TXRATE_HE
) {
46 count
= sscanf(arg
, "%u:%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
47 &inss
, &tab
[0], &tab
[1], &tab
[2], &tab
[3],
48 &tab
[4], &tab
[5], &tab
[6], &tab
[7], &tab
[8],
49 &tab
[9], &tab
[10], &tab
[11]);
51 count
= sscanf(arg
, "%u:%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", &inss
,
52 &tab
[0], &tab
[1], &tab
[2], &tab
[3], &tab
[4],
53 &tab
[5], &tab
[6], &tab
[7], &tab
[8], &tab
[9]);
59 if (inss
< 1 || inss
> max_nss
)
63 for (i
= 0; i
< count
- 1; i
++) {
73 static int parse_vht_chunk(const char *arg
, __u8
*nss
, __u16
*mcs
)
75 return parse_rate_chunk(arg
, nss
, mcs
, NL80211_TXRATE_VHT
);
78 static int parse_he_chunk(const char *arg
, __u8
*nss
, __u16
*mcs
)
80 return parse_rate_chunk(arg
, nss
, mcs
, NL80211_TXRATE_HE
);
83 static int setup_vht(struct nl80211_txrate_vht
*txrate_vht
,
84 int argc
, char **argv
)
90 memset(txrate_vht
, 0, sizeof(*txrate_vht
));
92 for (i
= 0; i
< argc
; i
++) {
93 if (!parse_vht_chunk(argv
[i
], &nss
, &mcs
))
97 txrate_vht
->mcs
[nss
] |= mcs
;
103 static int setup_he(struct nl80211_txrate_he
*txrate_he
,
104 int argc
, char **argv
)
110 memset(txrate_he
, 0, sizeof(*txrate_he
));
112 for (i
= 0; i
< argc
; i
++) {
113 if (!parse_he_chunk(argv
[i
], &nss
, &mcs
))
117 txrate_he
->mcs
[nss
] |= mcs
;
123 #define HE_GI_STR_MAX 16
124 #define HE_GI_08_STR "0.8"
125 #define HE_GI_16_STR "1.6"
126 #define HE_GI_32_STR "3.2"
127 static int parse_he_gi(char *he_gi
)
132 if (!strncmp(he_gi
, HE_GI_08_STR
, sizeof(HE_GI_08_STR
)))
133 return NL80211_RATE_INFO_HE_GI_0_8
;
134 if (!strncmp(he_gi
, HE_GI_16_STR
, sizeof(HE_GI_16_STR
)))
135 return NL80211_RATE_INFO_HE_GI_1_6
;
136 if (!strncmp(he_gi
, HE_GI_32_STR
, sizeof(HE_GI_32_STR
)))
137 return NL80211_RATE_INFO_HE_GI_3_2
;
142 #define VHT_ARGC_MAX 100
144 int set_bitrates(struct nl_msg
*msg
,
145 int argc
, char **argv
,
146 enum nl80211_attrs attr
)
148 struct nlattr
*nl_rates
, *nl_band
;
150 bool have_legacy_24
= false, have_legacy_5
= false;
151 uint8_t legacy_24
[32], legacy_5
[32];
152 int n_legacy_24
= 0, n_legacy_5
= 0;
153 uint8_t *legacy
= NULL
;
154 int *n_legacy
= NULL
;
155 bool have_ht_mcs_24
= false, have_ht_mcs_5
= false;
156 bool have_vht_mcs_24
= false, have_vht_mcs_5
= false;
157 bool have_he_mcs_24
= false, have_he_mcs_5
= false;
158 bool have_he_mcs_6
= false;
159 uint8_t ht_mcs_24
[77], ht_mcs_5
[77];
160 int n_ht_mcs_24
= 0, n_ht_mcs_5
= 0;
161 struct nl80211_txrate_vht txrate_vht_24
= {};
162 struct nl80211_txrate_vht txrate_vht_5
= {};
163 struct nl80211_txrate_he txrate_he_24
= {};
164 struct nl80211_txrate_he txrate_he_5
= {};
165 struct nl80211_txrate_he txrate_he_6
= {};
168 char *vht_argv_5
[VHT_ARGC_MAX
] = {}; char *vht_argv_24
[VHT_ARGC_MAX
] = {};
169 char *he_argv_5
[VHT_ARGC_MAX
] = {}; char *he_argv_24
[VHT_ARGC_MAX
] = {};
170 char *he_argv_6
[VHT_ARGC_MAX
] = {};
171 char **vht_argv
= NULL
, **he_argv
= NULL
;
172 int vht_argc_5
= 0; int vht_argc_24
= 0;
173 int he_argc_5
= 0; int he_argc_24
= 0;
175 int *vht_argc
= NULL
, *he_argc
= NULL
;
176 int sgi_24
= 0, sgi_5
= 0, lgi_24
= 0, lgi_5
= 0;
177 int has_he_gi_24
= 0, has_he_gi_5
= 0, has_he_ltf_24
= 0, has_he_ltf_5
= 0;
178 int has_he_gi_6
= 0, has_he_ltf_6
= 0;
179 int he_gi
= 0, he_ltf
= 0;
180 char *he_gi_argv
= NULL
;
191 } parser_state
= S_NONE
;
193 for (i
= 0; i
< argc
; i
++) {
198 if (strcmp(argv
[i
], "legacy-2.4") == 0) {
201 parser_state
= S_LEGACY
;
203 n_legacy
= &n_legacy_24
;
204 have_legacy_24
= true;
205 } else if (strcmp(argv
[i
], "legacy-5") == 0) {
208 parser_state
= S_LEGACY
;
210 n_legacy
= &n_legacy_5
;
211 have_legacy_5
= true;
213 else if (strcmp(argv
[i
], "ht-mcs-2.4") == 0) {
218 n_mcs
= &n_ht_mcs_24
;
219 have_ht_mcs_24
= true;
220 } else if (strcmp(argv
[i
], "ht-mcs-5") == 0) {
226 have_ht_mcs_5
= true;
227 } else if (strcmp(argv
[i
], "vht-mcs-2.4") == 0) {
230 parser_state
= S_VHT
;
231 vht_argv
= vht_argv_24
;
232 vht_argc
= &vht_argc_24
;
233 have_vht_mcs_24
= true;
234 } else if (strcmp(argv
[i
], "vht-mcs-5") == 0) {
237 parser_state
= S_VHT
;
238 vht_argv
= vht_argv_5
;
239 vht_argc
= &vht_argc_5
;
240 have_vht_mcs_5
= true;
241 } else if (strcmp(argv
[i
], "he-mcs-2.4") == 0) {
245 he_argv
= he_argv_24
;
246 he_argc
= &he_argc_24
;
247 have_he_mcs_24
= true;
248 } else if (strcmp(argv
[i
], "he-mcs-5") == 0) {
253 he_argc
= &he_argc_5
;
254 have_he_mcs_5
= true;
255 } else if (strcmp(argv
[i
], "he-mcs-6") == 0) {
260 he_argc
= &he_argc_6
;
261 have_he_mcs_6
= true;
262 } else if (strcmp(argv
[i
], "sgi-2.4") == 0) {
265 } else if (strcmp(argv
[i
], "sgi-5") == 0) {
268 } else if (strcmp(argv
[i
], "lgi-2.4") == 0) {
271 } else if (strcmp(argv
[i
], "lgi-5") == 0) {
274 } else if (strcmp(argv
[i
], "he-gi-2.4") == 0) {
276 parser_state
= S_HE_GI
;
277 } else if (strcmp(argv
[i
], "he-gi-5") == 0) {
279 parser_state
= S_HE_GI
;
280 } else if (strcmp(argv
[i
], "he-gi-6") == 0) {
282 parser_state
= S_HE_GI
;
283 } else if (strcmp(argv
[i
], "he-ltf-2.4") == 0) {
285 parser_state
= S_HE_LTF
;
286 } else if (strcmp(argv
[i
], "he-ltf-5") == 0) {
288 parser_state
= S_HE_LTF
;
289 } else if (strcmp(argv
[i
], "he-ltf-6") == 0) {
291 parser_state
= S_HE_LTF
;
292 } else switch (parser_state
) {
294 tmpd
= strtod(argv
[i
], &end
);
297 if (tmpd
< 1 || tmpd
> 255 * 2)
299 legacy
[(*n_legacy
)++] = tmpd
* 2;
302 tmpl
= strtol(argv
[i
], &end
, 0);
305 if (tmpl
< 0 || tmpl
> 255)
307 mcs
[(*n_mcs
)++] = tmpl
;
310 if (*vht_argc
>= VHT_ARGC_MAX
)
312 vht_argv
[(*vht_argc
)++] = argv
[i
];
315 if (*he_argc
>= VHT_ARGC_MAX
)
317 he_argv
[(*he_argc
)++] = argv
[i
];
322 he_gi_argv
= argv
[i
];
325 he_ltf
= strtol(argv
[i
], &end
, 0);
328 if (he_ltf
< 0 || he_ltf
> 4)
330 he_ltf
= he_ltf
>> 1;
333 if (attr
!= NL80211_ATTR_TX_RATES
)
340 if (attr
!= NL80211_ATTR_TX_RATES
)
344 if (!setup_vht(&txrate_vht_24
, vht_argc_24
, vht_argv_24
))
348 if (!setup_vht(&txrate_vht_5
, vht_argc_5
, vht_argv_5
))
352 if (!setup_he(&txrate_he_24
, he_argc_24
, he_argv_24
))
356 if (!setup_he(&txrate_he_5
, he_argc_5
, he_argv_5
))
360 if (!setup_he(&txrate_he_6
, he_argc_6
, he_argv_6
))
366 if (sgi_24
&& lgi_24
)
370 he_gi
= parse_he_gi(he_gi_argv
);
375 nl_rates
= nla_nest_start(msg
, attr
);
377 goto nla_put_failure
;
379 if (have_legacy_24
|| have_ht_mcs_24
|| have_vht_mcs_24
|| have_he_mcs_24
||
380 sgi_24
|| lgi_24
|| has_he_gi_24
|| has_he_ltf_24
) {
381 nl_band
= nla_nest_start(msg
, NL80211_BAND_2GHZ
);
383 goto nla_put_failure
;
385 nla_put(msg
, NL80211_TXRATE_LEGACY
, n_legacy_24
, legacy_24
);
387 nla_put(msg
, NL80211_TXRATE_HT
, n_ht_mcs_24
, ht_mcs_24
);
389 nla_put(msg
, NL80211_TXRATE_VHT
, sizeof(txrate_vht_24
), &txrate_vht_24
);
391 nla_put(msg
, NL80211_TXRATE_HE
, sizeof(txrate_he_24
),
394 nla_put_u8(msg
, NL80211_TXRATE_GI
, NL80211_TXRATE_FORCE_SGI
);
396 nla_put_u8(msg
, NL80211_TXRATE_GI
, NL80211_TXRATE_FORCE_LGI
);
398 nla_put_u8(msg
, NL80211_TXRATE_HE_GI
, he_gi
);
400 nla_put_u8(msg
, NL80211_TXRATE_HE_LTF
, he_ltf
);
401 nla_nest_end(msg
, nl_band
);
404 if (have_legacy_5
|| have_ht_mcs_5
|| have_vht_mcs_5
|| have_he_mcs_5
||
405 sgi_5
|| lgi_5
|| has_he_gi_5
|| has_he_ltf_5
) {
406 nl_band
= nla_nest_start(msg
, NL80211_BAND_5GHZ
);
408 goto nla_put_failure
;
410 nla_put(msg
, NL80211_TXRATE_LEGACY
, n_legacy_5
, legacy_5
);
412 nla_put(msg
, NL80211_TXRATE_HT
, n_ht_mcs_5
, ht_mcs_5
);
414 nla_put(msg
, NL80211_TXRATE_VHT
, sizeof(txrate_vht_5
), &txrate_vht_5
);
416 nla_put(msg
, NL80211_TXRATE_HE
, sizeof(txrate_he_5
),
419 nla_put_u8(msg
, NL80211_TXRATE_GI
, NL80211_TXRATE_FORCE_SGI
);
421 nla_put_u8(msg
, NL80211_TXRATE_GI
, NL80211_TXRATE_FORCE_LGI
);
423 nla_put_u8(msg
, NL80211_TXRATE_HE_GI
, he_gi
);
425 nla_put_u8(msg
, NL80211_TXRATE_HE_LTF
, he_ltf
);
426 nla_nest_end(msg
, nl_band
);
429 if (have_he_mcs_6
|| has_he_gi_6
|| has_he_ltf_6
) {
430 nl_band
= nla_nest_start(msg
, NL80211_BAND_6GHZ
);
432 goto nla_put_failure
;
434 nla_put(msg
, NL80211_TXRATE_HE
, sizeof(txrate_he_6
),
437 nla_put_u8(msg
, NL80211_TXRATE_HE_GI
, he_gi
);
439 nla_put_u8(msg
, NL80211_TXRATE_HE_LTF
, he_ltf
);
440 nla_nest_end(msg
, nl_band
);
443 nla_nest_end(msg
, nl_rates
);
450 static int handle_bitrates(struct nl80211_state
*state
,
452 int argc
, char **argv
,
455 return set_bitrates(msg
, argc
, argv
, NL80211_ATTR_TX_RATES
);
458 #define DESCR_LEGACY "[legacy-<2.4|5> <legacy rate in Mbps>*]"
459 #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]"
461 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 NL80211_CMD_SET_TX_BITRATE_MASK
, 0, CIB_NETDEV
, handle_bitrates
,
463 "Sets up the specified rate masks.\n"
464 "Not passing any arguments would clear the existing mask (if any).");