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>
17 typedef struct _any_t
{
26 /* describes a mesh parameter */
27 struct mesh_param_descr
{
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
*);
35 /* utility functions for manipulating and printing u8/u16/u32 values and
37 static int _my_nla_put_u8(struct nl_msg
*n
, int mesh_param_num
, _any
*value
)
39 return nla_put(n
, mesh_param_num
, sizeof(uint8_t), &value
->u
.as_8
);
42 static int _my_nla_put_u16(struct nl_msg
*n
, int mesh_param_num
, _any
*value
)
44 return nla_put(n
, mesh_param_num
, sizeof(uint16_t), &value
->u
.as_16
);
47 static int _my_nla_put_u32(struct nl_msg
*n
, int mesh_param_num
, _any
*value
)
49 return nla_put(n
, mesh_param_num
, sizeof(uint32_t), &value
->u
.as_32
);
52 static uint32_t _parse_u8(const char *str
, _any
*ret
)
55 unsigned long int v
= strtoul(str
, &endptr
, 10);
60 ret
->u
.as_8
= (uint8_t)v
;
64 static uint32_t _parse_u8_as_bool(const char *str
, _any
*ret
)
67 unsigned long int v
= strtoul(str
, &endptr
, 10);
72 ret
->u
.as_8
= (uint8_t)v
;
76 static uint32_t _parse_u16(const char *str
, _any
*ret
)
79 long int v
= strtol(str
, &endptr
, 10);
82 if ((v
< 0) || (v
> 0xffff))
84 ret
->u
.as_16
= (uint16_t)v
;
88 static uint32_t _parse_u32(const char *str
, _any
*ret
)
91 long long int v
= strtoll(str
, &endptr
, 10);
94 if ((v
< 0) || (v
> 0xffffffff))
96 ret
->u
.as_32
= (uint32_t)v
;
100 static uint32_t _parse_s32(const char *str
, _any
*ret
)
103 long int v
= strtol(str
, &endptr
, 10);
108 ret
->u
.as_s32
= (int32_t)v
;
112 static uint32_t _parse_u32_power_mode(const char *str
, _any
*ret
)
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
;
126 ret
->u
.as_32
= (uint32_t)v
;
130 static void _print_u8(struct nlattr
*a
)
132 printf("%d", nla_get_u8(a
));
135 static void _print_u16(struct nlattr
*a
)
137 printf("%d", nla_get_u16(a
));
140 static void _print_u16_timeout(struct nlattr
*a
)
142 printf("%d milliseconds", nla_get_u16(a
));
145 static void _print_u16_in_TUs(struct nlattr
*a
)
147 printf("%d TUs", nla_get_u16(a
));
150 static void _print_u32(struct nlattr
*a
)
152 printf("%d", nla_get_u32(a
));
155 static void _print_u32_timeout(struct nlattr
*a
)
157 printf("%u milliseconds", nla_get_u32(a
));
160 static void _print_u32_in_seconds(struct nlattr
*a
)
162 printf("%d seconds", nla_get_u32(a
));
165 static void _print_u32_in_TUs(struct nlattr
*a
)
167 printf("%d TUs", nla_get_u32(a
));
170 static void _print_u32_power_mode(struct nlattr
*a
)
172 unsigned long v
= nla_get_u32(a
);
175 case NL80211_MESH_POWER_ACTIVE
:
178 case NL80211_MESH_POWER_LIGHT_SLEEP
:
181 case NL80211_MESH_POWER_DEEP_SLEEP
:
190 static void _print_s32_in_dBm(struct nlattr
*a
)
192 printf("%d dBm", (int32_t) nla_get_u32(a
));
196 /* The current mesh parameters */
197 const static struct mesh_param_descr _mesh_param_descrs
[] =
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
},
212 NL80211_MESHCONF_MAX_RETRIES
,
213 _my_nla_put_u8
, _parse_u8
, _print_u8
},
215 NL80211_MESHCONF_TTL
,
216 _my_nla_put_u8
, _parse_u8
, _print_u8
},
218 NL80211_MESHCONF_ELEMENT_TTL
,
219 _my_nla_put_u8
, _parse_u8
, _print_u8
},
220 {"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
},
241 {"mesh_hwmp_rootmode", NL80211_MESHCONF_HWMP_ROOTMODE
,
242 _my_nla_put_u8
, _parse_u8
, _print_u8
},
243 {"mesh_hwmp_rann_interval", NL80211_MESHCONF_HWMP_RANN_INTERVAL
,
244 _my_nla_put_u16
, _parse_u16
, _print_u16_in_TUs
},
245 {"mesh_gate_announcements", NL80211_MESHCONF_GATE_ANNOUNCEMENTS
,
246 _my_nla_put_u8
, _parse_u8
, _print_u8
},
247 {"mesh_fwding", NL80211_MESHCONF_FORWARDING
,
248 _my_nla_put_u8
, _parse_u8_as_bool
, _print_u8
},
249 {"mesh_sync_offset_max_neighor",
250 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR
,
251 _my_nla_put_u32
, _parse_u32
, _print_u32
},
252 {"mesh_rssi_threshold", NL80211_MESHCONF_RSSI_THRESHOLD
,
253 _my_nla_put_u32
, _parse_s32
, _print_s32_in_dBm
},
254 {"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
},
262 {"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
},
266 {"mesh_plink_timeout", NL80211_MESHCONF_PLINK_TIMEOUT
,
267 _my_nla_put_u32
, _parse_u32
, _print_u32_in_seconds
},
270 static void print_all_mesh_param_descr(void)
274 printf("Possible mesh parameters are:\n");
276 for (i
= 0; i
< ARRAY_SIZE(_mesh_param_descrs
); i
++)
277 printf(" - %s\n", _mesh_param_descrs
[i
].name
);
280 static const struct mesh_param_descr
*find_mesh_param(const char *name
)
284 /* Find out what mesh parameter we want to change. */
285 for (i
= 0; i
< ARRAY_SIZE(_mesh_param_descrs
); i
++) {
286 if (strcmp(_mesh_param_descrs
[i
].name
, name
) == 0)
287 return _mesh_param_descrs
+ i
;
290 print_all_mesh_param_descr();
295 static int set_interface_meshparam(struct nl80211_state
*state
,
298 int argc
, char **argv
,
301 const struct mesh_param_descr
*mdescr
;
302 struct nlattr
*container
;
306 container
= nla_nest_start(msg
, NL80211_ATTR_MESH_PARAMS
);
318 memset(&any
, 0, sizeof(_any
));
321 value
= strchr(name
, '=');
328 /* backward compat -- accept w/o '=' */
330 printf("Must specify a value for %s.\n", name
);
338 mdescr
= find_mesh_param(name
);
342 /* Parse the new value */
343 ret
= mdescr
->parse_fn(value
, &any
);
345 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
);
350 printf("%s must be set to a number "
351 "between 0 and %u\n",
357 err
= mdescr
->nla_put_fn(msg
, mdescr
->mesh_param_num
, &any
);
361 nla_nest_end(msg
, container
);
366 COMMAND(set
, mesh_param
, "<param>=<value> [<param>=<value>]*",
367 NL80211_CMD_SET_MESH_PARAMS
, 0, CIB_NETDEV
, set_interface_meshparam
,
368 "Set mesh parameter (run command without any to see available ones).");
371 static int print_mesh_param_handler(struct nl_msg
*msg
, void *arg
)
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
));
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
];
386 /* unpack the mesh parameters */
387 if (nla_parse_nested(mesh_params
, NL80211_MESHCONF_ATTR_MAX
,
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
]);
403 /* print out the mesh parameter */
404 mdescr
->nla_print_fn(mesh_params
[mdescr
->mesh_param_num
]);
409 static int get_interface_meshparam(struct nl80211_state
*state
,
412 int argc
, char **argv
,
415 const struct mesh_param_descr
*mdescr
= NULL
;
421 mdescr
= find_mesh_param(argv
[0]);
426 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
,
427 print_mesh_param_handler
, (void *)mdescr
);
431 COMMAND(get
, mesh_param
, "[<param>]",
432 NL80211_CMD_GET_MESH_PARAMS
, 0, CIB_NETDEV
, get_interface_meshparam
,
433 "Retrieve mesh parameter (run command without any to see available ones).");
435 static int join_mesh(struct nl80211_state
*state
, struct nl_cb
*cb
,
436 struct nl_msg
*msg
, int argc
, char **argv
,
439 struct nlattr
*container
;
441 int bintval
, dtim_period
;
447 NLA_PUT(msg
, NL80211_ATTR_MESH_ID
, strlen(argv
[0]), argv
[0]);
451 if (argc
> 1 && strcmp(argv
[0], "mcast-rate") == 0) {
455 rate
= strtod(argv
[0], &end
);
459 NLA_PUT_U32(msg
, NL80211_ATTR_MCAST_RATE
, (int)(rate
* 10));
464 if (argc
> 1 && strcmp(argv
[0], "beacon-interval") == 0) {
468 bintval
= strtoul(argv
[0], &end
, 10);
472 NLA_PUT_U32(msg
, NL80211_ATTR_BEACON_INTERVAL
, bintval
);
477 if (argc
> 1 && strcmp(argv
[0], "dtim-period") == 0) {
481 dtim_period
= strtoul(argv
[0], &end
, 10);
485 NLA_PUT_U32(msg
, NL80211_ATTR_DTIM_PERIOD
, dtim_period
);
490 container
= nla_nest_start(msg
, NL80211_ATTR_MESH_SETUP
);
494 if (argc
> 1 && strcmp(argv
[0], "vendor_sync") == 0) {
497 if (strcmp(argv
[0], "on") == 0)
499 NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC
, 1);
502 NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC
, 0);
506 /* parse and put other NL80211_ATTR_MESH_SETUP elements here */
508 nla_nest_end(msg
, container
);
512 return set_interface_meshparam(state
, cb
, msg
, argc
, argv
, id
);
516 COMMAND(mesh
, join
, "<mesh ID> [mcast-rate <rate in Mbps>]"
517 " [beacon-interval <time in TUs>] [dtim-period <value>]"
518 " [vendor_sync on|off] [<param>=<value>]*",
519 NL80211_CMD_JOIN_MESH
, 0, CIB_NETDEV
, join_mesh
,
520 "Join a mesh with the given mesh ID with mcast-rate and mesh parameters.");
522 static int leave_mesh(struct nl80211_state
*state
, struct nl_cb
*cb
,
523 struct nl_msg
*msg
, int argc
, char **argv
,
531 COMMAND(mesh
, leave
, NULL
, NL80211_CMD_LEAVE_MESH
, 0, CIB_NETDEV
, leave_mesh
,