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