Added initial code for gtest
[platform/core/connectivity/wifi-mesh-manager.git] / src / wmesh-netlink.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  */
19 #include <glib.h>
20
21 #include <errno.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <net/if.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29
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>
36
37 #include "wmesh.h"
38 #include "wmesh-log.h"
39 #include "wmesh-util.h"
40 #include "wmesh-netlink.h"
41 #include "wmesh-request.h"
42
43 #include <linux/nl80211.h>
44 //#include "nl80211.h"
45
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
49 #define ETH_ALEN          6
50
51 #define BIT(x) (1ULL<<(x))
52
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
60
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
63
64 typedef enum {
65         MESH_NL_CALLBACK_FINISHED = 0,
66         MESH_NL_CALLBACK_TRYING,
67 } mesh_nl_callback_state_e;
68
69 typedef struct {
70         int nl80211_id;
71         int callback_state;
72         guint event_source;
73
74         struct nl_sock *nl_socket;
75         struct nl_msg *msg;
76         struct nl_cb *cb;
77         struct nl_cb *s_cb;
78
79         bool error_occured;
80         GList **station_list;
81         GList **mpath_list;
82         wmesh_meshconf_info_s **meshconf;
83 } mesh_nl_state;
84
85 typedef struct {
86         const char *group;
87         int id;
88 } multicast_group_id_args;
89
90 enum plink_state {
91         LISTEN,
92         OPN_SNT,
93         OPN_RCVD,
94         CNF_RCVD,
95         ESTAB,
96         HOLDING,
97         BLOCKED
98 };
99
100 /* For event handler */
101 static mesh_nl_state *event_state = NULL;
102
103 static int __initialize_nl80211(mesh_nl_state *state)
104 {
105         int err = WMESHD_ERROR_NONE;
106
107         state->nl_socket = nl_socket_alloc();
108         if (!state->nl_socket) {
109                 /* LCOV_EXCL_START */
110                 WMESH_LOGE("Failed to allocate netlink socket.");
111                 return WMESHD_ERROR_OUT_OF_MEMORY;
112                 /* LCOV_EXCL_STOP */
113         }
114
115         if (genl_connect(state->nl_socket)) {
116                 /* LCOV_EXCL_START */
117                 WMESH_LOGE("Failed to connect to generic netlink.");
118                 err = WMESHD_ERROR_OPERATION_FAILED;
119                 goto DESTROY;
120                 /* LCOV_EXCL_STOP */
121         }
122
123         nl_socket_set_buffer_size(state->nl_socket, 8192, 8192);
124
125         state->nl80211_id = genl_ctrl_resolve(state->nl_socket, "nl80211");
126         if (state->nl80211_id < 0) {
127                 /* LCOV_EXCL_START */
128                 WMESH_LOGE("nl80211 not found.");
129                 err = WMESHD_ERROR_NO_DATA;
130                 goto DESTROY;
131                 /* LCOV_EXCL_STOP */
132         }
133
134         return 0;
135
136 DESTROY:
137         /* LCOV_EXCL_START */
138         nl_socket_free(state->nl_socket);
139         return err;
140         /* LCOV_EXCL_STOP */
141 }
142
143 static void __clean_nl80211(mesh_nl_state *state)
144 {
145         if (!state)
146                 return; /* LCOV_EXCL_LINE */
147
148         if (state->nl_socket) {
149                 nl_socket_free(state->nl_socket);
150                 state->nl_socket = NULL;
151                 state->nl80211_id = -1;
152         }
153 }
154
155 static int __get_device_index_from_string(const char* if_name, int *index)
156 {
157         int device_index = 0;
158
159         if (NULL == if_name) {
160                 /* LCOV_EXCL_START */
161                 WMESH_LOGE("Invalid parameter");
162                 return WMESHD_ERROR_INVALID_PARAMETER;
163                 /* LCOV_EXCL_STOP */
164         }
165
166         device_index = if_nametoindex(if_name);
167         if (device_index == 0) {
168                 /* LCOV_EXCL_START */
169                 WMESH_LOGE("No interface index found [%s]", if_name);
170                 return WMESHD_ERROR_NO_DATA;
171                 /* LCOV_EXCL_STOP */
172         }
173         *index = device_index; /* LCOV_EXCL_LINE */
174
175         return WMESHD_ERROR_NONE; /* LCOV_EXCL_LINE */
176 }
177
178 /* LCOV_EXCL_START */
179 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
180 {
181         mesh_nl_state *state = (mesh_nl_state *)arg;
182         char buf[256] = { 0, };
183
184         NOTUSED(nla);
185
186         state->callback_state = MESH_NL_CALLBACK_FINISHED;
187         state->error_occured = TRUE;
188         strerror_r(err->error, buf, 255);
189
190         WMESH_LOGD("error_handler");
191         WMESH_LOGE("    %s (%d)", buf, err->error);
192
193         return NL_STOP;
194 }
195
196 static int finish_handler(struct nl_msg *msg, void *arg)
197 {
198         mesh_nl_state *state = (mesh_nl_state *)arg;
199
200         state->callback_state = MESH_NL_CALLBACK_FINISHED;
201
202         WMESH_LOGD("finish_handler");
203         NOTUSED(msg);
204
205         return NL_SKIP;
206 }
207
208 static int ack_handler(struct nl_msg *msg, void *arg)
209 {
210         mesh_nl_state *state = (mesh_nl_state *)arg;
211
212         state->callback_state = MESH_NL_CALLBACK_FINISHED;
213
214         WMESH_LOGD("ack_handler");
215         NOTUSED(msg);
216
217         return NL_STOP;
218 }
219 /* LCOV_EXCL_STOP */
220
221 static int ack_simple_handler(struct nl_msg *msg, void *arg)
222 {
223         int *ret = arg;
224
225         (void) msg;
226         *ret = 0;
227
228         WMESH_LOGD("ack_simple_handler");
229
230         return NL_STOP;
231 }
232
233 static int family_handler(struct nl_msg *msg, void *arg)
234 {
235         multicast_group_id_args *group = (multicast_group_id_args *)arg;
236         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
237         struct nlattr *tb[CTRL_ATTR_MAX + 1];
238         struct nlattr *mcast_group;
239         int rem_mcast_group;
240
241         WMESH_LOGD("family_handler");
242
243         nla_parse(tb, CTRL_ATTR_MAX,
244                         genlmsg_attrdata(gnlh, 0),
245                         genlmsg_attrlen(gnlh, 0), NULL);
246         if (!tb[CTRL_ATTR_MCAST_GROUPS])
247                 return NL_SKIP; //LCOV_EXCL_LINE
248
249         nla_for_each_nested(mcast_group, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcast_group) {
250                 struct nlattr *tb_mcast_group[CTRL_ATTR_MCAST_GRP_MAX + 1];
251
252                 nla_parse(tb_mcast_group, CTRL_ATTR_MCAST_GRP_MAX,
253                                 nla_data(mcast_group), nla_len(mcast_group), NULL);
254
255                 if (!tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME] ||
256                                 !tb_mcast_group[CTRL_ATTR_MCAST_GRP_ID])
257                         continue; //LCOV_EXCL_LINE
258
259                 if (strncmp(nla_data(tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME]),
260                                 group->group,
261                                 nla_len(tb_mcast_group[CTRL_ATTR_MCAST_GRP_NAME])))
262                         continue; //LCOV_EXCL_LINE
263
264                 group->id = nla_get_u32(tb_mcast_group[CTRL_ATTR_MCAST_GRP_ID]);
265                 WMESH_LOGD("mcast group id [%d]", group->id);
266                 break;
267         }
268
269         return NL_SKIP;
270 }
271
272 static int __nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group)
273 {
274         struct nl_msg *msg;
275         struct nl_cb *cb;
276         int ret, ctrlid;
277         multicast_group_id_args group_args = {
278                 .group = group,
279                 .id = -ENOENT,
280         };
281
282         msg = nlmsg_alloc();
283         if (!msg)
284                 return -ENOMEM; //LCOV_EXCL_LINE
285
286         cb = nl_cb_alloc(NL_CB_DEFAULT);
287         if (!cb) {
288                 /* LCOV_EXCL_START */
289                 ret = -ENOMEM;
290                 goto FAILURE;
291                 /* LCOV_EXCL_STOP */
292         }
293
294         ctrlid = genl_ctrl_resolve(sock, "nlctrl");
295
296         genlmsg_put(msg, 0, 0, ctrlid, 0,
297                     0, CTRL_CMD_GETFAMILY, 0);
298
299         ret = -ENOBUFS;
300         NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
301
302         ret = nl_send_auto(sock, msg);
303         if (ret < 0) {
304                 /* LCOV_EXCL_START */
305                 WMESH_LOGE("Failed to nl_send_auto");
306                 goto out;
307                 /* LCOV_EXCL_STOP */
308         }
309
310         ret = 1;
311         nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
312         nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_simple_handler, &ret);
313         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, family_handler, &group_args);
314
315         while (ret > 0)
316                 nl_recvmsgs(sock, cb);
317
318         if (ret == 0)
319                 ret = group_args.id;
320
321         WMESH_LOGD("mcid : [%d]", ret);
322
323  nla_put_failure:
324  out:
325         nl_cb_put(cb);
326
327  FAILURE:
328         nlmsg_free(msg);
329         return ret;
330 }
331
332 static int __prepare_listen_events(mesh_nl_state *state)
333 {
334         int mcid, ret;
335
336         /* Configuration multicast group */
337         mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "config");
338         if (mcid < 0) {
339                 /* LCOV_EXCL_START */
340                 WMESH_LOGE("Failed to get nl80211 config");
341                 return mcid;
342                 /* LCOV_EXCL_STOP */
343         }
344         WMESH_LOGD("Mesh multicast id (config): [%d]", mcid);
345
346         ret = nl_socket_add_membership(state->nl_socket, mcid);
347         if (ret) {
348                 /* LCOV_EXCL_START */
349                 WMESH_LOGE("Failed to nl_socket_add_membership");
350                 return ret;
351                 /* LCOV_EXCL_STOP */
352         }
353
354         /* Scan multicast group */
355         mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "scan");
356         if (mcid >= 0) {
357                 ret = nl_socket_add_membership(state->nl_socket, mcid);
358                 if (ret) {
359                         /* LCOV_EXCL_START */
360                         WMESH_LOGE("Failed to nl_socket_add_membership");
361                         return ret;
362                         /* LCOV_EXCL_STOP */
363                 }
364         }
365         WMESH_LOGD("Mesh multicast id (scan): [%d]", mcid);
366
367         /* Regulatory multicast group */
368         mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "regulatory");
369         if (mcid >= 0) {
370                 ret = nl_socket_add_membership(state->nl_socket, mcid);
371                 if (ret) {
372                         /* LCOV_EXCL_START */
373                         WMESH_LOGE("Failed to nl_socket_add_membership");
374                         return ret;
375                         /* LCOV_EXCL_STOP */
376                 }
377         }
378         WMESH_LOGD("Mesh multicast id (regulatory): [%d]", mcid);
379
380         /* MLME multicast group */
381         mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "mlme");
382         if (mcid >= 0) {
383                 ret = nl_socket_add_membership(state->nl_socket, mcid);
384                 if (ret) {
385                         /* LCOV_EXCL_START */
386                         WMESH_LOGE("Failed to nl_socket_add_membership");
387                         return ret;
388                         /* LCOV_EXCL_STOP */
389                 }
390         }
391         WMESH_LOGD("Mesh multicast id (mlme): [%d]", mcid);
392
393         mcid = __nl_get_multicast_id(state->nl_socket, "nl80211", "vendor");
394         if (mcid >= 0) {
395                 ret = nl_socket_add_membership(state->nl_socket, mcid);
396                 if (ret) {
397                         /* LCOV_EXCL_START */
398                         WMESH_LOGE("Failed to nl_socket_add_membership");
399                         return ret;
400                         /* LCOV_EXCL_STOP */
401                 }
402         }
403         WMESH_LOGD("Mesh multicast id (vendor): [%d]", mcid);
404
405         return 0;
406 }
407
408 static mesh_nl_state *_create_mesh_nl_state()
409 {
410         mesh_nl_state *state = g_new0(mesh_nl_state, 1);
411
412         state->nl80211_id = -1;
413         state->callback_state = MESH_NL_CALLBACK_TRYING;
414         state->error_occured = FALSE;
415
416         return state;
417 }
418
419 static void _delete_mesh_nl_state(mesh_nl_state **state)
420 {
421         if (NULL == state || NULL == *state)
422                 return; //LCOV_EXCL_LINE
423
424         g_free(*state);
425         *state = NULL;
426 }
427
428 /* LCOV_EXCL_START */
429 static int valid_handler(struct nl_msg *msg, void *arg)
430 {
431         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
432         mesh_nl_state *state = (mesh_nl_state *)arg;
433         WMESH_LOGD("valid_handler");
434
435         if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) {
436                 WMESH_LOGD("   Got NL80211_CMD_SCAN_ABORTED.");
437                 state->callback_state = MESH_NL_CALLBACK_FINISHED;
438
439                 /* Notify scan done status */
440                 wmesh_notify_scan_done();
441         } else if (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
442                 WMESH_LOGD("   Got NL80211_CMD_NEW_SCAN_RESULTS.");
443                 state->callback_state = MESH_NL_CALLBACK_FINISHED;
444
445                 /* Notify scan done status */
446                 wmesh_notify_scan_done();
447         } else {
448                 WMESH_LOGD("   Got [%d]", gnlh->cmd);
449         }
450
451         return NL_SKIP;
452 }
453 /* LCOV_EXCL_STOP */
454
455 static int no_seq_check(struct nl_msg *msg, void *arg)
456 {
457         NOTUSED(msg);
458         NOTUSED(arg);
459
460         return NL_OK;
461 }
462
463 static void __clean_netlink_message(mesh_nl_state *state)
464 {
465         if (!state)
466                 return; /* LCOV_EXCL_LINE */
467
468         if (state->cb)
469                 nl_cb_put(state->cb);
470         if (state->s_cb)
471                 nl_cb_put(state->s_cb);
472         if (state->msg)
473                 nlmsg_free(state->msg);
474
475         state->cb = NULL;
476         state->s_cb = NULL;
477         state->msg = NULL;
478
479         WMESH_LOGD("message and callback cleaned");
480 }
481
482 static int __initialize_netlink_message(mesh_nl_state *state)
483 {
484         int err = WMESHD_ERROR_NONE;
485
486         if (NULL == state) {
487                 /* LCOV_EXCL_START  */
488                 WMESH_LOGE("Invalid parameter !");
489                 return WMESHD_ERROR_INVALID_PARAMETER;
490                 /* LCOV_EXCL_STOP */
491         }
492
493         /* Create netlink message */
494         state->msg = nlmsg_alloc();
495         if (NULL == state->msg) {
496                 /* LCOV_EXCL_START */
497                 WMESH_LOGE("Failed to allocate netlink message");
498                 return WMESHD_ERROR_OUT_OF_MEMORY;
499                 /* LCOV_EXCL_STOP */
500         }
501
502         /* NL_CB_DEFAULT */
503         state->cb = nl_cb_alloc(NL_CB_DEFAULT);
504         state->s_cb = nl_cb_alloc(NL_CB_DEFAULT);
505         if (!state->cb) {
506                 /* LCOV_EXCL_START */
507                 WMESH_LOGE("Failed to allocate netlink callback");
508                 err = WMESHD_ERROR_OUT_OF_MEMORY;
509                 goto DESTROY;
510                 /* LCOV_EXCL_STOP */
511         }
512
513         /* Set socket callback */
514         nl_socket_set_cb(state->nl_socket, state->s_cb);
515
516         /* Set callbacks */
517         nl_cb_err(state->cb, NL_CB_CUSTOM, error_handler, state);
518         nl_cb_set(state->cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, state);
519         nl_cb_set(state->cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, state);
520         nl_cb_set(state->cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, state);
521
522         WMESH_LOGD("netlink socket initialized");
523
524         return WMESHD_ERROR_NONE;
525
526 DESTROY:
527         /* LCOV_EXCL_START */
528         __clean_netlink_message(state);
529
530         return err;
531         /* LCOV_EXCL_STOP */
532 }
533
534 static gboolean _on_socket_event_io_received(GIOChannel *source,
535                 GIOCondition condition, gpointer data)
536 {
537         mesh_nl_state *state = (mesh_nl_state *)data;
538         int test = 0;
539
540         NOTUSED(source);
541         NOTUSED(condition);
542
543         WMESH_LOGD("[Event] I/O received");
544
545         while (nl_recvmsgs_report(state->nl_socket, state->cb) > 0)
546                 WMESH_LOGD("  count [%02d]", ++test); //LCOV_EXCL_LINE
547
548         /* Do not remove I/O source */
549         return TRUE;
550 }
551
552 static void _on_remove_event_io_handler()
553 {
554         if (event_state) {
555                 g_source_remove(event_state->event_source);
556
557                 __clean_netlink_message(event_state);
558                 __clean_nl80211(event_state);
559                 _delete_mesh_nl_state(&event_state);
560         }
561 }
562
563 static void mac_addr_n2a(char *mac_addr, unsigned char *arg)
564 {
565         /* 11:22:33:44:55:66 (Len:17) */
566         snprintf(mac_addr, MAX_MAC_ADDR_LEN,
567                         "%02x:%02x:%02x:%02x:%02x:%02x",
568                         arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
569 }
570
571 /* LCOV_EXCL_START */
572 #if defined(NL80211_STA_INFO_CHAIN_SIGNAL) || defined(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)
573 static char *get_chain_signal(struct nlattr *attr_list)
574 {
575         struct nlattr *attr;
576         static char buf[64];
577         char *cur = buf;
578         int i = 0, rem;
579         const char *prefix;
580
581         if (!attr_list)
582                 return (char *)"";
583
584         nla_for_each_nested(attr, attr_list, rem) {
585                 if (i++ > 0)
586                         prefix = ", ";
587                 else
588                         prefix = "[";
589
590                 cur += snprintf(cur, sizeof(buf) - (cur - buf), "%s%d", prefix,
591                                 (int8_t) nla_get_u8(attr));
592         }
593
594         if (i)
595                 snprintf(cur, sizeof(buf) - (cur - buf), "] ");
596
597         return buf;
598 }
599 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL || NL80211_STA_INFO_CHAIN_SIGNAL_AVG */
600
601 static int parse_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen)
602 {
603         int rate = 0;
604         int pos = 0;
605         char str_rate[32] = { 0, };
606         char str_buf[128] = { 0, };
607         struct nlattr *rate_info[NL80211_RATE_INFO_MAX + 1];
608         static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
609                 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
610                 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
611                 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
612                 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
613                 [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 },
614         };
615
616         if (nla_parse_nested(rate_info, NL80211_RATE_INFO_MAX, bitrate_attr, rate_policy)) {
617                 if (buf)
618                         snprintf(buf, buflen, "failed to parse nested rate attributes!"); //LCOV_EXCL_LINE
619                 return 0;
620         }
621
622         if (rate_info[NL80211_RATE_INFO_MCS])
623                 pos += snprintf(str_buf + pos, 128 - pos,
624                                 " MCS %d", nla_get_u8(rate_info[NL80211_RATE_INFO_MCS]));
625         if (rate_info[NL80211_RATE_INFO_40_MHZ_WIDTH])
626                 pos += snprintf(str_buf + pos, 128 - pos, " 40MHz");
627         if (rate_info[NL80211_RATE_INFO_SHORT_GI])
628                 pos += snprintf(str_buf + pos, 128 - pos, " short GI");
629         if (rate_info[NL80211_RATE_INFO_VHT_MCS])
630                 pos += snprintf(str_buf + pos, 128 - pos,
631                                 " VHT-MCS %d", nla_get_u8(rate_info[NL80211_RATE_INFO_VHT_MCS]));
632         if (rate_info[NL80211_RATE_INFO_VHT_NSS])
633                 pos += snprintf(str_buf + pos, 128 - pos,
634                                 " VHT-NSS %d", nla_get_u8(rate_info[NL80211_RATE_INFO_VHT_NSS]));
635         if (rate_info[NL80211_RATE_INFO_80_MHZ_WIDTH])
636                 pos += snprintf(str_buf + pos, 128 - pos, " 80MHz");
637         if (rate_info[NL80211_RATE_INFO_80P80_MHZ_WIDTH])
638                 pos += snprintf(str_buf + pos, 128 - pos, " 80P80MHz");
639         if (rate_info[NL80211_RATE_INFO_160_MHZ_WIDTH])
640                 pos += snprintf(str_buf + pos, 128 - pos, " 160MHz");
641
642         if (rate_info[NL80211_RATE_INFO_BITRATE32])
643                 rate = nla_get_u32(rate_info[NL80211_RATE_INFO_BITRATE32]);
644         else if (rate_info[NL80211_RATE_INFO_BITRATE])
645                 rate = nla_get_u16(rate_info[NL80211_RATE_INFO_BITRATE]);
646         if (rate > 0)
647                 snprintf(str_rate, 32, "%d.%d MBit/s", rate / 10, rate % 10);
648
649         if (buf)
650                 snprintf(buf, buflen, "%s%s", str_rate, str_buf);
651
652         return rate;
653 }
654
655 static void parse_bss_param(struct nlattr *bss_param_attr, wmesh_station_info_s *station_info)
656 {
657         struct nlattr *bss_param_info[NL80211_STA_BSS_PARAM_MAX + 1], *info;
658         static struct nla_policy bss_poilcy[NL80211_STA_BSS_PARAM_MAX + 1] = {
659                 [NL80211_STA_BSS_PARAM_CTS_PROT] = { .type = NLA_FLAG },
660                 [NL80211_STA_BSS_PARAM_SHORT_PREAMBLE] = { .type = NLA_FLAG },
661                 [NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME] = { .type = NLA_FLAG },
662                 [NL80211_STA_BSS_PARAM_DTIM_PERIOD] = { .type = NLA_U8 },
663                 [NL80211_STA_BSS_PARAM_BEACON_INTERVAL] = { .type = NLA_U16 },
664         };
665
666         if (nla_parse_nested(bss_param_info, NL80211_STA_BSS_PARAM_MAX, bss_param_attr, bss_poilcy))
667                 WMESH_LOGE("failed to parse nested bss param attributes!");
668
669         info = bss_param_info[NL80211_STA_BSS_PARAM_DTIM_PERIOD];
670         if (info) {
671                 station_info->dtim_period = nla_get_u8(info);
672                 WMESH_LOGD("    DTIM period:\t%u", station_info->dtim_period);
673         }
674         info = bss_param_info[NL80211_STA_BSS_PARAM_BEACON_INTERVAL];
675         if (info) {
676                 station_info->beacon_interval = nla_get_u16(info);
677                 WMESH_LOGD("    beacon interval:%u", station_info->beacon_interval);
678         }
679         info = bss_param_info[NL80211_STA_BSS_PARAM_CTS_PROT];
680         if (info) {
681                 WMESH_LOGD("    CTS protection:");
682                 if (nla_get_u16(info)) {
683                         WMESH_LOGD("    yes");
684                         station_info->cts_protection = TRUE;
685                 } else {
686                         WMESH_LOGD("    no");
687                         station_info->cts_protection = FALSE;
688                 }
689         }
690         info = bss_param_info[NL80211_STA_BSS_PARAM_SHORT_PREAMBLE];
691         if (info) {
692                 WMESH_LOGD("    short preamble:");
693                 if (nla_get_u16(info)) {
694                         WMESH_LOGD("    yes");
695                         station_info->short_preamble = TRUE;
696                 } else {
697                         WMESH_LOGD("    no");
698                         station_info->short_preamble = FALSE;
699                 }
700         }
701         info = bss_param_info[NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME];
702         if (info) {
703                 WMESH_LOGD("    short slot time:");
704                 if (nla_get_u16(info)) {
705                         WMESH_LOGD("    yes");
706                         station_info->short_slot_time = TRUE;
707                 } else {
708                         WMESH_LOGD("    no");
709                         station_info->short_slot_time = FALSE;
710                 }
711         }
712 }
713
714 static void print_power_mode(struct nlattr *a)
715 {
716         enum nl80211_mesh_power_mode pm = nla_get_u32(a);
717
718         switch (pm) {
719         case NL80211_MESH_POWER_ACTIVE:
720                 WMESH_LOGD("ACTIVE");
721                 break;
722         case NL80211_MESH_POWER_LIGHT_SLEEP:
723                 WMESH_LOGD("LIGHT SLEEP");
724                 break;
725         case NL80211_MESH_POWER_DEEP_SLEEP:
726                 WMESH_LOGD("DEEP SLEEP");
727                 break;
728         default:
729                 WMESH_LOGD("UNKNOWN");
730                 break;
731         }
732 }
733
734 static int _on_receive_station_info(struct nl_msg *msg, void *arg)
735 {
736         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
737         struct nlattr *sta_info[NL80211_STA_INFO_MAX + 1];
738         struct nlattr *attr_info[NL80211_ATTR_MAX + 1];
739         struct nl80211_sta_flag_update *sta_flags;
740         static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
741                 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
742                 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
743                 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
744                 [NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
745                 [NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
746                 [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
747                 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
748                 [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
749                 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
750                 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
751                 [NL80211_STA_INFO_TX_RETRIES] = { .type = NLA_U32 },
752                 [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
753                 [NL80211_STA_INFO_RX_BITRATE] = { .type = NLA_NESTED },
754                 [NL80211_STA_INFO_BSS_PARAM] = { .type = NLA_NESTED },
755                 [NL80211_STA_INFO_STA_FLAGS] = { .minlen = sizeof(struct nl80211_sta_flag_update) },
756                 [NL80211_STA_INFO_BEACON_LOSS] = { .type = NLA_U32},
757                 [NL80211_STA_INFO_T_OFFSET] = { .type = NLA_U64 },
758                 [NL80211_STA_INFO_LOCAL_PM] = { .type = NLA_U32 },
759                 [NL80211_STA_INFO_PEER_PM] = { .type = NLA_U32 },
760                 [NL80211_STA_INFO_NONPEER_PM] = { .type = NLA_U32 },
761                 [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
762                 [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
763 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL
764                 [NL80211_STA_INFO_CHAIN_SIGNAL] = { .type = NLA_NESTED },
765 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL */
766
767 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL_AVG
768                 [NL80211_STA_INFO_CHAIN_SIGNAL_AVG] = { .type = NLA_NESTED },
769 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL_AVG */
770
771 #ifdef NL80211_STA_INFO_RX_DROP_MISC
772                 [NL80211_STA_INFO_RX_DROP_MISC] = { .type = NLA_U64 },
773 #endif /* NL80211_STA_INFO_RX_DROP_MISC */
774
775 #ifdef NL80211_STA_INFO_RX_DURATION
776                 [NL80211_STA_INFO_BEACON_RX] = { .type = NLA_U64 },
777 #endif /* NL80211_STA_INFO_RX_DURATION */
778
779 #ifdef NL80211_STA_INFO_TID_STATS
780                 [NL80211_STA_INFO_TID_STATS] = { .type = NLA_NESTED },
781 #endif /* NL80211_STA_INFO_TID_STATS */
782
783 #ifdef NL80211_STA_INFO_RX_DURATION
784                 [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 },
785 #endif /* NL80211_STA_INFO_RX_DURATION */
786         };
787         char mac_addr[MAX_MAC_ADDR_LEN], dev[IF_NAMESIZE];
788 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL
789         char *chain;
790 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL */
791         char *attr_mac = NULL;
792         mesh_nl_state *state = (mesh_nl_state *)arg;
793         wmesh_station_info_s *station_info = NULL;
794
795         nla_parse(attr_info, NL80211_ATTR_MAX,
796                         genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
797
798         if (!attr_info[NL80211_ATTR_STA_INFO]) {
799                 WMESH_LOGE("[Station] missing station stats !");
800                 return NL_SKIP;
801         }
802
803         if (nla_parse_nested(sta_info, NL80211_STA_INFO_MAX,
804                                 attr_info[NL80211_ATTR_STA_INFO], stats_policy)) {
805                 WMESH_LOGE("[Station] Failed to parse nested attributes!");
806                 return NL_SKIP;
807         }
808
809         /* Allocation */
810         station_info = g_try_new0(wmesh_station_info_s, 1);
811         if (NULL == station_info) {
812                 WMESH_LOGE("Failed to allocate station info !");
813                 return NL_SKIP;
814         }
815
816         /* BSSID */
817         attr_mac = nla_data(attr_info[NL80211_ATTR_MAC]);
818         snprintf(mac_addr, MAX_MAC_ADDR_LEN, "%02x:%02x:%02x:%02x:%02x:%02x",
819                         attr_mac[0], attr_mac[1], attr_mac[2],
820                         attr_mac[3], attr_mac[4], attr_mac[5]);
821         if_indextoname(nla_get_u32(attr_info[NL80211_ATTR_IFINDEX]), dev);
822         station_info->bssid = g_strdup(mac_addr);
823         WMESH_LOGD("Station %s [dev %s]", station_info->bssid, dev);
824
825         /* Inactive time */
826         if (0 != sta_info[NL80211_STA_INFO_INACTIVE_TIME]) {
827                 station_info->inactive_time =
828                         nla_get_u32(sta_info[NL80211_STA_INFO_INACTIVE_TIME]);
829                 WMESH_LOGE("    inactive time:\t%u ms", station_info->inactive_time);
830         }
831
832         /* RX Bytes */
833         if (0 != sta_info[NL80211_STA_INFO_RX_BYTES]) {
834                 station_info->rx_bytes =
835                                 nla_get_u32(sta_info[NL80211_STA_INFO_RX_BYTES]);
836                 WMESH_LOGD("    rx bytes:\t%u", station_info->rx_bytes);
837         } else if (0 != sta_info[NL80211_STA_INFO_RX_BYTES64]) {
838                 station_info->rx_bytes =
839                         (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_RX_BYTES64]);
840                 WMESH_LOGE("    rx bytes:\t%llu", station_info->rx_bytes);
841         }
842
843         /* RX Packets */
844         if (0 != sta_info[NL80211_STA_INFO_RX_PACKETS]) {
845                 station_info->rx_packets =
846                                 nla_get_u32(sta_info[NL80211_STA_INFO_RX_PACKETS]);
847                 WMESH_LOGD("    rx packets:\t%u", station_info->rx_packets);
848         }
849
850         /* TX Bytes */
851         if (0 != sta_info[NL80211_STA_INFO_TX_BYTES]) {
852                 station_info->tx_bytes =
853                                 nla_get_u32(sta_info[NL80211_STA_INFO_TX_BYTES]);
854                 WMESH_LOGD("    tx bytes:\t%u", station_info->tx_bytes);
855         } else if (0 != sta_info[NL80211_STA_INFO_TX_BYTES64]) {
856                 station_info->tx_bytes =
857                                 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_TX_BYTES64]);
858                 WMESH_LOGD("    tx bytes:\t%llu", station_info->rx_packets);
859         }
860
861         /* LLID, PLID */
862         if (0 != sta_info[NL80211_STA_INFO_LLID]) {
863                 station_info->llid = nla_get_u16(sta_info[NL80211_STA_INFO_LLID]);
864                 WMESH_LOGD("    mesh llid:\t%d", station_info->llid);
865         }
866         if (0 != sta_info[NL80211_STA_INFO_PLID]) {
867                 station_info->plid = nla_get_u16(sta_info[NL80211_STA_INFO_PLID]);
868                 WMESH_LOGD("    mesh plid:\t%d", station_info->plid);
869         }
870
871         /* Plink state */
872         if (0 != sta_info[NL80211_STA_INFO_PLINK_STATE]) {
873                 char state_name[10];
874                 station_info->mesh_plink =
875                                 nla_get_u8(sta_info[NL80211_STA_INFO_PLINK_STATE]);
876                 switch (station_info->mesh_plink) {
877                 case LISTEN:
878                         snprintf(state_name, 10, "%s", "LISTEN");
879                         break;
880                 case OPN_SNT:
881                         snprintf(state_name, 10, "%s", "OPN_SNT");
882                         break;
883                 case OPN_RCVD:
884                         snprintf(state_name, 10, "%s", "OPN_RCVD");
885                         break;
886                 case CNF_RCVD:
887                         snprintf(state_name, 10, "%s", "CNF_RCVD");
888                         break;
889                 case ESTAB:
890                         snprintf(state_name, 10, "%s", "ESTAB");
891                         break;
892                 case HOLDING:
893                         snprintf(state_name, 10, "%s", "HOLDING");
894                         break;
895                 case BLOCKED:
896                         snprintf(state_name, 10, "%s", "BLOCKED");
897                         break;
898                 default:
899                         snprintf(state_name, 10, "%s", "UNKNOWN");
900                         break;
901                 }
902                 WMESH_LOGD("    mesh plink:\t%s", state_name);
903         }
904 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL
905         /* RSSI Signal */
906         chain = get_chain_signal(sta_info[NL80211_STA_INFO_CHAIN_SIGNAL]);
907         if (0 != sta_info[NL80211_STA_INFO_SIGNAL]) {
908                 station_info->rssi =
909                                 (int8_t)nla_get_u8(sta_info[NL80211_STA_INFO_SIGNAL]);
910                 WMESH_LOGD("    signal:  \t%d %sdBm", station_info->rssi, chain);
911         }
912 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL */
913         /* TX Bitrate */
914         if (0 != sta_info[NL80211_STA_INFO_TX_BITRATE]) {
915                 char buf[100];
916                 station_info->tx_bitrate =
917                         parse_bitrate(sta_info[NL80211_STA_INFO_TX_BITRATE], buf, sizeof(buf));
918                 WMESH_LOGD("    tx bitrate:\t%s", buf);
919         }
920
921         if (0 != sta_info[NL80211_STA_INFO_TX_PACKETS]) {
922                 station_info->tx_packets =
923                                 nla_get_u32(sta_info[NL80211_STA_INFO_TX_PACKETS]);
924                 WMESH_LOGD("    tx packets:\t%u", station_info->tx_packets);
925         }
926         if (0 != sta_info[NL80211_STA_INFO_TX_RETRIES]) {
927                 station_info->tx_retries =
928                                 nla_get_u32(sta_info[NL80211_STA_INFO_TX_RETRIES]);
929                 WMESH_LOGD("    tx retries:\t%u", station_info->tx_retries);
930         }
931         if (0 != sta_info[NL80211_STA_INFO_TX_FAILED]) {
932                 station_info->tx_failed =
933                                 nla_get_u32(sta_info[NL80211_STA_INFO_TX_FAILED]);
934                 WMESH_LOGD("    tx failed:\t%u", station_info->tx_failed);
935         }
936 #ifdef NL80211_STA_INFO_CHAIN_SIGNAL_AVG
937         /* Signal average */
938         chain = get_chain_signal(sta_info[NL80211_STA_INFO_CHAIN_SIGNAL_AVG]);
939         if (0 != sta_info[NL80211_STA_INFO_SIGNAL_AVG]) {
940                 station_info->rssi_avg =
941                                 (int8_t)nla_get_u8(sta_info[NL80211_STA_INFO_SIGNAL_AVG]);
942                 WMESH_LOGD("    signal avg:\t%d %sdBm", station_info->rssi_avg, chain);
943         }
944 #endif /* NL80211_STA_INFO_CHAIN_SIGNAL_AVG */
945         if (0 != sta_info[NL80211_STA_INFO_RX_BITRATE]) {
946                 char buf[100];
947                 station_info->rx_bitrate =
948                         parse_bitrate(sta_info[NL80211_STA_INFO_RX_BITRATE], buf, sizeof(buf));
949                 WMESH_LOGD("    rx bitrate:\t%s", buf);
950         }
951
952         if (0 != sta_info[NL80211_STA_INFO_BSS_PARAM])
953                 parse_bss_param(sta_info[NL80211_STA_INFO_BSS_PARAM], station_info);
954
955         if (0 != sta_info[NL80211_STA_INFO_CONNECTED_TIME]) {
956                 station_info->connected_time =
957                                 nla_get_u32(sta_info[NL80211_STA_INFO_CONNECTED_TIME]);
958                 WMESH_LOGD("    connected time:\t%u seconds", station_info->connected_time);
959         }
960
961         if (0 != sta_info[NL80211_STA_INFO_STA_FLAGS]) {
962                 sta_flags = (struct nl80211_sta_flag_update *)
963                             nla_data(sta_info[NL80211_STA_INFO_STA_FLAGS]);
964
965                 if (sta_flags->mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
966                         WMESH_LOGD("    authorized:");
967                         if (sta_flags->set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
968                                 WMESH_LOGD("        yes");
969                                 station_info->authorized = TRUE;
970                         } else {
971                                 WMESH_LOGD("        no");
972                                 station_info->authorized = FALSE;
973                         }
974                 }
975
976                 if (sta_flags->mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
977                         WMESH_LOGD("    authenticated:");
978                         if (sta_flags->set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
979                                 WMESH_LOGD("        yes");
980                                 station_info->authenticated = TRUE;
981                         } else {
982                                 WMESH_LOGD("        no");
983                                 station_info->authenticated = FALSE;
984                         }
985                 }
986
987                 if (sta_flags->mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
988                         WMESH_LOGD("    associated:");
989                         if (sta_flags->set & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
990                                 WMESH_LOGD("        yes");
991                                 station_info->associated = TRUE;
992                         } else {
993                                 WMESH_LOGD("        no");
994                                 station_info->associated = FALSE;
995                         }
996                 }
997
998                 if (sta_flags->mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
999                         WMESH_LOGD("    preamble:");
1000                         if (sta_flags->set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
1001                                 WMESH_LOGD("        short");
1002                                 station_info->preamble = TRUE;
1003                         } else {
1004                                 WMESH_LOGD("        long");
1005                                 station_info->preamble = FALSE;
1006                         }
1007                 }
1008
1009                 if (sta_flags->mask & BIT(NL80211_STA_FLAG_WME)) {
1010                         WMESH_LOGD("    WMM/WME:");
1011                         if (sta_flags->set & BIT(NL80211_STA_FLAG_WME)) {
1012                                 WMESH_LOGD("        yes");
1013                                 station_info->wme = TRUE;
1014                         } else {
1015                                 WMESH_LOGD("        no");
1016                                 station_info->wme = FALSE;
1017                         }
1018                 }
1019
1020                 if (sta_flags->mask & BIT(NL80211_STA_FLAG_MFP)) {
1021                         WMESH_LOGD("    MFP:");
1022                         if (sta_flags->set & BIT(NL80211_STA_FLAG_MFP)) {
1023                                 WMESH_LOGD("        yes");
1024                                 station_info->mfp = TRUE;
1025                         } else {
1026                                 WMESH_LOGD("        no");
1027                                 station_info->mfp = FALSE;
1028                         }
1029                 }
1030
1031                 if (sta_flags->mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
1032                         WMESH_LOGD("    TDLS peer:");
1033                         if (sta_flags->set & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
1034                                 WMESH_LOGD("        yes");
1035                                 station_info->tdls_peer = TRUE;
1036                         } else {
1037                                 WMESH_LOGD("        no");
1038                                 station_info->tdls_peer = FALSE;
1039                         }
1040                 }
1041         }
1042
1043         if (0 != sta_info[NL80211_STA_INFO_BEACON_LOSS]) {
1044                 station_info->beacon_loss =
1045                                 nla_get_u32(sta_info[NL80211_STA_INFO_BEACON_LOSS]);
1046                 WMESH_LOGD("    beacon loss:\t%u", station_info->beacon_loss);
1047         }
1048
1049         if (0 != sta_info[NL80211_STA_INFO_T_OFFSET]) {
1050                 station_info->t_offset =
1051                         (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_T_OFFSET]);
1052                 WMESH_LOGD("    Toffset:\t%llu us", station_info->t_offset);
1053         }
1054
1055         if (0 != sta_info[NL80211_STA_INFO_LOCAL_PM]) {
1056                 station_info->local_ps_mode =
1057                                 nla_get_u32(sta_info[NL80211_STA_INFO_LOCAL_PM]);
1058                 WMESH_LOGD("    mesh local PS mode:\t");
1059                 print_power_mode(sta_info[NL80211_STA_INFO_LOCAL_PM]);
1060         }
1061         if (0 != sta_info[NL80211_STA_INFO_PEER_PM]) {
1062                 station_info->peer_ps_mode =
1063                                 nla_get_u32(sta_info[NL80211_STA_INFO_PEER_PM]);
1064                 WMESH_LOGD("    mesh peer PS mode:\t");
1065                 print_power_mode(sta_info[NL80211_STA_INFO_PEER_PM]);
1066         }
1067         if (0 != sta_info[NL80211_STA_INFO_NONPEER_PM]) {
1068                 station_info->non_peer_ps_mode =
1069                                 nla_get_u32(sta_info[NL80211_STA_INFO_NONPEER_PM]);
1070                 WMESH_LOGD("    mesh non-peer PS mode:\t");
1071                 print_power_mode(sta_info[NL80211_STA_INFO_NONPEER_PM]);
1072         }
1073 #ifdef NL80211_STA_INFO_RX_DROP_MISC
1074         if (0 != sta_info[NL80211_STA_INFO_RX_DROP_MISC]) {
1075                 station_info->rx_drop_misc =
1076                         (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_RX_DROP_MISC]);
1077                 WMESH_LOGD("    rx drop misc:\t%llu", station_info->rx_drop_misc);
1078         }
1079 #endif /* NL80211_STA_INFO_RX_DROP_MISC */
1080
1081 #ifdef NL80211_STA_INFO_BEACON_RX
1082         if (0 != sta_info[NL80211_STA_INFO_BEACON_RX]) {
1083                 station_info->beacon_rx =
1084                                 (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_BEACON_RX]);
1085                 WMESH_LOGD("    beacon rx:\t%llu", station_info->beacon_rx);
1086         }
1087 #endif /* NL80211_STA_INFO_BEACON_RX */
1088
1089 #ifdef NL80211_STA_INFO_BEACON_SIGNAL_AVG
1090         if (0 != sta_info[NL80211_STA_INFO_BEACON_SIGNAL_AVG]) {
1091                 station_info->beacon_signal_avg =
1092                                 nla_get_u8(sta_info[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
1093                 WMESH_LOGD("    beacon signal avg:\t%d dBm", station_info->beacon_signal_avg);
1094         }
1095 #endif /* NL80211_STA_INFO_BEACON_SIGNAL_AVG */
1096
1097 #ifdef NL80211_STA_INFO_RX_DURATION
1098         if (0 != sta_info[NL80211_STA_INFO_RX_DURATION]) {
1099                 station_info->rx_duration =
1100                         (unsigned long long)nla_get_u64(sta_info[NL80211_STA_INFO_RX_DURATION]);
1101                 WMESH_LOGD("    rx duration:\t%lld us", station_info->rx_duration);
1102         }
1103 #endif /* NL80211_STA_INFO_RX_DURATION */
1104         WMESH_LOGD("");
1105         *(state->station_list) = g_list_prepend(*(state->station_list), station_info);
1106
1107         return NL_SKIP;
1108 }
1109
1110 static int _on_receive_mpath_info(struct nl_msg *msg, void *arg)
1111 {
1112         struct nlattr *tb[NL80211_ATTR_MAX + 1];
1113         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1114         struct nlattr *pinfo[NL80211_MPATH_INFO_MAX + 1];
1115         char dst[20], next_hop[20], dev[20];
1116         static struct nla_policy mpath_policy[NL80211_MPATH_INFO_MAX + 1] = {
1117                 [NL80211_MPATH_INFO_FRAME_QLEN] = { .type = NLA_U32 },
1118                 [NL80211_MPATH_INFO_SN] = { .type = NLA_U32 },
1119                 [NL80211_MPATH_INFO_METRIC] = { .type = NLA_U32 },
1120                 [NL80211_MPATH_INFO_EXPTIME] = { .type = NLA_U32 },
1121                 [NL80211_MPATH_INFO_DISCOVERY_TIMEOUT] = { .type = NLA_U32 },
1122                 [NL80211_MPATH_INFO_DISCOVERY_RETRIES] = { .type = NLA_U8 },
1123                 [NL80211_MPATH_INFO_FLAGS] = { .type = NLA_U8 },
1124         };
1125
1126         mesh_nl_state *state = (mesh_nl_state *)arg;
1127         wmesh_mpath_info_s *mpath_info = NULL;
1128
1129         nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1130                 genlmsg_attrlen(gnlh, 0), NULL);
1131
1132         /*
1133          * TODO: validate the interface and mac address!
1134          * Otherwise, there's a race condition as soon as
1135          * the kernel starts sending mpath notifications.
1136          */
1137
1138         if (!tb[NL80211_ATTR_MPATH_INFO]) {
1139                 WMESH_LOGE("missing mesh path info!");
1140                 return NL_SKIP;
1141         }
1142         if (nla_parse_nested(pinfo, NL80211_MPATH_INFO_MAX,
1143                         tb[NL80211_ATTR_MPATH_INFO],
1144                         mpath_policy)) {
1145                 WMESH_LOGE("failed to parse nested attributes!");
1146                 return NL_SKIP;
1147         }
1148
1149         mpath_info = g_try_new0(wmesh_mpath_info_s, 1);
1150         if (NULL == mpath_info) {
1151                 WMESH_LOGE("Failed to allocate mesh path info !");
1152                 return NL_SKIP;
1153         }
1154
1155         mac_addr_n2a(dst, nla_data(tb[NL80211_ATTR_MAC]));
1156         mpath_info->dest_addr = g_strdup(dst);
1157         WMESH_LOGD("Destination Address : %s", mpath_info->dest_addr);
1158
1159         mac_addr_n2a(next_hop, nla_data(tb[NL80211_ATTR_MPATH_NEXT_HOP]));
1160         mpath_info->next_hop = g_strdup(next_hop);
1161         WMESH_LOGD("Next hop Address : %s", mpath_info->next_hop);
1162
1163         if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
1164         mpath_info->interface = g_strdup(dev);
1165         WMESH_LOGD("Interface : %s", mpath_info->interface);
1166
1167         if (pinfo[NL80211_MPATH_INFO_SN]) {
1168                 mpath_info->sn = nla_get_u32(pinfo[NL80211_MPATH_INFO_SN]);
1169                 WMESH_LOGD("SN : %u", mpath_info->sn);
1170         }
1171         if (pinfo[NL80211_MPATH_INFO_METRIC]) {
1172                 mpath_info->metric = nla_get_u32(pinfo[NL80211_MPATH_INFO_METRIC]);
1173                 WMESH_LOGD("Metric : %u", mpath_info->metric);
1174         }
1175         if (pinfo[NL80211_MPATH_INFO_FRAME_QLEN]) {
1176                 mpath_info->qlen = nla_get_u32(pinfo[NL80211_MPATH_INFO_FRAME_QLEN]);
1177                 WMESH_LOGD("QLEN : %u", mpath_info->qlen);
1178         }
1179         if (pinfo[NL80211_MPATH_INFO_EXPTIME]) {
1180                 mpath_info->exptime = nla_get_u32(pinfo[NL80211_MPATH_INFO_EXPTIME]);
1181                 WMESH_LOGD("ExpTime : %u", mpath_info->exptime);
1182         }
1183         if (pinfo[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT]) {
1184                 mpath_info->discovery_timeout =
1185                                 nla_get_u32(pinfo[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT]);
1186                 WMESH_LOGD("Discovery Timeout : %u", mpath_info->discovery_timeout);
1187         }
1188         if (pinfo[NL80211_MPATH_INFO_DISCOVERY_RETRIES]) {
1189                 mpath_info->discovery_retries =
1190                                 nla_get_u8(pinfo[NL80211_MPATH_INFO_DISCOVERY_RETRIES]);
1191                 WMESH_LOGD("Discovery Retries : %u", mpath_info->discovery_retries);
1192         }
1193         if (pinfo[NL80211_MPATH_INFO_FLAGS]) {
1194                 mpath_info->flags = nla_get_u8(pinfo[NL80211_MPATH_INFO_FLAGS]);
1195                 WMESH_LOGD("Flags : 0x%x", mpath_info->flags);
1196         }
1197
1198         WMESH_LOGD("");
1199         *(state->mpath_list) = g_list_prepend(*(state->mpath_list), mpath_info);
1200
1201         return NL_SKIP;
1202 }
1203
1204 static int _on_receive_meshconf_info(struct nl_msg *msg, void *arg)
1205 {
1206         struct nlattr *tb[NL80211_ATTR_MAX + 1];
1207         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1208         struct nlattr *pinfo[NL80211_MESHCONF_ATTR_MAX + 1];
1209         static struct nla_policy meshconf_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
1210                 [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 },
1211                 [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 },
1212                 [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 },
1213                 [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 },
1214                 [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 },
1215                 [NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
1216                 [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
1217                 [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
1218                 [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
1219                 [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
1220                 [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
1221                 [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
1222                 [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
1223                 [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
1224                 [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = { .type = NLA_U16 },
1225                 [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
1226                 [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
1227                 [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
1228                 [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
1229                 [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
1230                 [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 },
1231                 [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
1232                 [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
1233                 [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
1234                 [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
1235                 [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
1236                 [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
1237         };
1238
1239         mesh_nl_state *state = (mesh_nl_state *)arg;
1240         wmesh_meshconf_info_s *meshconf_info = NULL;
1241
1242         nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1243                 genlmsg_attrlen(gnlh, 0), NULL);
1244
1245         /*
1246          * TODO: validate the interface and mac address!
1247          * Otherwise, there's a race condition as soon as
1248          * the kernel starts sending mpath notifications.
1249          */
1250
1251         if (!tb[NL80211_ATTR_MESH_CONFIG]) {
1252                 WMESH_LOGE("missing mesh path info!");
1253                 return NL_SKIP;
1254         }
1255         if (nla_parse_nested(pinfo, NL80211_MESHCONF_ATTR_MAX,
1256                                                 tb[NL80211_ATTR_MESH_CONFIG], meshconf_policy)) {
1257                 WMESH_LOGE("failed to parse nested attributes!");
1258                 return NL_SKIP;
1259         }
1260
1261         meshconf_info = g_try_new0(wmesh_meshconf_info_s, 1);
1262         if (NULL == meshconf_info) {
1263                 WMESH_LOGE("Failed to allocate mesh path info !");
1264                 return NL_SKIP;
1265         }
1266
1267         if (pinfo[NL80211_MESHCONF_RETRY_TIMEOUT]) {
1268                 meshconf_info->retry_timeout =
1269                         nla_get_u16(pinfo[NL80211_MESHCONF_RETRY_TIMEOUT]);
1270                 WMESH_LOGD("Retry Timeout : %u", meshconf_info->retry_timeout);
1271         }
1272         if (pinfo[NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES]) {
1273                 meshconf_info->hwmp_max_preq_retries =
1274                         nla_get_u8(pinfo[NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES]);
1275                 WMESH_LOGD("HWMP Max PREQ Retries : %u",
1276                                    meshconf_info->hwmp_max_preq_retries);
1277         }
1278         if (pinfo[NL80211_MESHCONF_CONFIRM_TIMEOUT]) {
1279                 meshconf_info->confirm_timeout =
1280                         nla_get_u16(pinfo[NL80211_MESHCONF_CONFIRM_TIMEOUT]);
1281                 WMESH_LOGD("Confirm Timeout : %u", meshconf_info->confirm_timeout);
1282         }
1283         if (pinfo[NL80211_MESHCONF_PATH_REFRESH_TIME]) {
1284                 meshconf_info->path_refresh_time =
1285                         nla_get_u32(pinfo[NL80211_MESHCONF_PATH_REFRESH_TIME]);
1286                 WMESH_LOGD("Path Refresh Time : %u", meshconf_info->path_refresh_time);
1287         }
1288         if (pinfo[NL80211_MESHCONF_HOLDING_TIMEOUT]) {
1289                 meshconf_info->holding_timeout =
1290                         nla_get_u16(pinfo[NL80211_MESHCONF_HOLDING_TIMEOUT]);
1291                 WMESH_LOGD("Holding Timeout : %u", meshconf_info->holding_timeout);
1292         }
1293         if (pinfo[NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT]) {
1294                 meshconf_info->min_disc_timeout =
1295                         nla_get_u16(pinfo[NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT]);
1296                 WMESH_LOGD("Min Disc Timeout : %u", meshconf_info->min_disc_timeout);
1297         }
1298         if (pinfo[NL80211_MESHCONF_MAX_PEER_LINKS]) {
1299                 meshconf_info->max_peer_links =
1300                         nla_get_u16(pinfo[NL80211_MESHCONF_MAX_PEER_LINKS]);
1301                 WMESH_LOGD("MAX Peer Links : %u", meshconf_info->max_peer_links);
1302         }
1303         if (pinfo[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL]) {
1304                 meshconf_info->hwmp_preq_min_interval =
1305                         nla_get_u16(pinfo[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL]);
1306                 WMESH_LOGD("HWMP PREQ Min Interval : %u",
1307                                    meshconf_info->hwmp_preq_min_interval);
1308         }
1309         if (pinfo[NL80211_MESHCONF_TTL]) {
1310                 meshconf_info->ttl =
1311                         nla_get_u8(pinfo[NL80211_MESHCONF_TTL]);
1312                 WMESH_LOGD("TTL : %u", meshconf_info->ttl);
1313         }
1314         if (pinfo[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT]) {
1315                 meshconf_info->hwmp_active_path_timeout =
1316                         nla_get_u32(pinfo[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT]);
1317                 WMESH_LOGD("HWMP Active Path Timeout : %u",
1318                                    meshconf_info->hwmp_active_path_timeout);
1319         }
1320         if (pinfo[NL80211_MESHCONF_ELEMENT_TTL]) {
1321                 meshconf_info->element_ttl =
1322                         nla_get_u8(pinfo[NL80211_MESHCONF_ELEMENT_TTL]);
1323                 WMESH_LOGD("Element TTL : %u", meshconf_info->element_ttl);
1324         }
1325         if (pinfo[NL80211_MESHCONF_HWMP_RANN_INTERVAL]) {
1326                 meshconf_info->hwmp_rann_interval =
1327                         nla_get_u16(pinfo[NL80211_MESHCONF_HWMP_RANN_INTERVAL]);
1328                 WMESH_LOGD("HWMP RANN Interval : %u",
1329                                    meshconf_info->hwmp_rann_interval);
1330         }
1331         if (pinfo[NL80211_MESHCONF_GATE_ANNOUNCEMENTS]) {
1332                 meshconf_info->gate_announcements =
1333                         nla_get_u8(pinfo[NL80211_MESHCONF_GATE_ANNOUNCEMENTS]);
1334                 WMESH_LOGD("Gate Announcements : %u",
1335                                    meshconf_info->gate_announcements);
1336         }
1337
1338         WMESH_LOGD("");
1339         *(state->meshconf) = meshconf_info;
1340
1341         return NL_SKIP;
1342 }
1343
1344 static int _on_receive_mesh_event(struct nl_msg *msg, void *arg)
1345 {
1346         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1347         struct nlattr *tb[NL80211_ATTR_MAX + 1];
1348         char ifname[16] = { 0, };
1349         char macbuf[MAX_MAC_ADDR_LEN];
1350
1351         wmesh_service *service = arg;
1352         wmesh_interface_s *info = service->interface_info;
1353
1354         nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
1355
1356         if (tb[NL80211_ATTR_IFINDEX]) {
1357                 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
1358                 WMESH_LOGD("%s: ", ifname);
1359         }
1360
1361         switch (gnlh->cmd) {
1362         case NL80211_CMD_NEW_STATION:
1363                 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1364                 WMESH_LOGD("[%s] new station [%s]", ifname, macbuf);
1365
1366                 if (g_strcmp0(info->mesh_interface, ifname) == 0)
1367                         wmesh_notify_station_joined((const char*)macbuf,
1368                                                                                 WMESHD_STATION_TYPE_MESH_POINT);
1369                 else if (g_strcmp0(info->softap_interface, ifname) == 0)
1370                         wmesh_notify_station_joined((const char*)macbuf,
1371                                                                                 WMESHD_STATION_TYPE_SOFTAP);
1372
1373                 break;
1374         case NL80211_CMD_DEL_STATION:
1375                 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1376                 WMESH_LOGD("[%s] del station [%s]", ifname, macbuf);
1377
1378                 if (g_strcmp0(info->mesh_interface, ifname) == 0)
1379                         wmesh_notify_station_left((const char*)macbuf,
1380                                                                           WMESHD_STATION_TYPE_MESH_POINT);
1381                 else if (g_strcmp0(info->softap_interface, ifname) == 0)
1382                         wmesh_notify_station_left((const char*)macbuf,
1383                                                                           WMESHD_STATION_TYPE_SOFTAP);
1384
1385                 break;
1386         case NL80211_CMD_NEW_MPATH:
1387                 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1388                 WMESH_LOGD("[%s] new mpath [%s]", ifname, macbuf);
1389
1390                 break;
1391         case NL80211_CMD_DEL_MPATH:
1392                 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1393                 WMESH_LOGD("[%s] del mpath [%s]", ifname, macbuf);
1394
1395                 break;
1396         default:
1397                 WMESH_LOGD("event [%d] is not handled", gnlh->cmd);
1398                 break;
1399         }
1400
1401         return NL_SKIP;
1402 }
1403 /* LCOV_EXCL_STOP */
1404
1405 static int _send_nl_set_mesh_parameter(const char* mesh_if_name,
1406                 const char* param_name, unsigned int value)
1407 {
1408         mesh_nl_state state = {
1409                 .nl80211_id = -1,
1410                 .callback_state = MESH_NL_CALLBACK_TRYING,
1411                 .event_source = 0,
1412                 .nl_socket = NULL,
1413                 .msg = NULL,
1414                 .cb = NULL,
1415                 .s_cb = NULL,
1416                 .error_occured = FALSE,
1417         };
1418         struct nlattr *container;
1419
1420         int err = WMESHD_ERROR_NONE;
1421         int device_index = 0;
1422         int ret;
1423         int test = 0;
1424
1425         ret = __initialize_nl80211(&state);
1426         if (WMESHD_ERROR_NONE != ret) {
1427                 /* LCOV_EXCL_START */
1428                 WMESH_LOGE("Failed to initialize nl80211");
1429                 return ret;
1430                 /* LCOV_EXCL_STOP */
1431         }
1432
1433         ret = __initialize_netlink_message(&state);
1434         if (WMESHD_ERROR_NONE != ret) {
1435                 /* LCOV_EXCL_START */
1436                 WMESH_LOGE("Failed to initialize netlink message");
1437                 goto DESTROY;
1438                 /* LCOV_EXCL_STOP */
1439         }
1440
1441         /* Set command into message */
1442         genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1443                     0, NL80211_CMD_SET_MESH_PARAMS, 0);
1444
1445         /* Add attributes into message */
1446         ret = __get_device_index_from_string(mesh_if_name, &device_index);
1447         if (WMESHD_ERROR_NONE != ret) {
1448                 /* LCOV_EXCL_START */
1449                 WMESH_LOGE("Failed to get mesh device index");
1450                 err = ret;
1451                 goto DESTROY;
1452                 /* LCOV_EXCL_STOP */
1453         }
1454         NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1455
1456         container = nla_nest_start(state.msg, NL80211_ATTR_MESH_PARAMS);
1457         if (!container) {
1458                 /* LCOV_EXCL_START */
1459                 WMESH_LOGE("Failed to initialize netlink message");
1460                 goto DESTROY;
1461                 /* LCOV_EXCL_STOP */
1462         }
1463
1464         /* Logic need to be changed if additional parameter is required */
1465         if (g_strcmp0(MESH_PARAM_HWMP_ROOTMODE, param_name) == 0) {
1466                 WMESH_LOGD("  [mesh_hwmp_rootmode] : [%d]", value);
1467                 NLA_PUT_U8(state.msg, NL80211_MESHCONF_HWMP_ROOTMODE,
1468                                 (uint8_t)value);
1469         } else if (g_strcmp0(MESH_PARAM_GATE_ANNOUNCE, param_name) == 0) {
1470                 WMESH_LOGD("  [mesh_gate_announcements] : [%d]", value);
1471                 NLA_PUT_U8(state.msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
1472                                 (uint8_t)value);
1473         } else {
1474                 /* LCOV_EXCL_START */
1475                 WMESH_LOGE("Parameter [%s] is not required !", param_name);
1476                 nla_nest_end(state.msg, container);
1477                 goto DESTROY;
1478                 /* LCOV_EXCL_STOP */
1479         }
1480         nla_nest_end(state.msg, container);
1481
1482         /* Send message into kernel */
1483         ret = nl_send_auto(state.nl_socket, state.msg);
1484         if (ret < 0) {
1485                 /* LCOV_EXCL_START */
1486                 WMESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1487                                 nl_geterror(ret), ret);
1488                 err = WMESHD_ERROR_OPERATION_FAILED;
1489                 goto DESTROY;
1490                 /* LCOV_EXCL_STOP */
1491         }
1492
1493         /* sync response */
1494         state.callback_state = MESH_NL_CALLBACK_TRYING;
1495         while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1496                 WMESH_LOGD("  count [%02d]", ++test);
1497                 nl_recvmsgs(state.nl_socket, state.cb);
1498         }
1499
1500 DESTROY:
1501         __clean_netlink_message(&state);
1502         __clean_nl80211(&state);
1503
1504         return err;
1505
1506 nla_put_failure:
1507         /* LCOV_EXCL_START */
1508         WMESH_LOGE("Failed to message build");
1509         __clean_netlink_message(&state);
1510         __clean_nl80211(&state);
1511
1512         return WMESHD_ERROR_OPERATION_FAILED;
1513         /* LCOV_EXCL_STOP */
1514 }
1515
1516 static int _send_nl_get_station_info(const char* if_name, GList **station_list)
1517 {
1518         mesh_nl_state state = {
1519                 .nl80211_id = -1,
1520                 .callback_state = MESH_NL_CALLBACK_TRYING,
1521                 .event_source = 0,
1522                 .nl_socket = NULL,
1523                 .msg = NULL,
1524                 .cb = NULL,
1525                 .s_cb = NULL,
1526                 .station_list = station_list
1527         };
1528         int err = WMESHD_ERROR_NONE;
1529         int device_index = 0;
1530         int ret;
1531         int test = 0;
1532
1533         ret = __initialize_nl80211(&state);
1534         if (WMESHD_ERROR_NONE != ret) {
1535                 /* LCOV_EXCL_START */
1536                 WMESH_LOGE("Failed to initialize nl80211");
1537                 return ret;
1538                 /* LCOV_EXCL_STOP */
1539         }
1540
1541         ret = __initialize_netlink_message(&state);
1542         if (WMESHD_ERROR_NONE != ret) {
1543                 /* LCOV_EXCL_START */
1544                 WMESH_LOGE("Failed to initialize netlink message");
1545                 goto DESTROY;
1546                 /* LCOV_EXCL_STOP */
1547         }
1548
1549         /* Set command into message */
1550         genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1551                     NLM_F_DUMP, NL80211_CMD_GET_STATION, 0);
1552
1553         /* Add attributes into message */
1554         WMESH_LOGD("Dump station list with interface [%s]", if_name);
1555         ret = __get_device_index_from_string(if_name, &device_index);
1556         if (WMESHD_ERROR_NONE != ret) {
1557                 /* LCOV_EXCL_START */
1558                 WMESH_LOGE("Failed to get mesh interface device index");
1559                 err = ret;
1560                 goto DESTROY;
1561                 /* LCOV_EXCL_STOP */
1562         }
1563         NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1564
1565         /* Register valid callback to dump result */
1566         nl_cb_set(state.cb, NL_CB_VALID, NL_CB_CUSTOM,
1567                         _on_receive_station_info, &state);
1568
1569         /* Send message into kernel */
1570         ret = nl_send_auto(state.nl_socket, state.msg);
1571         if (ret < 0) {
1572                 /* LCOV_EXCL_START */
1573                 WMESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1574                                 nl_geterror(ret), ret);
1575                 err = WMESHD_ERROR_OPERATION_FAILED;
1576                 goto DESTROY;
1577                 /* LCOV_EXCL_STOP */
1578         }
1579
1580         /* sync response */
1581         state.callback_state = MESH_NL_CALLBACK_TRYING;
1582         while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1583                 /* LCOV_EXCL_START */
1584                 WMESH_LOGD("  count [%02d]", ++test);
1585                 nl_recvmsgs(state.nl_socket, state.cb);
1586                 /* LCOV_EXCL_STOP */
1587         }
1588         WMESH_LOGD("Finished");
1589
1590 DESTROY:
1591         __clean_netlink_message(&state);
1592         __clean_nl80211(&state);
1593
1594         return err;
1595
1596 nla_put_failure:
1597         /* LCOV_EXCL_START */
1598         WMESH_LOGE("Failed to message build");
1599         __clean_netlink_message(&state);
1600         __clean_nl80211(&state);
1601
1602         return WMESHD_ERROR_OPERATION_FAILED;
1603         /* LCOV_EXCL_STOP */
1604 }
1605
1606 static int _send_nl_get_mpath_info(const char* if_name, GList **mpath_list)
1607 {
1608         mesh_nl_state state = {
1609                 .nl80211_id = -1,
1610                 .callback_state = MESH_NL_CALLBACK_TRYING,
1611                 .event_source = 0,
1612                 .nl_socket = NULL,
1613                 .msg = NULL,
1614                 .cb = NULL,
1615                 .s_cb = NULL,
1616                 .mpath_list = mpath_list
1617         };
1618         int err = WMESHD_ERROR_NONE;
1619         int device_index = 0;
1620         int ret;
1621         int test = 0;
1622
1623         ret = __initialize_nl80211(&state);
1624         if (WMESHD_ERROR_NONE != ret) {
1625                 /* LCOV_EXCL_START */
1626                 WMESH_LOGE("Failed to initialize nl80211");
1627                 return ret;
1628                 /* LCOV_EXCL_STOP */
1629         }
1630
1631         ret = __initialize_netlink_message(&state);
1632         if (WMESHD_ERROR_NONE != ret) {
1633                 /* LCOV_EXCL_START */
1634                 WMESH_LOGE("Failed to initialize netlink message");
1635                 goto DESTROY;
1636                 /* LCOV_EXCL_STOP */
1637         }
1638
1639         /* Set command into message */
1640         genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1641                     NLM_F_DUMP, NL80211_CMD_GET_MPATH, 0);
1642
1643         /* Add attributes into message */
1644         WMESH_LOGD("Dump station list with interface [%s]", if_name);
1645         ret = __get_device_index_from_string(if_name, &device_index);
1646         if (WMESHD_ERROR_NONE != ret) {
1647                 /* LCOV_EXCL_START */
1648                 WMESH_LOGE("Failed to get mesh interface device index");
1649                 err = ret;
1650                 goto DESTROY;
1651                 /* LCOV_EXCL_STOP */
1652         }
1653         NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1654
1655         /* Register valid callback to dump result */
1656         nl_cb_set(state.cb, NL_CB_VALID, NL_CB_CUSTOM,
1657                         _on_receive_mpath_info, &state);
1658
1659         /* Send message into kernel */
1660         ret = nl_send_auto(state.nl_socket, state.msg);
1661         if (ret < 0) {
1662                 /* LCOV_EXCL_START */
1663                 WMESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1664                                 nl_geterror(ret), ret);
1665                 err = WMESHD_ERROR_OPERATION_FAILED;
1666                 goto DESTROY;
1667                 /* LCOV_EXCL_STOP */
1668         }
1669
1670         /* sync response */
1671         state.callback_state = MESH_NL_CALLBACK_TRYING;
1672         while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1673                 /* LCOV_EXCL_START */
1674                 WMESH_LOGD("  count [%02d]", ++test);
1675                 nl_recvmsgs(state.nl_socket, state.cb);
1676                 /* LCOV_EXCL_STOP */
1677         }
1678         WMESH_LOGD("Finished");
1679
1680 DESTROY:
1681         __clean_netlink_message(&state);
1682         __clean_nl80211(&state);
1683
1684         return err;
1685
1686 nla_put_failure:
1687         /* LCOV_EXCL_START */
1688         WMESH_LOGE("Failed to message build");
1689         __clean_netlink_message(&state);
1690         __clean_nl80211(&state);
1691
1692         return WMESHD_ERROR_OPERATION_FAILED;
1693         /* LCOV_EXCL_STOP */
1694 }
1695
1696 static int _send_nl_get_meshconf_info(wmesh_service *service)
1697 {
1698         mesh_nl_state state = {
1699                 .nl80211_id = -1,
1700                 .callback_state = MESH_NL_CALLBACK_TRYING,
1701                 .event_source = 0,
1702                 .nl_socket = NULL,
1703                 .msg = NULL,
1704                 .cb = NULL,
1705                 .s_cb = NULL,
1706                 .meshconf = &service->meshconf,
1707         };
1708         int err = WMESHD_ERROR_NONE;
1709         int device_index = 0;
1710         int ret;
1711         int test = 0;
1712
1713         ret = __initialize_nl80211(&state);
1714         if (WMESHD_ERROR_NONE != ret) {
1715                 /* LCOV_EXCL_START */
1716                 WMESH_LOGE("Failed to initialize nl80211");
1717                 return ret;
1718                 /* LCOV_EXCL_STOP */
1719         }
1720
1721         ret = __initialize_netlink_message(&state);
1722         if (WMESHD_ERROR_NONE != ret) {
1723                 /* LCOV_EXCL_START */
1724                 WMESH_LOGE("Failed to initialize netlink message");
1725                 goto DESTROY;
1726                 /* LCOV_EXCL_STOP */
1727         }
1728
1729         /* Set command into message */
1730         genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
1731                     0, NL80211_CMD_GET_MESH_CONFIG, 0);
1732
1733         /* Add attributes into message */
1734         WMESH_LOGD("Dump Mesh Config with interface [%s]",
1735                            service->interface_info->mesh_interface);
1736         ret = __get_device_index_from_string(
1737                                         service->interface_info->mesh_interface, &device_index);
1738         if (WMESHD_ERROR_NONE != ret)
1739                 /* LCOV_EXCL_START */{
1740                 WMESH_LOGE("Failed to get mesh interface device index");
1741                 err = ret;
1742                 goto DESTROY;
1743                 /* LCOV_EXCL_STOP */
1744         }
1745         NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
1746
1747         /* Register valid callback to dump result */
1748         nl_cb_set(state.cb, NL_CB_VALID, NL_CB_CUSTOM,
1749                         _on_receive_meshconf_info, &state);
1750
1751         /* Send message into kernel */
1752         ret = nl_send_auto(state.nl_socket, state.msg);
1753         if (ret < 0) {
1754                 /* LCOV_EXCL_START */
1755                 WMESH_LOGE("Failed to nl_send_auto() [%s](%d)",
1756                                 nl_geterror(ret), ret);
1757                 err = WMESHD_ERROR_OPERATION_FAILED;
1758                 goto DESTROY;
1759                 /* LCOV_EXCL_STOP */
1760         }
1761
1762         /* sync response */
1763         state.callback_state = MESH_NL_CALLBACK_TRYING;
1764         while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
1765                 /* LCOV_EXCL_START */
1766                 WMESH_LOGD("  count [%02d]", ++test);
1767                 nl_recvmsgs(state.nl_socket, state.cb);
1768                 /* LCOV_EXCL_STOP */
1769         }
1770         WMESH_LOGD("Finished");
1771
1772 DESTROY:
1773         __clean_netlink_message(&state);
1774         __clean_nl80211(&state);
1775
1776         return err;
1777
1778 nla_put_failure:
1779         /* LCOV_EXCL_START */
1780         WMESH_LOGE("Failed to message build");
1781         __clean_netlink_message(&state);
1782         __clean_nl80211(&state);
1783
1784         return WMESHD_ERROR_OPERATION_FAILED;
1785         /* LCOV_EXCL_STOP */
1786 }
1787
1788 static int _send_nl_register_event_handler(wmesh_service *service)
1789 {
1790         int err = WMESHD_ERROR_NONE;
1791         int ret;
1792         GIOChannel *recv_channel = NULL;
1793
1794         if (event_state) {
1795                 /* LCOV_EXCL_START */
1796                 WMESH_LOGE("Already event handler registered !");
1797                 return WMESHD_ERROR_IN_PROGRESS;
1798                 /* LCOV_EXCL_STOP */
1799         }
1800
1801         event_state = _create_mesh_nl_state("");
1802
1803         ret = __initialize_nl80211(event_state);
1804         if (WMESHD_ERROR_NONE != ret) {
1805                 /* LCOV_EXCL_START */
1806                 WMESH_LOGE("Failed to initialize nl80211");
1807                 return ret;
1808                 /* LCOV_EXCL_STOP */
1809         }
1810
1811         /* Subscribe multicast group should be proceed before scanning */
1812         ret = __prepare_listen_events(event_state);
1813         if (ret) {
1814                 /* LCOV_EXCL_START */
1815                 WMESH_LOGE("__prepare_listen_events : [%d]", ret);
1816                 goto DESTROY;
1817                 /* LCOV_EXCL_STOP */
1818         }
1819
1820         ret = __initialize_netlink_message(event_state);
1821         if (WMESHD_ERROR_NONE != ret) {
1822                 /* LCOV_EXCL_START */
1823                 WMESH_LOGE("Failed to initialize netlink message");
1824                 goto DESTROY;
1825                 /* LCOV_EXCL_STOP */
1826         }
1827
1828         /* Set command into message */
1829         genlmsg_put(event_state->msg, 0, 0, event_state->nl80211_id, 0, 0, 0, 0);
1830
1831         /* Set callbacks for event handler */
1832         nl_cb_set(event_state->cb, NL_CB_VALID, NL_CB_CUSTOM,
1833                         _on_receive_mesh_event, service);
1834         /* No sequence checking for multicast messages. */
1835         nl_cb_set(event_state->cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
1836
1837         WMESH_LOGD("Register event handler");
1838
1839         /* Change socket type to non-blocking */
1840         ret = nl_socket_set_nonblocking(event_state->nl_socket);
1841         if (ret < 0)
1842                 WMESH_LOGE("Failed to non-blocking socket [%s](%d)", nl_geterror(ret), ret); /* LCOV_EXCL_LINE */
1843
1844         /* Register I/O callback to wait asynchronously */
1845         /* LCOV_EXCL_START */
1846         if (FALSE == event_state->error_occured) {
1847                 recv_channel = g_io_channel_unix_new(nl_socket_get_fd(event_state->nl_socket));
1848                 event_state->event_source = g_io_add_watch(recv_channel,
1849                                 (G_IO_IN | G_IO_ERR), _on_socket_event_io_received, event_state);
1850                 g_io_channel_unref(recv_channel);
1851         } else {
1852                 WMESH_LOGE("Error responded. Failed to register event callback !!");
1853                 goto DESTROY;
1854         }
1855         /* LCOV_EXCL_STOP */
1856
1857         /* Resource should be free on I/O callback */
1858         return WMESHD_ERROR_NONE;
1859
1860 DESTROY:
1861         /* LCOV_EXCL_START */
1862         __clean_netlink_message(event_state);
1863         __clean_nl80211(event_state);
1864         _delete_mesh_nl_state(&event_state);
1865
1866         return err;
1867         /* LCOV_EXCL_STOP */
1868 }
1869 /* LCOV_EXCL_STOP */
1870
1871 int wmesh_netlink_set_mesh_parameter(const char* mesh_if_name,
1872                 const char* param_name, unsigned int value)
1873 {
1874         int ret = WMESHD_ERROR_NONE;
1875
1876         if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1877                 /* LCOV_EXCL_START */
1878                 WMESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1879                 return WMESHD_ERROR_INVALID_PARAMETER;
1880                 /* LCOV_EXCL_STOP */
1881         }
1882
1883         WMESH_LOGD("Set mesh[%s] param [%s] value [%d]",
1884                         mesh_if_name, param_name, value);
1885         ret = _send_nl_set_mesh_parameter(mesh_if_name, param_name, value);
1886
1887         return ret;
1888 }
1889
1890 int wmesh_netlink_get_station_info(const char* mesh_if_name, GList **station_list)
1891 {
1892         int ret = WMESHD_ERROR_NONE;
1893
1894         if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1895                 /* LCOV_EXCL_START */
1896                 WMESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1897                 return WMESHD_ERROR_INVALID_PARAMETER;
1898                 /* LCOV_EXCL_STOP */
1899         }
1900         if (NULL == station_list) {
1901                 /* LCOV_EXCL_START */
1902                 WMESH_LOGE("Invalid parameter [%p]", station_list);
1903                 return WMESHD_ERROR_INVALID_PARAMETER;
1904                 /* LCOV_EXCL_STOP */
1905         }
1906
1907         WMESH_LOGD("Get connected stations");
1908         ret = _send_nl_get_station_info(mesh_if_name, station_list);
1909
1910         return ret;
1911 }
1912
1913 int wmesh_netlink_get_mpath_info(const char* mesh_if_name, GList **mpath_list)
1914 {
1915         int ret = WMESHD_ERROR_NONE;
1916
1917         if (NULL == mesh_if_name || strlen(mesh_if_name) > IFNAMSIZ) {
1918                 /* LCOV_EXCL_START */
1919                 WMESH_LOGE("Invalid parameter [%p]", mesh_if_name);
1920                 return WMESHD_ERROR_INVALID_PARAMETER;
1921                 /* LCOV_EXCL_STOP */
1922         }
1923         if (NULL == mpath_list) {
1924                 /* LCOV_EXCL_START */
1925                 WMESH_LOGE("Invalid parameter [%p]", mpath_list);
1926                 return WMESHD_ERROR_INVALID_PARAMETER;
1927                 /* LCOV_EXCL_STOP */
1928         }
1929
1930         WMESH_LOGD("Get current mpath info");
1931         ret = _send_nl_get_mpath_info(mesh_if_name, mpath_list);
1932
1933         return ret;
1934 }
1935
1936 int wmesh_netlink_get_meshconf_info(wmesh_service *service)
1937 {
1938         int ret = WMESHD_ERROR_NONE;
1939
1940         if (NULL == service) {
1941                 /* LCOV_EXCL_START */
1942                 WMESH_LOGE("Invalid parameter [%p]", service);
1943                 return WMESHD_ERROR_INVALID_PARAMETER;
1944                 /* LCOV_EXCL_STOP */
1945         }
1946
1947         WMESH_LOGD("Get current Mesh Config info");
1948         ret = _send_nl_get_meshconf_info(service);
1949
1950         return ret;
1951 }
1952
1953 int wmesh_netlink_register_event_handler(wmesh_service *service)
1954 {
1955         int ret = WMESHD_ERROR_NONE;
1956
1957         WMESH_LOGD("Register mesh event handler");
1958         ret = _send_nl_register_event_handler(service);
1959
1960         return ret;
1961 }
1962
1963 int wmesh_netlink_unregister_event_handler()
1964 {
1965         int ret = WMESHD_ERROR_NONE;
1966
1967         WMESH_LOGD("Unregister mesh event handler");
1968
1969         _on_remove_event_io_handler();
1970
1971         return ret;
1972 }