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