blob: 8d69fca92bf5411ee5f8336b1b982149c9a34f90 [file] [log] [blame]
colin@cozybit.com46c1ad12008-10-22 09:55:20 +02001#include <net/if.h>
2#include <errno.h>
3#include <string.h>
4
5#include <netlink/genl/genl.h>
6#include <netlink/genl/family.h>
7#include <netlink/genl/ctrl.h>
8#include <netlink/msg.h>
9#include <netlink/attr.h>
10
11#include "nl80211.h"
12#include "iw.h"
13
Johannes Berg400efd32010-12-02 08:58:57 +010014SECTION(mesh);
15
16
colin@cozybit.com46c1ad12008-10-22 09:55:20 +020017typedef struct _any_t {
18 union {
19 uint32_t as_32;
Ashok Nagarajanbe97e512012-04-18 11:00:44 -070020 int32_t as_s32;
colin@cozybit.com46c1ad12008-10-22 09:55:20 +020021 uint16_t as_16;
22 uint8_t as_8;
23 } u;
24} _any;
25
26/* describes a mesh parameter */
27struct mesh_param_descr {
28 const char *name;
29 enum nl80211_meshconf_params mesh_param_num;
30 int (*nla_put_fn)(struct nl_msg*, int, _any*);
31 uint32_t (*parse_fn)(const char*, _any*);
32 void (*nla_print_fn)(struct nlattr *);
33};
34
35/* utility functions for manipulating and printing u8/u16/u32 values and
36 * timesouts. */
37static int _my_nla_put_u8(struct nl_msg *n, int mesh_param_num, _any *value)
38{
39 return nla_put(n, mesh_param_num, sizeof(uint8_t), &value->u.as_8);
40}
41
42static int _my_nla_put_u16(struct nl_msg *n, int mesh_param_num, _any *value)
43{
44 return nla_put(n, mesh_param_num, sizeof(uint16_t), &value->u.as_16);
45}
46
47static int _my_nla_put_u32(struct nl_msg *n, int mesh_param_num, _any *value)
48{
49 return nla_put(n, mesh_param_num, sizeof(uint32_t), &value->u.as_32);
50}
51
52static uint32_t _parse_u8(const char *str, _any *ret)
53{
54 char *endptr = NULL;
55 unsigned long int v = strtoul(str, &endptr, 10);
56 if (*endptr != '\0')
57 return 0xff;
58 if (v > 0xff)
59 return 0xff;
60 ret->u.as_8 = (uint8_t)v;
61 return 0;
62}
63
64static uint32_t _parse_u8_as_bool(const char *str, _any *ret)
65{
66 char *endptr = NULL;
67 unsigned long int v = strtoul(str, &endptr, 10);
68 if (*endptr != '\0')
69 return 0x1;
70 if (v > 0x1)
71 return 0x1;
72 ret->u.as_8 = (uint8_t)v;
73 return 0;
74}
75
76static uint32_t _parse_u16(const char *str, _any *ret)
77{
78 char *endptr = NULL;
79 long int v = strtol(str, &endptr, 10);
80 if (*endptr != '\0')
81 return 0xffff;
82 if ((v < 0) || (v > 0xffff))
83 return 0xffff;
84 ret->u.as_16 = (uint16_t)v;
85 return 0;
86}
87
88static uint32_t _parse_u32(const char *str, _any *ret)
89{
90 char *endptr = NULL;
91 long long int v = strtoll(str, &endptr, 10);
92 if (*endptr != '\0')
93 return 0xffffffff;
94 if ((v < 0) || (v > 0xffffffff))
95 return 0xffffffff;
96 ret->u.as_32 = (uint32_t)v;
97 return 0;
98}
99
Ashok Nagarajanbe97e512012-04-18 11:00:44 -0700100static uint32_t _parse_s32(const char *str, _any *ret)
101{
102 char *endptr = NULL;
103 long int v = strtol(str, &endptr, 10);
104 if (*endptr != '\0')
105 return 0xffffffff;
106 if (v > 0xff)
107 return 0xffffffff;
108 ret->u.as_s32 = (int32_t)v;
109 return 0;
110}
111
Marco Porsch46758fa2013-01-18 13:05:31 +0100112static uint32_t _parse_u32_power_mode(const char *str, _any *ret)
113{
114 unsigned long int v;
115
116 /* Parse attribute for the name of power mode */
117 if (!strcmp(str, "active"))
118 v = NL80211_MESH_POWER_ACTIVE;
119 else if (!strcmp(str, "light"))
120 v = NL80211_MESH_POWER_LIGHT_SLEEP;
121 else if (!strcmp(str, "deep"))
122 v = NL80211_MESH_POWER_DEEP_SLEEP;
123 else
124 return 0xff;
125
126 ret->u.as_32 = (uint32_t)v;
127 return 0;
128}
Ashok Nagarajanbe97e512012-04-18 11:00:44 -0700129
Johannes Berg656aa242008-12-08 18:30:22 +0100130static void _print_u8(struct nlattr *a)
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200131{
132 printf("%d", nla_get_u8(a));
133}
134
Johannes Berg656aa242008-12-08 18:30:22 +0100135static void _print_u16(struct nlattr *a)
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200136{
137 printf("%d", nla_get_u16(a));
138}
139
Johannes Berg656aa242008-12-08 18:30:22 +0100140static void _print_u16_timeout(struct nlattr *a)
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200141{
142 printf("%d milliseconds", nla_get_u16(a));
143}
144
Johannes Berg656aa242008-12-08 18:30:22 +0100145static void _print_u16_in_TUs(struct nlattr *a)
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200146{
147 printf("%d TUs", nla_get_u16(a));
148}
149
Ashok Nagarajand9f730c2012-04-12 17:45:12 -0700150static void _print_u32(struct nlattr *a)
151{
152 printf("%d", nla_get_u32(a));
153}
154
Johannes Berg656aa242008-12-08 18:30:22 +0100155static void _print_u32_timeout(struct nlattr *a)
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200156{
157 printf("%u milliseconds", nla_get_u32(a));
158}
159
Colleen Twitty770f80c2013-07-08 10:04:18 -0700160static void _print_u32_in_seconds(struct nlattr *a)
161{
162 printf("%d seconds", nla_get_u32(a));
163}
164
Johannes Berg656aa242008-12-08 18:30:22 +0100165static void _print_u32_in_TUs(struct nlattr *a)
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200166{
167 printf("%d TUs", nla_get_u32(a));
168}
169
Marco Porsch46758fa2013-01-18 13:05:31 +0100170static void _print_u32_power_mode(struct nlattr *a)
171{
172 unsigned long v = nla_get_u32(a);
173
174 switch (v) {
175 case NL80211_MESH_POWER_ACTIVE:
176 printf("active");
177 break;
178 case NL80211_MESH_POWER_LIGHT_SLEEP:
179 printf("light");
180 break;
181 case NL80211_MESH_POWER_DEEP_SLEEP:
182 printf("deep");
183 break;
184 default:
185 printf("undefined");
186 break;
187 }
188}
189
Ashok Nagarajanbe97e512012-04-18 11:00:44 -0700190static void _print_s32_in_dBm(struct nlattr *a)
191{
192 printf("%d dBm", (int32_t) nla_get_u32(a));
193}
194
195
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200196/* The current mesh parameters */
197const static struct mesh_param_descr _mesh_param_descrs[] =
198{
199 {"mesh_retry_timeout",
200 NL80211_MESHCONF_RETRY_TIMEOUT,
201 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
202 {"mesh_confirm_timeout",
203 NL80211_MESHCONF_CONFIRM_TIMEOUT,
204 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
205 {"mesh_holding_timeout",
206 NL80211_MESHCONF_HOLDING_TIMEOUT,
207 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
208 {"mesh_max_peer_links",
209 NL80211_MESHCONF_MAX_PEER_LINKS,
210 _my_nla_put_u16, _parse_u16, _print_u16},
211 {"mesh_max_retries",
212 NL80211_MESHCONF_MAX_RETRIES,
213 _my_nla_put_u8, _parse_u8, _print_u8},
214 {"mesh_ttl",
215 NL80211_MESHCONF_TTL,
216 _my_nla_put_u8, _parse_u8, _print_u8},
Johannes Berg247beb92010-12-03 09:18:42 +0100217 {"mesh_element_ttl",
218 NL80211_MESHCONF_ELEMENT_TTL,
219 _my_nla_put_u8, _parse_u8, _print_u8},
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200220 {"mesh_auto_open_plinks",
221 NL80211_MESHCONF_AUTO_OPEN_PLINKS,
222 _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
223 {"mesh_hwmp_max_preq_retries",
224 NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
225 _my_nla_put_u8, _parse_u8, _print_u8},
226 {"mesh_path_refresh_time",
227 NL80211_MESHCONF_PATH_REFRESH_TIME,
228 _my_nla_put_u32, _parse_u32, _print_u32_timeout},
229 {"mesh_min_discovery_timeout",
230 NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
231 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
232 {"mesh_hwmp_active_path_timeout",
233 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
234 _my_nla_put_u32, _parse_u32, _print_u32_in_TUs},
235 {"mesh_hwmp_preq_min_interval",
236 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
237 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
238 {"mesh_hwmp_net_diameter_traversal_time",
239 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
240 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
Rui Paulocc372182009-11-09 12:53:07 +0000241 {"mesh_hwmp_rootmode", NL80211_MESHCONF_HWMP_ROOTMODE,
242 _my_nla_put_u8, _parse_u8, _print_u8},
Javier Cardonab9aa7112011-08-09 17:03:30 -0700243 {"mesh_hwmp_rann_interval", NL80211_MESHCONF_HWMP_RANN_INTERVAL,
Chun-Yeow Yeohb1b57132012-07-05 00:26:33 +0800244 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
Javier Cardonab9aa7112011-08-09 17:03:30 -0700245 {"mesh_gate_announcements", NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
246 _my_nla_put_u8, _parse_u8, _print_u8},
Chun-Yeow Yeohaccd0d22012-03-05 01:41:46 +0800247 {"mesh_fwding", NL80211_MESHCONF_FORWARDING,
248 _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
Ashok Nagarajand9f730c2012-04-12 17:45:12 -0700249 {"mesh_sync_offset_max_neighor",
250 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
251 _my_nla_put_u32, _parse_u32, _print_u32},
Ashok Nagarajanbe97e512012-04-18 11:00:44 -0700252 {"mesh_rssi_threshold", NL80211_MESHCONF_RSSI_THRESHOLD,
253 _my_nla_put_u32, _parse_s32, _print_s32_in_dBm},
Chun-Yeow Yeohb1b57132012-07-05 00:26:33 +0800254 {"mesh_hwmp_active_path_to_root_timeout",
255 NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
256 _my_nla_put_u32, _parse_u32, _print_u32_in_TUs},
257 {"mesh_hwmp_root_interval", NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
258 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
259 {"mesh_hwmp_confirmation_interval",
260 NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
261 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
Marco Porsch46758fa2013-01-18 13:05:31 +0100262 {"mesh_power_mode", NL80211_MESHCONF_POWER_MODE,
263 _my_nla_put_u32, _parse_u32_power_mode, _print_u32_power_mode},
264 {"mesh_awake_window", NL80211_MESHCONF_AWAKE_WINDOW,
265 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
Colleen Twitty770f80c2013-07-08 10:04:18 -0700266 {"mesh_plink_timeout", NL80211_MESHCONF_PLINK_TIMEOUT,
267 _my_nla_put_u32, _parse_u32, _print_u32_in_seconds},
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200268};
269
270static void print_all_mesh_param_descr(void)
271{
272 int i;
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200273
Johannes Bergf0894712009-01-29 14:56:08 +0100274 printf("Possible mesh parameters are:\n");
275
276 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++)
277 printf(" - %s\n", _mesh_param_descrs[i].name);
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200278}
279
Johannes Berga34f62c2010-12-02 08:53:04 +0100280static const struct mesh_param_descr *find_mesh_param(const char *name)
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200281{
282 int i;
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200283
284 /* Find out what mesh parameter we want to change. */
Colin McCabe4d0d2ea2009-01-09 17:13:16 -0800285 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
Ashok Nagarajan83cb9792012-10-09 13:29:26 -0700286 if (strcmp(_mesh_param_descrs[i].name, name) == 0)
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200287 return _mesh_param_descrs + i;
Colin McCabe4d0d2ea2009-01-09 17:13:16 -0800288 }
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200289
Ashok Nagarajan83cb9792012-10-09 13:29:26 -0700290 print_all_mesh_param_descr();
291 return NULL;
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200292}
293
294/* Setter */
Johannes Berg7c37a242009-04-08 13:13:28 +0200295static int set_interface_meshparam(struct nl80211_state *state,
296 struct nl_cb *cb,
297 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200298 int argc, char **argv,
299 enum id_input id)
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200300{
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200301 const struct mesh_param_descr *mdescr;
Johannes Berg656aa242008-12-08 18:30:22 +0100302 struct nlattr *container;
Johannes Berga34f62c2010-12-02 08:53:04 +0100303 uint32_t ret;
304 int err;
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200305
Johannes Berg656aa242008-12-08 18:30:22 +0100306 container = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS);
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200307 if (!container)
308 return -ENOBUFS;
Johannes Berga34f62c2010-12-02 08:53:04 +0100309
310 if (!argc)
311 return 1;
312
313 while (argc) {
314 const char *name;
315 char *value;
316 _any any;
317
318 memset(&any, 0, sizeof(_any));
319
320 name = argv[0];
321 value = strchr(name, '=');
322 if (value) {
323 *value = '\0';
324 value++;
325 argc--;
326 argv++;
327 } else {
328 /* backward compat -- accept w/o '=' */
329 if (argc < 2) {
330 printf("Must specify a value for %s.\n", name);
331 return 2;
332 }
333 value = argv[1];
334 argc -= 2;
335 argv += 2;
336 }
337
338 mdescr = find_mesh_param(name);
339 if (!mdescr)
340 return 2;
341
342 /* Parse the new value */
343 ret = mdescr->parse_fn(value, &any);
344 if (ret != 0) {
Marco Porsch46758fa2013-01-18 13:05:31 +0100345 if (mdescr->mesh_param_num
346 == NL80211_MESHCONF_POWER_MODE)
347 printf("%s must be set to active, light or "
348 "deep.\n", mdescr->name);
349 else
350 printf("%s must be set to a number "
351 "between 0 and %u\n",
352 mdescr->name, ret);
353
Johannes Berga34f62c2010-12-02 08:53:04 +0100354 return 2;
355 }
356
357 err = mdescr->nla_put_fn(msg, mdescr->mesh_param_num, &any);
358 if (err)
359 return err;
360 }
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200361 nla_nest_end(msg, container);
362
363 return err;
364}
365
Johannes Berga34f62c2010-12-02 08:53:04 +0100366COMMAND(set, mesh_param, "<param>=<value> [<param>=<value>]*",
Johannes Berg70cf4542009-05-05 15:24:39 +0200367 NL80211_CMD_SET_MESH_PARAMS, 0, CIB_NETDEV, set_interface_meshparam,
368 "Set mesh parameter (run command without any to see available ones).");
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200369
370/* Getter */
371static int print_mesh_param_handler(struct nl_msg *msg, void *arg)
372{
373 const struct mesh_param_descr *mdescr = arg;
374 struct nlattr *attrs[NL80211_ATTR_MAX + 1];
375 struct nlattr *parent_attr;
376 struct nlattr *mesh_params[NL80211_MESHCONF_ATTR_MAX + 1];
377 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
378
379 /* locate NL80211_ATTR_MESH_PARAMS */
380 nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
381 genlmsg_attrlen(gnlh, 0), NULL);
382 parent_attr = attrs[NL80211_ATTR_MESH_PARAMS];
383 if (!parent_attr)
384 return -EINVAL;
385
386 /* unpack the mesh parameters */
387 if (nla_parse_nested(mesh_params, NL80211_MESHCONF_ATTR_MAX,
Johannes Berg97e21372010-12-02 08:44:07 +0100388 parent_attr, NULL))
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200389 return -EINVAL;
390
Johannes Berg97e21372010-12-02 08:44:07 +0100391 if (!mdescr) {
392 int i;
393
394 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
395 mdescr = &_mesh_param_descrs[i];
396 printf("%s = ", mdescr->name);
397 mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
398 printf("\n");
399 }
400 return NL_SKIP;
401 }
402
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200403 /* print out the mesh parameter */
404 mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
405 printf("\n");
406 return NL_SKIP;
407}
408
Johannes Berg7c37a242009-04-08 13:13:28 +0200409static int get_interface_meshparam(struct nl80211_state *state,
410 struct nl_cb *cb,
411 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200412 int argc, char **argv,
413 enum id_input id)
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200414{
Johannes Berg97e21372010-12-02 08:44:07 +0100415 const struct mesh_param_descr *mdescr = NULL;
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200416
Johannes Berg97e21372010-12-02 08:44:07 +0100417 if (argc > 1)
418 return 1;
419
420 if (argc == 1) {
Johannes Berga34f62c2010-12-02 08:53:04 +0100421 mdescr = find_mesh_param(argv[0]);
Johannes Berg97e21372010-12-02 08:44:07 +0100422 if (!mdescr)
423 return 2;
424 }
colin@cozybit.com46c1ad12008-10-22 09:55:20 +0200425
426 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
427 print_mesh_param_handler, (void *)mdescr);
428 return 0;
429}
430
Johannes Berg97e21372010-12-02 08:44:07 +0100431COMMAND(get, mesh_param, "[<param>]",
Johannes Berg70cf4542009-05-05 15:24:39 +0200432 NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, get_interface_meshparam,
433 "Retrieve mesh parameter (run command without any to see available ones).");
Johannes Berg400efd32010-12-02 08:58:57 +0100434
435static int join_mesh(struct nl80211_state *state, struct nl_cb *cb,
Johannes Berg05514f92012-07-19 11:50:50 +0200436 struct nl_msg *msg, int argc, char **argv,
437 enum id_input id)
Johannes Berg400efd32010-12-02 08:58:57 +0100438{
Ashok Nagarajan9560e432012-04-12 17:45:13 -0700439 struct nlattr *container;
Chun-Yeow Yeoh7d01a092011-12-08 10:25:15 -0800440 float rate;
Chun-Yeow Yeohc8473cb2014-09-23 09:14:49 +0800441 unsigned char rates[NL80211_MAX_SUPP_RATES];
442 int bintval, dtim_period, i, n_rates = 0;
443 char *end, *value = NULL, *sptr = NULL;
Chun-Yeow Yeoh957baf82014-09-23 09:14:48 +0800444 unsigned long freq = 0;
445 static const struct {
446 const char *name;
447 unsigned int width;
448 int freq1_diff;
449 int chantype; /* for older kernel */
450 } *chanmode_selected = NULL, chanmode[] = {
451 { .name = "HT20",
452 .width = NL80211_CHAN_WIDTH_20,
453 .freq1_diff = 0,
454 .chantype = NL80211_CHAN_HT20 },
455 { .name = "HT40+",
456 .width = NL80211_CHAN_WIDTH_40,
457 .freq1_diff = 10,
458 .chantype = NL80211_CHAN_HT40PLUS },
459 { .name = "HT40-",
460 .width = NL80211_CHAN_WIDTH_40,
461 .freq1_diff = -10,
462 .chantype = NL80211_CHAN_HT40MINUS },
463 { .name = "NOHT",
464 .width = NL80211_CHAN_WIDTH_20_NOHT,
465 .freq1_diff = 0,
466 .chantype = NL80211_CHAN_NO_HT },
467 };
Chun-Yeow Yeoh7d01a092011-12-08 10:25:15 -0800468
Johannes Berg400efd32010-12-02 08:58:57 +0100469 if (argc < 1)
470 return 1;
471
472 NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(argv[0]), argv[0]);
473 argc--;
474 argv++;
475
Chun-Yeow Yeoh957baf82014-09-23 09:14:48 +0800476 /* freq */
477 if (argc > 1 && strcmp(argv[0], "freq") == 0) {
478 argv++;
479 argc--;
480
481 freq = strtoul(argv[0], &end, 10);
482 if (*end != '\0')
483 return 1;
484 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
485
486 argv++;
487 argc--;
488 }
489
490 /* channel type */
491 if (argc) {
492 for (i = 0; i < ARRAY_SIZE(chanmode); i++) {
493 if (strcasecmp(chanmode[i].name, argv[0]) == 0) {
494 chanmode_selected = &chanmode[i];
495 break;
496 }
497 }
498
499 if (chanmode_selected) {
500 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
501 chanmode_selected->width);
502 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1,
503 freq + chanmode_selected->freq1_diff);
504 if (chanmode_selected->chantype != -1)
505 NLA_PUT_U32(msg,
506 NL80211_ATTR_WIPHY_CHANNEL_TYPE,
507 chanmode_selected->chantype);
508
509 argv++;
510 argc--;
511 }
512 }
513
Chun-Yeow Yeohc8473cb2014-09-23 09:14:49 +0800514 /* basic rates */
515 if (argc > 1 && strcmp(argv[0], "basic-rates") == 0) {
516 argv++;
517 argc--;
518
519 value = strtok_r(argv[0], ",", &sptr);
520
521 while (value && n_rates < NL80211_MAX_SUPP_RATES) {
522 rate = strtod(value, &end);
523 rates[n_rates] = rate * 2;
524
525 /* filter out suspicious values */
526 if (*end != '\0' || !rates[n_rates] ||
527 rate*2 != rates[n_rates])
528 return 1;
529
530 n_rates++;
531 value = strtok_r(NULL, ",", &sptr);
532 }
533
534 NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, n_rates, rates);
535 argv++;
536 argc--;
537 }
538
539 /* multicast rate */
Chun-Yeow Yeoh7d01a092011-12-08 10:25:15 -0800540 if (argc > 1 && strcmp(argv[0], "mcast-rate") == 0) {
541 argv++;
542 argc--;
543
544 rate = strtod(argv[0], &end);
545 if (*end != '\0')
546 return 1;
547
548 NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, (int)(rate * 10));
549 argv++;
550 argc--;
551 }
552
Marco Porscha8c2e762013-01-18 13:05:30 +0100553 if (argc > 1 && strcmp(argv[0], "beacon-interval") == 0) {
554 argc--;
555 argv++;
556
557 bintval = strtoul(argv[0], &end, 10);
558 if (*end != '\0')
559 return 1;
560
561 NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, bintval);
562 argv++;
563 argc--;
564 }
565
566 if (argc > 1 && strcmp(argv[0], "dtim-period") == 0) {
567 argc--;
568 argv++;
569
570 dtim_period = strtoul(argv[0], &end, 10);
571 if (*end != '\0')
572 return 1;
573
574 NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
575 argv++;
576 argc--;
577 }
578
Ashok Nagarajan9560e432012-04-12 17:45:13 -0700579 container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
580 if (!container)
581 return -ENOBUFS;
582
583 if (argc > 1 && strcmp(argv[0], "vendor_sync") == 0) {
584 argv++;
585 argc--;
586 if (strcmp(argv[0], "on") == 0)
587 NLA_PUT_U8(msg,
588 NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, 1);
589 else
590 NLA_PUT_U8(msg,
591 NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, 0);
592 argv++;
593 argc--;
594 }
595 /* parse and put other NL80211_ATTR_MESH_SETUP elements here */
596
597 nla_nest_end(msg, container);
598
Johannes Berg400efd32010-12-02 08:58:57 +0100599 if (!argc)
600 return 0;
Johannes Berg05514f92012-07-19 11:50:50 +0200601 return set_interface_meshparam(state, cb, msg, argc, argv, id);
Johannes Berg400efd32010-12-02 08:58:57 +0100602 nla_put_failure:
603 return -ENOBUFS;
604}
Chun-Yeow Yeohc8473cb2014-09-23 09:14:49 +0800605COMMAND(mesh, join, "<mesh ID> [[freq <freq in MHz> <HT20|HT40+|HT40-|NOHT>]"
606 " [basic-rates <rate in Mbps,rate2,...>]], [mcast-rate <rate in Mbps>]"
Marco Porscha8c2e762013-01-18 13:05:30 +0100607 " [beacon-interval <time in TUs>] [dtim-period <value>]"
608 " [vendor_sync on|off] [<param>=<value>]*",
Johannes Berg400efd32010-12-02 08:58:57 +0100609 NL80211_CMD_JOIN_MESH, 0, CIB_NETDEV, join_mesh,
Chun-Yeow Yeohc8473cb2014-09-23 09:14:49 +0800610 "Join a mesh with the given mesh ID with frequency, basic-rates,\n"
611 "mcast-rate and mesh parameters. Basic-rates are applied only if\n"
612 "frequency is provided.");
Johannes Berg400efd32010-12-02 08:58:57 +0100613
614static int leave_mesh(struct nl80211_state *state, struct nl_cb *cb,
Johannes Berg05514f92012-07-19 11:50:50 +0200615 struct nl_msg *msg, int argc, char **argv,
616 enum id_input id)
Johannes Berg400efd32010-12-02 08:58:57 +0100617{
618 if (argc)
619 return 1;
620
621 return 0;
622}
623COMMAND(mesh, leave, NULL, NL80211_CMD_LEAVE_MESH, 0, CIB_NETDEV, leave_mesh,
624 "Leave a mesh.");