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 WMESH_LOGE("Failed to allocate netlink socket.");
110 return WMESHD_ERROR_OUT_OF_MEMORY;
113 if (genl_connect(state->nl_socket)) {
114 WMESH_LOGE("Failed to connect to generic netlink.");
115 err = WMESHD_ERROR_OPERATION_FAILED;
119 nl_socket_set_buffer_size(state->nl_socket, 8192, 8192);
121 state->nl80211_id = genl_ctrl_resolve(state->nl_socket, "nl80211");
122 if (state->nl80211_id < 0) {
123 WMESH_LOGE("nl80211 not found.");
124 err = WMESHD_ERROR_NO_DATA;
131 nl_socket_free(state->nl_socket);
135 static void __clean_nl80211(mesh_nl_state *state)
140 if (state->nl_socket) {
141 nl_socket_free(state->nl_socket);
142 state->nl_socket = NULL;
143 state->nl80211_id = -1;
147 static int __get_device_index_from_string(const char* if_name, int *index)
149 int device_index = 0;
151 if (NULL == if_name) {
152 WMESH_LOGE("Invalid parameter");
153 return WMESHD_ERROR_INVALID_PARAMETER;
156 device_index = if_nametoindex(if_name);
157 if (device_index == 0) {
158 WMESH_LOGE("No interface index found [%s]", if_name);
159 return WMESHD_ERROR_NO_DATA;
161 *index = device_index;
163 return WMESHD_ERROR_NONE;
166 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
168 mesh_nl_state *state = (mesh_nl_state *)arg;
169 char buf[256] = { 0, };
173 state->callback_state = MESH_NL_CALLBACK_FINISHED;
174 state->error_occured = TRUE;
175 strerror_r(err->error, buf, 255);
177 WMESH_LOGD("error_handler");
178 WMESH_LOGE(" %s (%d)", buf, err->error);
183 static int finish_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 WMESH_LOGD("finish_handler");
195 static int ack_handler(struct nl_msg *msg, void *arg)
197 mesh_nl_state *state = (mesh_nl_state *)arg;
199 state->callback_state = MESH_NL_CALLBACK_FINISHED;
201 WMESH_LOGD("ack_handler");
207 static int ack_simple_handler(struct nl_msg *msg, void *arg)
214 WMESH_LOGD("ack_simple_handler");
219 static int family_handler(struct nl_msg *msg, void *arg)
221 multicast_group_id_args *group = (multicast_group_id_args *)arg;
222 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
223 struct nlattr *tb[CTRL_ATTR_MAX + 1];
224 struct nlattr *mcast_group;
227 WMESH_LOGD("family_handler");
229 nla_parse(tb, CTRL_ATTR_MAX,
230 genlmsg_attrdata(gnlh, 0),
231 genlmsg_attrlen(gnlh, 0), NULL);
232 if (!tb[CTRL_ATTR_MCAST_GROUPS])
235 nla_for_each_nested(mcast_group, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcast_group) {
236 struct nlattr *tb_mcast_group[CTRL_ATTR_MCAST_GRP_MAX + 1];
238 nla_parse(tb_mcast_group, CTRL_ATTR_MCAST_GRP_MAX,
239 nla_data(mcast_group), nla_len(mcast_group), NULL);
241 if (!tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME] ||
242 !tb_mcast_group[CTRL_ATTR_MCAST_GRP_ID])
245 if (strncmp(nla_data(tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME]),
247 nla_len(tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME])))
250 group->id = nla_get_u32(tb_mcast_group[CTRL_ATTR_MCAST_GRP_ID]);
251 WMESH_LOGD("mcast group id [%d]", group->id);
258 static int __nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group)
263 multicast_group_id_args group_args = {
272 cb = nl_cb_alloc(NL_CB_DEFAULT);
278 ctrlid = genl_ctrl_resolve(sock, "nlctrl");
280 genlmsg_put(msg, 0, 0, ctrlid, 0,
281 0, CTRL_CMD_GETFAMILY, 0);
284 NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
286 ret = nl_send_auto(sock, msg);
288 WMESH_LOGE("Failed to nl_send_auto");
293 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
294 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_simple_handler, &ret);
295 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, family_handler, &group_args);
298 nl_recvmsgs(sock, cb);
303 WMESH_LOGD("mcid : [%d]", ret);
314 static int __prepare_listen_events(mesh_nl_state *state)
318 /* Configuration multicast group */
319 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "config");
321 WMESH_LOGE("Failed to get nl80211 config");
324 WMESH_LOGD("Mesh multicast id (config): [%d]", mcid);
326 ret = nl_socket_add_membership(state->nl_socket, mcid);
328 WMESH_LOGE("Failed to nl_socket_add_membership");
332 /* Scan multicast group */
333 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "scan");
335 ret = nl_socket_add_membership(state->nl_socket, mcid);
337 WMESH_LOGE("Failed to nl_socket_add_membership");
341 WMESH_LOGD("Mesh multicast id (scan): [%d]", mcid);
343 /* Regulatory multicast group */
344 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "regulatory");
346 ret = nl_socket_add_membership(state->nl_socket, mcid);
348 WMESH_LOGE("Failed to nl_socket_add_membership");
352 WMESH_LOGD("Mesh multicast id (regulatory): [%d]", mcid);
354 /* MLME multicast group */
355 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "mlme");
357 ret = nl_socket_add_membership(state->nl_socket, mcid);
359 WMESH_LOGE("Failed to nl_socket_add_membership");
363 WMESH_LOGD("Mesh multicast id (mlme): [%d]", mcid);
365 mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "vendor");
367 ret = nl_socket_add_membership(state->nl_socket, mcid);
369 WMESH_LOGE("Failed to nl_socket_add_membership");
373 WMESH_LOGD("Mesh multicast id (vendor): [%d]", mcid);
378 static mesh_nl_state *_create_mesh_nl_state()
380 mesh_nl_state *state = g_new0(mesh_nl_state, 1);
382 state->nl80211_id = -1;
383 state->callback_state = MESH_NL_CALLBACK_TRYING;
384 state->error_occured = FALSE;
389 static void _delete_mesh_nl_state(mesh_nl_state **state)
391 if (NULL == state || NULL == *state)
398 static int valid_handler(struct nl_msg *msg, void *arg)
400 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
401 mesh_nl_state *state = (mesh_nl_state *)arg;
402 WMESH_LOGD("valid_handler");
404 if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) {
405 WMESH_LOGD(" Got NL80211_CMD_SCAN_ABORTED.");
406 state->callback_state = MESH_NL_CALLBACK_FINISHED;
408 /* Notify scan done status */
409 wmesh_notify_scan_done();
410 } else if (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
411 WMESH_LOGD(" Got NL80211_CMD_NEW_SCAN_RESULTS.");
412 state->callback_state = MESH_NL_CALLBACK_FINISHED;
414 /* Notify scan done status */
415 wmesh_notify_scan_done();
417 WMESH_LOGD(" Got [%d]", gnlh->cmd);
423 static int no_seq_check(struct nl_msg *msg, void *arg)
431 static void __clean_netlink_message(mesh_nl_state *state)
437 nl_cb_put(state->cb);
439 nl_cb_put(state->s_cb);
441 nlmsg_free(state->msg);
447 WMESH_LOGD("message and callback cleaned");
450 static int __initialize_netlink_message(mesh_nl_state *state)
452 int err = WMESHD_ERROR_NONE;
455 WMESH_LOGE("Invalid parameter !");
456 return WMESHD_ERROR_INVALID_PARAMETER;
459 /* Create netlink message */
460 state->msg = nlmsg_alloc();
461 if (NULL == state->msg) {
462 WMESH_LOGE("Failed to allocate netlink message");
463 return WMESHD_ERROR_OUT_OF_MEMORY;
467 state->cb = nl_cb_alloc(NL_CB_DEFAULT);
468 state->s_cb = nl_cb_alloc(NL_CB_DEFAULT);
470 WMESH_LOGE("Failed to allocate netlink callback");
471 err = WMESHD_ERROR_OUT_OF_MEMORY;
475 /* Set socket callback */
476 nl_socket_set_cb(state->nl_socket, state->s_cb);
479 nl_cb_err(state->cb, NL_CB_CUSTOM, error_handler, state);
480 nl_cb_set(state->cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, state);
481 nl_cb_set(state->cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, state);
482 nl_cb_set(state->cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, state);
484 WMESH_LOGD("netlink socket initialized");
486 return WMESHD_ERROR_NONE;
489 __clean_netlink_message(state);
494 static gboolean _on_socket_event_io_received(GIOChannel *source,
495 GIOCondition condition, gpointer data)
497 mesh_nl_state *state = (mesh_nl_state *)data;
503 WMESH_LOGD("[Event] I/O received");
505 while (nl_recvmsgs_report(state->nl_socket, state->cb) > 0)
506 WMESH_LOGD(" count [%02d]", ++test);
508 /* Do not remove I/O source */
512 static void _on_remove_event_io_handler()
515 g_source_remove(event_state->event_source);
517 __clean_netlink_message(event_state);
518 __clean_nl80211(event_state);
519 _delete_mesh_nl_state(&event_state);
523 static void mac_addr_n2a(char *mac_addr, unsigned char *arg)
525 /* 11:22:33:44:55:66 (Len:17) */
526 snprintf(mac_addr, MAX_MAC_ADDR_LEN,
527 "%02x:%02x:%02x:%02x:%02x:%02x",
528 arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
530 #if defined(NL80211_STA_INFO_CHAIN_SIGNAL) || defined(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)
531 static char *get_chain_signal(struct nlattr *attr_list)
542 nla_for_each_nested(attr, attr_list, rem) {
548 cur += snprintf(cur, sizeof(buf) - (cur - buf), "%s%d", prefix,
549 (int8_t) nla_get_u8(attr));
553 snprintf(cur, sizeof(buf) - (cur - buf), "] ");
557 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL || NL80211_STA_INFO_CHAIN_SIGNAL_AVG */
559 static int parse_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen)
563 char str_rate[32] = { 0, };
564 char str_buf[128] = { 0, };
565 struct nlattr *rate_info[NL80211_RATE_INFO_MAX + 1];
566 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
567 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
568 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
569 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
570 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
571 [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 },
574 if (nla_parse_nested(rate_info, NL80211_RATE_INFO_MAX, bitrate_attr, rate_policy)) {
576 snprintf(buf, buflen, "failed to parse nested rate attributes!");
580 if (rate_info[NL80211_RATE_INFO_MCS])
581 pos += snprintf(str_buf + pos, 128 - pos,
582 " MCS %d", nla_get_u8(rate_info[NL80211_RATE_INFO_MCS]));
583 if (rate_info[NL80211_RATE_INFO_40_MHZ_WIDTH])
584 pos += snprintf(str_buf + pos, 128 - pos, " 40MHz");
585 if (rate_info[NL80211_RATE_INFO_SHORT_GI])
586 pos += snprintf(str_buf + pos, 128 - pos, " short GI");
587 if (rate_info[NL80211_RATE_INFO_VHT_MCS])
588 pos += snprintf(str_buf + pos, 128 - pos,
589 " VHT-MCS %d", nla_get_u8(rate_info[NL80211_RATE_INFO_VHT_MCS]));
590 if (rate_info[NL80211_RATE_INFO_VHT_NSS])
591 pos += snprintf(str_buf + pos, 128 - pos,
592 " VHT-NSS %d", nla_get_u8(rate_info[NL80211_RATE_INFO_VHT_NSS]));
593 if (rate_info[NL80211_RATE_INFO_80_MHZ_WIDTH])
594 pos += snprintf(str_buf + pos, 128 - pos, " 80MHz");
595 if (rate_info[NL80211_RATE_INFO_80P80_MHZ_WIDTH])
596 pos += snprintf(str_buf + pos, 128 - pos, " 80P80MHz");
597 if (rate_info[NL80211_RATE_INFO_160_MHZ_WIDTH])
598 pos += snprintf(str_buf + pos, 128 - pos, " 160MHz");
600 if (rate_info[NL80211_RATE_INFO_BITRATE32])
601 rate = nla_get_u32(rate_info[NL80211_RATE_INFO_BITRATE32]);
602 else if (rate_info[NL80211_RATE_INFO_BITRATE])
603 rate = nla_get_u16(rate_info[NL80211_RATE_INFO_BITRATE]);
605 snprintf(str_rate, 32, "%d.%d MBit/s", rate / 10, rate % 10);
608 snprintf(buf, buflen, "%s%s", str_rate, str_buf);
613 static void parse_bss_param(struct nlattr *bss_param_attr, wmesh_station_info_s *station_info)
615 struct nlattr *bss_param_info[NL80211_STA_BSS_PARAM_MAX + 1], *info;
616 static struct nla_policy bss_poilcy[NL80211_STA_BSS_PARAM_MAX + 1] = {
617 [NL80211_STA_BSS_PARAM_CTS_PROT] = { .type = NLA_FLAG },
618 [NL80211_STA_BSS_PARAM_SHORT_PREAMBLE] = { .type = NLA_FLAG },
619 [NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME] = { .type = NLA_FLAG },
620 [NL80211_STA_BSS_PARAM_DTIM_PERIOD] = { .type = NLA_U8 },
621 [NL80211_STA_BSS_PARAM_BEACON_INTERVAL] = { .type = NLA_U16 },
624 if (nla_parse_nested(bss_param_info, NL80211_STA_BSS_PARAM_MAX, bss_param_attr, bss_poilcy))
625 WMESH_LOGE("failed to parse nested bss param attributes!");
627 info = bss_param_info[NL80211_STA_BSS_PARAM_DTIM_PERIOD];
629 station_info->dtim_period = nla_get_u8(info);
630 WMESH_LOGD(" DTIM period:\t%u", station_info->dtim_period);
632 info = bss_param_info[NL80211_STA_BSS_PARAM_BEACON_INTERVAL];
634 station_info->beacon_interval = nla_get_u16(info);
635 WMESH_LOGD(" beacon interval:%u", station_info->beacon_interval);
637 info = bss_param_info[NL80211_STA_BSS_PARAM_CTS_PROT];
639 WMESH_LOGD(" CTS protection:");
640 if (nla_get_u16(info)) {
642 station_info->cts_protection = TRUE;
645 station_info->cts_protection = FALSE;
648 info = bss_param_info[NL80211_STA_BSS_PARAM_SHORT_PREAMBLE];
650 WMESH_LOGD(" short preamble:");
651 if (nla_get_u16(info)) {
653 station_info->short_preamble = TRUE;
656 station_info->short_preamble = FALSE;
659 info = bss_param_info[NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME];
661 WMESH_LOGD(" short slot time:");
662 if (nla_get_u16(info)) {
664 station_info->short_slot_time = TRUE;
667 station_info->short_slot_time = FALSE;
672 static void print_power_mode(struct nlattr *a)
674 enum nl80211_mesh_power_mode pm = nla_get_u32(a);
677 case NL80211_MESH_POWER_ACTIVE:
678 WMESH_LOGD("ACTIVE");
680 case NL80211_MESH_POWER_LIGHT_SLEEP:
681 WMESH_LOGD("LIGHT SLEEP");
683 case NL80211_MESH_POWER_DEEP_SLEEP:
684 WMESH_LOGD("DEEP SLEEP");
687 WMESH_LOGD("UNKNOWN");
692 static int _on_receive_station_info(struct nl_msg *msg, void *arg)
694 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
695 struct nlattr *sta_info[NL80211_STA_INFO_MAX + 1];
696 struct nlattr *attr_info[NL80211_ATTR_MAX + 1];
697 struct nl80211_sta_flag_update *sta_flags;
698 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
699 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
700 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
701 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
702 [NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
703 [NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
704 [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
705 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
706 [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
707 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
708 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
709 [NL80211_STA_INFO_TX_RETRIES] = { .type = NLA_U32 },
710 [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
711 [NL80211_STA_INFO_RX_BITRATE] = { .type = NLA_NESTED },
712 [NL80211_STA_INFO_BSS_PARAM] = { .type = NLA_NESTED },
713 [NL80211_STA_INFO_STA_FLAGS] = { .minlen = sizeof(struct nl80211_sta_flag_update) },
714 [NL80211_STA_INFO_BEACON_LOSS] = { .type = NLA_U32},
715 [NL80211_STA_INFO_T_OFFSET] = { .type = NLA_U64 },
716 [NL80211_STA_INFO_LOCAL_PM] = { .type = NLA_U32 },
717 [NL80211_STA_INFO_PEER_PM] = { .type = NLA_U32 },
718 [NL80211_STA_INFO_NONPEER_PM] = { .type = NLA_U32 },
719 [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
720 [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
721 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL
722 [NL80211_STA_INFO_CHAIN_SIGNAL] = { .type = NLA_NESTED },
723 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL */
725 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL_AVG
726 [NL80211_STA_INFO_CHAIN_SIGNAL_AVG] = { .type = NLA_NESTED },
727 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL_AVG */
729 #ifdef NL80211_STA_INFO_RX_DROP_MISC
730 [NL80211_STA_INFO_RX_DROP_MISC] = { .type = NLA_U64 },
731 #endif /* NL80211_STA_INFO_RX_DROP_MISC */
733 #ifdef NL80211_STA_INFO_RX_DURATION
734 [NL80211_STA_INFO_BEACON_RX] = { .type = NLA_U64 },
735 #endif /* NL80211_STA_INFO_RX_DURATION */
737 #ifdef NL80211_STA_INFO_TID_STATS
738 [NL80211_STA_INFO_TID_STATS] = { .type = NLA_NESTED },
739 #endif /* NL80211_STA_INFO_TID_STATS */
741 #ifdef NL80211_STA_INFO_RX_DURATION
742 [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 },
743 #endif /* NL80211_STA_INFO_RX_DURATION */
745 char mac_addr[MAX_MAC_ADDR_LEN], dev[IF_NAMESIZE];
746 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL
748 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL */
749 char *attr_mac = NULL;
750 mesh_nl_state *state = (mesh_nl_state *)arg;
751 wmesh_station_info_s *station_info = NULL;
753 nla_parse(attr_info, NL80211_ATTR_MAX,
754 genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
756 if (!attr_info[NL80211_ATTR_STA_INFO]) {
757 WMESH_LOGE("[Station] missing station stats !");
761 if (nla_parse_nested(sta_info, NL80211_STA_INFO_MAX,
762 attr_info[NL80211_ATTR_STA_INFO], stats_policy)) {
763 WMESH_LOGE("[Station] Failed to parse nested attributes!");
768 station_info = g_try_new0(wmesh_station_info_s, 1);
769 if (NULL == station_info) {
770 WMESH_LOGE("Failed to allocate station info !");
775 attr_mac = nla_data(attr_info[NL80211_ATTR_MAC]);
776 snprintf(mac_addr, MAX_MAC_ADDR_LEN, "%02x:%02x:%02x:%02x:%02x:%02x",
777 attr_mac[0], attr_mac[1], attr_mac[2],
778 attr_mac[3], attr_mac[4], attr_mac[5]);
779 if_indextoname(nla_get_u32(attr_info[NL80211_ATTR_IFINDEX]), dev);
780 station_info->bssid = g_strdup(mac_addr);
781 WMESH_LOGD("Station %s [dev %s]", station_info->bssid, dev);
784 if (0 != sta_info[NL80211_STA_INFO_INACTIVE_TIME]) {
785 station_info->inactive_time =
786 nla_get_u32(sta_info[NL80211_STA_INFO_INACTIVE_TIME]);
787 WMESH_LOGE(" inactive time:\t%u ms", station_info->inactive_time);
791 if (0 != sta_info[NL80211_STA_INFO_RX_BYTES]) {
792 station_info->rx_bytes =
793 nla_get_u32(sta_info[NL80211_STA_INFO_RX_BYTES]);
794 WMESH_LOGD(" rx bytes:\t%u", station_info->rx_bytes);
795 } else if (0 != sta_info[NL80211_STA_INFO_RX_BYTES64]) {
796 station_info->rx_bytes =
797 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_RX_BYTES64]);
798 WMESH_LOGE(" rx bytes:\t%llu", station_info->rx_bytes);
802 if (0 != sta_info[NL80211_STA_INFO_RX_PACKETS]) {
803 station_info->rx_packets =
804 nla_get_u32(sta_info[NL80211_STA_INFO_RX_PACKETS]);
805 WMESH_LOGD(" rx packets:\t%u", station_info->rx_packets);
809 if (0 != sta_info[NL80211_STA_INFO_TX_BYTES]) {
810 station_info->tx_bytes =
811 nla_get_u32(sta_info[NL80211_STA_INFO_TX_BYTES]);
812 WMESH_LOGD(" tx bytes:\t%u", station_info->tx_bytes);
813 } else if (0 != sta_info[NL80211_STA_INFO_TX_BYTES64]) {
814 station_info->tx_bytes =
815 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_TX_BYTES64]);
816 WMESH_LOGD(" tx bytes:\t%llu", station_info->rx_packets);
820 if (0 != sta_info[NL80211_STA_INFO_LLID]) {
821 station_info->llid = nla_get_u16(sta_info[NL80211_STA_INFO_LLID]);
822 WMESH_LOGD(" mesh llid:\t%d", station_info->llid);
824 if (0 != sta_info[NL80211_STA_INFO_PLID]) {
825 station_info->plid = nla_get_u16(sta_info[NL80211_STA_INFO_PLID]);
826 WMESH_LOGD(" mesh plid:\t%d", station_info->plid);
830 if (0 != sta_info[NL80211_STA_INFO_PLINK_STATE]) {
832 station_info->mesh_plink =
833 nla_get_u8(sta_info[NL80211_STA_INFO_PLINK_STATE]);
834 switch (station_info->mesh_plink) {
836 snprintf(state_name, 10, "%s", "LISTEN");
839 snprintf(state_name, 10, "%s", "OPN_SNT");
842 snprintf(state_name, 10, "%s", "OPN_RCVD");
845 snprintf(state_name, 10, "%s", "CNF_RCVD");
848 snprintf(state_name, 10, "%s", "ESTAB");
851 snprintf(state_name, 10, "%s", "HOLDING");
854 snprintf(state_name, 10, "%s", "BLOCKED");
857 snprintf(state_name, 10, "%s", "UNKNOWN");
860 WMESH_LOGD(" mesh plink:\t%s", state_name);
862 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL
864 chain = get_chain_signal(sta_info[NL80211_STA_INFO_CHAIN_SIGNAL]);
865 if (0 != sta_info[NL80211_STA_INFO_SIGNAL]) {
867 (int8_t)nla_get_u8(sta_info[NL80211_STA_INFO_SIGNAL]);
868 WMESH_LOGD(" signal: \t%d %sdBm", station_info->rssi, chain);
870 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL */
872 if (0 != sta_info[NL80211_STA_INFO_TX_BITRATE]) {
874 station_info->tx_bitrate =
875 parse_bitrate(sta_info[NL80211_STA_INFO_TX_BITRATE], buf, sizeof(buf));
876 WMESH_LOGD(" tx bitrate:\t%s", buf);
879 if (0 != sta_info[NL80211_STA_INFO_TX_PACKETS]) {
880 station_info->tx_packets =
881 nla_get_u32(sta_info[NL80211_STA_INFO_TX_PACKETS]);
882 WMESH_LOGD(" tx packets:\t%u", station_info->tx_packets);
884 if (0 != sta_info[NL80211_STA_INFO_TX_RETRIES]) {
885 station_info->tx_retries =
886 nla_get_u32(sta_info[NL80211_STA_INFO_TX_RETRIES]);
887 WMESH_LOGD(" tx retries:\t%u", station_info->tx_retries);
889 if (0 != sta_info[NL80211_STA_INFO_TX_FAILED]) {
890 station_info->tx_failed =
891 nla_get_u32(sta_info[NL80211_STA_INFO_TX_FAILED]);
892 WMESH_LOGD(" tx failed:\t%u", station_info->tx_failed);
894 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL_AVG
896 chain = get_chain_signal(sta_info[NL80211_STA_INFO_CHAIN_SIGNAL_AVG]);
897 if (0 != sta_info[NL80211_STA_INFO_SIGNAL_AVG]) {
898 station_info->rssi_avg =
899 (int8_t)nla_get_u8(sta_info[NL80211_STA_INFO_SIGNAL_AVG]);
900 WMESH_LOGD(" signal avg:\t%d %sdBm", station_info->rssi_avg, chain);
902 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL_AVG */
903 if (0 != sta_info[NL80211_STA_INFO_RX_BITRATE]) {
905 station_info->rx_bitrate =
906 parse_bitrate(sta_info[NL80211_STA_INFO_RX_BITRATE], buf, sizeof(buf));
907 WMESH_LOGD(" rx bitrate:\t%s", buf);
910 if (0 != sta_info[NL80211_STA_INFO_BSS_PARAM])
911 parse_bss_param(sta_info[NL80211_STA_INFO_BSS_PARAM], station_info);
913 if (0 != sta_info[NL80211_STA_INFO_CONNECTED_TIME]) {
914 station_info->connected_time =
915 nla_get_u32(sta_info[NL80211_STA_INFO_CONNECTED_TIME]);
916 WMESH_LOGD(" connected time:\t%u seconds", station_info->connected_time);
919 if (0 != sta_info[NL80211_STA_INFO_STA_FLAGS]) {
920 sta_flags = (struct nl80211_sta_flag_update *)
921 nla_data(sta_info[NL80211_STA_INFO_STA_FLAGS]);
923 if (sta_flags->mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
924 WMESH_LOGD(" authorized:");
925 if (sta_flags->set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
927 station_info->authorized = TRUE;
930 station_info->authorized = FALSE;
934 if (sta_flags->mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
935 WMESH_LOGD(" authenticated:");
936 if (sta_flags->set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
938 station_info->authenticated = TRUE;
941 station_info->authenticated = FALSE;
945 if (sta_flags->mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
946 WMESH_LOGD(" associated:");
947 if (sta_flags->set & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
949 station_info->associated = TRUE;
952 station_info->associated = FALSE;
956 if (sta_flags->mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
957 WMESH_LOGD(" preamble:");
958 if (sta_flags->set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
959 WMESH_LOGD(" short");
960 station_info->preamble = TRUE;
963 station_info->preamble = FALSE;
967 if (sta_flags->mask & BIT(NL80211_STA_FLAG_WME)) {
968 WMESH_LOGD(" WMM/WME:");
969 if (sta_flags->set & BIT(NL80211_STA_FLAG_WME)) {
971 station_info->wme = TRUE;
974 station_info->wme = FALSE;
978 if (sta_flags->mask & BIT(NL80211_STA_FLAG_MFP)) {
980 if (sta_flags->set & BIT(NL80211_STA_FLAG_MFP)) {
982 station_info->mfp = TRUE;
985 station_info->mfp = FALSE;
989 if (sta_flags->mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
990 WMESH_LOGD(" TDLS peer:");
991 if (sta_flags->set & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
993 station_info->tdls_peer = TRUE;
996 station_info->tdls_peer = FALSE;
1001 if (0 != sta_info[NL80211_STA_INFO_BEACON_LOSS]) {
1002 station_info->beacon_loss =
1003 nla_get_u32(sta_info[NL80211_STA_INFO_BEACON_LOSS]);
1004 WMESH_LOGD(" beacon loss:\t%u", station_info->beacon_loss);
1007 if (0 != sta_info[NL80211_STA_INFO_T_OFFSET]) {
1008 station_info->t_offset =
1009 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_T_OFFSET]);
1010 WMESH_LOGD(" Toffset:\t%llu us", station_info->t_offset);
1013 if (0 != sta_info[NL80211_STA_INFO_LOCAL_PM]) {
1014 station_info->local_ps_mode =
1015 nla_get_u32(sta_info[NL80211_STA_INFO_LOCAL_PM]);
1016 WMESH_LOGD(" mesh local PS mode:\t");
1017 print_power_mode(sta_info[NL80211_STA_INFO_LOCAL_PM]);
1019 if (0 != sta_info[NL80211_STA_INFO_PEER_PM]) {
1020 station_info->peer_ps_mode =
1021 nla_get_u32(sta_info[NL80211_STA_INFO_PEER_PM]);
1022 WMESH_LOGD(" mesh peer PS mode:\t");
1023 print_power_mode(sta_info[NL80211_STA_INFO_PEER_PM]);
1025 if (0 != sta_info[NL80211_STA_INFO_NONPEER_PM]) {
1026 station_info->non_peer_ps_mode =
1027 nla_get_u32(sta_info[NL80211_STA_INFO_NONPEER_PM]);
1028 WMESH_LOGD(" mesh non-peer PS mode:\t");
1029 print_power_mode(sta_info[NL80211_STA_INFO_NONPEER_PM]);
1031 #ifdef NL80211_STA_INFO_RX_DROP_MISC
1032 if (0 != sta_info[NL80211_STA_INFO_RX_DROP_MISC]) {
1033 station_info->rx_drop_misc =
1034 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_RX_DROP_MISC]);
1035 WMESH_LOGD(" rx drop misc:\t%llu", station_info->rx_drop_misc);
1037 #endif /* NL80211_STA_INFO_RX_DROP_MISC */
1039 #ifdef NL80211_STA_INFO_BEACON_RX
1040 if (0 != sta_info[NL80211_STA_INFO_BEACON_RX]) {
1041 station_info->beacon_rx =
1042 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_BEACON_RX]);
1043 WMESH_LOGD(" beacon rx:\t%llu", station_info->beacon_rx);
1045 #endif /* NL80211_STA_INFO_BEACON_RX */
1047 #ifdef NL80211_STA_INFO_BEACON_SIGNAL_AVG
1048 if (0 != sta_info[NL80211_STA_INFO_BEACON_SIGNAL_AVG]) {
1049 station_info->beacon_signal_avg =
1050 nla_get_u8(sta_info[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
1051 WMESH_LOGD(" beacon signal avg:\t%d dBm", station_info->beacon_signal_avg);
1053 #endif /* NL80211_STA_INFO_BEACON_SIGNAL_AVG */
1055 #ifdef NL80211_STA_INFO_RX_DURATION
1056 if (0 != sta_info[NL80211_STA_INFO_RX_DURATION]) {
1057 station_info->rx_duration =
1058 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_RX_DURATION]);
1059 WMESH_LOGD(" rx duration:\t%lld us", station_info->rx_duration);
1061 #endif /* NL80211_STA_INFO_RX_DURATION */
1063 *(state->station_list) = g_list_prepend(*(state->station_list), station_info);
1068 static int _on_receive_mpath_info(struct nl_msg *msg, void *arg)
1070 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1071 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1072 struct nlattr *pinfo[NL80211_MPATH_INFO_MAX + 1];
1073 char dst[20], next_hop[20], dev[20];
1074 static struct nla_policy mpath_policy[NL80211_MPATH_INFO_MAX + 1] = {
1075 [NL80211_MPATH_INFO_FRAME_QLEN] = { .type = NLA_U32 },
1076 [NL80211_MPATH_INFO_SN] = { .type = NLA_U32 },
1077 [NL80211_MPATH_INFO_METRIC] = { .type = NLA_U32 },
1078 [NL80211_MPATH_INFO_EXPTIME] = { .type = NLA_U32 },
1079 [NL80211_MPATH_INFO_DISCOVERY_TIMEOUT] = { .type = NLA_U32 },
1080 [NL80211_MPATH_INFO_DISCOVERY_RETRIES] = { .type = NLA_U8 },
1081 [NL80211_MPATH_INFO_FLAGS] = { .type = NLA_U8 },
1084 mesh_nl_state *state = (mesh_nl_state *)arg;
1085 wmesh_mpath_info_s *mpath_info = NULL;
1087 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1088 genlmsg_attrlen(gnlh, 0), NULL);
1091 * TODO: validate the interface and mac address!
1092 * Otherwise, there's a race condition as soon as
1093 * the kernel starts sending mpath notifications.
1096 if (!tb[NL80211_ATTR_MPATH_INFO]) {
1097 WMESH_LOGE("missing mesh path info!");
1100 if (nla_parse_nested(pinfo, NL80211_MPATH_INFO_MAX,
1101 tb[NL80211_ATTR_MPATH_INFO],
1103 WMESH_LOGE("failed to parse nested attributes!");
1107 mpath_info = g_try_new0(wmesh_mpath_info_s, 1);
1108 if (NULL == mpath_info) {
1109 WMESH_LOGE("Failed to allocate mesh path info !");
1113 mac_addr_n2a(dst, nla_data(tb[NL80211_ATTR_MAC]));
1114 mpath_info->dest_addr = g_strdup(dst);
1115 WMESH_LOGD("Destination Address : %s", mpath_info->dest_addr);
1117 mac_addr_n2a(next_hop, nla_data(tb[NL80211_ATTR_MPATH_NEXT_HOP]));
1118 mpath_info->next_hop = g_strdup(next_hop);
1119 WMESH_LOGD("Next hop Address : %s", mpath_info->next_hop);
1121 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
1122 mpath_info->interface = g_strdup(dev);
1123 WMESH_LOGD("Interface : %s", mpath_info->interface);
1125 if (pinfo[NL80211_MPATH_INFO_SN]) {
1126 mpath_info->sn = nla_get_u32(pinfo[NL80211_MPATH_INFO_SN]);
1127 WMESH_LOGD("SN : %u", mpath_info->sn);
1129 if (pinfo[NL80211_MPATH_INFO_METRIC]) {
1130 mpath_info->metric = nla_get_u32(pinfo[NL80211_MPATH_INFO_METRIC]);
1131 WMESH_LOGD("Metric : %u", mpath_info->metric);
1133 if (pinfo[NL80211_MPATH_INFO_FRAME_QLEN]) {
1134 mpath_info->qlen = nla_get_u32(pinfo[NL80211_MPATH_INFO_FRAME_QLEN]);
1135 WMESH_LOGD("QLEN : %u", mpath_info->qlen);
1137 if (pinfo[NL80211_MPATH_INFO_EXPTIME]) {
1138 mpath_info->exptime = nla_get_u32(pinfo[NL80211_MPATH_INFO_EXPTIME]);
1139 WMESH_LOGD("ExpTime : %u", mpath_info->exptime);
1141 if (pinfo[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT]) {
1142 mpath_info->discovery_timeout =
1143 nla_get_u32(pinfo[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT]);
1144 WMESH_LOGD("Discovery Timeout : %u", mpath_info->discovery_timeout);
1146 if (pinfo[NL80211_MPATH_INFO_DISCOVERY_RETRIES]) {
1147 mpath_info->discovery_retries =
1148 nla_get_u8(pinfo[NL80211_MPATH_INFO_DISCOVERY_RETRIES]);
1149 WMESH_LOGD("Discovery Retries : %u", mpath_info->discovery_retries);
1151 if (pinfo[NL80211_MPATH_INFO_FLAGS]) {
1152 mpath_info->flags = nla_get_u8(pinfo[NL80211_MPATH_INFO_FLAGS]);
1153 WMESH_LOGD("Flags : 0x%x", mpath_info->flags);
1157 *(state->mpath_list) = g_list_prepend(*(state->mpath_list), mpath_info);
1162 static int _on_receive_meshconf_info(struct nl_msg *msg, void *arg)
1164 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1165 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1166 struct nlattr *pinfo[NL80211_MESHCONF_ATTR_MAX + 1];
1167 static struct nla_policy meshconf_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
1168 [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 },
1169 [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 },
1170 [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 },
1171 [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 },
1172 [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 },
1173 [NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
1174 [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
1175 [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
1176 [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
1177 [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
1178 [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
1179 [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
1180 [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
1181 [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
1182 [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = { .type = NLA_U16 },
1183 [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
1184 [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
1185 [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
1186 [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
1187 [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
1188 [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 },
1189 [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
1190 [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
1191 [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
1192 [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
1193 [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
1194 [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
1197 mesh_nl_state *state = (mesh_nl_state *)arg;
1198 wmesh_meshconf_info_s *meshconf_info = NULL;
1200 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1201 genlmsg_attrlen(gnlh, 0), NULL);
1204 * TODO: validate the interface and mac address!
1205 * Otherwise, there's a race condition as soon as
1206 * the kernel starts sending mpath notifications.
1209 if (!tb[NL80211_ATTR_MESH_CONFIG]) {
1210 WMESH_LOGE("missing mesh path info!");
1213 if (nla_parse_nested(pinfo, NL80211_MESHCONF_ATTR_MAX,
1214 tb[NL80211_ATTR_MESH_CONFIG], meshconf_policy)) {
1215 WMESH_LOGE("failed to parse nested attributes!");
1219 meshconf_info = g_try_new0(wmesh_meshconf_info_s, 1);
1220 if (NULL == meshconf_info) {
1221 WMESH_LOGE("Failed to allocate mesh path info !");
1225 if (pinfo[NL80211_MESHCONF_RETRY_TIMEOUT]) {
1226 meshconf_info->retry_timeout =
1227 nla_get_u16(pinfo[NL80211_MESHCONF_RETRY_TIMEOUT]);
1228 WMESH_LOGD("Retry Timeout : %u", meshconf_info->retry_timeout);
1230 if (pinfo[NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES]) {
1231 meshconf_info->hwmp_max_preq_retries =
1232 nla_get_u8(pinfo[NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES]);
1233 WMESH_LOGD("HWMP Max PREQ Retries : %u",
1234 meshconf_info->hwmp_max_preq_retries);
1236 if (pinfo[NL80211_MESHCONF_CONFIRM_TIMEOUT]) {
1237 meshconf_info->confirm_timeout =
1238 nla_get_u16(pinfo[NL80211_MESHCONF_CONFIRM_TIMEOUT]);
1239 WMESH_LOGD("Confirm Timeout : %u", meshconf_info->confirm_timeout);
1241 if (pinfo[NL80211_MESHCONF_PATH_REFRESH_TIME]) {
1242 meshconf_info->path_refresh_time =
1243 nla_get_u32(pinfo[NL80211_MESHCONF_PATH_REFRESH_TIME]);
1244 WMESH_LOGD("Path Refresh Time : %u", meshconf_info->path_refresh_time);
1246 if (pinfo[NL80211_MESHCONF_HOLDING_TIMEOUT]) {
1247 meshconf_info->holding_timeout =
1248 nla_get_u16(pinfo[NL80211_MESHCONF_HOLDING_TIMEOUT]);
1249 WMESH_LOGD("Holding Timeout : %u", meshconf_info->holding_timeout);
1251 if (pinfo[NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT]) {
1252 meshconf_info->min_disc_timeout =
1253 nla_get_u16(pinfo[NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT]);
1254 WMESH_LOGD("Min Disc Timeout : %u", meshconf_info->min_disc_timeout);
1256 if (pinfo[NL80211_MESHCONF_MAX_PEER_LINKS]) {
1257 meshconf_info->max_peer_links =
1258 nla_get_u16(pinfo[NL80211_MESHCONF_MAX_PEER_LINKS]);
1259 WMESH_LOGD("MAX Peer Links : %u", meshconf_info->max_peer_links);
1261 if (pinfo[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL]) {
1262 meshconf_info->hwmp_preq_min_interval =
1263 nla_get_u16(pinfo[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL]);
1264 WMESH_LOGD("HWMP PREQ Min Interval : %u",
1265 meshconf_info->hwmp_preq_min_interval);
1267 if (pinfo[NL80211_MESHCONF_TTL]) {
1268 meshconf_info->ttl =
1269 nla_get_u8(pinfo[NL80211_MESHCONF_TTL]);
1270 WMESH_LOGD("TTL : %u", meshconf_info->ttl);
1272 if (pinfo[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT]) {
1273 meshconf_info->hwmp_active_path_timeout =
1274 nla_get_u32(pinfo[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT]);
1275 WMESH_LOGD("HWMP Active Path Timeout : %u",
1276 meshconf_info->hwmp_active_path_timeout);
1278 if (pinfo[NL80211_MESHCONF_ELEMENT_TTL]) {
1279 meshconf_info->element_ttl =
1280 nla_get_u8(pinfo[NL80211_MESHCONF_ELEMENT_TTL]);
1281 WMESH_LOGD("Element TTL : %u", meshconf_info->element_ttl);
1283 if (pinfo[NL80211_MESHCONF_HWMP_RANN_INTERVAL]) {
1284 meshconf_info->hwmp_rann_interval =
1285 nla_get_u16(pinfo[NL80211_MESHCONF_HWMP_RANN_INTERVAL]);
1286 WMESH_LOGD("HWMP RANN Interval : %u",
1287 meshconf_info->hwmp_rann_interval);
1289 if (pinfo[NL80211_MESHCONF_GATE_ANNOUNCEMENTS]) {
1290 meshconf_info->gate_announcements =
1291 nla_get_u8(pinfo[NL80211_MESHCONF_GATE_ANNOUNCEMENTS]);
1292 WMESH_LOGD("Gate Announcements : %u",
1293 meshconf_info->gate_announcements);
1297 *(state->meshconf) = meshconf_info;
1302 static int _on_receive_mesh_event(struct nl_msg *msg, void *arg)
1304 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1305 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1306 char ifname[16] = { 0, };
1307 char macbuf[MAX_MAC_ADDR_LEN];
1309 wmesh_service *service = arg;
1310 wmesh_interface_s *info = service->interface_info;
1312 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
1314 if (tb[NL80211_ATTR_IFINDEX]) {
1315 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
1316 WMESH_LOGD("%s: ", ifname);
1319 switch (gnlh->cmd) {
1320 case NL80211_CMD_NEW_STATION:
1321 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1322 WMESH_LOGD("[%s] new station [%s]", ifname, macbuf);
1324 if (g_strcmp0(info->mesh_interface, ifname) == 0)
1325 wmesh_notify_station_joined((const char*)macbuf,
1326 WMESHD_STATION_TYPE_MESH_POINT);
1327 else if (g_strcmp0(info->softap_interface, ifname) == 0)
1328 wmesh_notify_station_joined((const char*)macbuf,
1329 WMESHD_STATION_TYPE_SOFTAP);
1332 case NL80211_CMD_DEL_STATION:
1333 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1334 WMESH_LOGD("[%s] del station [%s]", ifname, macbuf);
1336 if (g_strcmp0(info->mesh_interface, ifname) == 0)
1337 wmesh_notify_station_left((const char*)macbuf,
1338 WMESHD_STATION_TYPE_MESH_POINT);
1339 else if (g_strcmp0(info->softap_interface, ifname) == 0)
1340 wmesh_notify_station_left((const char*)macbuf,
1341 WMESHD_STATION_TYPE_SOFTAP);
1344 case NL80211_CMD_NEW_MPATH:
1345 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1346 WMESH_LOGD("[%s] new mpath [%s]", ifname, macbuf);
1349 case NL80211_CMD_DEL_MPATH:
1350 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1351 WMESH_LOGD("[%s] del mpath [%s]", ifname, macbuf);
1355 WMESH_LOGD("event [%d] is not handled", gnlh->cmd);
1362 static int _send_nl_set_mesh_parameter(const char* mesh_if_name,
1363 const char* param_name, unsigned int value)
1365 mesh_nl_state state = {
1367 .callback_state = MESH_NL_CALLBACK_TRYING,
1373 .error_occured = FALSE,
1375 struct nlattr *container;
1377 int err = WMESHD_ERROR_NONE;
1378 int device_index = 0;
1382 ret = __initialize_nl80211(&state);
1383 if (WMESHD_ERROR_NONE != ret) {
1384 WMESH_LOGE("Failed to initialize nl80211");
1388 ret = __initialize_netlink_message(&state);
1389 if (WMESHD_ERROR_NONE != ret) {
1390 WMESH_LOGE("Failed to initialize netlink message");
1394 /* Set command into message */
1395 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1396 0, NL80211_CMD_SET_MESH_PARAMS, 0);
1398 /* Add attributes into message */
1399 ret = __get_device_index_from_string(mesh_if_name, &device_index);
1400 if (WMESHD_ERROR_NONE != ret) {
1401 WMESH_LOGE("Failed to get mesh device index");
1405 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1407 container = nla_nest_start(state.msg, NL80211_ATTR_MESH_PARAMS);
1409 WMESH_LOGE("Failed to initialize netlink message");
1413 /* Logic need to be changed if additional parameter is required */
1414 if (g_strcmp0(MESH_PARAM_HWMP_ROOTMODE, param_name) == 0) {
1415 WMESH_LOGD(" [mesh_hwmp_rootmode] : [%d]", value);
1416 NLA_PUT_U8(state.msg, NL80211_MESHCONF_HWMP_ROOTMODE,
1418 } else if (g_strcmp0(MESH_PARAM_GATE_ANNOUNCE, param_name) == 0) {
1419 WMESH_LOGD(" [mesh_gate_announcements] : [%d]", value);
1420 NLA_PUT_U8(state.msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
1423 WMESH_LOGE("Parameter [%s] is not required !", param_name);
1424 nla_nest_end(state.msg, container);
1427 nla_nest_end(state.msg, container);
1429 /* Send message into kernel */
1430 ret = nl_send_auto(state.nl_socket, state.msg);
1432 WMESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1433 nl_geterror(ret), ret);
1434 err = WMESHD_ERROR_OPERATION_FAILED;
1439 state.callback_state = MESH_NL_CALLBACK_TRYING;
1440 while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1441 WMESH_LOGD(" count [%02d]", ++test);
1442 nl_recvmsgs(state.nl_socket, state.cb);
1446 __clean_netlink_message(&state);
1447 __clean_nl80211(&state);
1452 WMESH_LOGE("Failed to message build");
1453 __clean_netlink_message(&state);
1454 __clean_nl80211(&state);
1456 return WMESHD_ERROR_OPERATION_FAILED;
1459 static int _send_nl_get_station_info(const char* if_name, GList **station_list)
1461 mesh_nl_state state = {
1463 .callback_state = MESH_NL_CALLBACK_TRYING,
1469 .station_list = station_list
1471 int err = WMESHD_ERROR_NONE;
1472 int device_index = 0;
1476 ret = __initialize_nl80211(&state);
1477 if (WMESHD_ERROR_NONE != ret) {
1478 WMESH_LOGE("Failed to initialize nl80211");
1482 ret = __initialize_netlink_message(&state);
1483 if (WMESHD_ERROR_NONE != ret) {
1484 WMESH_LOGE("Failed to initialize netlink message");
1488 /* Set command into message */
1489 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1490 NLM_F_DUMP, NL80211_CMD_GET_STATION, 0);
1492 /* Add attributes into message */
1493 WMESH_LOGD("Dump station list with interface [%s]", if_name);
1494 ret = __get_device_index_from_string(if_name, &device_index);
1495 if (WMESHD_ERROR_NONE != ret) {
1496 WMESH_LOGE("Failed to get mesh interface device index");
1500 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1502 /* Register valid callback to dump result */
1503 nl_cb_set(state.cb, NL_CB_VALID, NL_CB_CUSTOM,
1504 _on_receive_station_info, &state);
1506 /* Send message into kernel */
1507 ret = nl_send_auto(state.nl_socket, state.msg);
1509 WMESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1510 nl_geterror(ret), ret);
1511 err = WMESHD_ERROR_OPERATION_FAILED;
1516 state.callback_state = MESH_NL_CALLBACK_TRYING;
1517 while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1518 WMESH_LOGD(" count [%02d]", ++test);
1519 nl_recvmsgs(state.nl_socket, state.cb);
1521 WMESH_LOGD("Finished");
1524 __clean_netlink_message(&state);
1525 __clean_nl80211(&state);
1530 WMESH_LOGE("Failed to message build");
1531 __clean_netlink_message(&state);
1532 __clean_nl80211(&state);
1534 return WMESHD_ERROR_OPERATION_FAILED;
1537 static int _send_nl_get_mpath_info(const char* if_name, GList **mpath_list)
1539 mesh_nl_state state = {
1541 .callback_state = MESH_NL_CALLBACK_TRYING,
1547 .mpath_list = mpath_list
1549 int err = WMESHD_ERROR_NONE;
1550 int device_index = 0;
1554 ret = __initialize_nl80211(&state);
1555 if (WMESHD_ERROR_NONE != ret) {
1556 WMESH_LOGE("Failed to initialize nl80211");
1560 ret = __initialize_netlink_message(&state);
1561 if (WMESHD_ERROR_NONE != ret) {
1562 WMESH_LOGE("Failed to initialize netlink message");
1566 /* Set command into message */
1567 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1568 NLM_F_DUMP, NL80211_CMD_GET_MPATH, 0);
1570 /* Add attributes into message */
1571 WMESH_LOGD("Dump station list with interface [%s]", if_name);
1572 ret = __get_device_index_from_string(if_name, &device_index);
1573 if (WMESHD_ERROR_NONE != ret) {
1574 WMESH_LOGE("Failed to get mesh interface device index");
1578 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1580 /* Register valid callback to dump result */
1581 nl_cb_set(state.cb, NL_CB_VALID, NL_CB_CUSTOM,
1582 _on_receive_mpath_info, &state);
1584 /* Send message into kernel */
1585 ret = nl_send_auto(state.nl_socket, state.msg);
1587 WMESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1588 nl_geterror(ret), ret);
1589 err = WMESHD_ERROR_OPERATION_FAILED;
1594 state.callback_state = MESH_NL_CALLBACK_TRYING;
1595 while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1596 WMESH_LOGD(" count [%02d]", ++test);
1597 nl_recvmsgs(state.nl_socket, state.cb);
1599 WMESH_LOGD("Finished");
1602 __clean_netlink_message(&state);
1603 __clean_nl80211(&state);
1608 WMESH_LOGE("Failed to message build");
1609 __clean_netlink_message(&state);
1610 __clean_nl80211(&state);
1612 return WMESHD_ERROR_OPERATION_FAILED;
1615 static int _send_nl_get_meshconf_info(wmesh_service *service)
1617 mesh_nl_state state = {
1619 .callback_state = MESH_NL_CALLBACK_TRYING,
1625 .meshconf = &service->meshconf,
1627 int err = WMESHD_ERROR_NONE;
1628 int device_index = 0;
1632 ret = __initialize_nl80211(&state);
1633 if (WMESHD_ERROR_NONE != ret) {
1634 WMESH_LOGE("Failed to initialize nl80211");
1638 ret = __initialize_netlink_message(&state);
1639 if (WMESHD_ERROR_NONE != ret) {
1640 WMESH_LOGE("Failed to initialize netlink message");
1644 /* Set command into message */
1645 genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1646 0, NL80211_CMD_GET_MESH_CONFIG, 0);
1648 /* Add attributes into message */
1649 WMESH_LOGD("Dump Mesh Config with interface [%s]",
1650 service->interface_info->mesh_interface);
1651 ret = __get_device_index_from_string(
1652 service->interface_info->mesh_interface, &device_index);
1653 if (WMESHD_ERROR_NONE != ret) {
1654 WMESH_LOGE("Failed to get mesh interface device index");
1658 NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1660 /* Register valid callback to dump result */
1661 nl_cb_set(state.cb, NL_CB_VALID, NL_CB_CUSTOM,
1662 _on_receive_meshconf_info, &state);
1664 /* Send message into kernel */
1665 ret = nl_send_auto(state.nl_socket, state.msg);
1667 WMESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1668 nl_geterror(ret), ret);
1669 err = WMESHD_ERROR_OPERATION_FAILED;
1674 state.callback_state = MESH_NL_CALLBACK_TRYING;
1675 while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1676 WMESH_LOGD(" count [%02d]", ++test);
1677 nl_recvmsgs(state.nl_socket, state.cb);
1679 WMESH_LOGD("Finished");
1682 __clean_netlink_message(&state);
1683 __clean_nl80211(&state);
1688 WMESH_LOGE("Failed to message build");
1689 __clean_netlink_message(&state);
1690 __clean_nl80211(&state);
1692 return WMESHD_ERROR_OPERATION_FAILED;
1695 static int _send_nl_register_event_handler(wmesh_service *service)
1697 int err = WMESHD_ERROR_NONE;
1699 GIOChannel *recv_channel = NULL;
1702 WMESH_LOGE("Already event handler registered !");
1703 return WMESHD_ERROR_IN_PROGRESS;
1706 event_state = _create_mesh_nl_state("");
1708 ret = __initialize_nl80211(event_state);
1709 if (WMESHD_ERROR_NONE != ret) {
1710 WMESH_LOGE("Failed to initialize nl80211");
1714 /* Subscribe multicast group should be proceed before scanning */
1715 ret = __prepare_listen_events(event_state);
1717 WMESH_LOGE("__prepare_listen_events : [%d]", ret);
1721 ret = __initialize_netlink_message(event_state);
1722 if (WMESHD_ERROR_NONE != ret) {
1723 WMESH_LOGE("Failed to initialize netlink message");
1727 /* Set command into message */
1728 genlmsg_put(event_state->msg, 0, 0, event_state->nl80211_id, 0, 0, 0, 0);
1730 /* Set callbacks for event handler */
1731 nl_cb_set(event_state->cb, NL_CB_VALID, NL_CB_CUSTOM,
1732 _on_receive_mesh_event, service);
1733 /* No sequence checking for multicast messages. */
1734 nl_cb_set(event_state->cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
1736 WMESH_LOGD("Register event handler");
1738 /* Change socket type to non-blocking */
1739 ret = nl_socket_set_nonblocking(event_state->nl_socket);
1741 WMESH_LOGE("Failed to non-blocking socket [%s](%d)", nl_geterror(ret), ret);
1743 /* Register I/O callback to wait asynchronously */
1744 if (FALSE == event_state->error_occured) {
1745 recv_channel = g_io_channel_unix_new(nl_socket_get_fd(event_state->nl_socket));
1746 event_state->event_source = g_io_add_watch(recv_channel,
1747 (G_IO_IN | G_IO_ERR), _on_socket_event_io_received, event_state);
1748 g_io_channel_unref(recv_channel);
1750 WMESH_LOGE("Error responded. Failed to register event callback !!");
1754 /* Resource should be free on I/O callback */
1755 return WMESHD_ERROR_NONE;
1758 __clean_netlink_message(event_state);
1759 __clean_nl80211(event_state);
1760 _delete_mesh_nl_state(&event_state);
1765 int wmesh_netlink_set_mesh_parameter(const char* mesh_if_name,
1766 const char* param_name, unsigned int value)
1768 int ret = WMESHD_ERROR_NONE;
1770 if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1771 WMESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1772 return WMESHD_ERROR_INVALID_PARAMETER;
1775 WMESH_LOGD("Set mesh[%s] param [%s] value [%d]",
1776 mesh_if_name, param_name, value);
1777 ret = _send_nl_set_mesh_parameter(mesh_if_name, param_name, value);
1782 int wmesh_netlink_get_station_info(const char* mesh_if_name, GList **station_list)
1784 int ret = WMESHD_ERROR_NONE;
1786 if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1787 WMESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1788 return WMESHD_ERROR_INVALID_PARAMETER;
1790 if (NULL == station_list) {
1791 WMESH_LOGE("Invalid parameter [%p]", station_list);
1792 return WMESHD_ERROR_INVALID_PARAMETER;
1795 WMESH_LOGD("Get connected stations");
1796 ret = _send_nl_get_station_info(mesh_if_name, station_list);
1801 int wmesh_netlink_get_mpath_info(const char* mesh_if_name, GList **mpath_list)
1803 int ret = WMESHD_ERROR_NONE;
1805 if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1806 WMESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1807 return WMESHD_ERROR_INVALID_PARAMETER;
1809 if (NULL == mpath_list) {
1810 WMESH_LOGE("Invalid parameter [%p]", mpath_list);
1811 return WMESHD_ERROR_INVALID_PARAMETER;
1814 WMESH_LOGD("Get current mpath info");
1815 ret = _send_nl_get_mpath_info(mesh_if_name, mpath_list);
1820 int wmesh_netlink_get_meshconf_info(wmesh_service *service)
1822 int ret = WMESHD_ERROR_NONE;
1824 if (NULL == service) {
1825 WMESH_LOGE("Invalid parameter [%p]", service);
1826 return WMESHD_ERROR_INVALID_PARAMETER;
1829 WMESH_LOGD("Get current Mesh Config info");
1830 ret = _send_nl_get_meshconf_info(service);
1835 int wmesh_netlink_register_event_handler(wmesh_service *service)
1837 int ret = WMESHD_ERROR_NONE;
1839 WMESH_LOGD("Register mesh event handler");
1840 ret = _send_nl_register_event_handler(service);
1845 int wmesh_netlink_unregister_event_handler()
1847 int ret = WMESHD_ERROR_NONE;
1849 WMESH_LOGD("Unregister mesh event handler");
1851 _on_remove_event_io_handler();