Add multi interfaces function
[platform/core/connectivity/net-config.git] / src / wifi-wps.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2000 - 2012 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
20 #include <errno.h>
21 #include <vconf.h>
22 #include <glib.h>
23
24 #include "log.h"
25 #include "util.h"
26 #include "netdbus.h"
27 #include "neterror.h"
28 #include "wifi-wps.h"
29 #include "wifi-power.h"
30 #include "wifi-state.h"
31 #include "netsupplicant.h"
32 #include "wifi-background-scan.h"
33
34 typedef struct {
35         char *interface_name;
36         char *pin;
37         gboolean pbc;
38 } wifi_wps_s;
39
40 GSList *g_wifi_wps_list = NULL;
41
42 static void __free_wifi_wps(gpointer data)
43 {
44         wifi_wps_s *wifi_wps = data;
45
46         g_free(wifi_wps->interface_name);
47         g_free(wifi_wps->pin);
48         g_free(wifi_wps);
49 }
50
51 static wifi_wps_s *__get_wifi_wps(const char *interface_name)
52 {
53         GSList *list = NULL;
54
55         for (list = g_wifi_wps_list; list; list = list->next) {
56                 wifi_wps_s *wifi_wps = list->data;
57                 if (g_strcmp0(wifi_wps->interface_name, interface_name) == 0)
58                         return wifi_wps;
59         }
60
61         return NULL;
62 }
63
64 static void __destroy_wifi_wps(const char *interface_name)
65 {
66         wifi_wps_s *wifi_wps;
67
68         wifi_wps = __get_wifi_wps(interface_name);
69         if (wifi_wps == NULL)
70                 return;
71
72         g_wifi_wps_list = g_slist_remove(g_wifi_wps_list, wifi_wps);
73         __free_wifi_wps(wifi_wps);
74 }
75
76 static void __create_wifi_wps(const char *interface_name)
77 {
78         wifi_wps_s *wifi_wps;
79
80         wifi_wps = g_try_new0(wifi_wps_s, 1);
81         if (wifi_wps == NULL)
82                 return;
83
84         wifi_wps->interface_name = g_strdup(interface_name);
85         g_wifi_wps_list = g_slist_append(g_wifi_wps_list, wifi_wps);
86 }
87
88 static void __set_wifi_wps(const char *interface_name, gboolean pbc, char *pin)
89 {
90         wifi_wps_s *wifi_wps;
91
92         wifi_wps = __get_wifi_wps(interface_name);
93         if (wifi_wps == NULL)
94                 return;
95
96         wifi_wps->pbc = pbc;
97         if (pin)
98                 wifi_wps->pin = g_strdup(pin);
99 }
100
101 static gboolean __get_wifi_wps_pbc(const char *interface_name)
102 {
103         wifi_wps_s *wifi_wps;
104
105         wifi_wps = __get_wifi_wps(interface_name);
106         if (wifi_wps == NULL)
107                 return FALSE;
108
109         return wifi_wps->pbc;
110 }
111
112 static char *__get_wifi_wps_pin(const char *interface_name)
113 {
114         wifi_wps_s *wifi_wps;
115
116         wifi_wps = __get_wifi_wps(interface_name);
117         if (wifi_wps == NULL)
118                 return NULL;
119
120         return wifi_wps->pin;
121 }
122
123 void netconfig_wifi_notify_wps_credentials(const char *interface_name,
124                 const char *ssid, gsize ssid_len, const char *wps_key)
125 {
126         GVariantBuilder *builder;
127         GVariant *params;
128         const char *sig_name = "WpsCredentials";
129         const char *prop_ssid = "ssid";
130         const char *prop_key = "key";
131         GVariantBuilder *rawssid_builder = NULL;
132         int i;
133
134         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
135         rawssid_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
136         for (i = 0; i < ssid_len; i++)
137                 g_variant_builder_add(rawssid_builder, "y", ssid[i]);
138         g_variant_builder_add(builder, "{sv}", prop_ssid, g_variant_new("ay", rawssid_builder));
139         g_variant_builder_unref(rawssid_builder);
140         g_variant_builder_add(builder, "{sv}", prop_key, g_variant_new_string(wps_key));
141
142         params = g_variant_new("(s@a{sv})", interface_name,
143                                 g_variant_builder_end(builder));
144         g_variant_builder_unref(builder);
145
146         netconfig_dbus_emit_signal(NULL,
147                                 NETCONFIG_WIFI_PATH,
148                                 NETCONFIG_WIFI_INTERFACE,
149                                 sig_name,
150                                 params);
151
152         INFO("Sent signal (%s)", sig_name);
153         return;
154 }
155
156 void netconfig_wifi_notify_wps_completed(const char *interface_name,
157                 const char *ssid, gsize ssid_len)
158 {
159         GVariantBuilder *builder;
160         GVariant *params;
161         const char *sig_name = "WpsCompleted";
162         const char *prop_ssid = "ssid";
163         GVariantBuilder *rawssid_builder = NULL;
164         int i;
165
166         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
167         rawssid_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
168         for (i = 0; i < ssid_len; i++)
169                 g_variant_builder_add(rawssid_builder, "y", ssid[i]);
170         g_variant_builder_add(builder, "{sv}", prop_ssid, g_variant_new("ay", rawssid_builder));
171         g_variant_builder_unref(rawssid_builder);
172
173         params = g_variant_new("(s@a{sv})", interface_name,
174                                 g_variant_builder_end(builder));
175         g_variant_builder_unref(builder);
176
177         netconfig_dbus_emit_signal(NULL,
178                                 NETCONFIG_WIFI_PATH,
179                                 NETCONFIG_WIFI_INTERFACE,
180                                 sig_name,
181                                 params);
182
183         INFO("Sent signal (%s)", sig_name);
184         return;
185 }
186
187 void netconfig_wifi_notify_wps_fail_event(const char *interface_name,
188                 int config_error, int error_indication)
189 {
190         GVariantBuilder *builder;
191         GVariant *params;
192         const char *sig_name = "WpsFailEvent";
193         const char *prop_config_error = "config_error";
194         const char *prop_error_indication = "error_indication";
195
196         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
197         g_variant_builder_add(builder, "{sv}", prop_config_error, g_variant_new_int32(config_error));
198         g_variant_builder_add(builder, "{sv}", prop_error_indication, g_variant_new_int32(error_indication));
199
200         params = g_variant_new("(s@a{sv})", interface_name,
201                                 g_variant_builder_end(builder));
202         g_variant_builder_unref(builder);
203
204         netconfig_dbus_emit_signal(NULL,
205                                 NETCONFIG_WIFI_PATH,
206                                 NETCONFIG_WIFI_INTERFACE,
207                                 sig_name,
208                                 params);
209
210         INFO("Sent signal (%s)", sig_name);
211         return;
212 }
213
214 static void interface_wps_start_result(GObject *source_object,
215                         GAsyncResult *res, gpointer user_data)
216 {
217         GVariant *reply;
218         GDBusConnection *conn = NULL;
219         GError *error = NULL;
220
221         conn = G_DBUS_CONNECTION(source_object);
222         reply = g_dbus_connection_call_finish(conn, res, &error);
223
224         if (reply == NULL) {
225                 if (error != NULL) {
226                         ERR("Fail to request status [%d: %s]",
227                                         error->code, error->message);
228                         g_error_free(error);
229                 } else {
230                         ERR("Fail torequest status");
231                 }
232         } else {
233                 DBG("Successfully M/W--->WPAS: Interface.WPS.Start Method");
234         }
235
236         g_variant_unref(reply);
237         netconfig_gdbus_pending_call_unref();
238 }
239
240 static void __netconfig_wifi_invoke_wps_connect(GObject *source_object,
241                         GAsyncResult *res, gpointer user_data)
242 {
243         GVariant *message = NULL;
244         GVariantBuilder *builder = NULL;
245         const char *role = "enrollee", *type, *key;
246         char *if_path = NULL;
247         gboolean reply = FALSE;
248         char *interface_name = user_data;
249
250         if_path = netconfig_wifi_get_supplicant_interface_path(interface_name);
251         if (if_path == NULL) {
252                 DBG("Fail to get wpa_supplicant DBus path");
253                 g_free(interface_name);
254                 return;
255         }
256
257         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
258
259         key = "Role";
260         g_variant_builder_add(builder, "{sv}", key, g_variant_new_string(role));
261
262         key = "Type";
263
264         if (__get_wifi_wps_pbc(interface_name) == TRUE)
265                 type = "pbc";
266         else
267                 type = "pin";
268
269         g_variant_builder_add(builder, "{sv}", key, g_variant_new_string(type));
270
271         if (__get_wifi_wps_pin(interface_name) != NULL) {
272                 key = "Pin";
273                 g_variant_builder_add(builder, "{sv}", key,
274                         g_variant_new_string(__get_wifi_wps_pin(interface_name)));
275         }
276         message = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
277         g_variant_builder_unref(builder);
278
279         DBG("[net-config]: TizenMW-->WPAS: .Interface.WPS.Start");
280         reply = netconfig_supplicant_invoke_dbus_method_nonblock(
281                         SUPPLICANT_SERVICE,
282                         if_path,
283                         SUPPLICANT_IFACE_WPS,
284                         "Start",
285                         message,
286                         (GAsyncReadyCallback) interface_wps_start_result,
287                         NULL);
288
289         if (reply != TRUE)
290                 ERR("Fail to Scan");
291
292         __destroy_wifi_wps(interface_name);
293         g_free(interface_name);
294         g_free(if_path);
295         return;
296 }
297
298 static gboolean __netconfig_wifi_invoke_wps_process_credentials(char *object_path,
299                         const char *interface_name)
300 {
301         gboolean reply = FALSE;
302         GVariant *params = NULL;
303         const char *interface = SUPPLICANT_IFACE_WPS;
304         const char *key = "ProcessCredentials";
305         gboolean credentials = TRUE;
306
307         params = g_variant_new("(ssv)", interface, key, g_variant_new_boolean(credentials));
308
309         INFO("[net-config]: TizenMW-->WPAS: .Set");
310         reply = netconfig_invoke_dbus_method_nonblock(SUPPLICANT_SERVICE,
311                         object_path, DBUS_INTERFACE_PROPERTIES, "Set", params,
312                         __netconfig_wifi_invoke_wps_connect, g_strdup(interface_name));
313
314         if (reply != TRUE)
315                 ERR("M/W--->WPAS: Interface.WPS.Set Method Failed");
316
317         return reply;
318 }
319
320 gboolean netconfig_wifi_wps_connect(const char *interface_name)
321 {
322         char *if_path = NULL;
323
324         if_path = netconfig_wifi_get_supplicant_interface_path(interface_name);
325         if (if_path == NULL) {
326                 DBG("Fail to get wpa_supplicant DBus path");
327                  return FALSE;
328         }
329
330         if (__netconfig_wifi_invoke_wps_process_credentials(if_path, interface_name) == TRUE) {
331                 ERR("Wi-Fi WPS Connect started");
332                 g_free(if_path);
333                 return TRUE;
334         }
335
336         g_free(if_path);
337         return FALSE;
338 }
339
340 static void __interface_wps_cancel_result(GObject *source_object,
341                         GAsyncResult *res, gpointer user_data)
342 {
343         GVariant *reply;
344         GDBusConnection *conn = NULL;
345         GError *error = NULL;
346
347         conn = G_DBUS_CONNECTION(source_object);
348         reply = g_dbus_connection_call_finish(conn, res, &error);
349
350         if (reply == NULL) {
351                 if (error != NULL) {
352                         ERR("Fail to request status [%d: %s]",
353                                         error->code, error->message);
354                         g_error_free(error);
355                 } else {
356                         ERR("Fail torequest status");
357                 }
358         } else {
359                 DBG("Successfully M/W--->WPAS: Interface.WPS.Cancel Method");
360         }
361
362         g_variant_unref(reply);
363         netconfig_gdbus_pending_call_unref();
364 }
365
366 static gboolean __netconfig_wifi_invoke_wps_cancel(const char *interface_name)
367 {
368         gboolean reply = FALSE;
369         char *if_path = NULL;
370
371         if_path = netconfig_wifi_get_supplicant_interface_path(interface_name);
372         if (if_path == NULL) {
373                 DBG("Fail to get wpa_supplicant DBus path");
374                 return -ESRCH;
375         }
376
377         DBG("M/W--->WPAS: Interface.WPS.Cancel Method");
378
379         reply = netconfig_invoke_dbus_method_nonblock(SUPPLICANT_SERVICE,
380                         if_path, SUPPLICANT_IFACE_WPS, "Cancel", NULL,
381                         __interface_wps_cancel_result, NULL);
382
383         if (reply != TRUE)
384                 ERR("M/W--->WPAS: Interface.WPS.Cancel Method Failed");
385
386         g_free(if_path);
387         return reply;
388 }
389
390 gboolean handle_request_wps_cancel(Wifi *wifi, GDBusMethodInvocation *context,
391                         const gchar *ifname)
392 {
393         INFO("Received WPS PBC Cancel Request");
394         g_return_val_if_fail(wifi != NULL, TRUE);
395         __netconfig_wifi_invoke_wps_cancel(ifname);
396
397         wifi_complete_request_wps_cancel(wifi, context);
398         return TRUE;
399 }
400
401 gboolean handle_request_wps_connect(Wifi *wifi, GDBusMethodInvocation *context,
402                         const gchar *ifname, gchar *param)
403 {
404         INFO("Received WPS PBC/PIN Connection Request");
405
406         g_return_val_if_fail(wifi != NULL, TRUE);
407
408         /* Checking the value of pin if param have a string "PBC"
409          * in that scenario PBC will trigger otherwise PIN Connection */
410          __create_wifi_wps(ifname);
411
412         if (g_strcmp0(param, "PBC") == 0)
413                 __set_wifi_wps(ifname, TRUE, NULL);
414         else
415                 __set_wifi_wps(ifname, FALSE, param);
416
417         netconfig_wifi_wps_connect(ifname);
418
419         wifi_complete_request_wps_connect(wifi, context);
420         return TRUE;
421 }