1942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg#include <errno.h>
2942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg
3942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg#include "nl80211.h"
4942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg#include "iw.h"
5942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg
6942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg
7118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzicstatic int parse_vht_chunk(const char *arg, __u8 *nss, __u16 *mcs)
8118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic{
9118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	int count, i;
10118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	unsigned int inss, mcs_start, mcs_end, tab[10];
11118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
12118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	*nss = 0; *mcs = 0;
13118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
14118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	if (strchr(arg, '-')) {
15118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		/* Format: NSS:MCS_START-MCS_END */
16118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		count = sscanf(arg, "%u:%u-%u", &inss, &mcs_start, &mcs_end);
17118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
18118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		if (count != 3)
19118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			return 0;
20118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
21118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		if (inss < 1 || inss > NL80211_VHT_NSS_MAX)
22118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			return 0;
23118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
24118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		if (mcs_start > mcs_end)
25118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			return 0;
26118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
27118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		if (mcs_start > 9 || mcs_end > 9)
28118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			return 0;
29118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
30118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		*nss = inss;
31118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		for (i = mcs_start; i <= mcs_end; i++)
32118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			*mcs |= 1 << i;
33118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
34118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	} else {
35118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		/* Format: NSS:MCSx,MCSy,... */
36118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		count = sscanf(arg, "%u:%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", &inss,
37118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			   &tab[0], &tab[1], &tab[2], &tab[3], &tab[4], &tab[5],
38118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			   &tab[6], &tab[7], &tab[8], &tab[9]);
39118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
40118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		if (count < 2)
41118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			return 0;
42118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
43118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		if (inss < 1 || inss > NL80211_VHT_NSS_MAX)
44118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			return 0;
45118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
46118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		*nss = inss;
47118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		for (i = 0; i < count - 1; i++) {
48118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			if (tab[i] > 9)
49118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic				return 0;
50118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			*mcs |= 1 << tab[i];
51118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		}
52118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	}
53118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
54118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	return 1;
55118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic}
56118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
57118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzicstatic int setup_vht(struct nl80211_txrate_vht *txrate_vht,
58118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		     int argc, char **argv)
59118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic{
60118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	__u8 nss;
61118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	__u16 mcs;
62118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	int i;
63118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
64118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	memset(txrate_vht, 0, sizeof(*txrate_vht));
65118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
66118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	for (i = 0; i < argc; i++) {
67118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		if(!parse_vht_chunk(argv[i], &nss, &mcs))
68118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			return 0;
69118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
70118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		nss--;
71118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		txrate_vht->mcs[nss] |= mcs;
72118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	}
73118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
74118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	return 1;
75118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic}
76118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
77118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic#define VHT_ARGC_MAX	100
78118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
79942b5cd86434724ac31ff3847baf3d1365b75022Johannes Bergstatic int handle_bitrates(struct nl80211_state *state,
80942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			   struct nl_cb *cb,
81942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			   struct nl_msg *msg,
8205514f9581f66b12ac9ee0f21c770ceb34310e9dJohannes Berg			   int argc, char **argv,
8305514f9581f66b12ac9ee0f21c770ceb34310e9dJohannes Berg			   enum id_input id)
84942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg{
85942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	struct nlattr *nl_rates, *nl_band;
86942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	int i;
87942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	bool have_legacy_24 = false, have_legacy_5 = false;
88942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	uint8_t legacy_24[32], legacy_5[32];
89942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	int n_legacy_24 = 0, n_legacy_5 = 0;
90942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	uint8_t *legacy = NULL;
91942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	int *n_legacy = NULL;
92118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	bool have_ht_mcs_24 = false, have_ht_mcs_5 = false;
93118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	bool have_vht_mcs_24 = false, have_vht_mcs_5 = false;
94118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	uint8_t ht_mcs_24[77], ht_mcs_5[77];
95118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	int n_ht_mcs_24 = 0, n_ht_mcs_5 = 0;
96118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	struct nl80211_txrate_vht txrate_vht_24 = {};
97118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	struct nl80211_txrate_vht txrate_vht_5 = {};
98942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	uint8_t *mcs = NULL;
99942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	int *n_mcs = NULL;
100118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	char *vht_argv_5[VHT_ARGC_MAX] = {}; char *vht_argv_24[VHT_ARGC_MAX] = {};
101118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	char **vht_argv = NULL;
102118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	int vht_argc_5 = 0; int vht_argc_24 = 0;
103118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	int *vht_argc = NULL;
104eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic	int sgi_24 = 0, sgi_5 = 0, lgi_24 = 0, lgi_5 = 0;
105118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
106942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	enum {
107942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		S_NONE,
108942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		S_LEGACY,
109118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		S_HT,
110118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		S_VHT,
111eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic		S_GI,
112942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	} parser_state = S_NONE;
113942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg
114942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	for (i = 0; i < argc; i++) {
115942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		char *end;
116bd0f464b76491e46a08e20a2f149092a5e4b335cJohannes Berg		double tmpd;
117942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		long tmpl;
118942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg
119942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		if (strcmp(argv[i], "legacy-2.4") == 0) {
120942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			if (have_legacy_24)
121942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg				return 1;
122942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			parser_state = S_LEGACY;
123942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			legacy = legacy_24;
124942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			n_legacy = &n_legacy_24;
125942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			have_legacy_24 = true;
126942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		} else if (strcmp(argv[i], "legacy-5") == 0) {
127942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			if (have_legacy_5)
128942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg				return 1;
129942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			parser_state = S_LEGACY;
130942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			legacy = legacy_5;
131942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			n_legacy = &n_legacy_5;
132942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			have_legacy_5 = true;
133942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		}
134118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		else if (strcmp(argv[i], "ht-mcs-2.4") == 0) {
135118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			if (have_ht_mcs_24)
136118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic				return 1;
137118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			parser_state = S_HT;
138118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			mcs = ht_mcs_24;
139118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			n_mcs = &n_ht_mcs_24;
140118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			have_ht_mcs_24 = true;
141118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		} else if (strcmp(argv[i], "ht-mcs-5") == 0) {
142118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			if (have_ht_mcs_5)
143118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic				return 1;
144118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			parser_state = S_HT;
145118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			mcs = ht_mcs_5;
146118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			n_mcs = &n_ht_mcs_5;
147118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			have_ht_mcs_5 = true;
148118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		} else if (strcmp(argv[i], "vht-mcs-2.4") == 0) {
149118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			if (have_vht_mcs_24)
150942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg				return 1;
151118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			parser_state = S_VHT;
152118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			vht_argv = vht_argv_24;
153118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			vht_argc = &vht_argc_24;
154118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			have_vht_mcs_24 = true;
155118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		} else if (strcmp(argv[i], "vht-mcs-5") == 0) {
156118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			if (have_vht_mcs_5)
157942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg				return 1;
158118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			parser_state = S_VHT;
159118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			vht_argv = vht_argv_5;
160118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			vht_argc = &vht_argc_5;
161118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			have_vht_mcs_5 = true;
162eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic		} else if (strcmp(argv[i], "sgi-2.4") == 0) {
163eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic			sgi_24 = 1;
164eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic			parser_state = S_GI;
165eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic		} else if (strcmp(argv[i], "sgi-5") == 0) {
166eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic			sgi_5 = 1;
167eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic			parser_state = S_GI;
168eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic		} else if (strcmp(argv[i], "lgi-2.4") == 0) {
169eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic			lgi_24 = 1;
170eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic			parser_state = S_GI;
171eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic		} else if (strcmp(argv[i], "lgi-5") == 0) {
172eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic			lgi_5 = 1;
173eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic			parser_state = S_GI;
174eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic		} else switch (parser_state) {
175942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		case S_LEGACY:
176bd0f464b76491e46a08e20a2f149092a5e4b335cJohannes Berg			tmpd = strtod(argv[i], &end);
177942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			if (*end != '\0')
178942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg				return 1;
179bd0f464b76491e46a08e20a2f149092a5e4b335cJohannes Berg			if (tmpd < 1 || tmpd > 255 * 2)
180942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg				return 1;
181bd0f464b76491e46a08e20a2f149092a5e4b335cJohannes Berg			legacy[(*n_legacy)++] = tmpd * 2;
182942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			break;
183118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		case S_HT:
184942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			tmpl = strtol(argv[i], &end, 0);
185942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			if (*end != '\0')
186942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg				return 1;
187942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			if (tmpl < 0 || tmpl > 255)
188942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg				return 1;
189942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			mcs[(*n_mcs)++] = tmpl;
190942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			break;
191118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		case S_VHT:
192118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			if (*vht_argc >= VHT_ARGC_MAX)
193118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic				return 1;
194118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			vht_argv[(*vht_argc)++] = argv[i];
195118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			break;
196eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic		case S_GI:
197eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic			break;
198942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		default:
199942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			return 1;
200942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		}
201942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	}
202942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg
203118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	if (have_vht_mcs_24)
204118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		if(!setup_vht(&txrate_vht_24, vht_argc_24, vht_argv_24))
205118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			return -EINVAL;
206118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
207118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic	if (have_vht_mcs_5)
208118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		if(!setup_vht(&txrate_vht_5, vht_argc_5, vht_argv_5))
209118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			return -EINVAL;
210118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic
211eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic	if (sgi_5 && lgi_5)
212eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic		return 1;
213eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic
214eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic	if (sgi_24 && lgi_24)
215eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic		return 1;
216eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic
217942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	nl_rates = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
218942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	if (!nl_rates)
219942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		goto nla_put_failure;
220942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg
221eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic	if (have_legacy_24 || have_ht_mcs_24 || have_vht_mcs_24 || sgi_24 || lgi_24) {
222942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		nl_band = nla_nest_start(msg, NL80211_BAND_2GHZ);
223942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		if (!nl_band)
224942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			goto nla_put_failure;
225942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		if (have_legacy_24)
226942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			nla_put(msg, NL80211_TXRATE_LEGACY, n_legacy_24, legacy_24);
227118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		if (have_ht_mcs_24)
228118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			nla_put(msg, NL80211_TXRATE_HT, n_ht_mcs_24, ht_mcs_24);
229118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		if (have_vht_mcs_24)
230118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			nla_put(msg, NL80211_TXRATE_VHT, sizeof(txrate_vht_24), &txrate_vht_24);
231eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic		if (sgi_24)
232eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic			nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_SGI);
233eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic		if (lgi_24)
234eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic			nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_LGI);
235942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		nla_nest_end(msg, nl_band);
236942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	}
237942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg
238eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic	if (have_legacy_5 || have_ht_mcs_5 || have_vht_mcs_5 || sgi_5 || lgi_5) {
239942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		nl_band = nla_nest_start(msg, NL80211_BAND_5GHZ);
240942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		if (!nl_band)
241942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			goto nla_put_failure;
242942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		if (have_legacy_5)
243942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg			nla_put(msg, NL80211_TXRATE_LEGACY, n_legacy_5, legacy_5);
244118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		if (have_ht_mcs_5)
245118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			nla_put(msg, NL80211_TXRATE_HT, n_ht_mcs_5, ht_mcs_5);
246118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic		if (have_vht_mcs_5)
247118976b2e36a9b9639657ac61aeff95770aa428aJanusz Dziedzic			nla_put(msg, NL80211_TXRATE_VHT, sizeof(txrate_vht_5), &txrate_vht_5);
248eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic		if (sgi_5)
249eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic			nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_SGI);
250eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic		if (lgi_5)
251eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic			nla_put_u8(msg, NL80211_TXRATE_GI, NL80211_TXRATE_FORCE_LGI);
252942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg		nla_nest_end(msg, nl_band);
253942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	}
254942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg
255942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	nla_nest_end(msg, nl_rates);
256942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg
257942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	return 0;
258942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg nla_put_failure:
259942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg	return -ENOBUFS;
260942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg}
261942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg
262942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg#define DESCR_LEGACY "[legacy-<2.4|5> <legacy rate in Mbps>*]"
263eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz Dziedzic#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]"
264942b5cd86434724ac31ff3847baf3d1365b75022Johannes Berg
265eaa166977a392cdccb75e7ca63bff85d4b66da40Janusz DziedzicCOMMAND(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]",
266135e65d67ffbefadb27948b9c6e490c635bc9d74Simon Wunderlich	NL80211_CMD_SET_TX_BITRATE_MASK, 0, CIB_NETDEV, handle_bitrates,
267dce7b72035abb76a95187a322ec91c76845dfb15Sujith Manoharan	"Sets up the specified rate masks.\n"
268dce7b72035abb76a95187a322ec91c76845dfb15Sujith Manoharan	"Not passing any arguments would clear the existing mask (if any).");
269