4 #include <netlink/genl/genl.h>
5 #include <netlink/genl/family.h>
6 #include <netlink/genl/ctrl.h>
7 #include <netlink/msg.h>
8 #include <netlink/attr.h>
16 typedef struct _any_t
{
25 /* describes a mesh parameter */
26 struct mesh_param_descr
{
28 enum nl80211_meshconf_params mesh_param_num
;
29 int (*nla_put_fn
)(struct nl_msg
*, int, _any
*);
30 uint32_t (*parse_fn
)(const char*, _any
*);
31 void (*nla_print_fn
)(struct nlattr
*);
34 /* utility functions for manipulating and printing u8/u16/u32 values and
36 static int _my_nla_put_u8(struct nl_msg
*n
, int mesh_param_num
, _any
*value
)
38 return nla_put(n
, mesh_param_num
, sizeof(uint8_t), &value
->u
.as_8
);
41 static int _my_nla_put_u16(struct nl_msg
*n
, int mesh_param_num
, _any
*value
)
43 return nla_put(n
, mesh_param_num
, sizeof(uint16_t), &value
->u
.as_16
);
46 static int _my_nla_put_u32(struct nl_msg
*n
, int mesh_param_num
, _any
*value
)
48 return nla_put(n
, mesh_param_num
, sizeof(uint32_t), &value
->u
.as_32
);
51 static uint32_t _parse_u8(const char *str
, _any
*ret
)
54 unsigned long int v
= strtoul(str
, &endptr
, 10);
59 ret
->u
.as_8
= (uint8_t)v
;
63 static uint32_t _parse_u8_as_bool(const char *str
, _any
*ret
)
66 unsigned long int v
= strtoul(str
, &endptr
, 10);
71 ret
->u
.as_8
= (uint8_t)v
;
75 static uint32_t _parse_u16(const char *str
, _any
*ret
)
78 long int v
= strtol(str
, &endptr
, 10);
81 if ((v
< 0) || (v
> 0xffff))
83 ret
->u
.as_16
= (uint16_t)v
;
87 static uint32_t _parse_u32(const char *str
, _any
*ret
)
90 long long int v
= strtoll(str
, &endptr
, 10);
93 if ((v
< 0) || (v
> 0xffffffff))
95 ret
->u
.as_32
= (uint32_t)v
;
99 static uint32_t _parse_s32(const char *str
, _any
*ret
)
102 long int v
= strtol(str
, &endptr
, 10);
107 ret
->u
.as_s32
= (int32_t)v
;
111 static uint32_t _parse_u32_power_mode(const char *str
, _any
*ret
)
115 /* Parse attribute for the name of power mode */
116 if (!strcmp(str
, "active"))
117 v
= NL80211_MESH_POWER_ACTIVE
;
118 else if (!strcmp(str
, "light"))
119 v
= NL80211_MESH_POWER_LIGHT_SLEEP
;
120 else if (!strcmp(str
, "deep"))
121 v
= NL80211_MESH_POWER_DEEP_SLEEP
;
125 ret
->u
.as_32
= (uint32_t)v
;
129 static void _print_u8(struct nlattr
*a
)
131 printf("%d", nla_get_u8(a
));
134 static void _print_u16(struct nlattr
*a
)
136 printf("%d", nla_get_u16(a
));
139 static void _print_u16_timeout(struct nlattr
*a
)
141 printf("%d milliseconds", nla_get_u16(a
));
144 static void _print_u16_in_TUs(struct nlattr
*a
)
146 printf("%d TUs", nla_get_u16(a
));
149 static void _print_u32(struct nlattr
*a
)
151 printf("%d", nla_get_u32(a
));
154 static void _print_u32_timeout(struct nlattr
*a
)
156 printf("%u milliseconds", nla_get_u32(a
));
159 static void _print_u32_in_seconds(struct nlattr
*a
)
161 printf("%d seconds", nla_get_u32(a
));
164 static void _print_u32_in_TUs(struct nlattr
*a
)
166 printf("%d TUs", nla_get_u32(a
));
169 static void _print_u32_power_mode(struct nlattr
*a
)
171 unsigned long v
= nla_get_u32(a
);
174 case NL80211_MESH_POWER_ACTIVE
:
177 case NL80211_MESH_POWER_LIGHT_SLEEP
:
180 case NL80211_MESH_POWER_DEEP_SLEEP
:
189 static void _print_s32_in_dBm(struct nlattr
*a
)
191 printf("%d dBm", (int32_t) nla_get_u32(a
));
195 /* The current mesh parameters */
196 const static struct mesh_param_descr _mesh_param_descrs
[] =
198 {"mesh_retry_timeout",
199 NL80211_MESHCONF_RETRY_TIMEOUT
,
200 _my_nla_put_u16
, _parse_u16
, _print_u16_timeout
},
201 {"mesh_confirm_timeout",
202 NL80211_MESHCONF_CONFIRM_TIMEOUT
,
203 _my_nla_put_u16
, _parse_u16
, _print_u16_timeout
},
204 {"mesh_holding_timeout",
205 NL80211_MESHCONF_HOLDING_TIMEOUT
,
206 _my_nla_put_u16
, _parse_u16
, _print_u16_timeout
},
207 {"mesh_max_peer_links",
208 NL80211_MESHCONF_MAX_PEER_LINKS
,
209 _my_nla_put_u16
, _parse_u16
, _print_u16
},
211 NL80211_MESHCONF_MAX_RETRIES
,
212 _my_nla_put_u8
, _parse_u8
, _print_u8
},
214 NL80211_MESHCONF_TTL
,
215 _my_nla_put_u8
, _parse_u8
, _print_u8
},
217 NL80211_MESHCONF_ELEMENT_TTL
,
218 _my_nla_put_u8
, _parse_u8
, _print_u8
},
219 {"mesh_auto_open_plinks",
220 NL80211_MESHCONF_AUTO_OPEN_PLINKS
,
221 _my_nla_put_u8
, _parse_u8_as_bool
, _print_u8
},
222 {"mesh_hwmp_max_preq_retries",
223 NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES
,
224 _my_nla_put_u8
, _parse_u8
, _print_u8
},
225 {"mesh_path_refresh_time",
226 NL80211_MESHCONF_PATH_REFRESH_TIME
,
227 _my_nla_put_u32
, _parse_u32
, _print_u32_timeout
},
228 {"mesh_min_discovery_timeout",
229 NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT
,
230 _my_nla_put_u16
, _parse_u16
, _print_u16_timeout
},
231 {"mesh_hwmp_active_path_timeout",
232 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT
,
233 _my_nla_put_u32
, _parse_u32
, _print_u32_in_TUs
},
234 {"mesh_hwmp_preq_min_interval",
235 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL
,
236 _my_nla_put_u16
, _parse_u16
, _print_u16_in_TUs
},
237 {"mesh_hwmp_net_diameter_traversal_time",
238 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME
,
239 _my_nla_put_u16
, _parse_u16
, _print_u16_in_TUs
},
240 {"mesh_hwmp_rootmode", NL80211_MESHCONF_HWMP_ROOTMODE
,
241 _my_nla_put_u8
, _parse_u8
, _print_u8
},
242 {"mesh_hwmp_rann_interval", NL80211_MESHCONF_HWMP_RANN_INTERVAL
,
243 _my_nla_put_u16
, _parse_u16
, _print_u16_in_TUs
},
244 {"mesh_gate_announcements", NL80211_MESHCONF_GATE_ANNOUNCEMENTS
,
245 _my_nla_put_u8
, _parse_u8
, _print_u8
},
246 {"mesh_fwding", NL80211_MESHCONF_FORWARDING
,
247 _my_nla_put_u8
, _parse_u8_as_bool
, _print_u8
},
248 {"mesh_sync_offset_max_neighor",
249 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR
,
250 _my_nla_put_u32
, _parse_u32
, _print_u32
},
251 {"mesh_rssi_threshold", NL80211_MESHCONF_RSSI_THRESHOLD
,
252 _my_nla_put_u32
, _parse_s32
, _print_s32_in_dBm
},
253 {"mesh_hwmp_active_path_to_root_timeout",
254 NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT
,
255 _my_nla_put_u32
, _parse_u32
, _print_u32_in_TUs
},
256 {"mesh_hwmp_root_interval", NL80211_MESHCONF_HWMP_ROOT_INTERVAL
,
257 _my_nla_put_u16
, _parse_u16
, _print_u16_in_TUs
},
258 {"mesh_hwmp_confirmation_interval",
259 NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL
,
260 _my_nla_put_u16
, _parse_u16
, _print_u16_in_TUs
},
261 {"mesh_power_mode", NL80211_MESHCONF_POWER_MODE
,
262 _my_nla_put_u32
, _parse_u32_power_mode
, _print_u32_power_mode
},
263 {"mesh_awake_window", NL80211_MESHCONF_AWAKE_WINDOW
,
264 _my_nla_put_u16
, _parse_u16
, _print_u16_in_TUs
},
265 {"mesh_plink_timeout", NL80211_MESHCONF_PLINK_TIMEOUT
,
266 _my_nla_put_u32
, _parse_u32
, _print_u32_in_seconds
},
269 static void print_all_mesh_param_descr(void)
273 printf("Possible mesh parameters are:\n");
275 for (i
= 0; i
< ARRAY_SIZE(_mesh_param_descrs
); i
++)
276 printf(" - %s\n", _mesh_param_descrs
[i
].name
);
279 static const struct mesh_param_descr
*find_mesh_param(const char *name
)
283 /* Find out what mesh parameter we want to change. */
284 for (i
= 0; i
< ARRAY_SIZE(_mesh_param_descrs
); i
++) {
285 if (strcmp(_mesh_param_descrs
[i
].name
, name
) == 0)
286 return _mesh_param_descrs
+ i
;
289 print_all_mesh_param_descr();
294 static int set_interface_meshparam(struct nl80211_state
*state
,
296 int argc
, char **argv
,
299 const struct mesh_param_descr
*mdescr
;
300 struct nlattr
*container
;
304 container
= nla_nest_start(msg
, NL80211_ATTR_MESH_PARAMS
);
316 memset(&any
, 0, sizeof(_any
));
319 value
= strchr(name
, '=');
326 /* backward compat -- accept w/o '=' */
328 printf("Must specify a value for %s.\n", name
);
336 mdescr
= find_mesh_param(name
);
340 /* Parse the new value */
341 ret
= mdescr
->parse_fn(value
, &any
);
343 if (mdescr
->mesh_param_num
344 == NL80211_MESHCONF_POWER_MODE
)
345 printf("%s must be set to active, light or "
346 "deep.\n", mdescr
->name
);
348 printf("%s must be set to a number "
349 "between 0 and %u\n",
355 err
= mdescr
->nla_put_fn(msg
, mdescr
->mesh_param_num
, &any
);
359 nla_nest_end(msg
, container
);
364 COMMAND(set
, mesh_param
, "<param>=<value> [<param>=<value>]*",
365 NL80211_CMD_SET_MESH_PARAMS
, 0, CIB_NETDEV
, set_interface_meshparam
,
366 "Set mesh parameter (run command without any to see available ones).");
369 static int print_mesh_param_handler(struct nl_msg
*msg
, void *arg
)
371 const struct mesh_param_descr
*mdescr
= arg
;
372 struct nlattr
*attrs
[NL80211_ATTR_MAX
+ 1];
373 struct nlattr
*parent_attr
;
374 struct nlattr
*mesh_params
[NL80211_MESHCONF_ATTR_MAX
+ 1];
375 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
377 /* locate NL80211_ATTR_MESH_PARAMS */
378 nla_parse(attrs
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
379 genlmsg_attrlen(gnlh
, 0), NULL
);
380 parent_attr
= attrs
[NL80211_ATTR_MESH_PARAMS
];
384 /* unpack the mesh parameters */
385 if (nla_parse_nested(mesh_params
, NL80211_MESHCONF_ATTR_MAX
,
392 for (i
= 0; i
< ARRAY_SIZE(_mesh_param_descrs
); i
++) {
393 mdescr
= &_mesh_param_descrs
[i
];
394 printf("%s = ", mdescr
->name
);
395 mdescr
->nla_print_fn(mesh_params
[mdescr
->mesh_param_num
]);
401 /* print out the mesh parameter */
402 mdescr
->nla_print_fn(mesh_params
[mdescr
->mesh_param_num
]);
407 static int get_interface_meshparam(struct nl80211_state
*state
,
409 int argc
, char **argv
,
412 const struct mesh_param_descr
*mdescr
= NULL
;
418 mdescr
= find_mesh_param(argv
[0]);
423 register_handler(print_mesh_param_handler
, (void *)mdescr
);
427 COMMAND(get
, mesh_param
, "[<param>]",
428 NL80211_CMD_GET_MESH_PARAMS
, 0, CIB_NETDEV
, get_interface_meshparam
,
429 "Retrieve mesh parameter (run command without any to see available ones).");
431 static int join_mesh(struct nl80211_state
*state
,
432 struct nl_msg
*msg
, int argc
, char **argv
,
435 struct nlattr
*container
;
437 unsigned char rates
[NL80211_MAX_SUPP_RATES
];
438 int bintval
, dtim_period
, i
, n_rates
= 0;
439 char *end
, *value
= NULL
, *sptr
= NULL
;
440 unsigned long freq
= 0;
441 static const struct {
445 int chantype
; /* for older kernel */
446 } *chanmode_selected
= NULL
, chanmode
[] = {
448 .width
= NL80211_CHAN_WIDTH_20
,
450 .chantype
= NL80211_CHAN_HT20
},
452 .width
= NL80211_CHAN_WIDTH_40
,
454 .chantype
= NL80211_CHAN_HT40PLUS
},
456 .width
= NL80211_CHAN_WIDTH_40
,
458 .chantype
= NL80211_CHAN_HT40MINUS
},
460 .width
= NL80211_CHAN_WIDTH_20_NOHT
,
462 .chantype
= NL80211_CHAN_NO_HT
},
468 NLA_PUT(msg
, NL80211_ATTR_MESH_ID
, strlen(argv
[0]), argv
[0]);
473 if (argc
> 1 && strcmp(argv
[0], "freq") == 0) {
477 freq
= strtoul(argv
[0], &end
, 10);
480 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_FREQ
, freq
);
488 for (i
= 0; i
< ARRAY_SIZE(chanmode
); i
++) {
489 if (strcasecmp(chanmode
[i
].name
, argv
[0]) == 0) {
490 chanmode_selected
= &chanmode
[i
];
495 if (chanmode_selected
) {
496 NLA_PUT_U32(msg
, NL80211_ATTR_CHANNEL_WIDTH
,
497 chanmode_selected
->width
);
498 NLA_PUT_U32(msg
, NL80211_ATTR_CENTER_FREQ1
,
499 freq
+ chanmode_selected
->freq1_diff
);
500 if (chanmode_selected
->chantype
!= -1)
502 NL80211_ATTR_WIPHY_CHANNEL_TYPE
,
503 chanmode_selected
->chantype
);
511 if (argc
> 1 && strcmp(argv
[0], "basic-rates") == 0) {
515 value
= strtok_r(argv
[0], ",", &sptr
);
517 while (value
&& n_rates
< NL80211_MAX_SUPP_RATES
) {
518 rate
= strtod(value
, &end
);
519 rates
[n_rates
] = rate
* 2;
521 /* filter out suspicious values */
522 if (*end
!= '\0' || !rates
[n_rates
] ||
523 rate
*2 != rates
[n_rates
])
527 value
= strtok_r(NULL
, ",", &sptr
);
530 NLA_PUT(msg
, NL80211_ATTR_BSS_BASIC_RATES
, n_rates
, rates
);
536 if (argc
> 1 && strcmp(argv
[0], "mcast-rate") == 0) {
540 rate
= strtod(argv
[0], &end
);
544 NLA_PUT_U32(msg
, NL80211_ATTR_MCAST_RATE
, (int)(rate
* 10));
549 if (argc
> 1 && strcmp(argv
[0], "beacon-interval") == 0) {
553 bintval
= strtoul(argv
[0], &end
, 10);
557 NLA_PUT_U32(msg
, NL80211_ATTR_BEACON_INTERVAL
, bintval
);
562 if (argc
> 1 && strcmp(argv
[0], "dtim-period") == 0) {
566 dtim_period
= strtoul(argv
[0], &end
, 10);
570 NLA_PUT_U32(msg
, NL80211_ATTR_DTIM_PERIOD
, dtim_period
);
575 container
= nla_nest_start(msg
, NL80211_ATTR_MESH_SETUP
);
579 if (argc
> 1 && strcmp(argv
[0], "vendor_sync") == 0) {
582 if (strcmp(argv
[0], "on") == 0)
584 NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC
, 1);
587 NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC
, 0);
591 /* parse and put other NL80211_ATTR_MESH_SETUP elements here */
593 nla_nest_end(msg
, container
);
597 return set_interface_meshparam(state
, msg
, argc
, argv
, id
);
601 COMMAND(mesh
, join
, "<mesh ID> [[freq <freq in MHz> <HT20|HT40+|HT40-|NOHT>]"
602 " [basic-rates <rate in Mbps,rate2,...>]], [mcast-rate <rate in Mbps>]"
603 " [beacon-interval <time in TUs>] [dtim-period <value>]"
604 " [vendor_sync on|off] [<param>=<value>]*",
605 NL80211_CMD_JOIN_MESH
, 0, CIB_NETDEV
, join_mesh
,
606 "Join a mesh with the given mesh ID with frequency, basic-rates,\n"
607 "mcast-rate and mesh parameters. Basic-rates are applied only if\n"
608 "frequency is provided.");
610 static int leave_mesh(struct nl80211_state
*state
,
611 struct nl_msg
*msg
, int argc
, char **argv
,
619 COMMAND(mesh
, leave
, NULL
, NL80211_CMD_LEAVE_MESH
, 0, CIB_NETDEV
, leave_mesh
,