[connman] Added Tizen Wi-Fi Mesh
[platform/upstream/connman.git] / src / mesh-netlink.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *
6  *  Copyright (C) 2017 Samsung Electronics Co., Ltd.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 2 as
10  *  published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  *  02110-1301  USA
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include "connman.h"
28 #include <connman/mesh-netlink.h>
29 #include <netlink/genl/genl.h>
30 #include <netlink/genl/family.h>
31 #include <netlink/genl/ctrl.h>
32 #include <netlink/msg.h>
33 #include <netlink/attr.h>
34 #include <netlink/netlink.h>
35
36 static int seq_check_cb(struct nl_msg *msg, void *arg)
37 {
38         DBG("");
39
40         return NL_OK;
41 }
42
43 static int finish_cb(struct nl_msg *msg, void *arg)
44 {
45         int *ret = arg;
46
47         DBG("");
48
49         *ret = 0;
50
51         return NL_SKIP;
52 }
53
54 static int ack_cb(struct nl_msg *msg, void *arg)
55 {
56         int *ret = arg;
57
58         DBG("");
59
60         *ret = 0;
61
62         return NL_STOP;
63 }
64
65 static int valid_cb(struct nl_msg *msg, void *arg)
66 {
67         DBG("");
68
69         return NL_SKIP;
70 }
71
72 static int error_cb(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
73 {
74         int *ret = arg;
75
76         *ret = err->error;
77
78         DBG("error %d", *ret);
79
80         return NL_STOP;
81 }
82
83 int __connman_mesh_netlink_set_gate_announce(mesh_nl80211_global *global,
84                                         int mesh_if_index, bool gate_announce, int hwmp_rootmode)
85 {
86         struct nl_msg *msg;
87         struct nlattr *container;
88         struct nl_cb *cb;
89         int err = -1;
90
91         msg = nlmsg_alloc();
92         if (!msg)
93                 return -1;
94
95         cb = nl_cb_clone(global->cb);
96         if (!cb)
97                 goto out;
98
99         genlmsg_put(msg, 0, 0, global->id, 0, 0, NL80211_CMD_SET_MESH_CONFIG, 0);
100         nla_put_u32(msg, NL80211_ATTR_IFINDEX, mesh_if_index);
101
102         container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
103
104         nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE, hwmp_rootmode);
105
106         nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS, gate_announce);
107
108         nla_nest_end(msg, container);
109
110         err = nl_send_auto_complete(global->nl_socket, msg);
111         if (err < 0) {
112                 DBG("Failed to send msg");
113                 goto out;
114         }
115
116         err = 1;
117
118         nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_cb, &err);
119         nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_cb, &err);
120         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_cb, &err);
121         nl_cb_err(cb, NL_CB_CUSTOM, error_cb, &err);
122
123         while (err > 0) {
124                 int res = nl_recvmsgs(global->nl_socket, cb);
125                 if (res < 0)
126                         DBG("nl_recvmsgs failed: %d", res);
127         }
128
129 out:
130         nl_cb_put(cb);
131         nlmsg_free(msg);
132         return err;
133 }
134
135 mesh_nl80211_global *__connman_mesh_nl80211_global_init(void)
136 {
137         mesh_nl80211_global *global;
138
139         DBG("");
140
141         global = g_malloc0(sizeof(mesh_nl80211_global));
142
143         global->nl_socket = nl_socket_alloc();
144         if (!global->nl_socket) {
145                 DBG("Failed to allocate netlink socket");
146                 g_free(global);
147                 return NULL;
148         }
149
150         if (genl_connect(global->nl_socket)) {
151                 DBG("Failed to connect to generic netlink");
152                 nl_socket_free(global->nl_socket);
153                 g_free(global);
154                 return NULL;
155         }
156
157         nl_socket_set_buffer_size(global->nl_socket, 8192, 8192);
158
159         global->id = genl_ctrl_resolve(global->nl_socket, "nl80211");
160         if (global->id < 0) {
161                 DBG("nl80211 generic netlink not found");
162                 nl_socket_free(global->nl_socket);
163                 g_free(global);
164                 return NULL;
165         }
166
167         global->cb = nl_cb_alloc(NL_CB_DEFAULT);
168         if (!global->cb) {
169                 DBG("Failed to allocate netwlink callbacks");
170                 nl_socket_free(global->nl_socket);
171                 g_free(global);
172                 return NULL;
173         }
174
175         nl_cb_set(global->cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, seq_check_cb, NULL);
176
177         return global;
178 }
179
180 void __connman_mesh_nl80211_global_deinit(mesh_nl80211_global *global)
181 {
182         DBG("");
183
184         nl_cb_put(global->cb);
185         nl_socket_free(global->nl_socket);
186         g_free(global);
187 }