2 * Network Configuration Module
4 * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
25 #include <sys/types.h>
30 #include <netlink/genl/genl.h>
31 #include <netlink/genl/family.h>
32 #include <netlink/genl/ctrl.h>
33 #include <netlink/msg.h>
34 #include <netlink/attr.h>
35 #include <netlink/netlink.h>
38 #include "wmesh-log.h"
39 #include "wmesh-util.h"
40 #include "wmesh-netlink.h"
41 #include "wmesh-request.h"
43 #include <linux/nl80211.h>
44 //#include "nl80211.h"
46 #define MESH_PARAM_HWMP_ROOTMODE "mesh_hwmp_rootmode"
47 #define MESH_PARAM_GATE_ANNOUNCE "mesh_gate_announcements"
48 #define MAX_MAC_ADDR_LEN 18
51 #define BIT(x) (1ULL<<(x))
53 #define NL80211_STA_INFO_CHAIN_SIGNAL NL80211_STA_INFO_TX_BYTES64 + 1
54 #define NL80211_STA_INFO_CHAIN_SIGNAL_AVG NL80211_STA_INFO_TX_BYTES64 + 2
55 #define NL80211_STA_INFO_EXPECTED_THROUGHPUT NL80211_STA_INFO_TX_BYTES64 + 3
56 #define NL80211_STA_INFO_RX_DROP_MISC NL80211_STA_INFO_TX_BYTES64 + 4
57 #define NL80211_STA_INFO_BEACON_RX NL80211_STA_INFO_TX_BYTES64 + 5
58 #define NL80211_STA_INFO_BEACON_SIGNAL_AVG NL80211_STA_INFO_TX_BYTES64 + 6
59 #define NL80211_STA_INFO_TID_STATS NL80211_STA_INFO_TX_BYTES64 + 7
61 #define __NL80211_STA_INFO_AFTER_LAST NL80211_STA_INFO_TX_BYTES64 + 8
62 #define NL80211_STA_INFO_MAX __NL80211_STA_INFO_AFTER_LAST - 1
65 MESH_NL_CALLBACK_FINISHED = 0,
66 MESH_NL_CALLBACK_TRYING,
67 } mesh_nl_callback_state_e;
74 struct nl_sock *nl_socket;
82 wmesh_meshconf_info_s **meshconf;
88 } multicast_group_id_args;
100 /* For event handler */
101 static mesh_nl_state *event_state = NULL;
103 static int __initialize_nl80211(mesh_nl_state *state)
105 int err = WMESHD_ERROR_NONE;
107 state->nl_socket = nl_socket_alloc();
108 if (!state->nl_socket) {
109 /* LCOV_EXCL_START */
110 WMESH_LOGE("Failed to allocate netlink socket.");
111 return WMESHD_ERROR_OUT_OF_MEMORY;
115 if (genl_connect(state->nl_socket)) {
116 /* LCOV_EXCL_START */
117 WMESH_LOGE("Failed to connect to generic netlink.");
118 err = WMESHD_ERROR_OPERATION_FAILED;
123 nl_socket_set_buffer_size(state->nl_socket, 8192, 8192);
125 state->nl80211_id = genl_ctrl_resolve(state->nl_socket, "nl80211");
126 if (state->nl80211_id < 0) {
127 /* LCOV_EXCL_START */
128 WMESH_LOGE("nl80211 not found.");
129 err = WMESHD_ERROR_NO_DATA;
137 /* LCOV_EXCL_START */
138 nl_socket_free(state->nl_socket);
143 static void __clean_nl80211(mesh_nl_state *state)
146 return; /* LCOV_EXCL_LINE */
148 if (state->nl_socket) {
149 nl_socket_free(state->nl_socket);
150 state->nl_socket = NULL;
151 state->nl80211_id = -1;
155 static int __get_device_index_from_string(const char* if_name, int *index)
157 int device_index = 0;
159 if (NULL == if_name) {
160 /* LCOV_EXCL_START */
161 WMESH_LOGE("Invalid parameter");
162 return WMESHD_ERROR_INVALID_PARAMETER;
166 device_index = if_nametoindex(if_name);
167 if (device_index == 0) {
168 /* LCOV_EXCL_START */
169 WMESH_LOGE("No interface index found [%s]", if_name);
170 return WMESHD_ERROR_NO_DATA;
173 *index = device_index; /* LCOV_EXCL_LINE */
175 return WMESHD_ERROR_NONE; /* LCOV_EXCL_LINE */
178 /* LCOV_EXCL_START */
179 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
181 mesh_nl_state *state = (mesh_nl_state *)arg;
182 char buf[256] = { 0, };
186 state->callback_state = MESH_NL_CALLBACK_FINISHED;
187 state->error_occured = TRUE;
188 strerror_r(err->error, buf, 255);
190 WMESH_LOGD("error_handler");
191 WMESH_LOGE(" %s (%d)", buf, err->error);
196 static int finish_handler(struct nl_msg *msg, void *arg)
198 mesh_nl_state *state = (mesh_nl_state *)arg;
200 state->callback_state = MESH_NL_CALLBACK_FINISHED;
202 WMESH_LOGD("finish_handler");
208 static int ack_handler(struct nl_msg *msg, void *arg)
210 mesh_nl_state *state = (mesh_nl_state *)arg;
212 state->callback_state = MESH_NL_CALLBACK_FINISHED;
214 WMESH_LOGD("ack_handler");
221 static int ack_simple_handler(struct nl_msg *msg, void *arg)
228 WMESH_LOGD("ack_simple_handler");
233 static int family_handler(struct nl_msg *msg, void *arg)
235 multicast_group_id_args *group = (multicast_group_id_args *)arg;
236 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
237 struct nlattr *tb[CTRL_ATTR_MAX + 1];
238 struct nlattr *mcast_group;
241 WMESH_LOGD("family_handler");
243 nla_parse(tb, CTRL_ATTR_MAX,
244 genlmsg_attrdata(gnlh, 0),
245 genlmsg_attrlen(gnlh, 0), NULL);
246 if (!tb[CTRL_ATTR_MCAST_GROUPS])
247 return NL_SKIP; //LCOV_EXCL_LINE
249 nla_for_each_nested(mcast_group, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcast_group) {
250 struct nlattr *tb_mcast_group[CTRL_ATTR_MCAST_GRP_MAX + 1];
252 nla_parse(tb_mcast_group, CTRL_ATTR_MCAST_GRP_MAX,
253 nla_data(mcast_group), nla_len(mcast_group), NULL);
255 if (!tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME] ||
256 !tb_mcast_group[CTRL_ATTR_MCAST_GRP_ID])
257 continue; //LCOV_EXCL_LINE
259 if (strncmp(nla_data(tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME]),
261 nla_len(tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME])))
262 continue; //LCOV_EXCL_LINE
264 group->id = nla_get_u32(tb_mcast_group[CTRL_ATTR_MCAST_GRP_ID]);
265 WMESH_LOGD("mcast group id [%d]", group->id);
272 static int __nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group)
277 multicast_group_id_args group_args = {
284 return -ENOMEM; //LCOV_EXCL_LINE
286 cb = nl_cb_alloc(NL_CB_DEFAULT);
288 /* LCOV_EXCL_START */
294 ctrlid = genl_ctrl_resolve(sock, "nlctrl");
296 genlmsg_put(msg, 0, 0, ctrlid, 0,
297 0, CTRL_CMD_GETFAMILY, 0);
300 NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
302 ret = nl_send_auto(sock, msg);
304 /* LCOV_EXCL_START */
305 WMESH_LOGE("Failed to nl_send_auto");
311 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
312 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_simple_handler, &ret);
313 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, family_handler, &group_args);
316 nl_recvmsgs(sock, cb);
321 WMESH_LOGD("mcid : [%d]", ret);
332 static int __prepare_listen_events(mesh_nl_state *state)
336 /* Configuration multicast group */
337 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "config");
339 /* LCOV_EXCL_START */
340 WMESH_LOGE("Failed to get nl80211 config");
344 WMESH_LOGD("Mesh multicast id (config): [%d]", mcid);
346 ret = nl_socket_add_membership(state->nl_socket, mcid);
348 /* LCOV_EXCL_START */
349 WMESH_LOGE("Failed to nl_socket_add_membership");
354 /* Scan multicast group */
355 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "scan");
357 ret = nl_socket_add_membership(state->nl_socket, mcid);
359 /* LCOV_EXCL_START */
360 WMESH_LOGE("Failed to nl_socket_add_membership");
365 WMESH_LOGD("Mesh multicast id (scan): [%d]", mcid);
367 /* Regulatory multicast group */
368 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "regulatory");
370 ret = nl_socket_add_membership(state->nl_socket, mcid);
372 /* LCOV_EXCL_START */
373 WMESH_LOGE("Failed to nl_socket_add_membership");
378 WMESH_LOGD("Mesh multicast id (regulatory): [%d]", mcid);
380 /* MLME multicast group */
381 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "mlme");
383 ret = nl_socket_add_membership(state->nl_socket, mcid);
385 /* LCOV_EXCL_START */
386 WMESH_LOGE("Failed to nl_socket_add_membership");
391 WMESH_LOGD("Mesh multicast id (mlme): [%d]", mcid);
393 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "vendor");
395 ret = nl_socket_add_membership(state->nl_socket, mcid);
397 /* LCOV_EXCL_START */
398 WMESH_LOGE("Failed to nl_socket_add_membership");
403 WMESH_LOGD("Mesh multicast id (vendor): [%d]", mcid);
408 static mesh_nl_state *_create_mesh_nl_state()
410 mesh_nl_state *state = g_new0(mesh_nl_state, 1);
412 state->nl80211_id = -1;
413 state->callback_state = MESH_NL_CALLBACK_TRYING;
414 state->error_occured = FALSE;
419 static void _delete_mesh_nl_state(mesh_nl_state **state)
421 if (NULL == state || NULL == *state)
422 return; //LCOV_EXCL_LINE
428 /* LCOV_EXCL_START */
429 static int valid_handler(struct nl_msg *msg, void *arg)
431 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
432 mesh_nl_state *state = (mesh_nl_state *)arg;
433 WMESH_LOGD("valid_handler");
435 if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) {
436 WMESH_LOGD(" Got NL80211_CMD_SCAN_ABORTED.");
437 state->callback_state = MESH_NL_CALLBACK_FINISHED;
439 /* Notify scan done status */
440 wmesh_notify_scan_done();
441 } else if (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
442 WMESH_LOGD(" Got NL80211_CMD_NEW_SCAN_RESULTS.");
443 state->callback_state = MESH_NL_CALLBACK_FINISHED;
445 /* Notify scan done status */
446 wmesh_notify_scan_done();
448 WMESH_LOGD(" Got [%d]", gnlh->cmd);
455 static int no_seq_check(struct nl_msg *msg, void *arg)
463 static void __clean_netlink_message(mesh_nl_state *state)
466 return; /* LCOV_EXCL_LINE */
469 nl_cb_put(state->cb);
471 nl_cb_put(state->s_cb);
473 nlmsg_free(state->msg);
479 WMESH_LOGD("message and callback cleaned");
482 static int __initialize_netlink_message(mesh_nl_state *state)
484 int err = WMESHD_ERROR_NONE;
487 /* LCOV_EXCL_START */
488 WMESH_LOGE("Invalid parameter !");
489 return WMESHD_ERROR_INVALID_PARAMETER;
493 /* Create netlink message */
494 state->msg = nlmsg_alloc();
495 if (NULL == state->msg) {
496 /* LCOV_EXCL_START */
497 WMESH_LOGE("Failed to allocate netlink message");
498 return WMESHD_ERROR_OUT_OF_MEMORY;
503 state->cb = nl_cb_alloc(NL_CB_DEFAULT);
504 state->s_cb = nl_cb_alloc(NL_CB_DEFAULT);
506 /* LCOV_EXCL_START */
507 WMESH_LOGE("Failed to allocate netlink callback");
508 err = WMESHD_ERROR_OUT_OF_MEMORY;
513 /* Set socket callback */
514 nl_socket_set_cb(state->nl_socket, state->s_cb);
517 nl_cb_err(state->cb, NL_CB_CUSTOM, error_handler, state);
518 nl_cb_set(state->cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, state);
519 nl_cb_set(state->cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, state);
520 nl_cb_set(state->cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, state);
522 WMESH_LOGD("netlink socket initialized");
524 return WMESHD_ERROR_NONE;
527 /* LCOV_EXCL_START */
528 __clean_netlink_message(state);
534 static gboolean _on_socket_event_io_received(GIOChannel *source,
535 GIOCondition condition, gpointer data)
537 mesh_nl_state *state = (mesh_nl_state *)data;
543 WMESH_LOGD("[Event] I/O received");
545 while (nl_recvmsgs_report(state->nl_socket, state->cb) > 0)
546 WMESH_LOGD(" count [%02d]", ++test); //LCOV_EXCL_LINE
548 /* Do not remove I/O source */
552 static void _on_remove_event_io_handler()
555 g_source_remove(event_state->event_source);
557 __clean_netlink_message(event_state);
558 __clean_nl80211(event_state);
559 _delete_mesh_nl_state(&event_state);
563 static void mac_addr_n2a(char *mac_addr, unsigned char *arg)
565 /* 11:22:33:44:55:66 (Len:17) */
566 snprintf(mac_addr, MAX_MAC_ADDR_LEN,
567 "%02x:%02x:%02x:%02x:%02x:%02x",
568 arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
571 /* LCOV_EXCL_START */
572 #if defined(NL80211_STA_INFO_CHAIN_SIGNAL) || defined(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)
573 static char *get_chain_signal(struct nlattr *attr_list)
584 nla_for_each_nested(attr, attr_list, rem) {
590 cur += snprintf(cur, sizeof(buf) - (cur - buf), "%s%d", prefix,
591 (int8_t) nla_get_u8(attr));
595 snprintf(cur, sizeof(buf) - (cur - buf), "] ");
599 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL || NL80211_STA_INFO_CHAIN_SIGNAL_AVG */
601 static int parse_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen)
605 char str_rate[32] = { 0, };
606 char str_buf[128] = { 0, };
607 struct nlattr *rate_info[NL80211_RATE_INFO_MAX + 1];
608 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
609 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
610 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
611 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
612 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
613 [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 },
616 if (nla_parse_nested(rate_info, NL80211_RATE_INFO_MAX, bitrate_attr, rate_policy)) {
618 snprintf(buf, buflen, "failed to parse nested rate attributes!"); //LCOV_EXCL_LINE
622 if (rate_info[NL80211_RATE_INFO_MCS])
623 pos += snprintf(str_buf + pos, 128 - pos,
624 " MCS %d", nla_get_u8(rate_info[NL80211_RATE_INFO_MCS]));
625 if (rate_info[NL80211_RATE_INFO_40_MHZ_WIDTH])
626 pos += snprintf(str_buf + pos, 128 - pos, " 40MHz");
627 if (rate_info[NL80211_RATE_INFO_SHORT_GI])
628 pos += snprintf(str_buf + pos, 128 - pos, " short GI");
629 if (rate_info[NL80211_RATE_INFO_VHT_MCS])
630 pos += snprintf(str_buf + pos, 128 - pos,
631 " VHT-MCS %d", nla_get_u8(rate_info[NL80211_RATE_INFO_VHT_MCS]));
632 if (rate_info[NL80211_RATE_INFO_VHT_NSS])
633 pos += snprintf(str_buf + pos, 128 - pos,
634 " VHT-NSS %d", nla_get_u8(rate_info[NL80211_RATE_INFO_VHT_NSS]));
635 if (rate_info[NL80211_RATE_INFO_80_MHZ_WIDTH])
636 pos += snprintf(str_buf + pos, 128 - pos, " 80MHz");
637 if (rate_info[NL80211_RATE_INFO_80P80_MHZ_WIDTH])
638 pos += snprintf(str_buf + pos, 128 - pos, " 80P80MHz");
639 if (rate_info[NL80211_RATE_INFO_160_MHZ_WIDTH])
640 pos += snprintf(str_buf + pos, 128 - pos, " 160MHz");
642 if (rate_info[NL80211_RATE_INFO_BITRATE32])
643 rate = nla_get_u32(rate_info[NL80211_RATE_INFO_BITRATE32]);
644 else if (rate_info[NL80211_RATE_INFO_BITRATE])
645 rate = nla_get_u16(rate_info[NL80211_RATE_INFO_BITRATE]);
647 snprintf(str_rate, 32, "%d.%d MBit/s", rate / 10, rate % 10);
650 snprintf(buf, buflen, "%s%s", str_rate, str_buf);
655 static void parse_bss_param(struct nlattr *bss_param_attr, wmesh_station_info_s *station_info)
657 struct nlattr *bss_param_info[NL80211_STA_BSS_PARAM_MAX + 1], *info;
658 static struct nla_policy bss_poilcy[NL80211_STA_BSS_PARAM_MAX + 1] = {
659 [NL80211_STA_BSS_PARAM_CTS_PROT] = { .type = NLA_FLAG },
660 [NL80211_STA_BSS_PARAM_SHORT_PREAMBLE] = { .type = NLA_FLAG },
661 [NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME] = { .type = NLA_FLAG },
662 [NL80211_STA_BSS_PARAM_DTIM_PERIOD] = { .type = NLA_U8 },
663 [NL80211_STA_BSS_PARAM_BEACON_INTERVAL] = { .type = NLA_U16 },
666 if (nla_parse_nested(bss_param_info, NL80211_STA_BSS_PARAM_MAX, bss_param_attr, bss_poilcy))
667 WMESH_LOGE("failed to parse nested bss param attributes!");
669 info = bss_param_info[NL80211_STA_BSS_PARAM_DTIM_PERIOD];
671 station_info->dtim_period = nla_get_u8(info);
672 WMESH_LOGD(" DTIM period:\t%u", station_info->dtim_period);
674 info = bss_param_info[NL80211_STA_BSS_PARAM_BEACON_INTERVAL];
676 station_info->beacon_interval = nla_get_u16(info);
677 WMESH_LOGD(" beacon interval:%u", station_info->beacon_interval);
679 info = bss_param_info[NL80211_STA_BSS_PARAM_CTS_PROT];
681 WMESH_LOGD(" CTS protection:");
682 if (nla_get_u16(info)) {
684 station_info->cts_protection = TRUE;
687 station_info->cts_protection = FALSE;
690 info = bss_param_info[NL80211_STA_BSS_PARAM_SHORT_PREAMBLE];
692 WMESH_LOGD(" short preamble:");
693 if (nla_get_u16(info)) {
695 station_info->short_preamble = TRUE;
698 station_info->short_preamble = FALSE;
701 info = bss_param_info[NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME];
703 WMESH_LOGD(" short slot time:");
704 if (nla_get_u16(info)) {
706 station_info->short_slot_time = TRUE;
709 station_info->short_slot_time = FALSE;
714 static void print_power_mode(struct nlattr *a)
716 enum nl80211_mesh_power_mode pm = nla_get_u32(a);
719 case NL80211_MESH_POWER_ACTIVE:
720 WMESH_LOGD("ACTIVE");
722 case NL80211_MESH_POWER_LIGHT_SLEEP:
723 WMESH_LOGD("LIGHT SLEEP");
725 case NL80211_MESH_POWER_DEEP_SLEEP:
726 WMESH_LOGD("DEEP SLEEP");
729 WMESH_LOGD("UNKNOWN");
734 static int _on_receive_station_info(struct nl_msg *msg, void *arg)
736 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
737 struct nlattr *sta_info[NL80211_STA_INFO_MAX + 1];
738 struct nlattr *attr_info[NL80211_ATTR_MAX + 1];
739 struct nl80211_sta_flag_update *sta_flags;
740 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
741 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
742 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
743 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
744 [NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
745 [NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
746 [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
747 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
748 [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
749 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
750 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
751 [NL80211_STA_INFO_TX_RETRIES] = { .type = NLA_U32 },
752 [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
753 [NL80211_STA_INFO_RX_BITRATE] = { .type = NLA_NESTED },
754 [NL80211_STA_INFO_BSS_PARAM] = { .type = NLA_NESTED },
755 [NL80211_STA_INFO_STA_FLAGS] = { .minlen = sizeof(struct nl80211_sta_flag_update) },
756 [NL80211_STA_INFO_BEACON_LOSS] = { .type = NLA_U32},
757 [NL80211_STA_INFO_T_OFFSET] = { .type = NLA_U64 },
758 [NL80211_STA_INFO_LOCAL_PM] = { .type = NLA_U32 },
759 [NL80211_STA_INFO_PEER_PM] = { .type = NLA_U32 },
760 [NL80211_STA_INFO_NONPEER_PM] = { .type = NLA_U32 },
761 [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
762 [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
763 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL
764 [NL80211_STA_INFO_CHAIN_SIGNAL] = { .type = NLA_NESTED },
765 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL */
767 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL_AVG
768 [NL80211_STA_INFO_CHAIN_SIGNAL_AVG] = { .type = NLA_NESTED },
769 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL_AVG */
771 #ifdef NL80211_STA_INFO_RX_DROP_MISC
772 [NL80211_STA_INFO_RX_DROP_MISC] = { .type = NLA_U64 },
773 #endif /* NL80211_STA_INFO_RX_DROP_MISC */
775 #ifdef NL80211_STA_INFO_RX_DURATION
776 [NL80211_STA_INFO_BEACON_RX] = { .type = NLA_U64 },
777 #endif /* NL80211_STA_INFO_RX_DURATION */
779 #ifdef NL80211_STA_INFO_TID_STATS
780 [NL80211_STA_INFO_TID_STATS] = { .type = NLA_NESTED },
781 #endif /* NL80211_STA_INFO_TID_STATS */
783 #ifdef NL80211_STA_INFO_RX_DURATION
784 [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 },
785 #endif /* NL80211_STA_INFO_RX_DURATION */
787 char mac_addr[MAX_MAC_ADDR_LEN], dev[IF_NAMESIZE];
788 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL
790 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL */
791 char *attr_mac = NULL;
792 mesh_nl_state *state = (mesh_nl_state *)arg;
793 wmesh_station_info_s *station_info = NULL;
795 nla_parse(attr_info, NL80211_ATTR_MAX,
796 genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
798 if (!attr_info[NL80211_ATTR_STA_INFO]) {
799 WMESH_LOGE("[Station] missing station stats !");
803 if (nla_parse_nested(sta_info, NL80211_STA_INFO_MAX,
804 attr_info[NL80211_ATTR_STA_INFO], stats_policy)) {
805 WMESH_LOGE("[Station] Failed to parse nested attributes!");
810 station_info = g_try_new0(wmesh_station_info_s, 1);
811 if (NULL == station_info) {
812 WMESH_LOGE("Failed to allocate station info !");
817 attr_mac = nla_data(attr_info[NL80211_ATTR_MAC]);
818 snprintf(mac_addr, MAX_MAC_ADDR_LEN, "%02x:%02x:%02x:%02x:%02x:%02x",
819 attr_mac[0], attr_mac[1], attr_mac[2],
820 attr_mac[3], attr_mac[4], attr_mac[5]);
821 if_indextoname(nla_get_u32(attr_info[NL80211_ATTR_IFINDEX]), dev);
822 station_info->bssid = g_strdup(mac_addr);
823 WMESH_LOGD("Station %s [dev %s]", station_info->bssid, dev);
826 if (0 != sta_info[NL80211_STA_INFO_INACTIVE_TIME]) {
827 station_info->inactive_time =
828 nla_get_u32(sta_info[NL80211_STA_INFO_INACTIVE_TIME]);
829 WMESH_LOGE(" inactive time:\t%u ms", station_info->inactive_time);
833 if (0 != sta_info[NL80211_STA_INFO_RX_BYTES]) {
834 station_info->rx_bytes =
835 nla_get_u32(sta_info[NL80211_STA_INFO_RX_BYTES]);
836 WMESH_LOGD(" rx bytes:\t%u", station_info->rx_bytes);
837 } else if (0 != sta_info[NL80211_STA_INFO_RX_BYTES64]) {
838 station_info->rx_bytes =
839 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_RX_BYTES64]);
840 WMESH_LOGE(" rx bytes:\t%llu", station_info->rx_bytes);
844 if (0 != sta_info[NL80211_STA_INFO_RX_PACKETS]) {
845 station_info->rx_packets =
846 nla_get_u32(sta_info[NL80211_STA_INFO_RX_PACKETS]);
847 WMESH_LOGD(" rx packets:\t%u", station_info->rx_packets);
851 if (0 != sta_info[NL80211_STA_INFO_TX_BYTES]) {
852 station_info->tx_bytes =
853 nla_get_u32(sta_info[NL80211_STA_INFO_TX_BYTES]);
854 WMESH_LOGD(" tx bytes:\t%u", station_info->tx_bytes);
855 } else if (0 != sta_info[NL80211_STA_INFO_TX_BYTES64]) {
856 station_info->tx_bytes =
857 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_TX_BYTES64]);
858 WMESH_LOGD(" tx bytes:\t%llu", station_info->rx_packets);
862 if (0 != sta_info[NL80211_STA_INFO_LLID]) {
863 station_info->llid = nla_get_u16(sta_info[NL80211_STA_INFO_LLID]);
864 WMESH_LOGD(" mesh llid:\t%d", station_info->llid);
866 if (0 != sta_info[NL80211_STA_INFO_PLID]) {
867 station_info->plid = nla_get_u16(sta_info[NL80211_STA_INFO_PLID]);
868 WMESH_LOGD(" mesh plid:\t%d", station_info->plid);
872 if (0 != sta_info[NL80211_STA_INFO_PLINK_STATE]) {
874 station_info->mesh_plink =
875 nla_get_u8(sta_info[NL80211_STA_INFO_PLINK_STATE]);
876 switch (station_info->mesh_plink) {
878 snprintf(state_name, 10, "%s", "LISTEN");
881 snprintf(state_name, 10, "%s", "OPN_SNT");
884 snprintf(state_name, 10, "%s", "OPN_RCVD");
887 snprintf(state_name, 10, "%s", "CNF_RCVD");
890 snprintf(state_name, 10, "%s", "ESTAB");
893 snprintf(state_name, 10, "%s", "HOLDING");
896 snprintf(state_name, 10, "%s", "BLOCKED");
899 snprintf(state_name, 10, "%s", "UNKNOWN");
902 WMESH_LOGD(" mesh plink:\t%s", state_name);
904 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL
906 chain = get_chain_signal(sta_info[NL80211_STA_INFO_CHAIN_SIGNAL]);
907 if (0 != sta_info[NL80211_STA_INFO_SIGNAL]) {
909 (int8_t)nla_get_u8(sta_info[NL80211_STA_INFO_SIGNAL]);
910 WMESH_LOGD(" signal: \t%d %sdBm", station_info->rssi, chain);
912 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL */
914 if (0 != sta_info[NL80211_STA_INFO_TX_BITRATE]) {
916 station_info->tx_bitrate =
917 parse_bitrate(sta_info[NL80211_STA_INFO_TX_BITRATE], buf, sizeof(buf));
918 WMESH_LOGD(" tx bitrate:\t%s", buf);
921 if (0 != sta_info[NL80211_STA_INFO_TX_PACKETS]) {
922 station_info->tx_packets =
923 nla_get_u32(sta_info[NL80211_STA_INFO_TX_PACKETS]);
924 WMESH_LOGD(" tx packets:\t%u", station_info->tx_packets);
926 if (0 != sta_info[NL80211_STA_INFO_TX_RETRIES]) {
927 station_info->tx_retries =
928 nla_get_u32(sta_info[NL80211_STA_INFO_TX_RETRIES]);
929 WMESH_LOGD(" tx retries:\t%u", station_info->tx_retries);
931 if (0 != sta_info[NL80211_STA_INFO_TX_FAILED]) {
932 station_info->tx_failed =
933 nla_get_u32(sta_info[NL80211_STA_INFO_TX_FAILED]);
934 WMESH_LOGD(" tx failed:\t%u", station_info->tx_failed);
936 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL_AVG
938 chain = get_chain_signal(sta_info[NL80211_STA_INFO_CHAIN_SIGNAL_AVG]);
939 if (0 != sta_info[NL80211_STA_INFO_SIGNAL_AVG]) {
940 station_info->rssi_avg =
941 (int8_t)nla_get_u8(sta_info[NL80211_STA_INFO_SIGNAL_AVG]);
942 WMESH_LOGD(" signal avg:\t%d %sdBm", station_info->rssi_avg, chain);
944 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL_AVG */
945 if (0 != sta_info[NL80211_STA_INFO_RX_BITRATE]) {
947 station_info->rx_bitrate =
948 parse_bitrate(sta_info[NL80211_STA_INFO_RX_BITRATE], buf, sizeof(buf));
949 WMESH_LOGD(" rx bitrate:\t%s", buf);
952 if (0 != sta_info[NL80211_STA_INFO_BSS_PARAM])
953 parse_bss_param(sta_info[NL80211_STA_INFO_BSS_PARAM], station_info);
955 if (0 != sta_info[NL80211_STA_INFO_CONNECTED_TIME]) {
956 station_info->connected_time =
957 nla_get_u32(sta_info[NL80211_STA_INFO_CONNECTED_TIME]);
958 WMESH_LOGD(" connected time:\t%u seconds", station_info->connected_time);
961 if (0 != sta_info[NL80211_STA_INFO_STA_FLAGS]) {
962 sta_flags = (struct nl80211_sta_flag_update *)
963 nla_data(sta_info[NL80211_STA_INFO_STA_FLAGS]);
965 if (sta_flags->mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
966 WMESH_LOGD(" authorized:");
967 if (sta_flags->set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
969 station_info->authorized = TRUE;
972 station_info->authorized = FALSE;
976 if (sta_flags->mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
977 WMESH_LOGD(" authenticated:");
978 if (sta_flags->set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
980 station_info->authenticated = TRUE;
983 station_info->authenticated = FALSE;
987 if (sta_flags->mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
988 WMESH_LOGD(" associated:");
989 if (sta_flags->set & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
991 station_info->associated = TRUE;
994 station_info->associated = FALSE;
998 if (sta_flags->mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
999 WMESH_LOGD(" preamble:");
1000 if (sta_flags->set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
1001 WMESH_LOGD(" short");
1002 station_info->preamble = TRUE;
1004 WMESH_LOGD(" long");
1005 station_info->preamble = FALSE;
1009 if (sta_flags->mask & BIT(NL80211_STA_FLAG_WME)) {
1010 WMESH_LOGD(" WMM/WME:");
1011 if (sta_flags->set & BIT(NL80211_STA_FLAG_WME)) {
1013 station_info->wme = TRUE;
1016 station_info->wme = FALSE;
1020 if (sta_flags->mask & BIT(NL80211_STA_FLAG_MFP)) {
1021 WMESH_LOGD(" MFP:");
1022 if (sta_flags->set & BIT(NL80211_STA_FLAG_MFP)) {
1024 station_info->mfp = TRUE;
1027 station_info->mfp = FALSE;
1031 if (sta_flags->mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
1032 WMESH_LOGD(" TDLS peer:");
1033 if (sta_flags->set & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
1035 station_info->tdls_peer = TRUE;
1038 station_info->tdls_peer = FALSE;
1043 if (0 != sta_info[NL80211_STA_INFO_BEACON_LOSS]) {
1044 station_info->beacon_loss =
1045 nla_get_u32(sta_info[NL80211_STA_INFO_BEACON_LOSS]);
1046 WMESH_LOGD(" beacon loss:\t%u", station_info->beacon_loss);
1049 if (0 != sta_info[NL80211_STA_INFO_T_OFFSET]) {
1050 station_info->t_offset =
1051 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_T_OFFSET]);
1052 WMESH_LOGD(" Toffset:\t%llu us", station_info->t_offset);
1055 if (0 != sta_info[NL80211_STA_INFO_LOCAL_PM]) {
1056 station_info->local_ps_mode =
1057 nla_get_u32(sta_info[NL80211_STA_INFO_LOCAL_PM]);
1058 WMESH_LOGD(" mesh local PS mode:\t");
1059 print_power_mode(sta_info[NL80211_STA_INFO_LOCAL_PM]);
1061 if (0 != sta_info[NL80211_STA_INFO_PEER_PM]) {
1062 station_info->peer_ps_mode =
1063 nla_get_u32(sta_info[NL80211_STA_INFO_PEER_PM]);
1064 WMESH_LOGD(" mesh peer PS mode:\t");
1065 print_power_mode(sta_info[NL80211_STA_INFO_PEER_PM]);
1067 if (0 != sta_info[NL80211_STA_INFO_NONPEER_PM]) {
1068 station_info->non_peer_ps_mode =
1069 nla_get_u32(sta_info[NL80211_STA_INFO_NONPEER_PM]);
1070 WMESH_LOGD(" mesh non-peer PS mode:\t");
1071 print_power_mode(sta_info[NL80211_STA_INFO_NONPEER_PM]);
1073 #ifdef NL80211_STA_INFO_RX_DROP_MISC
1074 if (0 != sta_info[NL80211_STA_INFO_RX_DROP_MISC]) {
1075 station_info->rx_drop_misc =
1076 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_RX_DROP_MISC]);
1077 WMESH_LOGD(" rx drop misc:\t%llu", station_info->rx_drop_misc);
1079 #endif /* NL80211_STA_INFO_RX_DROP_MISC */
1081 #ifdef NL80211_STA_INFO_BEACON_RX
1082 if (0 != sta_info[NL80211_STA_INFO_BEACON_RX]) {
1083 station_info->beacon_rx =
1084 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_BEACON_RX]);
1085 WMESH_LOGD(" beacon rx:\t%llu", station_info->beacon_rx);
1087 #endif /* NL80211_STA_INFO_BEACON_RX */
1089 #ifdef NL80211_STA_INFO_BEACON_SIGNAL_AVG
1090 if (0 != sta_info[NL80211_STA_INFO_BEACON_SIGNAL_AVG]) {
1091 station_info->beacon_signal_avg =
1092 nla_get_u8(sta_info[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
1093 WMESH_LOGD(" beacon signal avg:\t%d dBm", station_info->beacon_signal_avg);
1095 #endif /* NL80211_STA_INFO_BEACON_SIGNAL_AVG */
1097 #ifdef NL80211_STA_INFO_RX_DURATION
1098 if (0 != sta_info[NL80211_STA_INFO_RX_DURATION]) {
1099 station_info->rx_duration =
1100 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_RX_DURATION]);
1101 WMESH_LOGD(" rx duration:\t%lld us", station_info->rx_duration);
1103 #endif /* NL80211_STA_INFO_RX_DURATION */
1105 *(state->station_list) = g_list_prepend(*(state->station_list), station_info);
1110 static int _on_receive_mpath_info(struct nl_msg *msg, void *arg)
1112 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1113 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1114 struct nlattr *pinfo[NL80211_MPATH_INFO_MAX + 1];
1115 char dst[20], next_hop[20], dev[20];
1116 static struct nla_policy mpath_policy[NL80211_MPATH_INFO_MAX + 1] = {
1117 [NL80211_MPATH_INFO_FRAME_QLEN] = { .type = NLA_U32 },
1118 [NL80211_MPATH_INFO_SN] = { .type = NLA_U32 },
1119 [NL80211_MPATH_INFO_METRIC] = { .type = NLA_U32 },
1120 [NL80211_MPATH_INFO_EXPTIME] = { .type = NLA_U32 },
1121 [NL80211_MPATH_INFO_DISCOVERY_TIMEOUT] = { .type = NLA_U32 },
1122 [NL80211_MPATH_INFO_DISCOVERY_RETRIES] = { .type = NLA_U8 },
1123 [NL80211_MPATH_INFO_FLAGS] = { .type = NLA_U8 },
1126 mesh_nl_state *state = (mesh_nl_state *)arg;
1127 wmesh_mpath_info_s *mpath_info = NULL;
1129 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1130 genlmsg_attrlen(gnlh, 0), NULL);
1133 * TODO: validate the interface and mac address!
1134 * Otherwise, there's a race condition as soon as
1135 * the kernel starts sending mpath notifications.
1138 if (!tb[NL80211_ATTR_MPATH_INFO]) {
1139 WMESH_LOGE("missing mesh path info!");
1142 if (nla_parse_nested(pinfo, NL80211_MPATH_INFO_MAX,
1143 tb[NL80211_ATTR_MPATH_INFO],
1145 WMESH_LOGE("failed to parse nested attributes!");
1149 mpath_info = g_try_new0(wmesh_mpath_info_s, 1);
1150 if (NULL == mpath_info) {
1151 WMESH_LOGE("Failed to allocate mesh path info !");
1155 mac_addr_n2a(dst, nla_data(tb[NL80211_ATTR_MAC]));
1156 mpath_info->dest_addr = g_strdup(dst);
1157 WMESH_LOGD("Destination Address : %s", mpath_info->dest_addr);
1159 mac_addr_n2a(next_hop, nla_data(tb[NL80211_ATTR_MPATH_NEXT_HOP]));
1160 mpath_info->next_hop = g_strdup(next_hop);
1161 WMESH_LOGD("Next hop Address : %s", mpath_info->next_hop);
1163 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
1164 mpath_info->interface = g_strdup(dev);
1165 WMESH_LOGD("Interface : %s", mpath_info->interface);
1167 if (pinfo[NL80211_MPATH_INFO_SN]) {
1168 mpath_info->sn = nla_get_u32(pinfo[NL80211_MPATH_INFO_SN]);
1169 WMESH_LOGD("SN : %u", mpath_info->sn);
1171 if (pinfo[NL80211_MPATH_INFO_METRIC]) {
1172 mpath_info->metric = nla_get_u32(pinfo[NL80211_MPATH_INFO_METRIC]);
1173 WMESH_LOGD("Metric : %u", mpath_info->metric);
1175 if (pinfo[NL80211_MPATH_INFO_FRAME_QLEN]) {
1176 mpath_info->qlen = nla_get_u32(pinfo[NL80211_MPATH_INFO_FRAME_QLEN]);
1177 WMESH_LOGD("QLEN : %u", mpath_info->qlen);
1179 if (pinfo[NL80211_MPATH_INFO_EXPTIME]) {
1180 mpath_info->exptime = nla_get_u32(pinfo[NL80211_MPATH_INFO_EXPTIME]);
1181 WMESH_LOGD("ExpTime : %u", mpath_info->exptime);
1183 if (pinfo[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT]) {
1184 mpath_info->discovery_timeout =
1185 nla_get_u32(pinfo[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT]);
1186 WMESH_LOGD("Discovery Timeout : %u", mpath_info->discovery_timeout);
1188 if (pinfo[NL80211_MPATH_INFO_DISCOVERY_RETRIES]) {
1189 mpath_info->discovery_retries =
1190 nla_get_u8(pinfo[NL80211_MPATH_INFO_DISCOVERY_RETRIES]);
1191 WMESH_LOGD("Discovery Retries : %u", mpath_info->discovery_retries);
1193 if (pinfo[NL80211_MPATH_INFO_FLAGS]) {
1194 mpath_info->flags = nla_get_u8(pinfo[NL80211_MPATH_INFO_FLAGS]);
1195 WMESH_LOGD("Flags : 0x%x", mpath_info->flags);
1199 *(state->mpath_list) = g_list_prepend(*(state->mpath_list), mpath_info);
1204 static int _on_receive_meshconf_info(struct nl_msg *msg, void *arg)
1206 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1207 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1208 struct nlattr *pinfo[NL80211_MESHCONF_ATTR_MAX + 1];
1209 static struct nla_policy meshconf_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
1210 [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 },
1211 [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 },
1212 [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 },
1213 [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 },
1214 [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 },
1215 [NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
1216 [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
1217 [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
1218 [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
1219 [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
1220 [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
1221 [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
1222 [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
1223 [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
1224 [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = { .type = NLA_U16 },
1225 [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
1226 [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
1227 [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
1228 [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
1229 [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
1230 [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 },
1231 [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
1232 [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
1233 [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
1234 [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
1235 [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
1236 [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
1239 mesh_nl_state *state = (mesh_nl_state *)arg;
1240 wmesh_meshconf_info_s *meshconf_info = NULL;
1242 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1243 genlmsg_attrlen(gnlh, 0), NULL);
1246 * TODO: validate the interface and mac address!
1247 * Otherwise, there's a race condition as soon as
1248 * the kernel starts sending mpath notifications.
1251 if (!tb[NL80211_ATTR_MESH_CONFIG]) {
1252 WMESH_LOGE("missing mesh path info!");
1255 if (nla_parse_nested(pinfo, NL80211_MESHCONF_ATTR_MAX,
1256 tb[NL80211_ATTR_MESH_CONFIG], meshconf_policy)) {
1257 WMESH_LOGE("failed to parse nested attributes!");
1261 meshconf_info = g_try_new0(wmesh_meshconf_info_s, 1);
1262 if (NULL == meshconf_info) {
1263 WMESH_LOGE("Failed to allocate mesh path info !");
1267 if (pinfo[NL80211_MESHCONF_RETRY_TIMEOUT]) {
1268 meshconf_info->retry_timeout =
1269 nla_get_u16(pinfo[NL80211_MESHCONF_RETRY_TIMEOUT]);
1270 WMESH_LOGD("Retry Timeout : %u", meshconf_info->retry_timeout);
1272 if (pinfo[NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES]) {
1273 meshconf_info->hwmp_max_preq_retries =
1274 nla_get_u8(pinfo[NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES]);
1275 WMESH_LOGD("HWMP Max PREQ Retries : %u",
1276 meshconf_info->hwmp_max_preq_retries);
1278 if (pinfo[NL80211_MESHCONF_CONFIRM_TIMEOUT]) {
1279 meshconf_info->confirm_timeout =
1280 nla_get_u16(pinfo[NL80211_MESHCONF_CONFIRM_TIMEOUT]);
1281 WMESH_LOGD("Confirm Timeout : %u", meshconf_info->confirm_timeout);
1283 if (pinfo[NL80211_MESHCONF_PATH_REFRESH_TIME]) {
1284 meshconf_info->path_refresh_time =
1285 nla_get_u32(pinfo[NL80211_MESHCONF_PATH_REFRESH_TIME]);
1286 WMESH_LOGD("Path Refresh Time : %u", meshconf_info->path_refresh_time);
1288 if (pinfo[NL80211_MESHCONF_HOLDING_TIMEOUT]) {
1289 meshconf_info->holding_timeout =
1290 nla_get_u16(pinfo[NL80211_MESHCONF_HOLDING_TIMEOUT]);
1291 WMESH_LOGD("Holding Timeout : %u", meshconf_info->holding_timeout);
1293 if (pinfo[NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT]) {
1294 meshconf_info->min_disc_timeout =
1295 nla_get_u16(pinfo[NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT]);
1296 WMESH_LOGD("Min Disc Timeout : %u", meshconf_info->min_disc_timeout);
1298 if (pinfo[NL80211_MESHCONF_MAX_PEER_LINKS]) {
1299 meshconf_info->max_peer_links =
1300 nla_get_u16(pinfo[NL80211_MESHCONF_MAX_PEER_LINKS]);
1301 WMESH_LOGD("MAX Peer Links : %u", meshconf_info->max_peer_links);
1303 if (pinfo[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL]) {
1304 meshconf_info->hwmp_preq_min_interval =
1305 nla_get_u16(pinfo[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL]);
1306 WMESH_LOGD("HWMP PREQ Min Interval : %u",
1307 meshconf_info->hwmp_preq_min_interval);
1309 if (pinfo[NL80211_MESHCONF_TTL]) {
1310 meshconf_info->ttl =
1311 nla_get_u8(pinfo[NL80211_MESHCONF_TTL]);
1312 WMESH_LOGD("TTL : %u", meshconf_info->ttl);
1314 if (pinfo[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT]) {
1315 meshconf_info->hwmp_active_path_timeout =
1316 nla_get_u32(pinfo[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT]);
1317 WMESH_LOGD("HWMP Active Path Timeout : %u",
1318 meshconf_info->hwmp_active_path_timeout);
1320 if (pinfo[NL80211_MESHCONF_ELEMENT_TTL]) {
1321 meshconf_info->element_ttl =
1322 nla_get_u8(pinfo[NL80211_MESHCONF_ELEMENT_TTL]);
1323 WMESH_LOGD("Element TTL : %u", meshconf_info->element_ttl);
1325 if (pinfo[NL80211_MESHCONF_HWMP_RANN_INTERVAL]) {
1326 meshconf_info->hwmp_rann_interval =
1327 nla_get_u16(pinfo[NL80211_MESHCONF_HWMP_RANN_INTERVAL]);
1328 WMESH_LOGD("HWMP RANN Interval : %u",
1329 meshconf_info->hwmp_rann_interval);
1331 if (pinfo[NL80211_MESHCONF_GATE_ANNOUNCEMENTS]) {
1332 meshconf_info->gate_announcements =
1333 nla_get_u8(pinfo[NL80211_MESHCONF_GATE_ANNOUNCEMENTS]);
1334 WMESH_LOGD("Gate Announcements : %u",
1335 meshconf_info->gate_announcements);
1339 *(state->meshconf) = meshconf_info;
1344 static int _on_receive_mesh_event(struct nl_msg *msg, void *arg)
1346 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1347 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1348 char ifname[16] = { 0, };
1349 char macbuf[MAX_MAC_ADDR_LEN];
1351 wmesh_service *service = arg;
1352 wmesh_interface_s *info = service->interface_info;
1354 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
1356 if (tb[NL80211_ATTR_IFINDEX]) {
1357 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
1358 WMESH_LOGD("%s: ", ifname);
1361 switch (gnlh->cmd) {
1362 case NL80211_CMD_NEW_STATION:
1363 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1364 WMESH_LOGD("[%s] new station [%s]", ifname, macbuf);
1366 if (g_strcmp0(info->mesh_interface, ifname) == 0)
1367 wmesh_notify_station_joined((const char*)macbuf,
1368 WMESHD_STATION_TYPE_MESH_POINT);
1369 else if (g_strcmp0(info->softap_interface, ifname) == 0)
1370 wmesh_notify_station_joined((const char*)macbuf,
1371 WMESHD_STATION_TYPE_SOFTAP);
1374 case NL80211_CMD_DEL_STATION:
1375 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1376 WMESH_LOGD("[%s] del station [%s]", ifname, macbuf);
1378 if (g_strcmp0(info->mesh_interface, ifname) == 0)
1379 wmesh_notify_station_left((const char*)macbuf,
1380 WMESHD_STATION_TYPE_MESH_POINT);
1381 else if (g_strcmp0(info->softap_interface, ifname) == 0)
1382 wmesh_notify_station_left((const char*)macbuf,
1383 WMESHD_STATION_TYPE_SOFTAP);
1386 case NL80211_CMD_NEW_MPATH:
1387 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1388 WMESH_LOGD("[%s] new mpath [%s]", ifname, macbuf);
1391 case NL80211_CMD_DEL_MPATH:
1392 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1393 WMESH_LOGD("[%s] del mpath [%s]", ifname, macbuf);
1397 WMESH_LOGD("event [%d] is not handled", gnlh->cmd);
1403 /* LCOV_EXCL_STOP */
1405 static int _send_nl_set_mesh_parameter(const char* mesh_if_name,
1406 const char* param_name, unsigned int value)
1408 mesh_nl_state state = {
1410 .callback_state = MESH_NL_CALLBACK_TRYING,
1416 .error_occured = FALSE,
1418 struct nlattr *container;
1420 int err = WMESHD_ERROR_NONE;
1421 int device_index = 0;
1425 ret = __initialize_nl80211(&state);
1426 if (WMESHD_ERROR_NONE != ret) {
1427 /* LCOV_EXCL_START */
1428 WMESH_LOGE("Failed to initialize nl80211");
1430 /* LCOV_EXCL_STOP */
1433 ret = __initialize_netlink_message(&state);
1434 if (WMESHD_ERROR_NONE != ret) {
1435 /* LCOV_EXCL_START */
1436 WMESH_LOGE("Failed to initialize netlink message");
1438 /* LCOV_EXCL_STOP */
1441 /* Set command into message */
1442 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1443 0, NL80211_CMD_SET_MESH_PARAMS, 0);
1445 /* Add attributes into message */
1446 ret = __get_device_index_from_string(mesh_if_name, &device_index);
1447 if (WMESHD_ERROR_NONE != ret) {
1448 /* LCOV_EXCL_START */
1449 WMESH_LOGE("Failed to get mesh device index");
1452 /* LCOV_EXCL_STOP */
1454 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1456 container = nla_nest_start(state.msg, NL80211_ATTR_MESH_PARAMS);
1458 /* LCOV_EXCL_START */
1459 WMESH_LOGE("Failed to initialize netlink message");
1461 /* LCOV_EXCL_STOP */
1464 /* Logic need to be changed if additional parameter is required */
1465 if (g_strcmp0(MESH_PARAM_HWMP_ROOTMODE, param_name) == 0) {
1466 WMESH_LOGD(" [mesh_hwmp_rootmode] : [%d]", value);
1467 NLA_PUT_U8(state.msg, NL80211_MESHCONF_HWMP_ROOTMODE,
1469 } else if (g_strcmp0(MESH_PARAM_GATE_ANNOUNCE, param_name) == 0) {
1470 WMESH_LOGD(" [mesh_gate_announcements] : [%d]", value);
1471 NLA_PUT_U8(state.msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
1474 /* LCOV_EXCL_START */
1475 WMESH_LOGE("Parameter [%s] is not required !", param_name);
1476 nla_nest_end(state.msg, container);
1478 /* LCOV_EXCL_STOP */
1480 nla_nest_end(state.msg, container);
1482 /* Send message into kernel */
1483 ret = nl_send_auto(state.nl_socket, state.msg);
1485 /* LCOV_EXCL_START */
1486 WMESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1487 nl_geterror(ret), ret);
1488 err = WMESHD_ERROR_OPERATION_FAILED;
1490 /* LCOV_EXCL_STOP */
1494 state.callback_state = MESH_NL_CALLBACK_TRYING;
1495 while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1496 WMESH_LOGD(" count [%02d]", ++test);
1497 nl_recvmsgs(state.nl_socket, state.cb);
1501 __clean_netlink_message(&state);
1502 __clean_nl80211(&state);
1507 /* LCOV_EXCL_START */
1508 WMESH_LOGE("Failed to message build");
1509 __clean_netlink_message(&state);
1510 __clean_nl80211(&state);
1512 return WMESHD_ERROR_OPERATION_FAILED;
1513 /* LCOV_EXCL_STOP */
1516 static int _send_nl_get_station_info(const char* if_name, GList **station_list)
1518 mesh_nl_state state = {
1520 .callback_state = MESH_NL_CALLBACK_TRYING,
1526 .station_list = station_list
1528 int err = WMESHD_ERROR_NONE;
1529 int device_index = 0;
1533 ret = __initialize_nl80211(&state);
1534 if (WMESHD_ERROR_NONE != ret) {
1535 /* LCOV_EXCL_START */
1536 WMESH_LOGE("Failed to initialize nl80211");
1538 /* LCOV_EXCL_STOP */
1541 ret = __initialize_netlink_message(&state);
1542 if (WMESHD_ERROR_NONE != ret) {
1543 /* LCOV_EXCL_START */
1544 WMESH_LOGE("Failed to initialize netlink message");
1546 /* LCOV_EXCL_STOP */
1549 /* Set command into message */
1550 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1551 NLM_F_DUMP, NL80211_CMD_GET_STATION, 0);
1553 /* Add attributes into message */
1554 WMESH_LOGD("Dump station list with interface [%s]", if_name);
1555 ret = __get_device_index_from_string(if_name, &device_index);
1556 if (WMESHD_ERROR_NONE != ret) {
1557 /* LCOV_EXCL_START */
1558 WMESH_LOGE("Failed to get mesh interface device index");
1561 /* LCOV_EXCL_STOP */
1563 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1565 /* Register valid callback to dump result */
1566 nl_cb_set(state.cb, NL_CB_VALID, NL_CB_CUSTOM,
1567 _on_receive_station_info, &state);
1569 /* Send message into kernel */
1570 ret = nl_send_auto(state.nl_socket, state.msg);
1572 /* LCOV_EXCL_START */
1573 WMESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1574 nl_geterror(ret), ret);
1575 err = WMESHD_ERROR_OPERATION_FAILED;
1577 /* LCOV_EXCL_STOP */
1581 state.callback_state = MESH_NL_CALLBACK_TRYING;
1582 while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1583 /* LCOV_EXCL_START */
1584 WMESH_LOGD(" count [%02d]", ++test);
1585 nl_recvmsgs(state.nl_socket, state.cb);
1586 /* LCOV_EXCL_STOP */
1588 WMESH_LOGD("Finished");
1591 __clean_netlink_message(&state);
1592 __clean_nl80211(&state);
1597 /* LCOV_EXCL_START */
1598 WMESH_LOGE("Failed to message build");
1599 __clean_netlink_message(&state);
1600 __clean_nl80211(&state);
1602 return WMESHD_ERROR_OPERATION_FAILED;
1603 /* LCOV_EXCL_STOP */
1606 static int _send_nl_get_mpath_info(const char* if_name, GList **mpath_list)
1608 mesh_nl_state state = {
1610 .callback_state = MESH_NL_CALLBACK_TRYING,
1616 .mpath_list = mpath_list
1618 int err = WMESHD_ERROR_NONE;
1619 int device_index = 0;
1623 ret = __initialize_nl80211(&state);
1624 if (WMESHD_ERROR_NONE != ret) {
1625 /* LCOV_EXCL_START */
1626 WMESH_LOGE("Failed to initialize nl80211");
1628 /* LCOV_EXCL_STOP */
1631 ret = __initialize_netlink_message(&state);
1632 if (WMESHD_ERROR_NONE != ret) {
1633 /* LCOV_EXCL_START */
1634 WMESH_LOGE("Failed to initialize netlink message");
1636 /* LCOV_EXCL_STOP */
1639 /* Set command into message */
1640 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1641 NLM_F_DUMP, NL80211_CMD_GET_MPATH, 0);
1643 /* Add attributes into message */
1644 WMESH_LOGD("Dump station list with interface [%s]", if_name);
1645 ret = __get_device_index_from_string(if_name, &device_index);
1646 if (WMESHD_ERROR_NONE != ret) {
1647 /* LCOV_EXCL_START */
1648 WMESH_LOGE("Failed to get mesh interface device index");
1651 /* LCOV_EXCL_STOP */
1653 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1655 /* Register valid callback to dump result */
1656 nl_cb_set(state.cb, NL_CB_VALID, NL_CB_CUSTOM,
1657 _on_receive_mpath_info, &state);
1659 /* Send message into kernel */
1660 ret = nl_send_auto(state.nl_socket, state.msg);
1662 /* LCOV_EXCL_START */
1663 WMESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1664 nl_geterror(ret), ret);
1665 err = WMESHD_ERROR_OPERATION_FAILED;
1667 /* LCOV_EXCL_STOP */
1671 state.callback_state = MESH_NL_CALLBACK_TRYING;
1672 while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1673 /* LCOV_EXCL_START */
1674 WMESH_LOGD(" count [%02d]", ++test);
1675 nl_recvmsgs(state.nl_socket, state.cb);
1676 /* LCOV_EXCL_STOP */
1678 WMESH_LOGD("Finished");
1681 __clean_netlink_message(&state);
1682 __clean_nl80211(&state);
1687 /* LCOV_EXCL_START */
1688 WMESH_LOGE("Failed to message build");
1689 __clean_netlink_message(&state);
1690 __clean_nl80211(&state);
1692 return WMESHD_ERROR_OPERATION_FAILED;
1693 /* LCOV_EXCL_STOP */
1696 static int _send_nl_get_meshconf_info(wmesh_service *service)
1698 mesh_nl_state state = {
1700 .callback_state = MESH_NL_CALLBACK_TRYING,
1706 .meshconf = &service->meshconf,
1708 int err = WMESHD_ERROR_NONE;
1709 int device_index = 0;
1713 ret = __initialize_nl80211(&state);
1714 if (WMESHD_ERROR_NONE != ret) {
1715 /* LCOV_EXCL_START */
1716 WMESH_LOGE("Failed to initialize nl80211");
1718 /* LCOV_EXCL_STOP */
1721 ret = __initialize_netlink_message(&state);
1722 if (WMESHD_ERROR_NONE != ret) {
1723 /* LCOV_EXCL_START */
1724 WMESH_LOGE("Failed to initialize netlink message");
1726 /* LCOV_EXCL_STOP */
1729 /* Set command into message */
1730 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1731 0, NL80211_CMD_GET_MESH_CONFIG, 0);
1733 /* Add attributes into message */
1734 WMESH_LOGD("Dump Mesh Config with interface [%s]",
1735 service->interface_info->mesh_interface);
1736 ret = __get_device_index_from_string(
1737 service->interface_info->mesh_interface, &device_index);
1738 if (WMESHD_ERROR_NONE != ret)
1739 /* LCOV_EXCL_START */{
1740 WMESH_LOGE("Failed to get mesh interface device index");
1743 /* LCOV_EXCL_STOP */
1745 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1747 /* Register valid callback to dump result */
1748 nl_cb_set(state.cb, NL_CB_VALID, NL_CB_CUSTOM,
1749 _on_receive_meshconf_info, &state);
1751 /* Send message into kernel */
1752 ret = nl_send_auto(state.nl_socket, state.msg);
1754 /* LCOV_EXCL_START */
1755 WMESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1756 nl_geterror(ret), ret);
1757 err = WMESHD_ERROR_OPERATION_FAILED;
1759 /* LCOV_EXCL_STOP */
1763 state.callback_state = MESH_NL_CALLBACK_TRYING;
1764 while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1765 /* LCOV_EXCL_START */
1766 WMESH_LOGD(" count [%02d]", ++test);
1767 nl_recvmsgs(state.nl_socket, state.cb);
1768 /* LCOV_EXCL_STOP */
1770 WMESH_LOGD("Finished");
1773 __clean_netlink_message(&state);
1774 __clean_nl80211(&state);
1779 /* LCOV_EXCL_START */
1780 WMESH_LOGE("Failed to message build");
1781 __clean_netlink_message(&state);
1782 __clean_nl80211(&state);
1784 return WMESHD_ERROR_OPERATION_FAILED;
1785 /* LCOV_EXCL_STOP */
1788 static int _send_nl_register_event_handler(wmesh_service *service)
1790 int err = WMESHD_ERROR_NONE;
1792 GIOChannel *recv_channel = NULL;
1795 /* LCOV_EXCL_START */
1796 WMESH_LOGE("Already event handler registered !");
1797 return WMESHD_ERROR_IN_PROGRESS;
1798 /* LCOV_EXCL_STOP */
1801 event_state = _create_mesh_nl_state("");
1803 ret = __initialize_nl80211(event_state);
1804 if (WMESHD_ERROR_NONE != ret) {
1805 /* LCOV_EXCL_START */
1806 WMESH_LOGE("Failed to initialize nl80211");
1808 /* LCOV_EXCL_STOP */
1811 /* Subscribe multicast group should be proceed before scanning */
1812 ret = __prepare_listen_events(event_state);
1814 /* LCOV_EXCL_START */
1815 WMESH_LOGE("__prepare_listen_events : [%d]", ret);
1817 /* LCOV_EXCL_STOP */
1820 ret = __initialize_netlink_message(event_state);
1821 if (WMESHD_ERROR_NONE != ret) {
1822 /* LCOV_EXCL_START */
1823 WMESH_LOGE("Failed to initialize netlink message");
1825 /* LCOV_EXCL_STOP */
1828 /* Set command into message */
1829 genlmsg_put(event_state->msg, 0, 0, event_state->nl80211_id, 0, 0, 0, 0);
1831 /* Set callbacks for event handler */
1832 nl_cb_set(event_state->cb, NL_CB_VALID, NL_CB_CUSTOM,
1833 _on_receive_mesh_event, service);
1834 /* No sequence checking for multicast messages. */
1835 nl_cb_set(event_state->cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
1837 WMESH_LOGD("Register event handler");
1839 /* Change socket type to non-blocking */
1840 ret = nl_socket_set_nonblocking(event_state->nl_socket);
1842 WMESH_LOGE("Failed to non-blocking socket [%s](%d)", nl_geterror(ret), ret); /* LCOV_EXCL_LINE */
1844 /* Register I/O callback to wait asynchronously */
1845 /* LCOV_EXCL_START */
1846 if (FALSE == event_state->error_occured) {
1847 recv_channel = g_io_channel_unix_new(nl_socket_get_fd(event_state->nl_socket));
1848 event_state->event_source = g_io_add_watch(recv_channel,
1849 (G_IO_IN | G_IO_ERR), _on_socket_event_io_received, event_state);
1850 g_io_channel_unref(recv_channel);
1852 WMESH_LOGE("Error responded. Failed to register event callback !!");
1855 /* LCOV_EXCL_STOP */
1857 /* Resource should be free on I/O callback */
1858 return WMESHD_ERROR_NONE;
1861 /* LCOV_EXCL_START */
1862 __clean_netlink_message(event_state);
1863 __clean_nl80211(event_state);
1864 _delete_mesh_nl_state(&event_state);
1867 /* LCOV_EXCL_STOP */
1869 /* LCOV_EXCL_STOP */
1871 int wmesh_netlink_set_mesh_parameter(const char* mesh_if_name,
1872 const char* param_name, unsigned int value)
1874 int ret = WMESHD_ERROR_NONE;
1876 if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1877 /* LCOV_EXCL_START */
1878 WMESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1879 return WMESHD_ERROR_INVALID_PARAMETER;
1880 /* LCOV_EXCL_STOP */
1883 WMESH_LOGD("Set mesh[%s] param [%s] value [%d]",
1884 mesh_if_name, param_name, value);
1885 ret = _send_nl_set_mesh_parameter(mesh_if_name, param_name, value);
1890 int wmesh_netlink_get_station_info(const char* mesh_if_name, GList **station_list)
1892 int ret = WMESHD_ERROR_NONE;
1894 if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1895 /* LCOV_EXCL_START */
1896 WMESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1897 return WMESHD_ERROR_INVALID_PARAMETER;
1898 /* LCOV_EXCL_STOP */
1900 if (NULL == station_list) {
1901 /* LCOV_EXCL_START */
1902 WMESH_LOGE("Invalid parameter [%p]", station_list);
1903 return WMESHD_ERROR_INVALID_PARAMETER;
1904 /* LCOV_EXCL_STOP */
1907 WMESH_LOGD("Get connected stations");
1908 ret = _send_nl_get_station_info(mesh_if_name, station_list);
1913 int wmesh_netlink_get_mpath_info(const char* mesh_if_name, GList **mpath_list)
1915 int ret = WMESHD_ERROR_NONE;
1917 if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1918 /* LCOV_EXCL_START */
1919 WMESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1920 return WMESHD_ERROR_INVALID_PARAMETER;
1921 /* LCOV_EXCL_STOP */
1923 if (NULL == mpath_list) {
1924 /* LCOV_EXCL_START */
1925 WMESH_LOGE("Invalid parameter [%p]", mpath_list);
1926 return WMESHD_ERROR_INVALID_PARAMETER;
1927 /* LCOV_EXCL_STOP */
1930 WMESH_LOGD("Get current mpath info");
1931 ret = _send_nl_get_mpath_info(mesh_if_name, mpath_list);
1936 int wmesh_netlink_get_meshconf_info(wmesh_service *service)
1938 int ret = WMESHD_ERROR_NONE;
1940 if (NULL == service) {
1941 /* LCOV_EXCL_START */
1942 WMESH_LOGE("Invalid parameter [%p]", service);
1943 return WMESHD_ERROR_INVALID_PARAMETER;
1944 /* LCOV_EXCL_STOP */
1947 WMESH_LOGD("Get current Mesh Config info");
1948 ret = _send_nl_get_meshconf_info(service);
1953 int wmesh_netlink_register_event_handler(wmesh_service *service)
1955 int ret = WMESHD_ERROR_NONE;
1957 WMESH_LOGD("Register mesh event handler");
1958 ret = _send_nl_register_event_handler(service);
1963 int wmesh_netlink_unregister_event_handler()
1965 int ret = WMESHD_ERROR_NONE;
1967 WMESH_LOGD("Unregister mesh event handler");
1969 _on_remove_event_io_handler();