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