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"
45 #define MESH_PARAM_HWMP_ROOTMODE "mesh_hwmp_rootmode"
46 #define MESH_PARAM_GATE_ANNOUNCE "mesh_gate_announcements"
47 #define MAX_MAC_ADDR_LEN 18
50 #define BIT(x) (1ULL<<(x))
53 MESH_NL_CALLBACK_FINISHED = 0,
54 MESH_NL_CALLBACK_TRYING,
55 } mesh_nl_callback_state_e;
62 struct nl_sock *nl_socket;
75 } multicast_group_id_args;
87 /* For event handler */
88 static mesh_nl_state *event_state = NULL;
90 static int __initialize_nl80211(mesh_nl_state *state)
92 int err = MESHD_ERROR_NONE;
94 state->nl_socket = nl_socket_alloc();
95 if (!state->nl_socket) {
96 MESH_LOGE("Failed to allocate netlink socket.");
97 return MESHD_ERROR_OUT_OF_MEMORY;
100 if (genl_connect(state->nl_socket)) {
101 MESH_LOGE("Failed to connect to generic netlink.");
102 err = MESHD_ERROR_OPERATION_FAILED;
106 nl_socket_set_buffer_size(state->nl_socket, 8192, 8192);
108 state->nl80211_id = genl_ctrl_resolve(state->nl_socket, "nl80211");
109 if (state->nl80211_id < 0) {
110 MESH_LOGE("nl80211 not found.");
111 err = MESHD_ERROR_NO_DATA;
118 nl_socket_free(state->nl_socket);
122 static void __clean_nl80211(mesh_nl_state *state)
127 if (state->nl_socket) {
128 nl_socket_free(state->nl_socket);
129 state->nl_socket = NULL;
130 state->nl80211_id = -1;
134 static int __get_device_index_from_string(const char* if_name, int *index)
136 int device_index = 0;
138 if (NULL == if_name) {
139 MESH_LOGE("Invalid parameter");
140 return MESHD_ERROR_INVALID_PARAMETER;
143 device_index = if_nametoindex(if_name);
144 if (device_index == 0) {
145 MESH_LOGE("No interface index found [%s]", if_name);
146 return MESHD_ERROR_NO_DATA;
148 *index = device_index;
150 return MESHD_ERROR_NONE;
153 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
155 mesh_nl_state *state = (mesh_nl_state *)arg;
156 char buf[256] = { 0, };
160 state->callback_state = MESH_NL_CALLBACK_FINISHED;
161 state->error_occured = TRUE;
162 strerror_r(err->error, buf, 255);
164 MESH_LOGD("error_handler");
165 MESH_LOGE(" %s (%d)", buf, err->error);
170 static int finish_handler(struct nl_msg *msg, void *arg)
172 mesh_nl_state *state = (mesh_nl_state *)arg;
174 state->callback_state = MESH_NL_CALLBACK_FINISHED;
176 MESH_LOGD("finish_handler");
182 static int ack_handler(struct nl_msg *msg, void *arg)
184 mesh_nl_state *state = (mesh_nl_state *)arg;
186 state->callback_state = MESH_NL_CALLBACK_FINISHED;
188 MESH_LOGD("ack_handler");
194 static int ack_simple_handler(struct nl_msg *msg, void *arg)
201 MESH_LOGD("ack_simple_handler");
206 static int family_handler(struct nl_msg *msg, void *arg)
208 multicast_group_id_args *group = (multicast_group_id_args *)arg;
209 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
210 struct nlattr *tb[CTRL_ATTR_MAX + 1];
211 struct nlattr *mcast_group;
214 MESH_LOGD("family_handler");
216 nla_parse(tb, CTRL_ATTR_MAX,
217 genlmsg_attrdata(gnlh, 0),
218 genlmsg_attrlen(gnlh, 0), NULL);
219 if (!tb[CTRL_ATTR_MCAST_GROUPS])
222 nla_for_each_nested(mcast_group, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcast_group) {
223 struct nlattr *tb_mcast_group[CTRL_ATTR_MCAST_GRP_MAX + 1];
225 nla_parse(tb_mcast_group, CTRL_ATTR_MCAST_GRP_MAX,
226 nla_data(mcast_group), nla_len(mcast_group), NULL);
228 if (!tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME] ||
229 !tb_mcast_group[CTRL_ATTR_MCAST_GRP_ID])
232 if (strncmp(nla_data(tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME]),
234 nla_len(tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME])))
237 group->id = nla_get_u32(tb_mcast_group[CTRL_ATTR_MCAST_GRP_ID]);
238 MESH_LOGD("mcast group id [%d]", group->id);
245 static int __nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group)
250 multicast_group_id_args group_args = {
259 cb = nl_cb_alloc(NL_CB_DEFAULT);
265 ctrlid = genl_ctrl_resolve(sock, "nlctrl");
267 genlmsg_put(msg, 0, 0, ctrlid, 0,
268 0, CTRL_CMD_GETFAMILY, 0);
271 NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
273 ret = nl_send_auto(sock, msg);
275 MESH_LOGE("Failed to nl_send_auto");
280 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
281 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_simple_handler, &ret);
282 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, family_handler, &group_args);
285 nl_recvmsgs(sock, cb);
290 MESH_LOGD("mcid : [%d]", ret);
301 static int __prepare_listen_events(mesh_nl_state *state)
305 /* Configuration multicast group */
306 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "config");
308 MESH_LOGE("Failed to get nl80211 config");
311 MESH_LOGD("Mesh multicast id (config): [%d]", mcid);
313 ret = nl_socket_add_membership(state->nl_socket, mcid);
315 MESH_LOGE("Failed to nl_socket_add_membership");
319 /* Scan multicast group */
320 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "scan");
322 ret = nl_socket_add_membership(state->nl_socket, mcid);
324 MESH_LOGE("Failed to nl_socket_add_membership");
328 MESH_LOGD("Mesh multicast id (scan): [%d]", mcid);
330 /* Regulatory multicast group */
331 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "regulatory");
333 ret = nl_socket_add_membership(state->nl_socket, mcid);
335 MESH_LOGE("Failed to nl_socket_add_membership");
339 MESH_LOGD("Mesh multicast id (regulatory): [%d]", mcid);
341 /* MLME multicast group */
342 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "mlme");
344 ret = nl_socket_add_membership(state->nl_socket, mcid);
346 MESH_LOGE("Failed to nl_socket_add_membership");
350 MESH_LOGD("Mesh multicast id (mlme): [%d]", mcid);
352 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "vendor");
354 ret = nl_socket_add_membership(state->nl_socket, mcid);
356 MESH_LOGE("Failed to nl_socket_add_membership");
360 MESH_LOGD("Mesh multicast id (vendor): [%d]", mcid);
365 static mesh_nl_state *_create_mesh_nl_state()
367 mesh_nl_state *state = g_new0(mesh_nl_state, 1);
369 state->nl80211_id = -1;
370 state->callback_state = MESH_NL_CALLBACK_TRYING;
371 state->error_occured = FALSE;
376 static void _delete_mesh_nl_state(mesh_nl_state **state)
378 if (NULL == state || NULL == *state)
385 static int valid_handler(struct nl_msg *msg, void *arg)
387 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
388 mesh_nl_state *state = (mesh_nl_state *)arg;
389 MESH_LOGD("valid_handler");
391 if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) {
392 MESH_LOGD(" Got NL80211_CMD_SCAN_ABORTED.");
393 state->callback_state = MESH_NL_CALLBACK_FINISHED;
395 /* Notify scan done status */
396 mesh_notify_scan_done();
397 } else if (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
398 MESH_LOGD(" Got NL80211_CMD_NEW_SCAN_RESULTS.");
399 state->callback_state = MESH_NL_CALLBACK_FINISHED;
401 /* Notify scan done status */
402 mesh_notify_scan_done();
404 MESH_LOGD(" Got [%d]", gnlh->cmd);
410 static int no_seq_check(struct nl_msg *msg, void *arg)
418 static void __clean_netlink_message(mesh_nl_state *state)
424 nl_cb_put(state->cb);
426 nl_cb_put(state->s_cb);
428 nlmsg_free(state->msg);
434 MESH_LOGD("message and callback cleaned");
437 static int __initialize_netlink_message(mesh_nl_state *state)
439 int err = MESHD_ERROR_NONE;
442 MESH_LOGE("Invalid parameter !");
443 return MESHD_ERROR_INVALID_PARAMETER;
446 /* Create netlink message */
447 state->msg = nlmsg_alloc();
448 if (NULL == state->msg) {
449 MESH_LOGE("Failed to allocate netlink message");
450 return MESHD_ERROR_OUT_OF_MEMORY;
454 state->cb = nl_cb_alloc(NL_CB_DEFAULT);
455 state->s_cb = nl_cb_alloc(NL_CB_DEFAULT);
457 MESH_LOGE("Failed to allocate netlink callback");
458 err = MESHD_ERROR_OUT_OF_MEMORY;
462 /* Set socket callback */
463 nl_socket_set_cb(state->nl_socket, state->s_cb);
466 nl_cb_err(state->cb, NL_CB_CUSTOM, error_handler, state);
467 nl_cb_set(state->cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, state);
468 nl_cb_set(state->cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, state);
469 nl_cb_set(state->cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, state);
471 MESH_LOGD("netlink socket initialized");
473 return MESHD_ERROR_NONE;
476 __clean_netlink_message(state);
481 static gboolean _on_socket_event_io_received(GIOChannel *source,
482 GIOCondition condition, gpointer data)
484 mesh_nl_state *state = (mesh_nl_state *)data;
490 MESH_LOGD("[Event] I/O received");
492 while (nl_recvmsgs_report(state->nl_socket, state->cb) > 0)
493 MESH_LOGD(" count [%02d]", ++test);
495 /* Do not remove I/O source */
499 static void _on_remove_event_io_handler()
502 g_source_remove(event_state->event_source);
504 __clean_netlink_message(event_state);
505 __clean_nl80211(event_state);
506 _delete_mesh_nl_state(&event_state);
510 static void mac_addr_n2a(char *mac_addr, unsigned char *arg)
512 /* 11:22:33:44:55:66 (Len:17) */
513 snprintf(mac_addr, MAX_MAC_ADDR_LEN,
514 "%02X:%02X:%02X:%02X:%02X:%02X",
515 arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
518 static char *get_chain_signal(struct nlattr *attr_list)
529 nla_for_each_nested(attr, attr_list, rem) {
535 cur += snprintf(cur, sizeof(buf) - (cur - buf), "%s%d", prefix,
536 (int8_t) nla_get_u8(attr));
540 snprintf(cur, sizeof(buf) - (cur - buf), "] ");
545 static int parse_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen)
549 struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
550 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
551 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
552 [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 },
553 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
554 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
555 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
558 if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX, bitrate_attr, rate_policy)) {
559 snprintf(buf, buflen, "failed to parse nested rate attributes!");
563 if (rinfo[NL80211_RATE_INFO_BITRATE32])
564 rate = nla_get_u32(rinfo[NL80211_RATE_INFO_BITRATE32]);
565 else if (rinfo[NL80211_RATE_INFO_BITRATE])
566 rate = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
568 pos += snprintf(pos, buflen - (pos - buf),
569 "%d.%d MBit/s", rate / 10, rate % 10);
571 if (rinfo[NL80211_RATE_INFO_MCS])
572 pos += snprintf(pos, buflen - (pos - buf),
573 " MCS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]));
574 if (rinfo[NL80211_RATE_INFO_VHT_MCS])
575 pos += snprintf(pos, buflen - (pos - buf),
576 " VHT-MCS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_VHT_MCS]));
577 if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH])
578 pos += snprintf(pos, buflen - (pos - buf), " 40MHz");
579 if (rinfo[NL80211_RATE_INFO_80_MHZ_WIDTH])
580 pos += snprintf(pos, buflen - (pos - buf), " 80MHz");
581 if (rinfo[NL80211_RATE_INFO_80P80_MHZ_WIDTH])
582 pos += snprintf(pos, buflen - (pos - buf), " 80P80MHz");
583 if (rinfo[NL80211_RATE_INFO_160_MHZ_WIDTH])
584 pos += snprintf(pos, buflen - (pos - buf), " 160MHz");
585 if (rinfo[NL80211_RATE_INFO_SHORT_GI])
586 pos += snprintf(pos, buflen - (pos - buf), " short GI");
587 if (rinfo[NL80211_RATE_INFO_VHT_NSS])
588 pos += snprintf(pos, buflen - (pos - buf),
589 " VHT-NSS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_VHT_NSS]));
594 static void parse_bss_param(struct nlattr *bss_param_attr, mesh_station_info_s *station_info)
596 struct nlattr *bss_param_info[NL80211_STA_BSS_PARAM_MAX + 1], *info;
597 static struct nla_policy bss_poilcy[NL80211_STA_BSS_PARAM_MAX + 1] = {
598 [NL80211_STA_BSS_PARAM_CTS_PROT] = { .type = NLA_FLAG },
599 [NL80211_STA_BSS_PARAM_SHORT_PREAMBLE] = { .type = NLA_FLAG },
600 [NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME] = { .type = NLA_FLAG },
601 [NL80211_STA_BSS_PARAM_DTIM_PERIOD] = { .type = NLA_U8 },
602 [NL80211_STA_BSS_PARAM_BEACON_INTERVAL] = { .type = NLA_U16 },
605 if (nla_parse_nested(bss_param_info, NL80211_STA_BSS_PARAM_MAX, bss_param_attr, bss_poilcy))
606 MESH_LOGE("failed to parse nested bss param attributes!");
608 info = bss_param_info[NL80211_STA_BSS_PARAM_DTIM_PERIOD];
610 station_info->dtim_period = nla_get_u8(info);
611 MESH_LOGD(" DTIM period:\t%u", station_info->dtim_period);
613 info = bss_param_info[NL80211_STA_BSS_PARAM_BEACON_INTERVAL];
615 station_info->beacon_interval = nla_get_u16(info);
616 MESH_LOGD(" beacon interval:%u", station_info->beacon_interval);
618 info = bss_param_info[NL80211_STA_BSS_PARAM_CTS_PROT];
620 MESH_LOGD(" CTS protection:");
621 if (nla_get_u16(info)) {
623 station_info->cts_protection = TRUE;
626 station_info->cts_protection = FALSE;
629 info = bss_param_info[NL80211_STA_BSS_PARAM_SHORT_PREAMBLE];
631 MESH_LOGD(" short preamble:");
632 if (nla_get_u16(info)) {
634 station_info->short_preamble = TRUE;
637 station_info->short_preamble = FALSE;
640 info = bss_param_info[NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME];
642 MESH_LOGD(" short slot time:");
643 if (nla_get_u16(info)) {
645 station_info->short_slot_time = TRUE;
648 station_info->short_slot_time = FALSE;
653 static void print_power_mode(struct nlattr *a)
655 enum nl80211_mesh_power_mode pm = nla_get_u32(a);
658 case NL80211_MESH_POWER_ACTIVE:
661 case NL80211_MESH_POWER_LIGHT_SLEEP:
662 MESH_LOGD("LIGHT SLEEP");
664 case NL80211_MESH_POWER_DEEP_SLEEP:
665 MESH_LOGD("DEEP SLEEP");
668 MESH_LOGD("UNKNOWN");
673 static int _on_receive_station_info(struct nl_msg *msg, void *arg)
675 struct nlattr *tb[NL80211_ATTR_MAX + 1];
676 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
677 struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
678 struct nl80211_sta_flag_update *sta_flags;
679 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
680 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
681 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
682 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
683 [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
684 [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
685 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
686 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
687 [NL80211_STA_INFO_BEACON_RX] = { .type = NLA_U64},
688 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
689 [NL80211_STA_INFO_T_OFFSET] = { .type = NLA_U64 },
690 [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
691 [NL80211_STA_INFO_RX_BITRATE] = { .type = NLA_NESTED },
692 [NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
693 [NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
694 [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
695 [NL80211_STA_INFO_TX_RETRIES] = { .type = NLA_U32 },
696 [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
697 [NL80211_STA_INFO_BEACON_LOSS] = { .type = NLA_U32},
698 [NL80211_STA_INFO_RX_DROP_MISC] = { .type = NLA_U64},
699 [NL80211_STA_INFO_STA_FLAGS] = { .minlen = sizeof(struct nl80211_sta_flag_update) },
700 [NL80211_STA_INFO_LOCAL_PM] = { .type = NLA_U32},
701 [NL80211_STA_INFO_PEER_PM] = { .type = NLA_U32},
702 [NL80211_STA_INFO_NONPEER_PM] = { .type = NLA_U32},
703 [NL80211_STA_INFO_CHAIN_SIGNAL] = { .type = NLA_NESTED },
704 [NL80211_STA_INFO_CHAIN_SIGNAL_AVG] = { .type = NLA_NESTED },
705 [NL80211_STA_INFO_TID_STATS] = { .type = NLA_NESTED },
706 [NL80211_STA_INFO_BSS_PARAM] = { .type = NLA_NESTED },
707 [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 },
709 char mac_addr[MAX_MAC_ADDR_LEN], state_name[10], dev[20];
711 mesh_nl_state *state = (mesh_nl_state *)arg;
712 mesh_station_info_s *station_info = NULL;
714 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
715 genlmsg_attrlen(gnlh, 0), NULL);
718 * TODO: validate the interface and mac address!
719 * Otherwise, there's a race condition as soon as
720 * the kernel starts sending station notifications.
723 if (!tb[NL80211_ATTR_STA_INFO]) {
724 MESH_LOGE("missing station stats !");
727 if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
728 tb[NL80211_ATTR_STA_INFO],
730 MESH_LOGE("failed to parse nested attributes!");
734 station_info = g_try_new0(mesh_station_info_s, 1);
735 if (NULL == station_info) {
736 MESH_LOGE("Failed to allocate station info !");
740 mac_addr_n2a(mac_addr, nla_data(tb[NL80211_ATTR_MAC]));
741 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
742 MESH_LOGD("Station %s (on %s)", mac_addr, dev);
743 station_info->bssid = g_strdup(mac_addr);
745 if (sinfo[NL80211_STA_INFO_INACTIVE_TIME]) {
746 station_info->inactive_time =
747 nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME]);
748 MESH_LOGE(" inactive time:\t%u ms", station_info->inactive_time);
751 if (sinfo[NL80211_STA_INFO_RX_BYTES64]) {
752 station_info->rx_bytes =
753 (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_RX_BYTES64]);
754 MESH_LOGE(" rx bytes:\t%llu", station_info->rx_bytes);
755 } else if (sinfo[NL80211_STA_INFO_RX_BYTES]) {
756 station_info->rx_bytes =
757 nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES]);
758 MESH_LOGD(" rx bytes:\t%u", station_info->rx_bytes);
760 if (sinfo[NL80211_STA_INFO_RX_PACKETS]) {
761 station_info->rx_packets =
762 nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS]);
763 MESH_LOGD(" rx packets:\t%u", station_info->rx_packets);
766 if (sinfo[NL80211_STA_INFO_TX_BYTES64]) {
767 station_info->tx_bytes =
768 (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_TX_BYTES64]);
769 MESH_LOGD(" tx bytes:\t%llu", station_info->rx_packets);
770 } else if (sinfo[NL80211_STA_INFO_TX_BYTES]) {
771 station_info->tx_bytes =
772 nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES]);
773 MESH_LOGD(" tx bytes:\t%u", station_info->tx_bytes);
775 if (sinfo[NL80211_STA_INFO_TX_PACKETS]) {
776 station_info->tx_packets =
777 nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS]);
778 MESH_LOGD(" tx packets:\t%u", station_info->tx_packets);
780 if (sinfo[NL80211_STA_INFO_TX_RETRIES]) {
781 station_info->tx_retries =
782 nla_get_u32(sinfo[NL80211_STA_INFO_TX_RETRIES]);
783 MESH_LOGD(" tx retries:\t%u", station_info->tx_retries);
785 if (sinfo[NL80211_STA_INFO_TX_FAILED]) {
786 station_info->tx_failed =
787 nla_get_u32(sinfo[NL80211_STA_INFO_TX_FAILED]);
788 MESH_LOGD(" tx failed:\t%u", station_info->tx_failed);
790 if (sinfo[NL80211_STA_INFO_BEACON_LOSS]) {
791 station_info->beacon_loss =
792 nla_get_u32(sinfo[NL80211_STA_INFO_BEACON_LOSS]);
793 MESH_LOGD(" beacon loss:\t%u", station_info->beacon_loss);
795 if (sinfo[NL80211_STA_INFO_BEACON_RX]) {
796 station_info->beacon_rx =
797 (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_BEACON_RX]);
798 MESH_LOGD(" beacon rx:\t%llu", station_info->beacon_rx);
800 if (sinfo[NL80211_STA_INFO_RX_DROP_MISC]) {
801 station_info->rx_drop_misc =
802 (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_RX_DROP_MISC]);
803 MESH_LOGD(" rx drop misc:\t%llu", station_info->rx_drop_misc);
806 chain = get_chain_signal(sinfo[NL80211_STA_INFO_CHAIN_SIGNAL]);
807 if (sinfo[NL80211_STA_INFO_SIGNAL]) {
809 (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
810 MESH_LOGD(" signal: \t%d %sdBm", station_info->rssi, chain);
813 chain = get_chain_signal(sinfo[NL80211_STA_INFO_CHAIN_SIGNAL_AVG]);
814 if (sinfo[NL80211_STA_INFO_SIGNAL_AVG]) {
815 station_info->rssi_avg =
816 (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
817 MESH_LOGD(" signal avg:\t%d %sdBm", station_info->rssi_avg, chain);
820 if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]) {
821 station_info->beacon_signal_avg =
822 nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
823 MESH_LOGD(" beacon signal avg:\t%d dBm", station_info->beacon_signal_avg);
825 if (sinfo[NL80211_STA_INFO_T_OFFSET]) {
826 station_info->t_offset =
827 (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_T_OFFSET]);
828 MESH_LOGD(" Toffset:\t%llu us", station_info->t_offset);
831 if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
833 station_info->tx_bitrate =
834 parse_bitrate(sinfo[NL80211_STA_INFO_TX_BITRATE], buf, sizeof(buf));
835 MESH_LOGD(" tx bitrate:\t%s", buf);
838 if (sinfo[NL80211_STA_INFO_RX_BITRATE]) {
840 station_info->rx_bitrate =
841 parse_bitrate(sinfo[NL80211_STA_INFO_RX_BITRATE], buf, sizeof(buf));
842 MESH_LOGD(" rx bitrate:\t%s", buf);
845 if (sinfo[NL80211_STA_INFO_RX_DURATION]) {
846 station_info->rx_duration =
847 (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_RX_DURATION]);
848 MESH_LOGD(" rx duration:\t%lld us", station_info->rx_duration);
851 if (sinfo[NL80211_STA_INFO_LLID]) {
852 station_info->llid = nla_get_u16(sinfo[NL80211_STA_INFO_LLID]);
853 MESH_LOGD(" mesh llid:\t%d", station_info->llid);
855 if (sinfo[NL80211_STA_INFO_PLID]) {
856 station_info->llid = nla_get_u16(sinfo[NL80211_STA_INFO_PLID]);
857 MESH_LOGD(" mesh plid:\t%d", station_info->plid);
859 if (sinfo[NL80211_STA_INFO_PLINK_STATE]) {
860 station_info->mesh_plink =
861 nla_get_u8(sinfo[NL80211_STA_INFO_PLINK_STATE]);
862 switch (station_info->mesh_plink) {
864 snprintf(state_name, 10, "%s", "LISTEN");
867 snprintf(state_name, 10, "%s", "OPN_SNT");
870 snprintf(state_name, 10, "%s", "OPN_RCVD");
873 snprintf(state_name, 10, "%s", "CNF_RCVD");
876 snprintf(state_name, 10, "%s", "ESTAB");
879 snprintf(state_name, 10, "%s", "HOLDING");
882 snprintf(state_name, 10, "%s", "BLOCKED");
885 snprintf(state_name, 10, "%s", "UNKNOWN");
888 MESH_LOGD(" mesh plink:\t%s", state_name);
890 if (sinfo[NL80211_STA_INFO_LOCAL_PM]) {
891 station_info->local_ps_mode =
892 nla_get_u32(sinfo[NL80211_STA_INFO_LOCAL_PM]);
893 MESH_LOGD(" mesh local PS mode:\t");
894 print_power_mode(sinfo[NL80211_STA_INFO_LOCAL_PM]);
896 if (sinfo[NL80211_STA_INFO_PEER_PM]) {
897 station_info->peer_ps_mode =
898 nla_get_u32(sinfo[NL80211_STA_INFO_PEER_PM]);
899 MESH_LOGD(" mesh peer PS mode:\t");
900 print_power_mode(sinfo[NL80211_STA_INFO_PEER_PM]);
902 if (sinfo[NL80211_STA_INFO_NONPEER_PM]) {
903 station_info->non_peer_ps_mode =
904 nla_get_u32(sinfo[NL80211_STA_INFO_NONPEER_PM]);
905 MESH_LOGD(" mesh non-peer PS mode:\t");
906 print_power_mode(sinfo[NL80211_STA_INFO_NONPEER_PM]);
909 if (sinfo[NL80211_STA_INFO_STA_FLAGS]) {
910 sta_flags = (struct nl80211_sta_flag_update *)
911 nla_data(sinfo[NL80211_STA_INFO_STA_FLAGS]);
913 if (sta_flags->mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
914 MESH_LOGD(" authorized:");
915 if (sta_flags->set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
917 station_info->authorized = TRUE;
920 station_info->authorized = FALSE;
924 if (sta_flags->mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
925 MESH_LOGD(" authenticated:");
926 if (sta_flags->set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
928 station_info->authenticated = TRUE;
931 station_info->authenticated = FALSE;
935 if (sta_flags->mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
936 MESH_LOGD(" associated:");
937 if (sta_flags->set & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
939 station_info->associated = TRUE;
942 station_info->associated = FALSE;
946 if (sta_flags->mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
947 MESH_LOGD(" preamble:");
948 if (sta_flags->set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
950 station_info->preamble = TRUE;
953 station_info->preamble = FALSE;
957 if (sta_flags->mask & BIT(NL80211_STA_FLAG_WME)) {
958 MESH_LOGD(" WMM/WME:");
959 if (sta_flags->set & BIT(NL80211_STA_FLAG_WME)) {
961 station_info->wme = TRUE;
964 station_info->wme = FALSE;
968 if (sta_flags->mask & BIT(NL80211_STA_FLAG_MFP)) {
970 if (sta_flags->set & BIT(NL80211_STA_FLAG_MFP)) {
972 station_info->mfp = TRUE;
975 station_info->mfp = FALSE;
979 if (sta_flags->mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
980 MESH_LOGD(" TDLS peer:");
981 if (sta_flags->set & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
983 station_info->tdls_peer = TRUE;
986 station_info->tdls_peer = FALSE;
991 if (sinfo[NL80211_STA_INFO_BSS_PARAM])
992 parse_bss_param(sinfo[NL80211_STA_INFO_BSS_PARAM], station_info);
993 if (sinfo[NL80211_STA_INFO_CONNECTED_TIME]) {
994 station_info->connected_time =
995 nla_get_u32(sinfo[NL80211_STA_INFO_CONNECTED_TIME]);
996 MESH_LOGD(" connected time:\t%u seconds", station_info->connected_time);
1000 *(state->station_list) = g_list_prepend(*(state->station_list), station_info);
1005 static int _on_receive_mpath_info(struct nl_msg *msg, void *arg)
1007 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1008 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1009 struct nlattr *pinfo[NL80211_MPATH_INFO_MAX + 1];
1010 char dst[20], next_hop[20], dev[20];
1011 static struct nla_policy mpath_policy[NL80211_MPATH_INFO_MAX + 1] = {
1012 [NL80211_MPATH_INFO_FRAME_QLEN] = { .type = NLA_U32 },
1013 [NL80211_MPATH_INFO_SN] = { .type = NLA_U32 },
1014 [NL80211_MPATH_INFO_METRIC] = { .type = NLA_U32 },
1015 [NL80211_MPATH_INFO_EXPTIME] = { .type = NLA_U32 },
1016 [NL80211_MPATH_INFO_DISCOVERY_TIMEOUT] = { .type = NLA_U32 },
1017 [NL80211_MPATH_INFO_DISCOVERY_RETRIES] = { .type = NLA_U8 },
1018 [NL80211_MPATH_INFO_FLAGS] = { .type = NLA_U8 },
1021 mesh_nl_state *state = (mesh_nl_state *)arg;
1022 mesh_mpath_info_s *mpath_info = NULL;
1024 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1025 genlmsg_attrlen(gnlh, 0), NULL);
1028 * TODO: validate the interface and mac address!
1029 * Otherwise, there's a race condition as soon as
1030 * the kernel starts sending mpath notifications.
1033 if (!tb[NL80211_ATTR_MPATH_INFO]) {
1034 MESH_LOGE("missing mesh path info!");
1037 if (nla_parse_nested(pinfo, NL80211_MPATH_INFO_MAX,
1038 tb[NL80211_ATTR_MPATH_INFO],
1040 MESH_LOGE("failed to parse nested attributes!");
1044 mpath_info = g_try_new0(mesh_mpath_info_s, 1);
1045 if (NULL == mpath_info) {
1046 MESH_LOGE("Failed to allocate mesh path info !");
1050 mac_addr_n2a(dst, nla_data(tb[NL80211_ATTR_MAC]));
1051 mpath_info->dest_addr = g_strdup(dst);
1052 MESH_LOGD("Destination Address : %s", mpath_info->dest_addr);
1054 mac_addr_n2a(next_hop, nla_data(tb[NL80211_ATTR_MPATH_NEXT_HOP]));
1055 mpath_info->next_hop = g_strdup(next_hop);
1056 MESH_LOGD("Next hop Address : %s", mpath_info->next_hop);
1058 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
1059 mpath_info->interface = g_strdup(dev);
1060 MESH_LOGD("Interface : %s", mpath_info->interface);
1062 if (pinfo[NL80211_MPATH_INFO_SN]) {
1063 mpath_info->sn = nla_get_u32(pinfo[NL80211_MPATH_INFO_SN]);
1064 MESH_LOGD("SN : %u", mpath_info->sn);
1066 if (pinfo[NL80211_MPATH_INFO_METRIC]) {
1067 mpath_info->metric = nla_get_u32(pinfo[NL80211_MPATH_INFO_METRIC]);
1068 MESH_LOGD("Metric : %u", mpath_info->metric);
1070 if (pinfo[NL80211_MPATH_INFO_FRAME_QLEN]) {
1071 mpath_info->qlen = nla_get_u32(pinfo[NL80211_MPATH_INFO_FRAME_QLEN]);
1072 MESH_LOGD("QLEN : %u", mpath_info->qlen);
1074 if (pinfo[NL80211_MPATH_INFO_EXPTIME]) {
1075 mpath_info->exptime = nla_get_u32(pinfo[NL80211_MPATH_INFO_EXPTIME]);
1076 MESH_LOGD("ExpTime : %u", mpath_info->exptime);
1078 if (pinfo[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT]) {
1079 mpath_info->discovery_timeout =
1080 nla_get_u32(pinfo[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT]);
1081 MESH_LOGD("Discovery Timeout : %u", mpath_info->discovery_timeout);
1083 if (pinfo[NL80211_MPATH_INFO_DISCOVERY_RETRIES]) {
1084 mpath_info->discovery_retries =
1085 nla_get_u8(pinfo[NL80211_MPATH_INFO_DISCOVERY_RETRIES]);
1086 MESH_LOGD("Discovery Retries : %u", mpath_info->discovery_retries);
1088 if (pinfo[NL80211_MPATH_INFO_FLAGS]) {
1089 mpath_info->flags = nla_get_u8(pinfo[NL80211_MPATH_INFO_FLAGS]);
1090 MESH_LOGD("Flags : 0x%x", mpath_info->flags);
1094 *(state->mpath_list) = g_list_prepend(*(state->mpath_list), mpath_info);
1099 static int _on_receive_mesh_event(struct nl_msg *msg, void *arg)
1101 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1102 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1103 char ifname[16] = { 0, };
1104 char macbuf[MAX_MAC_ADDR_LEN];
1108 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
1110 if (tb[NL80211_ATTR_IFINDEX]) {
1111 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
1112 MESH_LOGD("%s: ", ifname);
1115 switch (gnlh->cmd) {
1116 case NL80211_CMD_NEW_STATION:
1117 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1118 MESH_LOGD("[%s] new station [%s]", ifname, macbuf);
1120 case NL80211_CMD_DEL_STATION:
1121 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1122 MESH_LOGD("[%s] del station [%s]", ifname, macbuf);
1124 case NL80211_CMD_NEW_MPATH:
1125 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1126 MESH_LOGD("[%s] new mpath [%s]", ifname, macbuf);
1128 mesh_notify_station_joined((const char*)macbuf);
1130 case NL80211_CMD_DEL_MPATH:
1131 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1132 MESH_LOGD("[%s] del mpath [%s]", ifname, macbuf);
1134 mesh_notify_station_left((const char*)macbuf);
1137 MESH_LOGD("event [%d] is not handled", gnlh->cmd);
1144 static int _send_nl_set_mesh_parameter(const char* mesh_if_name,
1145 const char* param_name, unsigned int value)
1147 mesh_nl_state state = {
1149 .callback_state = MESH_NL_CALLBACK_TRYING,
1155 .error_occured = FALSE,
1157 struct nlattr *container;
1159 int err = MESHD_ERROR_NONE;
1160 int device_index = 0;
1164 ret = __initialize_nl80211(&state);
1165 if (MESHD_ERROR_NONE != ret) {
1166 MESH_LOGE("Failed to initialize nl80211");
1170 ret = __initialize_netlink_message(&state);
1171 if (MESHD_ERROR_NONE != ret) {
1172 MESH_LOGE("Failed to initialize netlink message");
1176 /* Set command into message */
1177 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1178 0, NL80211_CMD_SET_MESH_PARAMS, 0);
1180 /* Add attributes into message */
1181 ret = __get_device_index_from_string(mesh_if_name, &device_index);
1182 if (MESHD_ERROR_NONE != ret) {
1183 MESH_LOGE("Failed to get mesh device index");
1187 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1189 container = nla_nest_start(state.msg, NL80211_ATTR_MESH_PARAMS);
1191 MESH_LOGE("Failed to initialize netlink message");
1195 /* Logic need to be changed if additional parameter is required */
1196 if (g_strcmp0(MESH_PARAM_HWMP_ROOTMODE, param_name) == 0) {
1197 MESH_LOGD(" [mesh_hwmp_rootmode] : [%d]", value);
1198 NLA_PUT_U8(state.msg, NL80211_MESHCONF_HWMP_ROOTMODE,
1200 } else if (g_strcmp0(MESH_PARAM_GATE_ANNOUNCE, param_name) == 0) {
1201 MESH_LOGD(" [mesh_gate_announcements] : [%d]", value);
1202 NLA_PUT_U8(state.msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
1205 MESH_LOGE("Parameter [%s] is not required !", param_name);
1206 nla_nest_end(state.msg, container);
1209 nla_nest_end(state.msg, container);
1211 /* Send message into kernel */
1212 ret = nl_send_auto(state.nl_socket, state.msg);
1214 MESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1215 nl_geterror(ret), ret);
1216 err = MESHD_ERROR_OPERATION_FAILED;
1221 state.callback_state = MESH_NL_CALLBACK_TRYING;
1222 while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1223 MESH_LOGD(" count [%02d]", ++test);
1224 nl_recvmsgs(state.nl_socket, state.cb);
1228 __clean_netlink_message(&state);
1229 __clean_nl80211(&state);
1234 MESH_LOGE("Failed to message build");
1235 __clean_netlink_message(&state);
1236 __clean_nl80211(&state);
1238 return MESHD_ERROR_OPERATION_FAILED;
1241 static int _send_nl_get_station_info(const char* if_name, GList **station_list)
1243 mesh_nl_state state = {
1245 .callback_state = MESH_NL_CALLBACK_TRYING,
1251 .station_list = station_list
1253 int err = MESHD_ERROR_NONE;
1254 int device_index = 0;
1258 ret = __initialize_nl80211(&state);
1259 if (MESHD_ERROR_NONE != ret) {
1260 MESH_LOGE("Failed to initialize nl80211");
1264 ret = __initialize_netlink_message(&state);
1265 if (MESHD_ERROR_NONE != ret) {
1266 MESH_LOGE("Failed to initialize netlink message");
1270 /* Set command into message */
1271 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1272 NLM_F_DUMP, NL80211_CMD_GET_STATION, 0);
1274 /* Add attributes into message */
1275 MESH_LOGD("Dump station list with interface [%s]", if_name);
1276 ret = __get_device_index_from_string(if_name, &device_index);
1277 if (MESHD_ERROR_NONE != ret) {
1278 MESH_LOGE("Failed to get mesh interface device index");
1282 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1284 /* Register valid callback to dump result */
1285 nl_cb_set(state.cb, NL_CB_VALID, NL_CB_CUSTOM,
1286 _on_receive_station_info, &state);
1288 /* Send message into kernel */
1289 ret = nl_send_auto(state.nl_socket, state.msg);
1291 MESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1292 nl_geterror(ret), ret);
1293 err = MESHD_ERROR_OPERATION_FAILED;
1298 state.callback_state = MESH_NL_CALLBACK_TRYING;
1299 while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1300 MESH_LOGD(" count [%02d]", ++test);
1301 nl_recvmsgs(state.nl_socket, state.cb);
1303 MESH_LOGD("Finished");
1306 __clean_netlink_message(&state);
1307 __clean_nl80211(&state);
1312 MESH_LOGE("Failed to message build");
1313 __clean_netlink_message(&state);
1314 __clean_nl80211(&state);
1316 return MESHD_ERROR_OPERATION_FAILED;
1319 static int _send_nl_del_station_info(const char* if_name, char* peer)
1321 mesh_nl_state state = {
1323 .callback_state = MESH_NL_CALLBACK_FINISHED,
1329 .station_list = NULL,
1331 int err = MESHD_ERROR_NONE;
1332 int device_index = 0;
1335 ret = __initialize_nl80211(&state);
1336 if (MESHD_ERROR_NONE != ret) {
1337 MESH_LOGE("Failed to initialize nl80211");
1341 ret = __initialize_netlink_message(&state);
1342 if (MESHD_ERROR_NONE != ret) {
1343 MESH_LOGE("Failed to initialize netlink message");
1347 /* Set command into message */
1348 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1349 NLM_F_DUMP, NL80211_CMD_DEL_STATION, 0);
1351 /* Add attributes into message */
1352 MESH_LOGD("Delete a station [%s] with interface [%s]", peer, if_name);
1353 ret = __get_device_index_from_string(if_name, &device_index);
1354 if (MESHD_ERROR_NONE != ret) {
1355 MESH_LOGE("Failed to get mesh interface device index");
1359 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1360 NLA_PUT(state.msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
1362 /* Send message into kernel */
1363 ret = nl_send_auto(state.nl_socket, state.msg);
1365 MESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1366 nl_geterror(ret), ret);
1367 err = MESHD_ERROR_OPERATION_FAILED;
1372 __clean_netlink_message(&state);
1373 __clean_nl80211(&state);
1378 MESH_LOGE("Failed to message build");
1379 __clean_netlink_message(&state);
1380 __clean_nl80211(&state);
1382 return MESHD_ERROR_OPERATION_FAILED;
1385 static int _send_nl_get_mpath_info(const char* if_name, GList **mpath_list)
1387 mesh_nl_state state = {
1389 .callback_state = MESH_NL_CALLBACK_TRYING,
1395 .mpath_list = mpath_list
1397 int err = MESHD_ERROR_NONE;
1398 int device_index = 0;
1402 ret = __initialize_nl80211(&state);
1403 if (MESHD_ERROR_NONE != ret) {
1404 MESH_LOGE("Failed to initialize nl80211");
1408 ret = __initialize_netlink_message(&state);
1409 if (MESHD_ERROR_NONE != ret) {
1410 MESH_LOGE("Failed to initialize netlink message");
1414 /* Set command into message */
1415 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1416 NLM_F_DUMP, NL80211_CMD_GET_MPATH, 0);
1418 /* Add attributes into message */
1419 MESH_LOGD("Dump station list with interface [%s]", if_name);
1420 ret = __get_device_index_from_string(if_name, &device_index);
1421 if (MESHD_ERROR_NONE != ret) {
1422 MESH_LOGE("Failed to get mesh interface device index");
1426 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1428 /* Register valid callback to dump result */
1429 nl_cb_set(state.cb, NL_CB_VALID, NL_CB_CUSTOM,
1430 _on_receive_mpath_info, &state);
1432 /* Send message into kernel */
1433 ret = nl_send_auto(state.nl_socket, state.msg);
1435 MESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1436 nl_geterror(ret), ret);
1437 err = MESHD_ERROR_OPERATION_FAILED;
1442 state.callback_state = MESH_NL_CALLBACK_TRYING;
1443 while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1444 MESH_LOGD(" count [%02d]", ++test);
1445 nl_recvmsgs(state.nl_socket, state.cb);
1447 MESH_LOGD("Finished");
1450 __clean_netlink_message(&state);
1451 __clean_nl80211(&state);
1456 MESH_LOGE("Failed to message build");
1457 __clean_netlink_message(&state);
1458 __clean_nl80211(&state);
1460 return MESHD_ERROR_OPERATION_FAILED;
1463 static int _send_nl_register_event_handler()
1465 int err = MESHD_ERROR_NONE;
1467 GIOChannel *recv_channel = NULL;
1470 MESH_LOGE("Already event handler registered !");
1471 return MESHD_ERROR_IN_PROGRESS;
1474 event_state = _create_mesh_nl_state("");
1476 ret = __initialize_nl80211(event_state);
1477 if (MESHD_ERROR_NONE != ret) {
1478 MESH_LOGE("Failed to initialize nl80211");
1482 /* Subscribe multicast group should be proceed before scanning */
1483 ret = __prepare_listen_events(event_state);
1485 MESH_LOGE("__prepare_listen_events : [%d]", ret);
1489 ret = __initialize_netlink_message(event_state);
1490 if (MESHD_ERROR_NONE != ret) {
1491 MESH_LOGE("Failed to initialize netlink message");
1495 /* Set command into message */
1496 genlmsg_put(event_state->msg, 0, 0, event_state->nl80211_id, 0, 0, 0, 0);
1498 /* Set callbacks for event handler */
1499 nl_cb_set(event_state->cb, NL_CB_VALID, NL_CB_CUSTOM,
1500 _on_receive_mesh_event, event_state);
1501 /* No sequence checking for multicast messages. */
1502 nl_cb_set(event_state->cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
1504 MESH_LOGD("Register event handler");
1506 /* Change socket type to non-blocking */
1507 ret = nl_socket_set_nonblocking(event_state->nl_socket);
1509 MESH_LOGE("Failed to non-blocking socket [%s](%d)", nl_geterror(ret), ret);
1511 /* Register I/O callback to wait asynchronously */
1512 if (FALSE == event_state->error_occured) {
1513 recv_channel = g_io_channel_unix_new(nl_socket_get_fd(event_state->nl_socket));
1514 event_state->event_source = g_io_add_watch(recv_channel,
1515 (G_IO_IN | G_IO_ERR), _on_socket_event_io_received, event_state);
1516 g_io_channel_unref(recv_channel);
1518 MESH_LOGE("Error responded. Failed to register event callback !!");
1522 /* Resource should be free on I/O callback */
1523 return MESHD_ERROR_NONE;
1526 __clean_netlink_message(event_state);
1527 __clean_nl80211(event_state);
1528 _delete_mesh_nl_state(&event_state);
1533 int mesh_netlink_set_mesh_parameter(const char* mesh_if_name,
1534 const char* param_name, unsigned int value)
1536 int ret = MESHD_ERROR_NONE;
1538 if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1539 MESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1540 return MESHD_ERROR_INVALID_PARAMETER;
1543 MESH_LOGD("Set mesh[%s] param [%s] value [%d]",
1544 mesh_if_name, param_name, value);
1545 ret = _send_nl_set_mesh_parameter(mesh_if_name, param_name, value);
1550 int mesh_netlink_get_station_info(const char* mesh_if_name, GList **station_list)
1552 int ret = MESHD_ERROR_NONE;
1554 if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1555 MESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1556 return MESHD_ERROR_INVALID_PARAMETER;
1558 if (NULL == station_list) {
1559 MESH_LOGE("Invalid parameter [%p]", station_list);
1560 return MESHD_ERROR_INVALID_PARAMETER;
1563 MESH_LOGD("Get connected stations");
1564 ret = _send_nl_get_station_info(mesh_if_name, station_list);
1569 int mesh_netlink_del_station_info(const char* mesh_if_name, char *peer)
1571 int ret = MESHD_ERROR_NONE;
1573 if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1574 MESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1575 return MESHD_ERROR_INVALID_PARAMETER;
1578 MESH_LOGE("Invalid parameter [%p]", peer);
1579 return MESHD_ERROR_INVALID_PARAMETER;
1582 MESH_LOGD("Del connected station : [%s]", peer);
1583 ret = _send_nl_del_station_info(mesh_if_name, peer);
1588 int mesh_netlink_get_mpath_info(const char* mesh_if_name, GList **mpath_list)
1590 int ret = MESHD_ERROR_NONE;
1592 if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1593 MESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1594 return MESHD_ERROR_INVALID_PARAMETER;
1596 if (NULL == mpath_list) {
1597 MESH_LOGE("Invalid parameter [%p]", mpath_list);
1598 return MESHD_ERROR_INVALID_PARAMETER;
1601 MESH_LOGD("Get current mpath info");
1602 ret = _send_nl_get_mpath_info(mesh_if_name, mpath_list);
1607 int mesh_netlink_register_event_handler()
1609 int ret = MESHD_ERROR_NONE;
1611 MESH_LOGD("Register mesh event handler");
1612 ret = _send_nl_register_event_handler();
1617 int mesh_netlink_unregister_event_handler()
1619 int ret = MESHD_ERROR_NONE;
1621 MESH_LOGD("Unregister mesh event handler");
1623 _on_remove_event_io_handler();