modified logs to add agent fields settings
[platform/core/connectivity/net-config.git] / src / wifi-agent.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 <stdio.h>
21 #include <vconf.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <vconf-keys.h>
25
26 #include "log.h"
27 #include "util.h"
28 #include "wifi.h"
29 #include "netdbus.h"
30 #include "wifi-agent.h"
31 #include "wifi-state.h"
32 #include "wifi-eap-config.h"
33 #include "network-state.h"
34 #include "network-accessibility.h"
35 #include "wifi-key-encryption.h"
36
37 #define NETCONFIG_AGENT_FIELD_NAME                              "Name"
38 #define NETCONFIG_AGENT_FIELD_SSID                              "SSID"
39 #define NETCONFIG_AGENT_FIELD_IDENTITY                  "Identity"
40 #define NETCONFIG_AGENT_FIELD_PASSPHRASE                "Passphrase"
41 #define NETCONFIG_AGENT_FIELD_WPS                               "WPS"
42 #define NETCONFIG_AGENT_FIELD_WPS_PBC                   "WPS_PBC"
43 #define NETCONFIG_AGENT_FIELD_WPS_PIN                   "WPS_PIN"
44
45 #define NETCONFIG_AGENT_ERR_CONNECT_FAILED              "connect-failed"
46
47 struct netconfig_wifi_agent {
48         GByteArray *ssid;
49         char *name;
50         char *identity;
51         char *passphrase;
52         char *wps_pin;
53         gboolean wps_pbc;
54 };
55
56 static struct netconfig_wifi_agent agent;
57
58 static void __netconfig_agent_clear_fields(void)
59 {
60         if (agent.ssid)
61                 g_byte_array_free(agent.ssid, TRUE);
62         g_free(agent.name);
63         g_free(agent.identity);
64         g_free(agent.passphrase);
65         g_free(agent.wps_pin);
66
67         agent.ssid = NULL;
68         agent.name = NULL;
69         agent.identity = NULL;
70         agent.passphrase = NULL;
71         agent.wps_pin = NULL;
72         agent.wps_pbc = FALSE;
73 }
74
75 int connman_register_agent(void)
76 {
77         GVariant *reply = NULL;
78         GVariant *params = NULL;
79
80         params = g_variant_new("(o)", NETCONFIG_WIFI_PATH);
81         reply = netconfig_invoke_dbus_method(CONNMAN_SERVICE,
82                         CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE,
83                         "RegisterAgent", params);
84
85         if (reply == NULL) {
86                         ERR("Fail to register agent");
87                         return FALSE;
88         } else
89                 g_variant_unref(reply);
90
91         INFO("Registered to connman agent successfully");
92
93         return TRUE;
94 }
95
96 int connman_unregister_agent(void)
97 {
98         gboolean reply = FALSE;
99         GVariant *param = NULL;
100         const char *path = NETCONFIG_WIFI_PATH;
101
102         param = g_variant_new("(o)", path);
103
104         DBG("ConnMan agent unregister");
105
106         reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
107                         CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE,
108                         "UnregisterAgent", param, NULL);
109
110         if (reply != TRUE)
111                 ERR("Fail to unregister agent");
112
113         /* Clearing the agent fields */
114         __netconfig_agent_clear_fields();
115
116         return reply;
117 }
118
119 gboolean netconfig_wifi_set_agent_field_for_eap_network(
120                 const char *name, const char *identity, const char *passphrase)
121 {
122         int name_len;
123
124         if (name == NULL)
125                 return FALSE;
126
127         __netconfig_agent_clear_fields();
128
129         name_len = strlen(name);
130         agent.ssid = g_byte_array_sized_new(name_len);
131         agent.ssid->len = name_len;
132         memcpy(agent.ssid->data, name, name_len + 1);
133
134         if (identity)
135                 agent.identity = g_strdup(identity);
136
137         if (passphrase)
138                 agent.passphrase = g_strdup(passphrase);
139
140         gchar *enc_data = NULL;
141         enc_data = _netconfig_encrypt_passphrase(agent.passphrase);
142
143         if (!enc_data) {
144                 ERR("Failed to encrypt the passphrase");
145         } else {
146                 g_free(agent.passphrase);
147                 agent.passphrase = enc_data;
148         }
149
150         DBG("Successfully configured for EAP network");
151
152         return TRUE;
153 }
154
155 gboolean handle_set_field(NetConnmanAgent *connman_agent,
156                 GDBusMethodInvocation *context, const gchar *service, GVariant *fields)
157 {
158         GError *error = NULL;
159         GVariantIter *iter;
160         gpointer field;
161         GVariant *value;
162         gboolean updated = FALSE;
163         gboolean reply = FALSE;
164
165         g_return_val_if_fail(connman_agent != NULL, FALSE);
166
167         DBG("Set agent fields for %s", service);
168
169         if (netconfig_is_wifi_profile(service) != TRUE) {
170                 error = g_error_new(G_DBUS_ERROR,
171                                 G_DBUS_ERROR_AUTH_FAILED,
172                                 CONNMAN_ERROR_INTERFACE ".InvalidService");
173
174                 g_dbus_method_invocation_return_gerror(context, error);
175                 g_clear_error(&error);
176
177                 return reply;
178         }
179
180         __netconfig_agent_clear_fields();
181         g_variant_get(fields, "a{sv}", &iter);
182         while (g_variant_iter_loop(iter, "{sv}", &field, &value)) {
183                 if (g_strcmp0(field, NETCONFIG_AGENT_FIELD_PASSPHRASE) == 0) {
184                         if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
185                                 agent.passphrase = g_strdup(g_variant_get_string(value, NULL));
186                                 updated = TRUE;
187
188                                 DBG("Field [%s] - [%s]", field, agent.passphrase);
189
190                                 if (agent.passphrase == NULL)
191                                         continue;
192
193                                 if (netconfig_check_passphrase(service, agent.passphrase) == FALSE) {
194                                         ERR("Invalid passphrase");
195
196                                         g_free(agent.passphrase);
197                                         agent.passphrase = NULL;
198
199                                         updated = FALSE;
200                                         continue;
201                                 }
202
203                                 gchar *enc_data = NULL;
204                                 enc_data = _netconfig_encrypt_passphrase(agent.passphrase);
205
206                                 if (!enc_data) {
207                                         ERR("Failed to encrypt the passphrase");
208                                         continue;
209                                 }
210
211                                 g_free(agent.passphrase);
212                                 agent.passphrase = enc_data;
213                         }
214                 } else if (g_strcmp0(field, NETCONFIG_AGENT_FIELD_WPS_PBC) == 0) {
215                         if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) &&
216                                         g_strcmp0(g_variant_get_string(value, NULL), "enable") == 0) {
217                                 agent.wps_pbc = TRUE;
218                                 updated = TRUE;
219
220                                 DBG("Field [%s] - [%d]", field, agent.wps_pbc);
221                         }
222                 } else if (g_strcmp0(field, NETCONFIG_AGENT_FIELD_WPS_PIN) == 0) {
223                         if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
224                                 agent.wps_pin = g_strdup(g_variant_get_string(value, NULL));
225                                 updated = TRUE;
226
227                                 DBG("Field [%s] - [%s]", field, agent.wps_pin);
228                         }
229                 } else if (g_strcmp0(field, NETCONFIG_AGENT_FIELD_NAME) == 0) {
230                         if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
231                                 agent.name = g_strdup(g_variant_get_string(value, NULL));
232                                 updated = TRUE;
233
234                                 DBG("Field [%s] - [%s]", field, agent.name);
235                         }
236                 } else if (g_strcmp0(field, NETCONFIG_AGENT_FIELD_SSID) == 0) {
237                         if (agent.ssid != NULL) {
238                                 g_byte_array_free(agent.ssid, TRUE);
239                                 agent.ssid = NULL;
240                         }
241
242                         if (g_variant_is_of_type(value, G_VARIANT_TYPE_BYTESTRING)) {
243                                 guint8 char_value;
244                                 GVariantIter *iter1;
245                                 GByteArray *array = g_byte_array_new();
246
247                                 g_variant_get(value, "ay", &iter1);
248                                 while (g_variant_iter_loop(iter1, "y", &char_value))
249                                         g_byte_array_append(array, &char_value, 1);
250                                 g_variant_iter_free(iter1);
251                                 if (array != NULL && (array->len > 0)) {
252                                         agent.ssid = g_byte_array_sized_new(array->len);
253                                         agent.ssid->len = array->len;
254                                         memcpy(agent.ssid->data, array->data, array->len);
255                                         updated = TRUE;
256
257                                         DBG("Field [%s] - []", field);
258                                 }
259                         }
260                 } else if (g_strcmp0(field, NETCONFIG_AGENT_FIELD_IDENTITY) == 0) {
261                         if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
262                                 agent.identity = g_strdup(g_variant_get_string(value, NULL));
263                                 updated = TRUE;
264
265                                 DBG("Field [%s] - [%s]", field, agent.identity);
266                         }
267                 }
268         }
269
270         if (updated == TRUE) {
271                 reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
272                                 service, CONNMAN_SERVICE_INTERFACE, "Connect",
273                                 NULL, __netconfig_wifi_connect_reply);
274                 if (reply != TRUE) {
275                         ERR("Fail to connect Wi-Fi");
276                         __netconfig_agent_clear_fields();
277                         error = g_error_new(G_DBUS_ERROR,
278                                         G_DBUS_ERROR_AUTH_FAILED,
279                                         CONNMAN_ERROR_INTERFACE ".InvalidArguments");
280
281                         g_dbus_method_invocation_return_gerror(context, error);
282                         g_clear_error(&error);
283                         g_variant_iter_free(iter);
284                         return reply;
285                 }
286         } else {
287                 error = g_error_new(G_DBUS_ERROR,
288                                 G_DBUS_ERROR_AUTH_FAILED,
289                                 CONNMAN_ERROR_INTERFACE ".InvalidArguments");
290
291                 g_dbus_method_invocation_return_gerror(context, error);
292                 g_clear_error(&error);
293                 g_variant_iter_free(iter);
294                 return reply;
295         }
296
297         g_variant_iter_free(iter);
298
299         net_connman_agent_complete_set_field(connman_agent, context);
300         return reply;
301 }
302
303 gboolean handle_request_input(NetConnmanAgent *connman_agent,
304                 GDBusMethodInvocation *context, const gchar *service, GVariant *fields)
305 {
306         GVariantIter *iter;
307         gchar *field = NULL;
308         GVariant *r_value = NULL;
309         GVariant *out_table = NULL;
310         gboolean updated = FALSE;
311         GVariantBuilder *builder = NULL;
312
313         g_return_val_if_fail(connman_agent != NULL, FALSE);
314
315         if (NULL == service)
316                 return FALSE;
317
318         DBG("Agent fields requested for service: %s", service);
319
320         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
321
322         g_variant_get(fields, "a{sv}", &iter);
323         while (g_variant_iter_loop(iter, "{sv}", &field, &r_value)) {
324
325                 if (g_strcmp0(field, NETCONFIG_AGENT_FIELD_PASSPHRASE) == 0 &&
326                                 agent.passphrase != NULL) {
327                         g_variant_builder_add(builder, "{sv}", NETCONFIG_AGENT_FIELD_PASSPHRASE,
328                                                         g_variant_new_string(agent.passphrase));
329
330                         updated = TRUE;
331                         DBG("Setting [%s] - [%s]", field, agent.passphrase);
332                 } else if (g_strcmp0(field, NETCONFIG_AGENT_FIELD_WPS) == 0 &&
333                                 (agent.wps_pbc == TRUE || agent.wps_pin != NULL)) {
334                         if (agent.wps_pbc == TRUE) {
335                                 /* Sending empty string for WPS push button method */
336                                 g_variant_builder_add(builder, "{sv}", NETCONFIG_AGENT_FIELD_WPS, g_variant_new_string(""));
337
338                                 updated = TRUE;
339                                 DBG("Setting empty string for [%s]", field);
340                         } else if (agent.wps_pin != NULL) {
341                                 g_variant_builder_add(builder, "{sv}", NETCONFIG_AGENT_FIELD_WPS, g_variant_new_string(agent.wps_pin));
342
343                                 updated = TRUE;
344                                 DBG("Setting string [%s] - [%s]", field, agent.wps_pin);
345                         }
346                 } else if (g_strcmp0(field, NETCONFIG_AGENT_FIELD_NAME) == 0 &&
347                                 agent.name != NULL) {
348                         g_variant_builder_add(builder, "{sv}", NETCONFIG_AGENT_FIELD_NAME, g_variant_new_string(agent.name));
349
350                         updated = TRUE;
351                         DBG("Settings [%s] - [%s]", field, agent.name);
352                 } else if (g_strcmp0(field, NETCONFIG_AGENT_FIELD_SSID) == 0 &&
353                                 agent.ssid != NULL) {
354                         int i = 0;
355                         GVariantBuilder *builder1 = NULL;
356                         builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
357
358                         for (i = 0; i < (agent.ssid->len); i++)
359                                 g_variant_builder_add(builder1, "y", agent.ssid->data[i]);
360
361                         g_variant_builder_add(builder, "{sv}", NETCONFIG_AGENT_FIELD_SSID, g_variant_builder_end(builder1));
362                         if (builder1 != NULL)
363                                 g_variant_builder_unref(builder1);
364
365                         updated = TRUE;
366                         DBG("Settings [%s] - []", field);
367                 } else if (g_strcmp0(field, NETCONFIG_AGENT_FIELD_IDENTITY) == 0 &&
368                                 agent.identity != NULL) {
369                         g_variant_builder_add(builder, "{sv}", NETCONFIG_AGENT_FIELD_IDENTITY, g_variant_new_string(agent.identity));
370
371                         updated = TRUE;
372                         DBG("Settings [%s] - [%s]", field, agent.identity);
373                 }
374         }
375
376         out_table = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
377
378         if (builder)
379                 g_variant_builder_unref(builder);
380
381         g_variant_iter_free(iter);
382
383
384         if (NULL == out_table) {
385                 net_connman_agent_complete_request_input(connman_agent, context, out_table);
386
387                 return FALSE;
388         }
389
390         if (updated == TRUE)
391                 g_dbus_method_invocation_return_value(context, out_table);
392         else {
393                 GError *error = NULL;
394                 error = g_error_new(G_DBUS_ERROR,
395                                 G_DBUS_ERROR_AUTH_FAILED,
396                                 "net.connman.Agent.Error.Canceled");
397
398                 g_dbus_method_invocation_return_gerror(context, error);
399                 g_clear_error(&error);
400         }
401
402         __netconfig_agent_clear_fields();
403
404         return updated;
405 }
406
407
408 gboolean handle_report_error(NetConnmanAgent *connman_agent,
409                 GDBusMethodInvocation *context, const gchar *service, const gchar *error)
410 {
411         gboolean ret = TRUE;
412
413         g_return_val_if_fail(connman_agent != NULL, FALSE);
414
415         net_connman_agent_complete_report_error(connman_agent, context);
416         DBG("Agent error for service[%s] - [%s]", service, error);
417
418         /* Do something when it failed to make a connection */
419
420         return ret;
421 }
422
423 #if defined TIZEN_CAPTIVE_PORTAL
424 #if defined TIZEN_WEARABLE
425 #define QUERY_FOR_INTERNET_INTERVAL                     2
426 #define TIMER_THRESHOLD                                         4
427 #else
428 #define QUERY_FOR_INTERNET_INTERVAL                     20
429 #define TIMER_THRESHOLD                                         120
430 #endif
431
432 static gboolean is_monitor_notifier_registered = FALSE;
433
434 #if defined TIZEN_WEARABLE
435 static gboolean is_portal_msg_shown = FALSE;
436 #endif
437
438 struct poll_timer_data {
439         guint time_elapsed;
440         guint timer_id;
441         void* data;
442 };
443
444 static struct poll_timer_data timer_data = {
445                 QUERY_FOR_INTERNET_INTERVAL, 0, NULL};
446
447 static gboolean __check_ignore_portal_list(const char * ssid)
448 {
449         char def_str[1024];
450         int i = 0;
451         int ignore_ap_count = 0;
452
453         if (ssid == NULL)
454                 return FALSE;
455
456         DBG("checking ssid [%s]", ssid);
457
458         DBG("csc string [%s]", def_str);
459         gchar ** ignore_ap_list = g_strsplit(def_str, ",", 0);
460         ignore_ap_count = g_strv_length(ignore_ap_list);
461         for (i = 0; i < ignore_ap_count; i++) {
462                 DBG("[%d] - [%s]", i, ignore_ap_list[i]);
463                 if (strncmp(ignore_ap_list[i], ssid, strlen(ssid)) == 0) {
464                         g_strfreev(ignore_ap_list);
465                         return TRUE;
466                 }
467         }
468
469         g_strfreev(ignore_ap_list);
470         return FALSE;
471 }
472
473 static void __wifi_state_monitor(wifi_service_state_e state,
474                 void *user_data);
475
476 static wifi_state_notifier wifi_state_monitor_notifier = {
477                 .wifi_state_changed = __wifi_state_monitor,
478                 .user_data = NULL,
479 };
480
481 static void __wifi_state_monitor(wifi_service_state_e state,
482                 void *user_data)
483 {
484         DBG("Wi-Fi state: %x", state);
485
486         if (state == NETCONFIG_WIFI_CONNECTED)
487                 return;
488
489         if (is_monitor_notifier_registered == TRUE) {
490                 wifi_state_notifier_unregister(&wifi_state_monitor_notifier);
491                 is_monitor_notifier_registered = FALSE;
492         }
493
494 #if defined TIZEN_WEARABLE
495         is_portal_msg_shown = FALSE;
496 #endif
497
498         /* suspend if Internet check activity in progress */
499         if (timer_data.timer_id == 0)
500                 return;
501
502         netconfig_stop_timer(&timer_data.timer_id);
503         netconfig_stop_internet_check();
504
505         DBG("Stopped Internet accessibility check");
506 }
507
508 static gboolean __netconfig_wifi_portal_login_timeout(gpointer data)
509 {
510         char *service_profile = NULL;
511         GVariant *reply = NULL;
512
513         DBG("");
514
515         struct poll_timer_data *timer = (struct poll_timer_data *)data;
516         if (timer == NULL)
517                 return FALSE;
518
519         if (TRUE == netconfig_get_internet_status()) {
520                 if (is_monitor_notifier_registered == TRUE) {
521                         wifi_state_notifier_unregister(&wifi_state_monitor_notifier);
522                         is_monitor_notifier_registered = FALSE;
523                 }
524
525                 DBG("Portal logged in successfully and update ConnMan state");
526                 return FALSE; /* to stop the timer */
527         } else {
528                 if (timer->time_elapsed >= TIMER_THRESHOLD) {
529                         DBG("Login failed, update ConnMan");
530
531                         if (is_monitor_notifier_registered == TRUE) {
532                                 wifi_state_notifier_unregister(&wifi_state_monitor_notifier);
533                                 is_monitor_notifier_registered = FALSE;
534                         }
535
536                         /* Disconnect and forget the AP */
537                         service_profile = (char*) netconfig_get_default_profile();
538                         if (service_profile && netconfig_is_wifi_profile(service_profile)) {
539                                 /* Now forget the AP*/
540                                 reply = netconfig_invoke_dbus_method(CONNMAN_SERVICE,
541                                                 service_profile, CONNMAN_SERVICE_INTERFACE, "Remove",
542                                                 NULL);
543
544                                 if (reply != NULL)
545                                         g_variant_unref(reply);
546                                 else
547                                         ERR("Failed to forget the AP ");
548                         }
549                 } else {
550                         if (NETCONFIG_WIFI_CONNECTED ==
551                                         wifi_state_get_service_state()) {
552                                 /* check Internet availability by sending and receiving data*/
553                                 netconfig_check_internet_accessibility();
554                                 /* Returning TRUE itself is enough to restart the timer */
555                                 timer->time_elapsed = timer->time_elapsed +
556                                                                         QUERY_FOR_INTERNET_INTERVAL;
557                                 return TRUE;
558                         }
559                 }
560         }
561
562         return FALSE;
563 }
564
565 static void __netconfig_wifi_portal_login_timer_start(struct poll_timer_data
566                 *data)
567 {
568         DBG("__netconfig_wifi_browser_start_timer...starting timer");
569
570         if (data == NULL)
571                 return;
572
573         netconfig_stop_timer(&(data->timer_id));
574
575         /* Timer logic: After successful launch of browser, we would check for
576          * Internet status for every 20s until a threshold of 120s
577          */
578
579         data->time_elapsed = QUERY_FOR_INTERNET_INTERVAL;
580         netconfig_start_timer_seconds(QUERY_FOR_INTERNET_INTERVAL,
581                 __netconfig_wifi_portal_login_timeout, data, &(data->timer_id));
582 }
583 #endif
584
585 gboolean handle_request_browser(NetConnmanAgent *connman_agent,
586                 GDBusMethodInvocation *context, const gchar *service, const gchar *url)
587 {
588 #if defined TIZEN_CAPTIVE_PORTAL
589         gboolean ret = FALSE;
590         gboolean ignore_portal = FALSE;
591         const char * ssid = NULL;
592
593         g_return_val_if_fail(connman_agent != NULL, FALSE);
594
595         DBG("service[%s] - url[%s]", service, url);
596
597         ssid = netconfig_wifi_get_connected_essid(netconfig_get_default_profile());
598         if (ssid == NULL) {
599                 ERR("Connected AP name is NULL!!");
600                 net_connman_agent_complete_request_browser(connman_agent, context);
601                 return FALSE;
602         }
603
604         ignore_portal = __check_ignore_portal_list(ssid);
605
606         if (ignore_portal == TRUE) {
607                 net_connman_agent_complete_request_browser(connman_agent, context);
608                 return TRUE;
609         }
610         /* Register for Wifi state change notifier*/
611         if (is_monitor_notifier_registered == FALSE) {
612                 wifi_state_notifier_register(&wifi_state_monitor_notifier);
613                 is_monitor_notifier_registered = TRUE;
614         }
615
616         ret = netconfig_send_notification_to_net_popup(NETCONFIG_ADD_PORTAL_NOTI, ssid);
617
618         timer_data.time_elapsed = 0;
619         __netconfig_wifi_portal_login_timer_start(&timer_data);
620
621         net_connman_agent_complete_request_browser(connman_agent, context);
622         return ret;
623 #else
624         GError *error = NULL;
625         error = g_error_new(G_DBUS_ERROR,
626                         G_DBUS_ERROR_AUTH_FAILED,
627                         CONNMAN_ERROR_INTERFACE ".NotSupported");
628
629         g_dbus_method_invocation_return_gerror(context, error);
630         g_clear_error(&error);
631
632         return FALSE;
633 #endif
634 }