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