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