xref: /aosp_15_r20/external/iw/mesh.c (revision 92022041c981f431db0b590d0c3272306d0ea2a2)
1*92022041SSam Saccone #include <errno.h>
2*92022041SSam Saccone #include <string.h>
3*92022041SSam Saccone 
4*92022041SSam Saccone #include <netlink/genl/genl.h>
5*92022041SSam Saccone #include <netlink/genl/family.h>
6*92022041SSam Saccone #include <netlink/genl/ctrl.h>
7*92022041SSam Saccone #include <netlink/msg.h>
8*92022041SSam Saccone #include <netlink/attr.h>
9*92022041SSam Saccone 
10*92022041SSam Saccone #include "nl80211.h"
11*92022041SSam Saccone #include "iw.h"
12*92022041SSam Saccone 
13*92022041SSam Saccone SECTION(mesh);
14*92022041SSam Saccone SECTION(mesh_param);
15*92022041SSam Saccone 
16*92022041SSam Saccone 
17*92022041SSam Saccone typedef struct _any_t {
18*92022041SSam Saccone 	union {
19*92022041SSam Saccone 		uint32_t as_32;
20*92022041SSam Saccone 		int32_t as_s32;
21*92022041SSam Saccone 		uint16_t as_16;
22*92022041SSam Saccone 		uint8_t as_8;
23*92022041SSam Saccone 	} u;
24*92022041SSam Saccone } _any;
25*92022041SSam Saccone 
26*92022041SSam Saccone /* describes a mesh parameter */
27*92022041SSam Saccone struct mesh_param_descr {
28*92022041SSam Saccone 	const char *name;
29*92022041SSam Saccone 	enum nl80211_meshconf_params mesh_param_num;
30*92022041SSam Saccone 	int (*nla_put_fn)(struct nl_msg*, int, _any*);
31*92022041SSam Saccone 	uint32_t (*parse_fn)(const char*, _any*);
32*92022041SSam Saccone 	void (*nla_print_fn)(struct nlattr *);
33*92022041SSam Saccone };
34*92022041SSam Saccone 
35*92022041SSam Saccone /* utility functions for manipulating and printing u8/u16/u32 values and
36*92022041SSam Saccone  * timesouts. */
_my_nla_put_u8(struct nl_msg * n,int mesh_param_num,_any * value)37*92022041SSam Saccone static int _my_nla_put_u8(struct nl_msg *n, int mesh_param_num, _any *value)
38*92022041SSam Saccone {
39*92022041SSam Saccone 	return nla_put(n, mesh_param_num, sizeof(uint8_t), &value->u.as_8);
40*92022041SSam Saccone }
41*92022041SSam Saccone 
_my_nla_put_u16(struct nl_msg * n,int mesh_param_num,_any * value)42*92022041SSam Saccone static int _my_nla_put_u16(struct nl_msg *n, int mesh_param_num, _any *value)
43*92022041SSam Saccone {
44*92022041SSam Saccone 	return nla_put(n, mesh_param_num, sizeof(uint16_t), &value->u.as_16);
45*92022041SSam Saccone }
46*92022041SSam Saccone 
_my_nla_put_u32(struct nl_msg * n,int mesh_param_num,_any * value)47*92022041SSam Saccone static int _my_nla_put_u32(struct nl_msg *n, int mesh_param_num, _any *value)
48*92022041SSam Saccone {
49*92022041SSam Saccone 	return nla_put(n, mesh_param_num, sizeof(uint32_t), &value->u.as_32);
50*92022041SSam Saccone }
51*92022041SSam Saccone 
_parse_u8(const char * str,_any * ret)52*92022041SSam Saccone static uint32_t _parse_u8(const char *str, _any *ret)
53*92022041SSam Saccone {
54*92022041SSam Saccone 	char *endptr = NULL;
55*92022041SSam Saccone 	unsigned long int v = strtoul(str, &endptr, 10);
56*92022041SSam Saccone 	if (*endptr != '\0')
57*92022041SSam Saccone 		return 0xff;
58*92022041SSam Saccone 	if (v > 0xff)
59*92022041SSam Saccone 		return 0xff;
60*92022041SSam Saccone 	ret->u.as_8 = (uint8_t)v;
61*92022041SSam Saccone 	return 0;
62*92022041SSam Saccone }
63*92022041SSam Saccone 
_parse_u8_as_bool(const char * str,_any * ret)64*92022041SSam Saccone static uint32_t _parse_u8_as_bool(const char *str, _any *ret)
65*92022041SSam Saccone {
66*92022041SSam Saccone 	char *endptr = NULL;
67*92022041SSam Saccone 	unsigned long int v = strtoul(str, &endptr, 10);
68*92022041SSam Saccone 	if (*endptr != '\0')
69*92022041SSam Saccone 		return 0x1;
70*92022041SSam Saccone 	if (v > 0x1)
71*92022041SSam Saccone 		return 0x1;
72*92022041SSam Saccone 	ret->u.as_8 = (uint8_t)v;
73*92022041SSam Saccone 	return 0;
74*92022041SSam Saccone }
75*92022041SSam Saccone 
_parse_u16(const char * str,_any * ret)76*92022041SSam Saccone static uint32_t _parse_u16(const char *str, _any *ret)
77*92022041SSam Saccone {
78*92022041SSam Saccone 	char *endptr = NULL;
79*92022041SSam Saccone 	long int v = strtol(str, &endptr, 10);
80*92022041SSam Saccone 	if (*endptr != '\0')
81*92022041SSam Saccone 		return 0xffff;
82*92022041SSam Saccone 	if ((v < 0) || (v > 0xffff))
83*92022041SSam Saccone 		return 0xffff;
84*92022041SSam Saccone 	ret->u.as_16 = (uint16_t)v;
85*92022041SSam Saccone 	return 0;
86*92022041SSam Saccone }
87*92022041SSam Saccone 
_parse_u32(const char * str,_any * ret)88*92022041SSam Saccone static uint32_t _parse_u32(const char *str, _any *ret)
89*92022041SSam Saccone {
90*92022041SSam Saccone 	char *endptr = NULL;
91*92022041SSam Saccone 	long long int v = strtoll(str, &endptr, 10);
92*92022041SSam Saccone 	if (*endptr != '\0')
93*92022041SSam Saccone 		return 0xffffffff;
94*92022041SSam Saccone 	if ((v < 0) || (v > 0xffffffff))
95*92022041SSam Saccone 		return 0xffffffff;
96*92022041SSam Saccone 	ret->u.as_32 = (uint32_t)v;
97*92022041SSam Saccone 	return 0;
98*92022041SSam Saccone }
99*92022041SSam Saccone 
_parse_s32(const char * str,_any * ret)100*92022041SSam Saccone static uint32_t _parse_s32(const char *str, _any *ret)
101*92022041SSam Saccone {
102*92022041SSam Saccone 	char *endptr = NULL;
103*92022041SSam Saccone 	long int v = strtol(str, &endptr, 10);
104*92022041SSam Saccone 	if (*endptr != '\0')
105*92022041SSam Saccone 		return 0xffffffff;
106*92022041SSam Saccone 	if (v > 0xff)
107*92022041SSam Saccone 		return 0xffffffff;
108*92022041SSam Saccone 	ret->u.as_s32 = (int32_t)v;
109*92022041SSam Saccone 	return 0;
110*92022041SSam Saccone }
111*92022041SSam Saccone 
_parse_u32_power_mode(const char * str,_any * ret)112*92022041SSam Saccone static uint32_t _parse_u32_power_mode(const char *str, _any *ret)
113*92022041SSam Saccone {
114*92022041SSam Saccone 	unsigned long int v;
115*92022041SSam Saccone 
116*92022041SSam Saccone 	/* Parse attribute for the name of power mode */
117*92022041SSam Saccone 	if (!strcmp(str, "active"))
118*92022041SSam Saccone 		v = NL80211_MESH_POWER_ACTIVE;
119*92022041SSam Saccone 	else if (!strcmp(str, "light"))
120*92022041SSam Saccone 		v = NL80211_MESH_POWER_LIGHT_SLEEP;
121*92022041SSam Saccone 	else if (!strcmp(str, "deep"))
122*92022041SSam Saccone 		v = NL80211_MESH_POWER_DEEP_SLEEP;
123*92022041SSam Saccone 	else
124*92022041SSam Saccone 		return 0xff;
125*92022041SSam Saccone 
126*92022041SSam Saccone 	ret->u.as_32 = (uint32_t)v;
127*92022041SSam Saccone 	return 0;
128*92022041SSam Saccone }
129*92022041SSam Saccone 
_print_u8(struct nlattr * a)130*92022041SSam Saccone static void _print_u8(struct nlattr *a)
131*92022041SSam Saccone {
132*92022041SSam Saccone 	printf("%d", nla_get_u8(a));
133*92022041SSam Saccone }
134*92022041SSam Saccone 
_print_u16(struct nlattr * a)135*92022041SSam Saccone static void _print_u16(struct nlattr *a)
136*92022041SSam Saccone {
137*92022041SSam Saccone 	printf("%d", nla_get_u16(a));
138*92022041SSam Saccone }
139*92022041SSam Saccone 
_print_u16_timeout(struct nlattr * a)140*92022041SSam Saccone static void _print_u16_timeout(struct nlattr *a)
141*92022041SSam Saccone {
142*92022041SSam Saccone 	printf("%d milliseconds", nla_get_u16(a));
143*92022041SSam Saccone }
144*92022041SSam Saccone 
_print_u16_in_TUs(struct nlattr * a)145*92022041SSam Saccone static void _print_u16_in_TUs(struct nlattr *a)
146*92022041SSam Saccone {
147*92022041SSam Saccone 	printf("%d TUs", nla_get_u16(a));
148*92022041SSam Saccone }
149*92022041SSam Saccone 
_print_u32(struct nlattr * a)150*92022041SSam Saccone static void _print_u32(struct nlattr *a)
151*92022041SSam Saccone {
152*92022041SSam Saccone 	printf("%d", nla_get_u32(a));
153*92022041SSam Saccone }
154*92022041SSam Saccone 
_print_u32_timeout(struct nlattr * a)155*92022041SSam Saccone static void _print_u32_timeout(struct nlattr *a)
156*92022041SSam Saccone {
157*92022041SSam Saccone 	printf("%u milliseconds", nla_get_u32(a));
158*92022041SSam Saccone }
159*92022041SSam Saccone 
_print_u32_in_seconds(struct nlattr * a)160*92022041SSam Saccone static void _print_u32_in_seconds(struct nlattr *a)
161*92022041SSam Saccone {
162*92022041SSam Saccone 	printf("%d seconds", nla_get_u32(a));
163*92022041SSam Saccone }
164*92022041SSam Saccone 
_print_u32_in_TUs(struct nlattr * a)165*92022041SSam Saccone static void _print_u32_in_TUs(struct nlattr *a)
166*92022041SSam Saccone {
167*92022041SSam Saccone 	printf("%d TUs", nla_get_u32(a));
168*92022041SSam Saccone }
169*92022041SSam Saccone 
_print_u32_power_mode(struct nlattr * a)170*92022041SSam Saccone static void _print_u32_power_mode(struct nlattr *a)
171*92022041SSam Saccone {
172*92022041SSam Saccone 	unsigned long v = nla_get_u32(a);
173*92022041SSam Saccone 
174*92022041SSam Saccone 	switch (v) {
175*92022041SSam Saccone 	case NL80211_MESH_POWER_ACTIVE:
176*92022041SSam Saccone 		printf("active");
177*92022041SSam Saccone 		break;
178*92022041SSam Saccone 	case NL80211_MESH_POWER_LIGHT_SLEEP:
179*92022041SSam Saccone 		printf("light");
180*92022041SSam Saccone 		break;
181*92022041SSam Saccone 	case NL80211_MESH_POWER_DEEP_SLEEP:
182*92022041SSam Saccone 		printf("deep");
183*92022041SSam Saccone 		break;
184*92022041SSam Saccone 	default:
185*92022041SSam Saccone 		printf("undefined");
186*92022041SSam Saccone 		break;
187*92022041SSam Saccone 	}
188*92022041SSam Saccone }
189*92022041SSam Saccone 
_print_s32_in_dBm(struct nlattr * a)190*92022041SSam Saccone static void _print_s32_in_dBm(struct nlattr *a)
191*92022041SSam Saccone {
192*92022041SSam Saccone 	printf("%d dBm", (int32_t) nla_get_u32(a));
193*92022041SSam Saccone }
194*92022041SSam Saccone 
195*92022041SSam Saccone 
196*92022041SSam Saccone /* The current mesh parameters */
197*92022041SSam Saccone static const struct mesh_param_descr _mesh_param_descrs[] =
198*92022041SSam Saccone {
199*92022041SSam Saccone 	{"mesh_retry_timeout",
200*92022041SSam Saccone 	NL80211_MESHCONF_RETRY_TIMEOUT,
201*92022041SSam Saccone 	_my_nla_put_u16, _parse_u16, _print_u16_timeout},
202*92022041SSam Saccone 	{"mesh_confirm_timeout",
203*92022041SSam Saccone 	NL80211_MESHCONF_CONFIRM_TIMEOUT,
204*92022041SSam Saccone 	_my_nla_put_u16, _parse_u16, _print_u16_timeout},
205*92022041SSam Saccone 	{"mesh_holding_timeout",
206*92022041SSam Saccone 	NL80211_MESHCONF_HOLDING_TIMEOUT,
207*92022041SSam Saccone 	_my_nla_put_u16, _parse_u16, _print_u16_timeout},
208*92022041SSam Saccone 	{"mesh_max_peer_links",
209*92022041SSam Saccone 	NL80211_MESHCONF_MAX_PEER_LINKS,
210*92022041SSam Saccone 	_my_nla_put_u16, _parse_u16, _print_u16},
211*92022041SSam Saccone 	{"mesh_max_retries",
212*92022041SSam Saccone 	NL80211_MESHCONF_MAX_RETRIES,
213*92022041SSam Saccone 	_my_nla_put_u8, _parse_u8, _print_u8},
214*92022041SSam Saccone 	{"mesh_ttl",
215*92022041SSam Saccone 	NL80211_MESHCONF_TTL,
216*92022041SSam Saccone 	_my_nla_put_u8, _parse_u8, _print_u8},
217*92022041SSam Saccone 	{"mesh_element_ttl",
218*92022041SSam Saccone 	NL80211_MESHCONF_ELEMENT_TTL,
219*92022041SSam Saccone 	_my_nla_put_u8, _parse_u8, _print_u8},
220*92022041SSam Saccone 	{"mesh_auto_open_plinks",
221*92022041SSam Saccone 	NL80211_MESHCONF_AUTO_OPEN_PLINKS,
222*92022041SSam Saccone 	_my_nla_put_u8, _parse_u8_as_bool, _print_u8},
223*92022041SSam Saccone 	{"mesh_hwmp_max_preq_retries",
224*92022041SSam Saccone 	NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
225*92022041SSam Saccone 	_my_nla_put_u8, _parse_u8, _print_u8},
226*92022041SSam Saccone 	{"mesh_path_refresh_time",
227*92022041SSam Saccone 	NL80211_MESHCONF_PATH_REFRESH_TIME,
228*92022041SSam Saccone 	_my_nla_put_u32, _parse_u32, _print_u32_timeout},
229*92022041SSam Saccone 	{"mesh_min_discovery_timeout",
230*92022041SSam Saccone 	NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
231*92022041SSam Saccone 	_my_nla_put_u16, _parse_u16, _print_u16_timeout},
232*92022041SSam Saccone 	{"mesh_hwmp_active_path_timeout",
233*92022041SSam Saccone 	NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
234*92022041SSam Saccone 	_my_nla_put_u32, _parse_u32, _print_u32_in_TUs},
235*92022041SSam Saccone 	{"mesh_hwmp_preq_min_interval",
236*92022041SSam Saccone 	NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
237*92022041SSam Saccone 	_my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
238*92022041SSam Saccone 	{"mesh_hwmp_net_diameter_traversal_time",
239*92022041SSam Saccone 	NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
240*92022041SSam Saccone 	_my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
241*92022041SSam Saccone 	{"mesh_hwmp_rootmode", NL80211_MESHCONF_HWMP_ROOTMODE,
242*92022041SSam Saccone 	_my_nla_put_u8, _parse_u8, _print_u8},
243*92022041SSam Saccone 	{"mesh_hwmp_rann_interval", NL80211_MESHCONF_HWMP_RANN_INTERVAL,
244*92022041SSam Saccone 	_my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
245*92022041SSam Saccone 	{"mesh_gate_announcements", NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
246*92022041SSam Saccone 	_my_nla_put_u8, _parse_u8, _print_u8},
247*92022041SSam Saccone 	{"mesh_fwding", NL80211_MESHCONF_FORWARDING,
248*92022041SSam Saccone 	_my_nla_put_u8, _parse_u8_as_bool, _print_u8},
249*92022041SSam Saccone 	{"mesh_sync_offset_max_neighor",
250*92022041SSam Saccone 	NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
251*92022041SSam Saccone 	_my_nla_put_u32, _parse_u32, _print_u32},
252*92022041SSam Saccone 	{"mesh_rssi_threshold", NL80211_MESHCONF_RSSI_THRESHOLD,
253*92022041SSam Saccone 	_my_nla_put_u32, _parse_s32, _print_s32_in_dBm},
254*92022041SSam Saccone 	{"mesh_hwmp_active_path_to_root_timeout",
255*92022041SSam Saccone 	NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
256*92022041SSam Saccone 	_my_nla_put_u32, _parse_u32, _print_u32_in_TUs},
257*92022041SSam Saccone 	{"mesh_hwmp_root_interval", NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
258*92022041SSam Saccone 	_my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
259*92022041SSam Saccone 	{"mesh_hwmp_confirmation_interval",
260*92022041SSam Saccone 	NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
261*92022041SSam Saccone 	_my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
262*92022041SSam Saccone 	{"mesh_power_mode", NL80211_MESHCONF_POWER_MODE,
263*92022041SSam Saccone 	_my_nla_put_u32, _parse_u32_power_mode, _print_u32_power_mode},
264*92022041SSam Saccone 	{"mesh_awake_window", NL80211_MESHCONF_AWAKE_WINDOW,
265*92022041SSam Saccone 	_my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
266*92022041SSam Saccone 	{"mesh_plink_timeout", NL80211_MESHCONF_PLINK_TIMEOUT,
267*92022041SSam Saccone 	_my_nla_put_u32, _parse_u32, _print_u32_in_seconds},
268*92022041SSam Saccone 	{"mesh_connected_to_gate", NL80211_MESHCONF_CONNECTED_TO_GATE,
269*92022041SSam Saccone 	_my_nla_put_u8, _parse_u8_as_bool, _print_u8},
270*92022041SSam Saccone 	{"mesh_nolearn", NL80211_MESHCONF_NOLEARN,
271*92022041SSam Saccone 	_my_nla_put_u8, _parse_u8_as_bool, _print_u8},
272*92022041SSam Saccone 	{"mesh_connected_to_as", NL80211_MESHCONF_CONNECTED_TO_AS,
273*92022041SSam Saccone 	_my_nla_put_u8, _parse_u8_as_bool, _print_u8},
274*92022041SSam Saccone };
275*92022041SSam Saccone 
print_all_mesh_param_descr(void)276*92022041SSam Saccone static void print_all_mesh_param_descr(void)
277*92022041SSam Saccone {
278*92022041SSam Saccone 	unsigned int i;
279*92022041SSam Saccone 
280*92022041SSam Saccone 	printf("Possible mesh parameters are:\n");
281*92022041SSam Saccone 
282*92022041SSam Saccone 	for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++)
283*92022041SSam Saccone 		printf(" - %s\n", _mesh_param_descrs[i].name);
284*92022041SSam Saccone }
285*92022041SSam Saccone 
find_mesh_param(const char * name)286*92022041SSam Saccone static const struct mesh_param_descr *find_mesh_param(const char *name)
287*92022041SSam Saccone {
288*92022041SSam Saccone 	unsigned int i;
289*92022041SSam Saccone 
290*92022041SSam Saccone 	/* Find out what mesh parameter we want to change. */
291*92022041SSam Saccone 	for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
292*92022041SSam Saccone 		if (strcmp(_mesh_param_descrs[i].name, name) == 0)
293*92022041SSam Saccone 			return _mesh_param_descrs + i;
294*92022041SSam Saccone 	}
295*92022041SSam Saccone 
296*92022041SSam Saccone 	return NULL;
297*92022041SSam Saccone }
298*92022041SSam Saccone 
299*92022041SSam Saccone /* Setter */
set_interface_meshparam(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)300*92022041SSam Saccone static int set_interface_meshparam(struct nl80211_state *state,
301*92022041SSam Saccone 				   struct nl_msg *msg,
302*92022041SSam Saccone 				   int argc, char **argv,
303*92022041SSam Saccone 				   enum id_input id)
304*92022041SSam Saccone {
305*92022041SSam Saccone 	const struct mesh_param_descr *mdescr;
306*92022041SSam Saccone 	struct nlattr *container;
307*92022041SSam Saccone 	uint32_t ret;
308*92022041SSam Saccone 	int err = 2;
309*92022041SSam Saccone 
310*92022041SSam Saccone 	container = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS);
311*92022041SSam Saccone 	if (!container)
312*92022041SSam Saccone 		return -ENOBUFS;
313*92022041SSam Saccone 
314*92022041SSam Saccone 	if (!argc) {
315*92022041SSam Saccone 		print_all_mesh_param_descr();
316*92022041SSam Saccone 		return 1;
317*92022041SSam Saccone 	}
318*92022041SSam Saccone 
319*92022041SSam Saccone 	while (argc) {
320*92022041SSam Saccone 		const char *name;
321*92022041SSam Saccone 		char *value;
322*92022041SSam Saccone 		_any any;
323*92022041SSam Saccone 
324*92022041SSam Saccone 		memset(&any, 0, sizeof(_any));
325*92022041SSam Saccone 
326*92022041SSam Saccone 		name = argv[0];
327*92022041SSam Saccone 		value = strchr(name, '=');
328*92022041SSam Saccone 		if (value) {
329*92022041SSam Saccone 			*value = '\0';
330*92022041SSam Saccone 			value++;
331*92022041SSam Saccone 			argc--;
332*92022041SSam Saccone 			argv++;
333*92022041SSam Saccone 		} else {
334*92022041SSam Saccone 			/* backward compat -- accept w/o '=' */
335*92022041SSam Saccone 			if (argc < 2) {
336*92022041SSam Saccone 				printf("Must specify a value for %s.\n", name);
337*92022041SSam Saccone 				return 2;
338*92022041SSam Saccone 			}
339*92022041SSam Saccone 			value = argv[1];
340*92022041SSam Saccone 			argc -= 2;
341*92022041SSam Saccone 			argv += 2;
342*92022041SSam Saccone 		}
343*92022041SSam Saccone 
344*92022041SSam Saccone 		mdescr = find_mesh_param(name);
345*92022041SSam Saccone 		if (!mdescr) {
346*92022041SSam Saccone 			printf("Could not find the parameter %s.\n", name);
347*92022041SSam Saccone 			print_all_mesh_param_descr();
348*92022041SSam Saccone 			return 2;
349*92022041SSam Saccone 		}
350*92022041SSam Saccone 
351*92022041SSam Saccone 		/* Parse the new value */
352*92022041SSam Saccone 		ret = mdescr->parse_fn(value, &any);
353*92022041SSam Saccone 		if (ret != 0) {
354*92022041SSam Saccone 			if (mdescr->mesh_param_num
355*92022041SSam Saccone 			    == NL80211_MESHCONF_POWER_MODE)
356*92022041SSam Saccone 				printf("%s must be set to active, light or "
357*92022041SSam Saccone 					"deep.\n", mdescr->name);
358*92022041SSam Saccone 			else
359*92022041SSam Saccone 				printf("%s must be set to a number "
360*92022041SSam Saccone 					"between 0 and %u\n",
361*92022041SSam Saccone 					mdescr->name, ret);
362*92022041SSam Saccone 
363*92022041SSam Saccone 			return 2;
364*92022041SSam Saccone 		}
365*92022041SSam Saccone 
366*92022041SSam Saccone 		err = mdescr->nla_put_fn(msg, mdescr->mesh_param_num, &any);
367*92022041SSam Saccone 		if (err)
368*92022041SSam Saccone 			return err;
369*92022041SSam Saccone 	}
370*92022041SSam Saccone 	nla_nest_end(msg, container);
371*92022041SSam Saccone 
372*92022041SSam Saccone 	return err;
373*92022041SSam Saccone }
374*92022041SSam Saccone 
375*92022041SSam Saccone COMMAND(set, mesh_param, "<param>=<value> [<param>=<value>]*",
376*92022041SSam Saccone 	NL80211_CMD_SET_MESH_PARAMS, 0, CIB_NETDEV, set_interface_meshparam,
377*92022041SSam Saccone 	"Set mesh parameter (run command without any to see available ones).");
378*92022041SSam Saccone 
379*92022041SSam Saccone /* Getter */
print_mesh_param_handler(struct nl_msg * msg,void * arg)380*92022041SSam Saccone static int print_mesh_param_handler(struct nl_msg *msg, void *arg)
381*92022041SSam Saccone {
382*92022041SSam Saccone 	const struct mesh_param_descr *mdescr = arg;
383*92022041SSam Saccone 	struct nlattr *attrs[NL80211_ATTR_MAX + 1];
384*92022041SSam Saccone 	struct nlattr *parent_attr;
385*92022041SSam Saccone 	struct nlattr *mesh_params[NL80211_MESHCONF_ATTR_MAX + 1];
386*92022041SSam Saccone 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
387*92022041SSam Saccone 
388*92022041SSam Saccone 	/* locate NL80211_ATTR_MESH_PARAMS */
389*92022041SSam Saccone 	nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
390*92022041SSam Saccone 		  genlmsg_attrlen(gnlh, 0), NULL);
391*92022041SSam Saccone 	parent_attr = attrs[NL80211_ATTR_MESH_PARAMS];
392*92022041SSam Saccone 	if (!parent_attr)
393*92022041SSam Saccone 		return -EINVAL;
394*92022041SSam Saccone 
395*92022041SSam Saccone 	/* unpack the mesh parameters */
396*92022041SSam Saccone 	if (nla_parse_nested(mesh_params, NL80211_MESHCONF_ATTR_MAX,
397*92022041SSam Saccone 			     parent_attr, NULL))
398*92022041SSam Saccone 		return -EINVAL;
399*92022041SSam Saccone 
400*92022041SSam Saccone 	if (!mdescr) {
401*92022041SSam Saccone 		unsigned int i;
402*92022041SSam Saccone 
403*92022041SSam Saccone 		/* print out all the supported mesh parameters */
404*92022041SSam Saccone 		for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
405*92022041SSam Saccone 			mdescr = &_mesh_param_descrs[i];
406*92022041SSam Saccone 			if (mesh_params[mdescr->mesh_param_num]) {
407*92022041SSam Saccone 				printf("%s = ", mdescr->name);
408*92022041SSam Saccone 				mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
409*92022041SSam Saccone 				printf("\n");
410*92022041SSam Saccone 			}
411*92022041SSam Saccone 		}
412*92022041SSam Saccone 		return NL_SKIP;
413*92022041SSam Saccone 	}
414*92022041SSam Saccone 
415*92022041SSam Saccone 	/* print out the requested mesh parameter */
416*92022041SSam Saccone 	if (mesh_params[mdescr->mesh_param_num]) {
417*92022041SSam Saccone 		mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
418*92022041SSam Saccone 		printf("\n");
419*92022041SSam Saccone 	}
420*92022041SSam Saccone 	return NL_SKIP;
421*92022041SSam Saccone }
422*92022041SSam Saccone 
get_interface_meshparam(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)423*92022041SSam Saccone static int get_interface_meshparam(struct nl80211_state *state,
424*92022041SSam Saccone 				   struct nl_msg *msg,
425*92022041SSam Saccone 				   int argc, char **argv,
426*92022041SSam Saccone 				   enum id_input id)
427*92022041SSam Saccone {
428*92022041SSam Saccone 	const struct mesh_param_descr *mdescr = NULL;
429*92022041SSam Saccone 
430*92022041SSam Saccone 	if (argc == 0) {
431*92022041SSam Saccone 		print_all_mesh_param_descr();
432*92022041SSam Saccone 		return 1;
433*92022041SSam Saccone 	} else if (argc == 1) {
434*92022041SSam Saccone 		mdescr = find_mesh_param(argv[0]);
435*92022041SSam Saccone 		if (!mdescr) {
436*92022041SSam Saccone 			printf("Could not find the parameter %s.\n", argv[0]);
437*92022041SSam Saccone 			print_all_mesh_param_descr();
438*92022041SSam Saccone 			return 2;
439*92022041SSam Saccone 		}
440*92022041SSam Saccone 	} else {
441*92022041SSam Saccone 		return 1;
442*92022041SSam Saccone 	}
443*92022041SSam Saccone 
444*92022041SSam Saccone 	register_handler(print_mesh_param_handler, (void *)mdescr);
445*92022041SSam Saccone 	return 0;
446*92022041SSam Saccone }
447*92022041SSam Saccone 
448*92022041SSam Saccone COMMAND(get, mesh_param, "[<param>]",
449*92022041SSam Saccone 	NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, get_interface_meshparam,
450*92022041SSam Saccone 	"Retrieve mesh parameter (run command without any to see available ones).");
451*92022041SSam Saccone 
dump_interface_meshparam(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)452*92022041SSam Saccone static int dump_interface_meshparam(struct nl80211_state *state,
453*92022041SSam Saccone 				    struct nl_msg *msg,
454*92022041SSam Saccone 				    int argc, char **argv,
455*92022041SSam Saccone 				    enum id_input id)
456*92022041SSam Saccone {
457*92022041SSam Saccone 	register_handler(print_mesh_param_handler, NULL);
458*92022041SSam Saccone 	return 0;
459*92022041SSam Saccone }
460*92022041SSam Saccone 
461*92022041SSam Saccone COMMAND(mesh_param, dump, "",
462*92022041SSam Saccone 	NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, dump_interface_meshparam,
463*92022041SSam Saccone 	"List all supported mesh parameters");
464*92022041SSam Saccone 
join_mesh(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)465*92022041SSam Saccone static int join_mesh(struct nl80211_state *state,
466*92022041SSam Saccone 		     struct nl_msg *msg, int argc, char **argv,
467*92022041SSam Saccone 		     enum id_input id)
468*92022041SSam Saccone {
469*92022041SSam Saccone 	struct nlattr *container;
470*92022041SSam Saccone 	float rate;
471*92022041SSam Saccone 	unsigned char rates[NL80211_MAX_SUPP_RATES];
472*92022041SSam Saccone 	int bintval, dtim_period, n_rates = 0;
473*92022041SSam Saccone 	char *end, *value = NULL, *sptr = NULL;
474*92022041SSam Saccone 
475*92022041SSam Saccone 	if (argc < 1)
476*92022041SSam Saccone 		return 1;
477*92022041SSam Saccone 
478*92022041SSam Saccone 	NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(argv[0]), argv[0]);
479*92022041SSam Saccone 	argc--;
480*92022041SSam Saccone 	argv++;
481*92022041SSam Saccone 
482*92022041SSam Saccone 	/* freq */
483*92022041SSam Saccone 	if (argc > 1 && strcmp(argv[0], "freq") == 0) {
484*92022041SSam Saccone 		struct chandef chandef;
485*92022041SSam Saccone 		int err, parsed;
486*92022041SSam Saccone 
487*92022041SSam Saccone 		err = parse_freqchan(&chandef, false, argc - 1, argv + 1,
488*92022041SSam Saccone 				     &parsed);
489*92022041SSam Saccone 		if (err)
490*92022041SSam Saccone 			return err;
491*92022041SSam Saccone 
492*92022041SSam Saccone 		argv += parsed + 1;
493*92022041SSam Saccone 		argc -= parsed + 1;
494*92022041SSam Saccone 
495*92022041SSam Saccone 		err = put_chandef(msg, &chandef);
496*92022041SSam Saccone 		if (err)
497*92022041SSam Saccone 			return err;
498*92022041SSam Saccone 	}
499*92022041SSam Saccone 
500*92022041SSam Saccone 	/* basic rates */
501*92022041SSam Saccone 	if (argc > 1 && strcmp(argv[0], "basic-rates") == 0) {
502*92022041SSam Saccone 		argv++;
503*92022041SSam Saccone 		argc--;
504*92022041SSam Saccone 
505*92022041SSam Saccone 		value = strtok_r(argv[0], ",", &sptr);
506*92022041SSam Saccone 
507*92022041SSam Saccone 		while (value && n_rates < NL80211_MAX_SUPP_RATES) {
508*92022041SSam Saccone 			rate = strtod(value, &end);
509*92022041SSam Saccone 			rates[n_rates] = rate * 2;
510*92022041SSam Saccone 
511*92022041SSam Saccone 			/* filter out suspicious values  */
512*92022041SSam Saccone 			if (*end != '\0' || !rates[n_rates] ||
513*92022041SSam Saccone 			    rate*2 != rates[n_rates])
514*92022041SSam Saccone 				return 1;
515*92022041SSam Saccone 
516*92022041SSam Saccone 			n_rates++;
517*92022041SSam Saccone 			value = strtok_r(NULL, ",", &sptr);
518*92022041SSam Saccone 		}
519*92022041SSam Saccone 
520*92022041SSam Saccone 		NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, n_rates, rates);
521*92022041SSam Saccone 		argv++;
522*92022041SSam Saccone 		argc--;
523*92022041SSam Saccone 	}
524*92022041SSam Saccone 
525*92022041SSam Saccone 	/* multicast rate */
526*92022041SSam Saccone 	if (argc > 1 && strcmp(argv[0], "mcast-rate") == 0) {
527*92022041SSam Saccone 		argv++;
528*92022041SSam Saccone 		argc--;
529*92022041SSam Saccone 
530*92022041SSam Saccone 		rate = strtod(argv[0], &end);
531*92022041SSam Saccone 		if (*end != '\0')
532*92022041SSam Saccone 			return 1;
533*92022041SSam Saccone 
534*92022041SSam Saccone 		NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, (int)(rate * 10));
535*92022041SSam Saccone 		argv++;
536*92022041SSam Saccone 		argc--;
537*92022041SSam Saccone 	}
538*92022041SSam Saccone 
539*92022041SSam Saccone 	if (argc > 1 && strcmp(argv[0], "beacon-interval") == 0) {
540*92022041SSam Saccone 		argc--;
541*92022041SSam Saccone 		argv++;
542*92022041SSam Saccone 
543*92022041SSam Saccone 		bintval = strtoul(argv[0], &end, 10);
544*92022041SSam Saccone 		if (*end != '\0')
545*92022041SSam Saccone 			return 1;
546*92022041SSam Saccone 
547*92022041SSam Saccone 		NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, bintval);
548*92022041SSam Saccone 		argv++;
549*92022041SSam Saccone 		argc--;
550*92022041SSam Saccone 	}
551*92022041SSam Saccone 
552*92022041SSam Saccone 	if (argc > 1 && strcmp(argv[0], "dtim-period") == 0) {
553*92022041SSam Saccone 		argc--;
554*92022041SSam Saccone 		argv++;
555*92022041SSam Saccone 
556*92022041SSam Saccone 		dtim_period = strtoul(argv[0], &end, 10);
557*92022041SSam Saccone 		if (*end != '\0')
558*92022041SSam Saccone 			return 1;
559*92022041SSam Saccone 
560*92022041SSam Saccone 		NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
561*92022041SSam Saccone 		argv++;
562*92022041SSam Saccone 		argc--;
563*92022041SSam Saccone 	}
564*92022041SSam Saccone 
565*92022041SSam Saccone 	container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
566*92022041SSam Saccone 	if (!container)
567*92022041SSam Saccone 		return -ENOBUFS;
568*92022041SSam Saccone 
569*92022041SSam Saccone 	if (argc > 1 && strcmp(argv[0], "vendor_sync") == 0) {
570*92022041SSam Saccone 		argv++;
571*92022041SSam Saccone 		argc--;
572*92022041SSam Saccone 		if (strcmp(argv[0], "on") == 0)
573*92022041SSam Saccone 			NLA_PUT_U8(msg,
574*92022041SSam Saccone 				   NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, 1);
575*92022041SSam Saccone 		else
576*92022041SSam Saccone 			NLA_PUT_U8(msg,
577*92022041SSam Saccone 				   NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, 0);
578*92022041SSam Saccone 		argv++;
579*92022041SSam Saccone 		argc--;
580*92022041SSam Saccone 	}
581*92022041SSam Saccone 	/* parse and put other NL80211_ATTR_MESH_SETUP elements here */
582*92022041SSam Saccone 
583*92022041SSam Saccone 	nla_nest_end(msg, container);
584*92022041SSam Saccone 
585*92022041SSam Saccone 	if (!argc)
586*92022041SSam Saccone 		return 0;
587*92022041SSam Saccone 	return set_interface_meshparam(state, msg, argc, argv, id);
588*92022041SSam Saccone  nla_put_failure:
589*92022041SSam Saccone 	return -ENOBUFS;
590*92022041SSam Saccone }
591*92022041SSam Saccone COMMAND(mesh, join, "<mesh ID> [[freq <freq in MHz> <NOHT|HT20|HT40+|HT40-|80MHz>]"
592*92022041SSam Saccone 	" [basic-rates <rate in Mbps,rate2,...>]], [mcast-rate <rate in Mbps>]"
593*92022041SSam Saccone 	" [beacon-interval <time in TUs>] [dtim-period <value>]"
594*92022041SSam Saccone 	" [vendor_sync on|off] [<param>=<value>]*",
595*92022041SSam Saccone 	NL80211_CMD_JOIN_MESH, 0, CIB_NETDEV, join_mesh,
596*92022041SSam Saccone 	"Join a mesh with the given mesh ID with frequency, basic-rates,\n"
597*92022041SSam Saccone 	"mcast-rate and mesh parameters. Basic-rates are applied only if\n"
598*92022041SSam Saccone 	"frequency is provided.");
599*92022041SSam Saccone 
leave_mesh(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)600*92022041SSam Saccone static int leave_mesh(struct nl80211_state *state,
601*92022041SSam Saccone 		      struct nl_msg *msg, int argc, char **argv,
602*92022041SSam Saccone 		      enum id_input id)
603*92022041SSam Saccone {
604*92022041SSam Saccone 	if (argc)
605*92022041SSam Saccone 		return 1;
606*92022041SSam Saccone 
607*92022041SSam Saccone 	return 0;
608*92022041SSam Saccone }
609*92022041SSam Saccone COMMAND(mesh, leave, NULL, NL80211_CMD_LEAVE_MESH, 0, CIB_NETDEV, leave_mesh,
610*92022041SSam Saccone 	"Leave a mesh.");
611