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>
39 #include "mesh-util.h"
40 #include "mesh-netlink.h"
41 #include "mesh-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))
54 MESH_NL_CALLBACK_FINISHED = 0,
55 MESH_NL_CALLBACK_TRYING,
56 } mesh_nl_callback_state_e;
63 struct nl_sock *nl_socket;
76 } multicast_group_id_args;
88 /* For event handler */
89 static mesh_nl_state *event_state = NULL;
91 static int __initialize_nl80211(mesh_nl_state *state)
93 int err = MESHD_ERROR_NONE;
95 state->nl_socket = nl_socket_alloc();
96 if (!state->nl_socket) {
97 MESH_LOGE("Failed to allocate netlink socket.");
98 return MESHD_ERROR_OUT_OF_MEMORY;
101 if (genl_connect(state->nl_socket)) {
102 MESH_LOGE("Failed to connect to generic netlink.");
103 err = MESHD_ERROR_OPERATION_FAILED;
107 nl_socket_set_buffer_size(state->nl_socket, 8192, 8192);
109 state->nl80211_id = genl_ctrl_resolve(state->nl_socket, "nl80211");
110 if (state->nl80211_id < 0) {
111 MESH_LOGE("nl80211 not found.");
112 err = MESHD_ERROR_NO_DATA;
119 nl_socket_free(state->nl_socket);
123 static void __clean_nl80211(mesh_nl_state *state)
128 if (state->nl_socket) {
129 nl_socket_free(state->nl_socket);
130 state->nl_socket = NULL;
131 state->nl80211_id = -1;
135 static int __get_device_index_from_string(const char* if_name, int *index)
137 int device_index = 0;
139 if (NULL == if_name) {
140 MESH_LOGE("Invalid parameter");
141 return MESHD_ERROR_INVALID_PARAMETER;
144 device_index = if_nametoindex(if_name);
145 if (device_index == 0) {
146 MESH_LOGE("No interface index found [%s]", if_name);
147 return MESHD_ERROR_NO_DATA;
149 *index = device_index;
151 return MESHD_ERROR_NONE;
154 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
156 mesh_nl_state *state = (mesh_nl_state *)arg;
157 char buf[256] = { 0, };
161 state->callback_state = MESH_NL_CALLBACK_FINISHED;
162 state->error_occured = TRUE;
163 strerror_r(err->error, buf, 255);
165 MESH_LOGD("error_handler");
166 MESH_LOGE(" %s (%d)", buf, err->error);
171 static int finish_handler(struct nl_msg *msg, void *arg)
173 mesh_nl_state *state = (mesh_nl_state *)arg;
175 state->callback_state = MESH_NL_CALLBACK_FINISHED;
177 MESH_LOGD("finish_handler");
183 static int ack_handler(struct nl_msg *msg, void *arg)
185 mesh_nl_state *state = (mesh_nl_state *)arg;
187 state->callback_state = MESH_NL_CALLBACK_FINISHED;
189 MESH_LOGD("ack_handler");
195 static int ack_simple_handler(struct nl_msg *msg, void *arg)
202 MESH_LOGD("ack_simple_handler");
207 static int family_handler(struct nl_msg *msg, void *arg)
209 multicast_group_id_args *group = (multicast_group_id_args *)arg;
210 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
211 struct nlattr *tb[CTRL_ATTR_MAX + 1];
212 struct nlattr *mcast_group;
215 MESH_LOGD("family_handler");
217 nla_parse(tb, CTRL_ATTR_MAX,
218 genlmsg_attrdata(gnlh, 0),
219 genlmsg_attrlen(gnlh, 0), NULL);
220 if (!tb[CTRL_ATTR_MCAST_GROUPS])
223 nla_for_each_nested(mcast_group, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcast_group) {
224 struct nlattr *tb_mcast_group[CTRL_ATTR_MCAST_GRP_MAX + 1];
226 nla_parse(tb_mcast_group, CTRL_ATTR_MCAST_GRP_MAX,
227 nla_data(mcast_group), nla_len(mcast_group), NULL);
229 if (!tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME] ||
230 !tb_mcast_group[CTRL_ATTR_MCAST_GRP_ID])
233 if (strncmp(nla_data(tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME]),
235 nla_len(tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME])))
238 group->id = nla_get_u32(tb_mcast_group[CTRL_ATTR_MCAST_GRP_ID]);
239 MESH_LOGD("mcast group id [%d]", group->id);
246 static int __nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group)
251 multicast_group_id_args group_args = {
260 cb = nl_cb_alloc(NL_CB_DEFAULT);
266 ctrlid = genl_ctrl_resolve(sock, "nlctrl");
268 genlmsg_put(msg, 0, 0, ctrlid, 0,
269 0, CTRL_CMD_GETFAMILY, 0);
272 NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
274 ret = nl_send_auto(sock, msg);
276 MESH_LOGE("Failed to nl_send_auto");
281 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
282 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_simple_handler, &ret);
283 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, family_handler, &group_args);
286 nl_recvmsgs(sock, cb);
291 MESH_LOGD("mcid : [%d]", ret);
302 static int __prepare_listen_events(mesh_nl_state *state)
306 /* Configuration multicast group */
307 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "config");
309 MESH_LOGE("Failed to get nl80211 config");
312 MESH_LOGD("Mesh multicast id (config): [%d]", mcid);
314 ret = nl_socket_add_membership(state->nl_socket, mcid);
316 MESH_LOGE("Failed to nl_socket_add_membership");
320 /* Scan multicast group */
321 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "scan");
323 ret = nl_socket_add_membership(state->nl_socket, mcid);
325 MESH_LOGE("Failed to nl_socket_add_membership");
329 MESH_LOGD("Mesh multicast id (scan): [%d]", mcid);
331 /* Regulatory multicast group */
332 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "regulatory");
334 ret = nl_socket_add_membership(state->nl_socket, mcid);
336 MESH_LOGE("Failed to nl_socket_add_membership");
340 MESH_LOGD("Mesh multicast id (regulatory): [%d]", mcid);
342 /* MLME multicast group */
343 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "mlme");
345 ret = nl_socket_add_membership(state->nl_socket, mcid);
347 MESH_LOGE("Failed to nl_socket_add_membership");
351 MESH_LOGD("Mesh multicast id (mlme): [%d]", mcid);
353 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "vendor");
355 ret = nl_socket_add_membership(state->nl_socket, mcid);
357 MESH_LOGE("Failed to nl_socket_add_membership");
361 MESH_LOGD("Mesh multicast id (vendor): [%d]", mcid);
366 static mesh_nl_state *_create_mesh_nl_state()
368 mesh_nl_state *state = g_new0(mesh_nl_state, 1);
370 state->nl80211_id = -1;
371 state->callback_state = MESH_NL_CALLBACK_TRYING;
372 state->error_occured = FALSE;
377 static void _delete_mesh_nl_state(mesh_nl_state **state)
379 if (NULL == state || NULL == *state)
386 static int valid_handler(struct nl_msg *msg, void *arg)
388 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
389 mesh_nl_state *state = (mesh_nl_state *)arg;
390 MESH_LOGD("valid_handler");
392 if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) {
393 MESH_LOGD(" Got NL80211_CMD_SCAN_ABORTED.");
394 state->callback_state = MESH_NL_CALLBACK_FINISHED;
396 /* Notify scan done status */
397 mesh_notify_scan_done();
398 } else if (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
399 MESH_LOGD(" Got NL80211_CMD_NEW_SCAN_RESULTS.");
400 state->callback_state = MESH_NL_CALLBACK_FINISHED;
402 /* Notify scan done status */
403 mesh_notify_scan_done();
405 MESH_LOGD(" Got [%d]", gnlh->cmd);
411 static int no_seq_check(struct nl_msg *msg, void *arg)
419 static void __clean_netlink_message(mesh_nl_state *state)
425 nl_cb_put(state->cb);
427 nl_cb_put(state->s_cb);
429 nlmsg_free(state->msg);
435 MESH_LOGD("message and callback cleaned");
438 static int __initialize_netlink_message(mesh_nl_state *state)
440 int err = MESHD_ERROR_NONE;
443 MESH_LOGE("Invalid parameter !");
444 return MESHD_ERROR_INVALID_PARAMETER;
447 /* Create netlink message */
448 state->msg = nlmsg_alloc();
449 if (NULL == state->msg) {
450 MESH_LOGE("Failed to allocate netlink message");
451 return MESHD_ERROR_OUT_OF_MEMORY;
455 state->cb = nl_cb_alloc(NL_CB_DEFAULT);
456 state->s_cb = nl_cb_alloc(NL_CB_DEFAULT);
458 MESH_LOGE("Failed to allocate netlink callback");
459 err = MESHD_ERROR_OUT_OF_MEMORY;
463 /* Set socket callback */
464 nl_socket_set_cb(state->nl_socket, state->s_cb);
467 nl_cb_err(state->cb, NL_CB_CUSTOM, error_handler, state);
468 nl_cb_set(state->cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, state);
469 nl_cb_set(state->cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, state);
470 nl_cb_set(state->cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, state);
472 MESH_LOGD("netlink socket initialized");
474 return MESHD_ERROR_NONE;
477 __clean_netlink_message(state);
482 static gboolean _on_socket_event_io_received(GIOChannel *source,
483 GIOCondition condition, gpointer data)
485 mesh_nl_state *state = (mesh_nl_state *)data;
491 MESH_LOGD("[Event] I/O received");
493 while (nl_recvmsgs_report(state->nl_socket, state->cb) > 0)
494 MESH_LOGD(" count [%02d]", ++test);
496 /* Do not remove I/O source */
500 static void _on_remove_event_io_handler()
503 g_source_remove(event_state->event_source);
505 __clean_netlink_message(event_state);
506 __clean_nl80211(event_state);
507 _delete_mesh_nl_state(&event_state);
511 static void mac_addr_n2a(char *mac_addr, unsigned char *arg)
513 /* 11:22:33:44:55:66 (Len:17) */
514 snprintf(mac_addr, MAX_MAC_ADDR_LEN,
515 "%02X:%02X:%02X:%02X:%02X:%02X",
516 arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
518 #if defined(NL80211_STA_INFO_CHAIN_SIGNAL) || defined(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)
519 static char *get_chain_signal(struct nlattr *attr_list)
530 nla_for_each_nested(attr, attr_list, rem) {
536 cur += snprintf(cur, sizeof(buf) - (cur - buf), "%s%d", prefix,
537 (int8_t) nla_get_u8(attr));
541 snprintf(cur, sizeof(buf) - (cur - buf), "] ");
545 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL || NL80211_STA_INFO_CHAIN_SIGNAL_AVG */
547 static int parse_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen)
551 char str_rate[32] = { 0, };
552 char str_buf[128] = { 0, };
553 struct nlattr *rate_info[NL80211_RATE_INFO_MAX + 1];
554 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
555 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
556 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
557 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
558 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
559 [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 },
562 if (nla_parse_nested(rate_info, NL80211_RATE_INFO_MAX, bitrate_attr, rate_policy)) {
564 snprintf(buf, buflen, "failed to parse nested rate attributes!");
568 if (rate_info[NL80211_RATE_INFO_MCS])
569 pos += snprintf(str_buf + pos, 128 - pos,
570 " MCS %d", nla_get_u8(rate_info[NL80211_RATE_INFO_MCS]));
571 if (rate_info[NL80211_RATE_INFO_40_MHZ_WIDTH])
572 pos += snprintf(str_buf + pos, 128 - pos, " 40MHz");
573 if (rate_info[NL80211_RATE_INFO_SHORT_GI])
574 pos += snprintf(str_buf + pos, 128 - pos, " short GI");
575 if (rate_info[NL80211_RATE_INFO_VHT_MCS])
576 pos += snprintf(str_buf + pos, 128 - pos,
577 " VHT-MCS %d", nla_get_u8(rate_info[NL80211_RATE_INFO_VHT_MCS]));
578 if (rate_info[NL80211_RATE_INFO_VHT_NSS])
579 pos += snprintf(str_buf + pos, 128 - pos,
580 " VHT-NSS %d", nla_get_u8(rate_info[NL80211_RATE_INFO_VHT_NSS]));
581 if (rate_info[NL80211_RATE_INFO_80_MHZ_WIDTH])
582 pos += snprintf(str_buf + pos, 128 - pos, " 80MHz");
583 if (rate_info[NL80211_RATE_INFO_80P80_MHZ_WIDTH])
584 pos += snprintf(str_buf + pos, 128 - pos, " 80P80MHz");
585 if (rate_info[NL80211_RATE_INFO_160_MHZ_WIDTH])
586 pos += snprintf(str_buf + pos, 128 - pos, " 160MHz");
588 if (rate_info[NL80211_RATE_INFO_BITRATE32])
589 rate = nla_get_u32(rate_info[NL80211_RATE_INFO_BITRATE32]);
590 else if (rate_info[NL80211_RATE_INFO_BITRATE])
591 rate = nla_get_u16(rate_info[NL80211_RATE_INFO_BITRATE]);
593 snprintf(str_rate, 32, "%d.%d MBit/s", rate / 10, rate % 10);
596 snprintf(buf, buflen, "%s%s", str_rate, str_buf);
601 static void parse_bss_param(struct nlattr *bss_param_attr, mesh_station_info_s *station_info)
603 struct nlattr *bss_param_info[NL80211_STA_BSS_PARAM_MAX + 1], *info;
604 static struct nla_policy bss_poilcy[NL80211_STA_BSS_PARAM_MAX + 1] = {
605 [NL80211_STA_BSS_PARAM_CTS_PROT] = { .type = NLA_FLAG },
606 [NL80211_STA_BSS_PARAM_SHORT_PREAMBLE] = { .type = NLA_FLAG },
607 [NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME] = { .type = NLA_FLAG },
608 [NL80211_STA_BSS_PARAM_DTIM_PERIOD] = { .type = NLA_U8 },
609 [NL80211_STA_BSS_PARAM_BEACON_INTERVAL] = { .type = NLA_U16 },
612 if (nla_parse_nested(bss_param_info, NL80211_STA_BSS_PARAM_MAX, bss_param_attr, bss_poilcy))
613 MESH_LOGE("failed to parse nested bss param attributes!");
615 info = bss_param_info[NL80211_STA_BSS_PARAM_DTIM_PERIOD];
617 station_info->dtim_period = nla_get_u8(info);
618 MESH_LOGD(" DTIM period:\t%u", station_info->dtim_period);
620 info = bss_param_info[NL80211_STA_BSS_PARAM_BEACON_INTERVAL];
622 station_info->beacon_interval = nla_get_u16(info);
623 MESH_LOGD(" beacon interval:%u", station_info->beacon_interval);
625 info = bss_param_info[NL80211_STA_BSS_PARAM_CTS_PROT];
627 MESH_LOGD(" CTS protection:");
628 if (nla_get_u16(info)) {
630 station_info->cts_protection = TRUE;
633 station_info->cts_protection = FALSE;
636 info = bss_param_info[NL80211_STA_BSS_PARAM_SHORT_PREAMBLE];
638 MESH_LOGD(" short preamble:");
639 if (nla_get_u16(info)) {
641 station_info->short_preamble = TRUE;
644 station_info->short_preamble = FALSE;
647 info = bss_param_info[NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME];
649 MESH_LOGD(" short slot time:");
650 if (nla_get_u16(info)) {
652 station_info->short_slot_time = TRUE;
655 station_info->short_slot_time = FALSE;
660 static void print_power_mode(struct nlattr *a)
662 enum nl80211_mesh_power_mode pm = nla_get_u32(a);
665 case NL80211_MESH_POWER_ACTIVE:
668 case NL80211_MESH_POWER_LIGHT_SLEEP:
669 MESH_LOGD("LIGHT SLEEP");
671 case NL80211_MESH_POWER_DEEP_SLEEP:
672 MESH_LOGD("DEEP SLEEP");
675 MESH_LOGD("UNKNOWN");
680 static int _on_receive_station_info(struct nl_msg *msg, void *arg)
682 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
683 struct nlattr *sta_info[NL80211_STA_INFO_MAX + 1];
684 struct nlattr *attr_info[NL80211_ATTR_MAX + 1];
685 struct nl80211_sta_flag_update *sta_flags;
686 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
687 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
688 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
689 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
690 [NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
691 [NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
692 [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
693 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
694 [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
695 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
696 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
697 [NL80211_STA_INFO_TX_RETRIES] = { .type = NLA_U32 },
698 [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
699 [NL80211_STA_INFO_RX_BITRATE] = { .type = NLA_NESTED },
700 [NL80211_STA_INFO_BSS_PARAM] = { .type = NLA_NESTED },
701 [NL80211_STA_INFO_STA_FLAGS] = { .minlen = sizeof(struct nl80211_sta_flag_update) },
702 [NL80211_STA_INFO_BEACON_LOSS] = { .type = NLA_U32},
703 [NL80211_STA_INFO_T_OFFSET] = { .type = NLA_U64 },
704 [NL80211_STA_INFO_LOCAL_PM] = { .type = NLA_U32 },
705 [NL80211_STA_INFO_PEER_PM] = { .type = NLA_U32 },
706 [NL80211_STA_INFO_NONPEER_PM] = { .type = NLA_U32 },
707 [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
708 [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
709 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL
710 [NL80211_STA_INFO_CHAIN_SIGNAL] = { .type = NLA_NESTED },
711 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL */
713 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL_AVG
714 [NL80211_STA_INFO_CHAIN_SIGNAL_AVG] = { .type = NLA_NESTED },
715 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL_AVG */
717 #ifdef NL80211_STA_INFO_RX_DROP_MISC
718 [NL80211_STA_INFO_RX_DROP_MISC] = { .type = NLA_U64 },
719 #endif /* NL80211_STA_INFO_RX_DROP_MISC */
721 #ifdef NL80211_STA_INFO_RX_DURATION
722 [NL80211_STA_INFO_BEACON_RX] = { .type = NLA_U64 },
723 #endif /* NL80211_STA_INFO_RX_DURATION */
725 #ifdef NL80211_STA_INFO_TID_STATS
726 [NL80211_STA_INFO_TID_STATS] = { .type = NLA_NESTED },
727 #endif /* NL80211_STA_INFO_TID_STATS */
729 #ifdef NL80211_STA_INFO_RX_DURATION
730 [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 },
731 #endif /* NL80211_STA_INFO_RX_DURATION */
733 char mac_addr[MAX_MAC_ADDR_LEN], dev[IF_NAMESIZE];
734 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL
736 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL */
737 char *attr_mac = NULL;
738 mesh_nl_state *state = (mesh_nl_state *)arg;
739 mesh_station_info_s *station_info = NULL;
741 nla_parse(attr_info, NL80211_ATTR_MAX,
742 genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
744 if (!attr_info[NL80211_ATTR_STA_INFO]) {
745 MESH_LOGE("[Station] missing station stats !");
749 if (nla_parse_nested(sta_info, NL80211_STA_INFO_MAX,
750 attr_info[NL80211_ATTR_STA_INFO], stats_policy)) {
751 MESH_LOGE("[Station] Failed to parse nested attributes!");
756 station_info = g_try_new0(mesh_station_info_s, 1);
757 if (NULL == station_info) {
758 MESH_LOGE("Failed to allocate station info !");
763 attr_mac = nla_data(attr_info[NL80211_ATTR_MAC]);
764 snprintf(mac_addr, MAX_MAC_ADDR_LEN, "%02X:%02X:%02X:%02X:%02X:%02X",
765 attr_mac[0], attr_mac[1], attr_mac[2],
766 attr_mac[3], attr_mac[4], attr_mac[5]);
767 if_indextoname(nla_get_u32(attr_info[NL80211_ATTR_IFINDEX]), dev);
768 station_info->bssid = g_strdup(mac_addr);
769 MESH_LOGD("Station %s [dev %s]", station_info->bssid, dev);
772 if (0 != sta_info[NL80211_STA_INFO_INACTIVE_TIME]) {
773 station_info->inactive_time =
774 nla_get_u32(sta_info[NL80211_STA_INFO_INACTIVE_TIME]);
775 MESH_LOGE(" inactive time:\t%u ms", station_info->inactive_time);
779 if (0 != sta_info[NL80211_STA_INFO_RX_BYTES]) {
780 station_info->rx_bytes =
781 nla_get_u32(sta_info[NL80211_STA_INFO_RX_BYTES]);
782 MESH_LOGD(" rx bytes:\t%u", station_info->rx_bytes);
783 } else if (0 != sta_info[NL80211_STA_INFO_RX_BYTES64]) {
784 station_info->rx_bytes =
785 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_RX_BYTES64]);
786 MESH_LOGE(" rx bytes:\t%llu", station_info->rx_bytes);
790 if (0 != sta_info[NL80211_STA_INFO_RX_PACKETS]) {
791 station_info->rx_packets =
792 nla_get_u32(sta_info[NL80211_STA_INFO_RX_PACKETS]);
793 MESH_LOGD(" rx packets:\t%u", station_info->rx_packets);
797 if (0 != sta_info[NL80211_STA_INFO_TX_BYTES]) {
798 station_info->tx_bytes =
799 nla_get_u32(sta_info[NL80211_STA_INFO_TX_BYTES]);
800 MESH_LOGD(" tx bytes:\t%u", station_info->tx_bytes);
801 } else if (0 != sta_info[NL80211_STA_INFO_TX_BYTES64]) {
802 station_info->tx_bytes =
803 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_TX_BYTES64]);
804 MESH_LOGD(" tx bytes:\t%llu", station_info->rx_packets);
808 if (0 != sta_info[NL80211_STA_INFO_LLID]) {
809 station_info->llid = nla_get_u16(sta_info[NL80211_STA_INFO_LLID]);
810 MESH_LOGD(" mesh llid:\t%d", station_info->llid);
812 if (0 != sta_info[NL80211_STA_INFO_PLID]) {
813 station_info->llid = nla_get_u16(sta_info[NL80211_STA_INFO_PLID]);
814 MESH_LOGD(" mesh plid:\t%d", station_info->plid);
818 if (0 != sta_info[NL80211_STA_INFO_PLINK_STATE]) {
820 station_info->mesh_plink =
821 nla_get_u8(sta_info[NL80211_STA_INFO_PLINK_STATE]);
822 switch (station_info->mesh_plink) {
824 snprintf(state_name, 10, "%s", "LISTEN");
827 snprintf(state_name, 10, "%s", "OPN_SNT");
830 snprintf(state_name, 10, "%s", "OPN_RCVD");
833 snprintf(state_name, 10, "%s", "CNF_RCVD");
836 snprintf(state_name, 10, "%s", "ESTAB");
839 snprintf(state_name, 10, "%s", "HOLDING");
842 snprintf(state_name, 10, "%s", "BLOCKED");
845 snprintf(state_name, 10, "%s", "UNKNOWN");
848 MESH_LOGD(" mesh plink:\t%s", state_name);
850 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL
852 chain = get_chain_signal(sta_info[NL80211_STA_INFO_CHAIN_SIGNAL]);
853 if (0 != sta_info[NL80211_STA_INFO_SIGNAL]) {
855 (int8_t)nla_get_u8(sta_info[NL80211_STA_INFO_SIGNAL]);
856 MESH_LOGD(" signal: \t%d %sdBm", station_info->rssi, chain);
858 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL */
860 if (0 != sta_info[NL80211_STA_INFO_TX_BITRATE]) {
862 station_info->tx_bitrate =
863 parse_bitrate(sta_info[NL80211_STA_INFO_TX_BITRATE], buf, sizeof(buf));
864 MESH_LOGD(" tx bitrate:\t%s", buf);
867 if (0 != sta_info[NL80211_STA_INFO_TX_PACKETS]) {
868 station_info->tx_packets =
869 nla_get_u32(sta_info[NL80211_STA_INFO_TX_PACKETS]);
870 MESH_LOGD(" tx packets:\t%u", station_info->tx_packets);
872 if (0 != sta_info[NL80211_STA_INFO_TX_RETRIES]) {
873 station_info->tx_retries =
874 nla_get_u32(sta_info[NL80211_STA_INFO_TX_RETRIES]);
875 MESH_LOGD(" tx retries:\t%u", station_info->tx_retries);
877 if (0 != sta_info[NL80211_STA_INFO_TX_FAILED]) {
878 station_info->tx_failed =
879 nla_get_u32(sta_info[NL80211_STA_INFO_TX_FAILED]);
880 MESH_LOGD(" tx failed:\t%u", station_info->tx_failed);
882 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL_AVG
884 chain = get_chain_signal(sta_info[NL80211_STA_INFO_CHAIN_SIGNAL_AVG]);
885 if (0 != sta_info[NL80211_STA_INFO_SIGNAL_AVG]) {
886 station_info->rssi_avg =
887 (int8_t)nla_get_u8(sta_info[NL80211_STA_INFO_SIGNAL_AVG]);
888 MESH_LOGD(" signal avg:\t%d %sdBm", station_info->rssi_avg, chain);
890 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL_AVG */
891 if (0 != sta_info[NL80211_STA_INFO_RX_BITRATE]) {
893 station_info->rx_bitrate =
894 parse_bitrate(sta_info[NL80211_STA_INFO_RX_BITRATE], buf, sizeof(buf));
895 MESH_LOGD(" rx bitrate:\t%s", buf);
898 if (0 != sta_info[NL80211_STA_INFO_BSS_PARAM])
899 parse_bss_param(sta_info[NL80211_STA_INFO_BSS_PARAM], station_info);
901 if (0 != sta_info[NL80211_STA_INFO_CONNECTED_TIME]) {
902 station_info->connected_time =
903 nla_get_u32(sta_info[NL80211_STA_INFO_CONNECTED_TIME]);
904 MESH_LOGD(" connected time:\t%u seconds", station_info->connected_time);
907 if (0 != sta_info[NL80211_STA_INFO_STA_FLAGS]) {
908 sta_flags = (struct nl80211_sta_flag_update *)
909 nla_data(sta_info[NL80211_STA_INFO_STA_FLAGS]);
911 if (sta_flags->mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
912 MESH_LOGD(" authorized:");
913 if (sta_flags->set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
915 station_info->authorized = TRUE;
918 station_info->authorized = FALSE;
922 if (sta_flags->mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
923 MESH_LOGD(" authenticated:");
924 if (sta_flags->set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
926 station_info->authenticated = TRUE;
929 station_info->authenticated = FALSE;
933 if (sta_flags->mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
934 MESH_LOGD(" associated:");
935 if (sta_flags->set & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
937 station_info->associated = TRUE;
940 station_info->associated = FALSE;
944 if (sta_flags->mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
945 MESH_LOGD(" preamble:");
946 if (sta_flags->set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
948 station_info->preamble = TRUE;
951 station_info->preamble = FALSE;
955 if (sta_flags->mask & BIT(NL80211_STA_FLAG_WME)) {
956 MESH_LOGD(" WMM/WME:");
957 if (sta_flags->set & BIT(NL80211_STA_FLAG_WME)) {
959 station_info->wme = TRUE;
962 station_info->wme = FALSE;
966 if (sta_flags->mask & BIT(NL80211_STA_FLAG_MFP)) {
968 if (sta_flags->set & BIT(NL80211_STA_FLAG_MFP)) {
970 station_info->mfp = TRUE;
973 station_info->mfp = FALSE;
977 if (sta_flags->mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
978 MESH_LOGD(" TDLS peer:");
979 if (sta_flags->set & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
981 station_info->tdls_peer = TRUE;
984 station_info->tdls_peer = FALSE;
989 if (0 != sta_info[NL80211_STA_INFO_BEACON_LOSS]) {
990 station_info->beacon_loss =
991 nla_get_u32(sta_info[NL80211_STA_INFO_BEACON_LOSS]);
992 MESH_LOGD(" beacon loss:\t%u", station_info->beacon_loss);
995 if (0 != sta_info[NL80211_STA_INFO_T_OFFSET]) {
996 station_info->t_offset =
997 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_T_OFFSET]);
998 MESH_LOGD(" Toffset:\t%llu us", station_info->t_offset);
1001 if (0 != sta_info[NL80211_STA_INFO_LOCAL_PM]) {
1002 station_info->local_ps_mode =
1003 nla_get_u32(sta_info[NL80211_STA_INFO_LOCAL_PM]);
1004 MESH_LOGD(" mesh local PS mode:\t");
1005 print_power_mode(sta_info[NL80211_STA_INFO_LOCAL_PM]);
1007 if (0 != sta_info[NL80211_STA_INFO_PEER_PM]) {
1008 station_info->peer_ps_mode =
1009 nla_get_u32(sta_info[NL80211_STA_INFO_PEER_PM]);
1010 MESH_LOGD(" mesh peer PS mode:\t");
1011 print_power_mode(sta_info[NL80211_STA_INFO_PEER_PM]);
1013 if (0 != sta_info[NL80211_STA_INFO_NONPEER_PM]) {
1014 station_info->non_peer_ps_mode =
1015 nla_get_u32(sta_info[NL80211_STA_INFO_NONPEER_PM]);
1016 MESH_LOGD(" mesh non-peer PS mode:\t");
1017 print_power_mode(sta_info[NL80211_STA_INFO_NONPEER_PM]);
1019 #ifdef NL80211_STA_INFO_RX_DROP_MISC
1020 if (0 != sta_info[NL80211_STA_INFO_RX_DROP_MISC]) {
1021 station_info->rx_drop_misc =
1022 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_RX_DROP_MISC]);
1023 MESH_LOGD(" rx drop misc:\t%llu", station_info->rx_drop_misc);
1025 #endif /* NL80211_STA_INFO_RX_DROP_MISC */
1027 #ifdef NL80211_STA_INFO_BEACON_RX
1028 if (0 != sta_info[NL80211_STA_INFO_BEACON_RX]) {
1029 station_info->beacon_rx =
1030 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_BEACON_RX]);
1031 MESH_LOGD(" beacon rx:\t%llu", station_info->beacon_rx);
1033 #endif /* NL80211_STA_INFO_BEACON_RX */
1035 #ifdef NL80211_STA_INFO_BEACON_SIGNAL_AVG
1036 if (0 != sta_info[NL80211_STA_INFO_BEACON_SIGNAL_AVG]) {
1037 station_info->beacon_signal_avg =
1038 nla_get_u8(sta_info[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
1039 MESH_LOGD(" beacon signal avg:\t%d dBm", station_info->beacon_signal_avg);
1041 #endif /* NL80211_STA_INFO_BEACON_SIGNAL_AVG */
1043 #ifdef NL80211_STA_INFO_RX_DURATION
1044 if (0 != sta_info[NL80211_STA_INFO_RX_DURATION]) {
1045 station_info->rx_duration =
1046 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_RX_DURATION]);
1047 MESH_LOGD(" rx duration:\t%lld us", station_info->rx_duration);
1049 #endif /* NL80211_STA_INFO_RX_DURATION */
1051 *(state->station_list) = g_list_prepend(*(state->station_list), station_info);
1056 static int _on_receive_mpath_info(struct nl_msg *msg, void *arg)
1058 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1059 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1060 struct nlattr *pinfo[NL80211_MPATH_INFO_MAX + 1];
1061 char dst[20], next_hop[20], dev[20];
1062 static struct nla_policy mpath_policy[NL80211_MPATH_INFO_MAX + 1] = {
1063 [NL80211_MPATH_INFO_FRAME_QLEN] = { .type = NLA_U32 },
1064 [NL80211_MPATH_INFO_SN] = { .type = NLA_U32 },
1065 [NL80211_MPATH_INFO_METRIC] = { .type = NLA_U32 },
1066 [NL80211_MPATH_INFO_EXPTIME] = { .type = NLA_U32 },
1067 [NL80211_MPATH_INFO_DISCOVERY_TIMEOUT] = { .type = NLA_U32 },
1068 [NL80211_MPATH_INFO_DISCOVERY_RETRIES] = { .type = NLA_U8 },
1069 [NL80211_MPATH_INFO_FLAGS] = { .type = NLA_U8 },
1072 mesh_nl_state *state = (mesh_nl_state *)arg;
1073 mesh_mpath_info_s *mpath_info = NULL;
1075 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1076 genlmsg_attrlen(gnlh, 0), NULL);
1079 * TODO: validate the interface and mac address!
1080 * Otherwise, there's a race condition as soon as
1081 * the kernel starts sending mpath notifications.
1084 if (!tb[NL80211_ATTR_MPATH_INFO]) {
1085 MESH_LOGE("missing mesh path info!");
1088 if (nla_parse_nested(pinfo, NL80211_MPATH_INFO_MAX,
1089 tb[NL80211_ATTR_MPATH_INFO],
1091 MESH_LOGE("failed to parse nested attributes!");
1095 mpath_info = g_try_new0(mesh_mpath_info_s, 1);
1096 if (NULL == mpath_info) {
1097 MESH_LOGE("Failed to allocate mesh path info !");
1101 mac_addr_n2a(dst, nla_data(tb[NL80211_ATTR_MAC]));
1102 mpath_info->dest_addr = g_strdup(dst);
1103 MESH_LOGD("Destination Address : %s", mpath_info->dest_addr);
1105 mac_addr_n2a(next_hop, nla_data(tb[NL80211_ATTR_MPATH_NEXT_HOP]));
1106 mpath_info->next_hop = g_strdup(next_hop);
1107 MESH_LOGD("Next hop Address : %s", mpath_info->next_hop);
1109 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
1110 mpath_info->interface = g_strdup(dev);
1111 MESH_LOGD("Interface : %s", mpath_info->interface);
1113 if (pinfo[NL80211_MPATH_INFO_SN]) {
1114 mpath_info->sn = nla_get_u32(pinfo[NL80211_MPATH_INFO_SN]);
1115 MESH_LOGD("SN : %u", mpath_info->sn);
1117 if (pinfo[NL80211_MPATH_INFO_METRIC]) {
1118 mpath_info->metric = nla_get_u32(pinfo[NL80211_MPATH_INFO_METRIC]);
1119 MESH_LOGD("Metric : %u", mpath_info->metric);
1121 if (pinfo[NL80211_MPATH_INFO_FRAME_QLEN]) {
1122 mpath_info->qlen = nla_get_u32(pinfo[NL80211_MPATH_INFO_FRAME_QLEN]);
1123 MESH_LOGD("QLEN : %u", mpath_info->qlen);
1125 if (pinfo[NL80211_MPATH_INFO_EXPTIME]) {
1126 mpath_info->exptime = nla_get_u32(pinfo[NL80211_MPATH_INFO_EXPTIME]);
1127 MESH_LOGD("ExpTime : %u", mpath_info->exptime);
1129 if (pinfo[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT]) {
1130 mpath_info->discovery_timeout =
1131 nla_get_u32(pinfo[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT]);
1132 MESH_LOGD("Discovery Timeout : %u", mpath_info->discovery_timeout);
1134 if (pinfo[NL80211_MPATH_INFO_DISCOVERY_RETRIES]) {
1135 mpath_info->discovery_retries =
1136 nla_get_u8(pinfo[NL80211_MPATH_INFO_DISCOVERY_RETRIES]);
1137 MESH_LOGD("Discovery Retries : %u", mpath_info->discovery_retries);
1139 if (pinfo[NL80211_MPATH_INFO_FLAGS]) {
1140 mpath_info->flags = nla_get_u8(pinfo[NL80211_MPATH_INFO_FLAGS]);
1141 MESH_LOGD("Flags : 0x%x", mpath_info->flags);
1145 *(state->mpath_list) = g_list_prepend(*(state->mpath_list), mpath_info);
1150 static int _on_receive_mesh_event(struct nl_msg *msg, void *arg)
1152 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1153 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1154 char ifname[16] = { 0, };
1155 char macbuf[MAX_MAC_ADDR_LEN];
1159 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
1161 if (tb[NL80211_ATTR_IFINDEX]) {
1162 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
1163 MESH_LOGD("%s: ", ifname);
1166 switch (gnlh->cmd) {
1167 case NL80211_CMD_NEW_STATION:
1168 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1169 MESH_LOGD("[%s] new station [%s]", ifname, macbuf);
1171 case NL80211_CMD_DEL_STATION:
1172 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1173 MESH_LOGD("[%s] del station [%s]", ifname, macbuf);
1175 case NL80211_CMD_NEW_MPATH:
1176 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1177 MESH_LOGD("[%s] new mpath [%s]", ifname, macbuf);
1179 mesh_notify_station_joined((const char*)macbuf);
1181 case NL80211_CMD_DEL_MPATH:
1182 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1183 MESH_LOGD("[%s] del mpath [%s]", ifname, macbuf);
1185 mesh_notify_station_left((const char*)macbuf);
1188 MESH_LOGD("event [%d] is not handled", gnlh->cmd);
1195 static int _send_nl_set_mesh_parameter(const char* mesh_if_name,
1196 const char* param_name, unsigned int value)
1198 mesh_nl_state state = {
1200 .callback_state = MESH_NL_CALLBACK_TRYING,
1206 .error_occured = FALSE,
1208 struct nlattr *container;
1210 int err = MESHD_ERROR_NONE;
1211 int device_index = 0;
1215 ret = __initialize_nl80211(&state);
1216 if (MESHD_ERROR_NONE != ret) {
1217 MESH_LOGE("Failed to initialize nl80211");
1221 ret = __initialize_netlink_message(&state);
1222 if (MESHD_ERROR_NONE != ret) {
1223 MESH_LOGE("Failed to initialize netlink message");
1227 /* Set command into message */
1228 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1229 0, NL80211_CMD_SET_MESH_PARAMS, 0);
1231 /* Add attributes into message */
1232 ret = __get_device_index_from_string(mesh_if_name, &device_index);
1233 if (MESHD_ERROR_NONE != ret) {
1234 MESH_LOGE("Failed to get mesh device index");
1238 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1240 container = nla_nest_start(state.msg, NL80211_ATTR_MESH_PARAMS);
1242 MESH_LOGE("Failed to initialize netlink message");
1246 /* Logic need to be changed if additional parameter is required */
1247 if (g_strcmp0(MESH_PARAM_HWMP_ROOTMODE, param_name) == 0) {
1248 MESH_LOGD(" [mesh_hwmp_rootmode] : [%d]", value);
1249 NLA_PUT_U8(state.msg, NL80211_MESHCONF_HWMP_ROOTMODE,
1251 } else if (g_strcmp0(MESH_PARAM_GATE_ANNOUNCE, param_name) == 0) {
1252 MESH_LOGD(" [mesh_gate_announcements] : [%d]", value);
1253 NLA_PUT_U8(state.msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
1256 MESH_LOGE("Parameter [%s] is not required !", param_name);
1257 nla_nest_end(state.msg, container);
1260 nla_nest_end(state.msg, container);
1262 /* Send message into kernel */
1263 ret = nl_send_auto(state.nl_socket, state.msg);
1265 MESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1266 nl_geterror(ret), ret);
1267 err = MESHD_ERROR_OPERATION_FAILED;
1272 state.callback_state = MESH_NL_CALLBACK_TRYING;
1273 while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1274 MESH_LOGD(" count [%02d]", ++test);
1275 nl_recvmsgs(state.nl_socket, state.cb);
1279 __clean_netlink_message(&state);
1280 __clean_nl80211(&state);
1285 MESH_LOGE("Failed to message build");
1286 __clean_netlink_message(&state);
1287 __clean_nl80211(&state);
1289 return MESHD_ERROR_OPERATION_FAILED;
1292 static int _send_nl_get_station_info(const char* if_name, GList **station_list)
1294 mesh_nl_state state = {
1296 .callback_state = MESH_NL_CALLBACK_TRYING,
1302 .station_list = station_list
1304 int err = MESHD_ERROR_NONE;
1305 int device_index = 0;
1309 ret = __initialize_nl80211(&state);
1310 if (MESHD_ERROR_NONE != ret) {
1311 MESH_LOGE("Failed to initialize nl80211");
1315 ret = __initialize_netlink_message(&state);
1316 if (MESHD_ERROR_NONE != ret) {
1317 MESH_LOGE("Failed to initialize netlink message");
1321 /* Set command into message */
1322 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1323 NLM_F_DUMP, NL80211_CMD_GET_STATION, 0);
1325 /* Add attributes into message */
1326 MESH_LOGD("Dump station list with interface [%s]", if_name);
1327 ret = __get_device_index_from_string(if_name, &device_index);
1328 if (MESHD_ERROR_NONE != ret) {
1329 MESH_LOGE("Failed to get mesh interface device index");
1333 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1335 /* Register valid callback to dump result */
1336 nl_cb_set(state.cb, NL_CB_VALID, NL_CB_CUSTOM,
1337 _on_receive_station_info, &state);
1339 /* Send message into kernel */
1340 ret = nl_send_auto(state.nl_socket, state.msg);
1342 MESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1343 nl_geterror(ret), ret);
1344 err = MESHD_ERROR_OPERATION_FAILED;
1349 state.callback_state = MESH_NL_CALLBACK_TRYING;
1350 while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1351 MESH_LOGD(" count [%02d]", ++test);
1352 nl_recvmsgs(state.nl_socket, state.cb);
1354 MESH_LOGD("Finished");
1357 __clean_netlink_message(&state);
1358 __clean_nl80211(&state);
1363 MESH_LOGE("Failed to message build");
1364 __clean_netlink_message(&state);
1365 __clean_nl80211(&state);
1367 return MESHD_ERROR_OPERATION_FAILED;
1370 static int _send_nl_del_station_info(const char* if_name, char* peer)
1372 mesh_nl_state state = {
1374 .callback_state = MESH_NL_CALLBACK_FINISHED,
1380 .station_list = NULL,
1382 int err = MESHD_ERROR_NONE;
1383 int device_index = 0;
1386 ret = __initialize_nl80211(&state);
1387 if (MESHD_ERROR_NONE != ret) {
1388 MESH_LOGE("Failed to initialize nl80211");
1392 ret = __initialize_netlink_message(&state);
1393 if (MESHD_ERROR_NONE != ret) {
1394 MESH_LOGE("Failed to initialize netlink message");
1398 /* Set command into message */
1399 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1400 NLM_F_DUMP, NL80211_CMD_DEL_STATION, 0);
1402 /* Add attributes into message */
1403 MESH_LOGD("Delete a station [%s] with interface [%s]", peer, if_name);
1404 ret = __get_device_index_from_string(if_name, &device_index);
1405 if (MESHD_ERROR_NONE != ret) {
1406 MESH_LOGE("Failed to get mesh interface device index");
1410 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1411 NLA_PUT(state.msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
1413 /* Send message into kernel */
1414 ret = nl_send_auto(state.nl_socket, state.msg);
1416 MESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1417 nl_geterror(ret), ret);
1418 err = MESHD_ERROR_OPERATION_FAILED;
1423 __clean_netlink_message(&state);
1424 __clean_nl80211(&state);
1429 MESH_LOGE("Failed to message build");
1430 __clean_netlink_message(&state);
1431 __clean_nl80211(&state);
1433 return MESHD_ERROR_OPERATION_FAILED;
1436 static int _send_nl_get_mpath_info(const char* if_name, GList **mpath_list)
1438 mesh_nl_state state = {
1440 .callback_state = MESH_NL_CALLBACK_TRYING,
1446 .mpath_list = mpath_list
1448 int err = MESHD_ERROR_NONE;
1449 int device_index = 0;
1453 ret = __initialize_nl80211(&state);
1454 if (MESHD_ERROR_NONE != ret) {
1455 MESH_LOGE("Failed to initialize nl80211");
1459 ret = __initialize_netlink_message(&state);
1460 if (MESHD_ERROR_NONE != ret) {
1461 MESH_LOGE("Failed to initialize netlink message");
1465 /* Set command into message */
1466 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1467 NLM_F_DUMP, NL80211_CMD_GET_MPATH, 0);
1469 /* Add attributes into message */
1470 MESH_LOGD("Dump station list with interface [%s]", if_name);
1471 ret = __get_device_index_from_string(if_name, &device_index);
1472 if (MESHD_ERROR_NONE != ret) {
1473 MESH_LOGE("Failed to get mesh interface device index");
1477 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1479 /* Register valid callback to dump result */
1480 nl_cb_set(state.cb, NL_CB_VALID, NL_CB_CUSTOM,
1481 _on_receive_mpath_info, &state);
1483 /* Send message into kernel */
1484 ret = nl_send_auto(state.nl_socket, state.msg);
1486 MESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1487 nl_geterror(ret), ret);
1488 err = MESHD_ERROR_OPERATION_FAILED;
1493 state.callback_state = MESH_NL_CALLBACK_TRYING;
1494 while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1495 MESH_LOGD(" count [%02d]", ++test);
1496 nl_recvmsgs(state.nl_socket, state.cb);
1498 MESH_LOGD("Finished");
1501 __clean_netlink_message(&state);
1502 __clean_nl80211(&state);
1507 MESH_LOGE("Failed to message build");
1508 __clean_netlink_message(&state);
1509 __clean_nl80211(&state);
1511 return MESHD_ERROR_OPERATION_FAILED;
1514 static int _send_nl_register_event_handler()
1516 int err = MESHD_ERROR_NONE;
1518 GIOChannel *recv_channel = NULL;
1521 MESH_LOGE("Already event handler registered !");
1522 return MESHD_ERROR_IN_PROGRESS;
1525 event_state = _create_mesh_nl_state("");
1527 ret = __initialize_nl80211(event_state);
1528 if (MESHD_ERROR_NONE != ret) {
1529 MESH_LOGE("Failed to initialize nl80211");
1533 /* Subscribe multicast group should be proceed before scanning */
1534 ret = __prepare_listen_events(event_state);
1536 MESH_LOGE("__prepare_listen_events : [%d]", ret);
1540 ret = __initialize_netlink_message(event_state);
1541 if (MESHD_ERROR_NONE != ret) {
1542 MESH_LOGE("Failed to initialize netlink message");
1546 /* Set command into message */
1547 genlmsg_put(event_state->msg, 0, 0, event_state->nl80211_id, 0, 0, 0, 0);
1549 /* Set callbacks for event handler */
1550 nl_cb_set(event_state->cb, NL_CB_VALID, NL_CB_CUSTOM,
1551 _on_receive_mesh_event, event_state);
1552 /* No sequence checking for multicast messages. */
1553 nl_cb_set(event_state->cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
1555 MESH_LOGD("Register event handler");
1557 /* Change socket type to non-blocking */
1558 ret = nl_socket_set_nonblocking(event_state->nl_socket);
1560 MESH_LOGE("Failed to non-blocking socket [%s](%d)", nl_geterror(ret), ret);
1562 /* Register I/O callback to wait asynchronously */
1563 if (FALSE == event_state->error_occured) {
1564 recv_channel = g_io_channel_unix_new(nl_socket_get_fd(event_state->nl_socket));
1565 event_state->event_source = g_io_add_watch(recv_channel,
1566 (G_IO_IN | G_IO_ERR), _on_socket_event_io_received, event_state);
1567 g_io_channel_unref(recv_channel);
1569 MESH_LOGE("Error responded. Failed to register event callback !!");
1573 /* Resource should be free on I/O callback */
1574 return MESHD_ERROR_NONE;
1577 __clean_netlink_message(event_state);
1578 __clean_nl80211(event_state);
1579 _delete_mesh_nl_state(&event_state);
1584 int mesh_netlink_set_mesh_parameter(const char* mesh_if_name,
1585 const char* param_name, unsigned int value)
1587 int ret = MESHD_ERROR_NONE;
1589 if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1590 MESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1591 return MESHD_ERROR_INVALID_PARAMETER;
1594 MESH_LOGD("Set mesh[%s] param [%s] value [%d]",
1595 mesh_if_name, param_name, value);
1596 ret = _send_nl_set_mesh_parameter(mesh_if_name, param_name, value);
1601 int mesh_netlink_get_station_info(const char* mesh_if_name, GList **station_list)
1603 int ret = MESHD_ERROR_NONE;
1605 if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1606 MESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1607 return MESHD_ERROR_INVALID_PARAMETER;
1609 if (NULL == station_list) {
1610 MESH_LOGE("Invalid parameter [%p]", station_list);
1611 return MESHD_ERROR_INVALID_PARAMETER;
1614 MESH_LOGD("Get connected stations");
1615 ret = _send_nl_get_station_info(mesh_if_name, station_list);
1620 int mesh_netlink_del_station_info(const char* mesh_if_name, char *peer)
1622 int ret = MESHD_ERROR_NONE;
1624 if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1625 MESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1626 return MESHD_ERROR_INVALID_PARAMETER;
1629 MESH_LOGE("Invalid parameter [%p]", peer);
1630 return MESHD_ERROR_INVALID_PARAMETER;
1633 MESH_LOGD("Del connected station : [%s]", peer);
1634 ret = _send_nl_del_station_info(mesh_if_name, peer);
1639 int mesh_netlink_get_mpath_info(const char* mesh_if_name, GList **mpath_list)
1641 int ret = MESHD_ERROR_NONE;
1643 if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1644 MESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1645 return MESHD_ERROR_INVALID_PARAMETER;
1647 if (NULL == mpath_list) {
1648 MESH_LOGE("Invalid parameter [%p]", mpath_list);
1649 return MESHD_ERROR_INVALID_PARAMETER;
1652 MESH_LOGD("Get current mpath info");
1653 ret = _send_nl_get_mpath_info(mesh_if_name, mpath_list);
1658 int mesh_netlink_register_event_handler()
1660 int ret = MESHD_ERROR_NONE;
1662 MESH_LOGD("Register mesh event handler");
1663 ret = _send_nl_register_event_handler();
1668 int mesh_netlink_unregister_event_handler()
1670 int ret = MESHD_ERROR_NONE;
1672 MESH_LOGD("Unregister mesh event handler");
1674 _on_remove_event_io_handler();