6067c3b46fa25252916396be23370f26ead44c56
[platform/core/connectivity/net-config.git] / src / signal-handler.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 <string.h>
22 #include <vconf.h>
23 #include <vconf-keys.h>
24
25 #include "log.h"
26 #include "util.h"
27 #include "netdbus.h"
28 #include "neterror.h"
29 #include "wifi-wps.h"
30 #include "wifi-agent.h"
31 #include "wifi-power.h"
32 #include "wifi-state.h"
33 #include "netsupplicant.h"
34 #include "network-state.h"
35 #include "cellular-state.h"
36 #include "signal-handler.h"
37 #include "wifi-ssid-scan.h"
38 #include "wifi-background-scan.h"
39
40 #if defined TIZEN_DEBUG_DISABLE
41 #include "wifi-dump.h"
42 #endif
43
44 #define DBUS_SERVICE_DBUS                       "org.freedesktop.DBus"
45 #define DBUS_INTERFACE_DBUS                     "org.freedesktop.DBus"
46 #define SIGNAL_INTERFACE_REMOVED                "InterfaceRemoved"
47 #define SIGNAL_SCAN_DONE                        "ScanDone"
48 #define SIGNAL_BSS_ADDED                        "BSSAdded"
49 #define SIGNAL_PROPERTIES_CHANGED               "PropertiesChanged"
50 #define SIGNAL_PROPERTIES_DRIVER_HANGED         "DriverHanged"
51 #define SIGNAL_PROPERTIES_SESSION_OVERLAPPED    "SessionOverlapped"
52 #define CONNMAN_SIGNAL_SERVICES_CHANGED         "ServicesChanged"
53 #define CONNMAN_SIGNAL_PROPERTY_CHANGED         "PropertyChanged"
54 #define CONNMAN_SIGNAL_NAME_CHANGED             "NameOwnerChanged"
55
56 #define MAX_SIG_LEN 64
57 #define TOTAL_CONN_SIGNALS 3
58
59 typedef enum {
60         SIG_INTERFACE_REMOVED = 0,
61         SIG_PROPERTIES_CHANGED,
62         SIG_BSS_ADDED,
63         SIG_SCAN_DONE,
64         SIG_DRIVER_HANGED,
65         SIG_SESSION_OVERLAPPED,
66         SIG_MAX
67 } SuppSigArrayIndex;
68
69 static int conn_subscription_ids[TOTAL_CONN_SIGNALS] = {0};
70 static const char supp_signals[SIG_MAX][MAX_SIG_LEN] = {
71                 SIGNAL_INTERFACE_REMOVED,
72                 SIGNAL_PROPERTIES_CHANGED,
73                 SIGNAL_BSS_ADDED,
74                 SIGNAL_SCAN_DONE,
75                 SIGNAL_PROPERTIES_DRIVER_HANGED,
76                 SIGNAL_PROPERTIES_SESSION_OVERLAPPED,
77 };
78
79 static int supp_subscription_ids[SIG_MAX] = {0};
80 static int dumpservice_subscription_id = 0;
81
82 typedef void (*netconfig_supplicant_signal_handler)(GDBusConnection *conn,
83                 const gchar *name, const gchar *path, const gchar *interface,
84                 const gchar *sig, GVariant *param, gpointer user_data);
85 typedef void (*netconfig_connman_signal_handler)(GDBusConnection *conn,
86                 const gchar *name, const gchar *path, const gchar *interface,
87                 const gchar *sig, GVariant *param, gpointer user_data);
88
89 static void __netconfig_technology_signal_handler(GDBusConnection *conn,
90                 const gchar *name, const gchar *path, const gchar *interface,
91                 const gchar *sig, GVariant *param, gpointer user_data)
92 {
93         const char *key = NULL;
94         gboolean value = FALSE;
95         GVariant *var;
96
97         if (param == NULL)
98                 return;
99
100         if (g_str_has_prefix(path, CONNMAN_WIFI_TECHNOLOGY_PREFIX) == TRUE) {
101                 g_variant_get(param, "(sv)", &key, &var);
102                 if (g_strcmp0(key, "Powered") == 0) {
103                         /* Power state */
104                         value = g_variant_get_boolean(var);
105                         if (value == TRUE) {
106                                 netconfig_wifi_update_power_state(TRUE);
107                         } else {
108                                 netconfig_wifi_update_power_state(FALSE);
109                         }
110                 } else if (g_strcmp0(key, "Connected") == 0) {
111                         /* Connection state */
112                         netconfig_wifi_state_set_technology_state(
113                                         NETCONFIG_WIFI_TECH_CONNECTED);
114                 } else if (g_strcmp0(key, "Tethering") == 0) {
115                         /* Tethering state */
116                         netconfig_wifi_state_set_technology_state(
117                                         NETCONFIG_WIFI_TECH_TETHERED);
118                 }
119         }
120 }
121
122 static void __netconfig_service_signal_handler(GDBusConnection *conn,
123                 const gchar *name, const gchar *path,
124                 const gchar *interface, const gchar *sig, GVariant *param, gpointer user_data)
125 {
126         gchar *sigvalue = NULL;
127         gchar *property;
128         GVariant *variant = NULL, *var;
129         GVariantIter *iter;
130         const gchar *value = NULL;
131
132         if (path == NULL || param == NULL)
133                 goto done;
134
135         g_variant_get(param, "(sv)", &sigvalue, &variant);
136         if (sigvalue == NULL)
137                 goto done;
138
139         if (g_strcmp0(sig, CONNMAN_SIGNAL_PROPERTY_CHANGED) != 0) {
140                 goto done;
141         }
142
143         if (g_strcmp0(sigvalue, "State") == 0) {
144                 g_variant_get(variant, "s", &property);
145
146                 DBG("[%s] %s", property, path);
147                 if (netconfig_is_wifi_profile(path) == TRUE) {
148                         int wifi_state = 0;
149
150                         vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
151                         if (wifi_state == VCONFKEY_WIFI_OFF)
152                                 goto done;
153
154                         if (g_strcmp0(property, "ready") == 0 || g_strcmp0(property, "online") == 0) {
155                                 if (wifi_state >= VCONFKEY_WIFI_CONNECTED)
156                                         goto done;
157
158                                 netconfig_update_default_profile(path);
159
160                                 netconfig_wifi_state_set_service_state(NETCONFIG_WIFI_CONNECTED);
161
162                         } else if (g_strcmp0(property, "failure") == 0 || g_strcmp0(property, "disconnect") == 0 || g_strcmp0(property, "idle") == 0) {
163                                 if (netconfig_get_default_profile() == NULL ||
164                                                 netconfig_is_wifi_profile(netconfig_get_default_profile())
165                                                 != TRUE) {
166                                         if (g_strcmp0(property, "failure") == 0)
167                                                 netconfig_wifi_state_set_service_state(
168                                                                                         NETCONFIG_WIFI_FAILURE);
169                                         else
170                                                 netconfig_wifi_state_set_service_state(
171                                                                                         NETCONFIG_WIFI_IDLE);
172                                         goto done;
173                                 }
174
175                                 if (g_strcmp0(path, netconfig_get_default_profile()) != 0)
176                                         goto done;
177
178                                 netconfig_update_default_profile(NULL);
179
180                                 if (g_strcmp0(property, "failure") == 0)
181                                         netconfig_wifi_state_set_service_state(
182                                                                                 NETCONFIG_WIFI_FAILURE);
183                                 else
184                                         netconfig_wifi_state_set_service_state(
185                                                                                 NETCONFIG_WIFI_IDLE);
186
187                         } else if (g_strcmp0(property, "association") == 0 ||   g_strcmp0(property, "configuration") == 0) {
188                                 if (netconfig_get_default_profile() == NULL ||
189                                                 netconfig_is_wifi_profile(netconfig_get_default_profile()) != TRUE) {
190                                         if (g_strcmp0(property, "association") == 0)
191                                                 netconfig_wifi_state_set_service_state(
192                                                                                         NETCONFIG_WIFI_ASSOCIATION);
193                                         else
194                                                 netconfig_wifi_state_set_service_state(
195                                                                                         NETCONFIG_WIFI_CONFIGURATION);
196                                         goto done;
197                                 }
198
199                                 if (g_strcmp0(path, netconfig_get_default_profile()) != 0)
200                                         goto done;
201
202                                 netconfig_update_default_profile(NULL);
203
204                                 if (g_strcmp0(property, "association") == 0)
205                                         netconfig_wifi_state_set_service_state(
206                                                                                 NETCONFIG_WIFI_ASSOCIATION);
207                                 else
208                                         netconfig_wifi_state_set_service_state(
209                                                                                 NETCONFIG_WIFI_CONFIGURATION);
210
211                         }
212                 } else {
213                         if (g_strcmp0(property, "ready") == 0 || g_strcmp0(property, "online") == 0) {
214                                 if (netconfig_get_default_profile() == NULL) {
215                                         if(!netconfig_is_cellular_profile(path)) {
216                                                 netconfig_update_default_profile(path);
217                                         } else {
218                                                 if (netconfig_is_cellular_internet_profile(path)) {
219                                                         netconfig_update_default_profile(path);
220                                                         netconfig_cellular_state_set_service_state(NETCONFIG_CELLULAR_ONLINE);
221                                                 }
222                                         }
223                                 }
224                         } else if (g_strcmp0(property, "failure") == 0 || g_strcmp0(property, "disconnect") == 0 || g_strcmp0(property, "idle") == 0) {
225                                 if (netconfig_get_default_profile() == NULL)
226                                         goto done;
227
228                                 if (netconfig_is_cellular_profile(path) == TRUE)
229                                         netconfig_cellular_state_set_service_state(NETCONFIG_CELLULAR_IDLE);
230
231                                 if (g_strcmp0(path, netconfig_get_default_profile()) != 0)
232                                         goto done;
233
234                                 netconfig_update_default_profile(NULL);
235                         } else if (g_strcmp0(property, "association") == 0 ||   g_strcmp0(property, "configuration") == 0) {
236                                 if (netconfig_get_default_profile() == NULL)
237                                         goto done;
238
239                                 if (netconfig_is_cellular_profile(path) == TRUE)
240                                         netconfig_cellular_state_set_service_state(NETCONFIG_CELLULAR_CONNECTING);
241
242                                 if (g_strcmp0(path, netconfig_get_default_profile()) != 0)
243                                         goto done;
244
245                                 netconfig_update_default_profile(NULL);
246                         }
247                 }
248         } else if (g_strcmp0(sigvalue, "Proxy") == 0) {
249                 if (netconfig_is_wifi_profile(path) != TRUE || g_strcmp0(path, netconfig_get_default_profile()) != 0)
250                         goto done;
251
252                 if (!g_variant_type_equal(variant, G_VARIANT_TYPE_ARRAY))
253                         goto done;
254
255                 g_variant_get(variant, "a{sv}", &iter);
256                 while (g_variant_iter_loop(iter, "{sv}", &property, &var)) {
257                         if (g_strcmp0(property, "Servers") == 0) {
258                                 GVariantIter *iter_sub = NULL;
259
260                                 g_variant_get(var, "as", &iter_sub);
261                                 g_variant_iter_loop(iter_sub, "s", &value);
262                                 g_variant_iter_free(iter_sub);
263
264                                 DBG("Proxy - [%s]", value);
265                                 vconf_set_str(VCONFKEY_NETWORK_PROXY, value);
266
267                                 g_free(property);
268                                 g_variant_unref(var);
269                                 break;
270                         } else if (g_strcmp0(property, "Method") == 0) {
271                                 value = g_variant_get_string(var, NULL);
272                                 DBG("Method - [%s]", value);
273
274                                 if (g_strcmp0(value, "direct") == 0)
275                                         vconf_set_str(VCONFKEY_NETWORK_PROXY, "");
276
277                                 g_free(property);
278                                 g_variant_unref(var);
279                                 break;
280                         }
281                 }
282
283                 g_variant_iter_free(iter);
284         } else if (g_strcmp0(sigvalue, "Error") == 0) {
285                 g_variant_get(variant, "s", &property);
286                 INFO("[%s] Property : %s", sigvalue, property);
287         }
288 done:
289         if (sigvalue)
290                 g_free(sigvalue);
291
292         if (variant)
293                 g_variant_unref(variant);
294
295         return;
296 }
297
298 static void __netconfig_dbus_name_changed_signal_handler(GDBusConnection *conn,
299                 const gchar *Name, const gchar *path, const gchar *interface,
300                 const gchar *sig, GVariant *param, gpointer user_data)
301 {
302         char *name, *old, *new;
303
304         if (param == NULL)
305                 return;
306
307         g_variant_get(param, "(sss)", &name, &old, &new);
308
309         if (g_strcmp0(name, CONNMAN_SERVICE) == 0 && *new == '\0') {
310                 DBG("ConnMan destroyed: name %s, old %s, new %s", name, old, new);
311
312                 netconfig_agent_register();
313         }
314
315         return;
316 }
317
318 static void __netconfig_supplicant_interface_removed(GDBusConnection *conn,
319                 const gchar *name, const gchar *path, const gchar *interface,
320                 const gchar *sig, GVariant *param, gpointer user_data)
321 {
322         DBG("Interface removed handling!");
323         if (netconfig_wifi_is_wps_enabled() == TRUE)
324                 netconfig_wifi_wps_signal_scanaborted();
325
326         return;
327 }
328
329 static void __netconfig_supplicant_properties_changed(GDBusConnection *conn,
330                 const gchar *name, const gchar *path, const gchar *interface,
331                 const gchar *sig, GVariant *param, gpointer user_data)
332 {
333         DBG("Properties changed handling!");
334         gchar *key;
335         GVariantIter *iter;
336         GVariant *variant;
337         gboolean scanning = FALSE;
338
339         if (param == NULL)
340                 return;
341
342         g_variant_get(param, "(a{sv})", &iter);
343         while (g_variant_iter_loop(iter, "{sv}", &key, &variant)) {
344                 if (g_strcmp0(key, "Scanning") == 0) {
345                         scanning = g_variant_get_boolean(variant);
346                         if (scanning == TRUE)
347                                 netconfig_wifi_set_scanning(TRUE);
348
349                         g_variant_unref(variant);
350                         g_free(key);
351                         break;
352                 }
353         }
354
355         g_variant_iter_free(iter);
356
357         return;
358 }
359
360 static void __netconfig_supplicant_bss_added(GDBusConnection *conn,
361                 const gchar *name, const gchar *path, const gchar *interface,
362                 const gchar *sig, GVariant *param, gpointer user_data)
363 {
364         DBG("BSS added handling!");
365         if (netconfig_wifi_get_ssid_scan_state() == TRUE)
366                 netconfig_wifi_bss_added(param);
367         else
368                 netconfig_wifi_set_bss_found(TRUE);
369
370         return;
371 }
372
373 static void __netconfig_supplicant_scan_done(GDBusConnection *conn,
374                 const gchar *name, const gchar *path, const gchar *interface,
375                 const gchar *sig, GVariant *param, gpointer user_data)
376 {
377         DBG("Scan Done handling!");
378         netconfig_wifi_set_scanning(FALSE);
379
380         if (netconfig_wifi_is_wps_enabled() == TRUE) {
381                 netconfig_wifi_wps_signal_scandone();
382                 if (netconfig_wifi_state_get_technology_state() <
383                                 NETCONFIG_WIFI_TECH_POWERED)
384                         return;
385         }
386
387         if (netconfig_wifi_get_bgscan_state() != TRUE) {
388                 if (netconfig_wifi_get_ssid_scan_state() == TRUE)
389                         netconfig_wifi_notify_ssid_scan_done();
390                 else
391                         netconfig_wifi_ssid_scan(NULL);
392         } else {
393                 if (netconfig_wifi_state_get_technology_state() >=
394                                 NETCONFIG_WIFI_TECH_POWERED)
395                         netconfig_wifi_bgscan_start(FALSE);
396
397                 netconfig_wifi_start_timer_network_notification();
398         }
399
400         return;
401 }
402
403 static void __netconfig_supplicant_driver_hanged(GDBusConnection *conn,
404                 const gchar *name, const gchar *path, const gchar *interface,
405                 const gchar *sig, GVariant *param, gpointer user_data)
406 {
407         DBG("Driver Hanged handling!");
408         ERR("Critical. Wi-Fi firmware crashed");
409
410         netconfig_wifi_recover_firmware();
411
412         return;
413 }
414
415 static void __netconfig_supplicant_session_overlapped(GDBusConnection *conn,
416                 const gchar *name, const gchar *path, const gchar *interface,
417                 const gchar *sig, GVariant *param, gpointer user_data)
418 {
419         DBG("Driver session overlapped handling!");
420         ERR("WPS PBC SESSION OVERLAPPED");
421 #if defined TIZEN_WEARABLE
422         wc_launch_syspopup(WC_POPUP_TYPE_SESSION_OVERLAPPED);
423 #else
424         netconfig_send_message_to_net_popup("WPS Error",
425                                         "wps session overlapped", "popup", NULL);
426 #endif
427 }
428
429 static netconfig_supplicant_signal_handler supp_handlers[SIG_MAX] = {
430                 __netconfig_supplicant_interface_removed,
431                 __netconfig_supplicant_properties_changed,
432                 __netconfig_supplicant_bss_added,
433                 __netconfig_supplicant_scan_done,
434                 __netconfig_supplicant_driver_hanged,
435                 __netconfig_supplicant_session_overlapped
436 };
437
438 #if defined TIZEN_DEBUG_DISABLE
439 static void __netconfig_dumpservice_handler(GDBusConnection *conn,
440                 const gchar *name, const gchar *path, const gchar *interface,
441                 const gchar *sig, GVariant *param, gpointer user_data)
442 {
443         int mode;
444         gchar *signal_path = NULL;
445
446         if (param == NULL)
447                 return;
448
449         g_variant_get(param, "(io)", &mode, &signal_path);
450         DBG("Path: %s and mode: %d", signal_path, mode);
451         netconfig_dump_log(path);
452
453         return;
454 }
455 #endif
456
457 void netconfig_register_signal(void)
458 {
459         GDBusConnection *connection = NULL;
460         const char *interface = NULL;
461         SuppSigArrayIndex sig;
462         connection = netconfig_gdbus_get_connection();
463
464         if (connection == NULL) {
465                 ERR("Failed to get GDbus Connection");
466                 return;
467         }
468
469         /* listening to messages from all objects as no path is specified */
470         /* see signals from the given interface */
471         conn_subscription_ids[0] = g_dbus_connection_signal_subscribe(
472                         connection,
473                         CONNMAN_SERVICE,
474                         CONNMAN_TECHNOLOGY_INTERFACE,
475                         NULL,
476                         NULL,
477                         NULL,
478                         G_DBUS_SIGNAL_FLAGS_NONE,
479                         __netconfig_technology_signal_handler,
480                         NULL,
481                         NULL);
482
483         conn_subscription_ids[1] = g_dbus_connection_signal_subscribe(
484                         connection,
485                         CONNMAN_SERVICE,
486                         CONNMAN_SERVICE_INTERFACE,
487                         CONNMAN_SIGNAL_PROPERTY_CHANGED,
488                         NULL,
489                         NULL,
490                         G_DBUS_SIGNAL_FLAGS_NONE,
491                         __netconfig_service_signal_handler,
492                         NULL,
493                         NULL);
494
495         conn_subscription_ids[2] = g_dbus_connection_signal_subscribe(
496                         connection,
497                         DBUS_SERVICE_DBUS,
498                         DBUS_INTERFACE_DBUS,
499                         CONNMAN_SIGNAL_NAME_CHANGED,
500                         NULL,
501                         CONNMAN_SERVICE,
502                         G_DBUS_SIGNAL_FLAGS_NONE,
503                         __netconfig_dbus_name_changed_signal_handler,
504                         NULL,
505                         NULL);
506
507         INFO("Successfully register connman DBus signal filters");
508
509         for (sig = SIG_INTERFACE_REMOVED; sig < SIG_MAX; sig++) {
510                 /*
511                  * For SIG_INTERFACE_REMOVED INTERFACE_ADDED
512                  */
513                 interface = (sig == SIG_INTERFACE_REMOVED) ?
514                                 SUPPLICANT_INTERFACE : SUPPLICANT_IFACE_INTERFACE;
515
516                 supp_subscription_ids[sig] = g_dbus_connection_signal_subscribe(
517                                 connection,
518                                 SUPPLICANT_SERVICE,
519                                 interface,
520                                 supp_signals[sig],
521                                 NULL,
522                                 NULL,
523                                 G_DBUS_SIGNAL_FLAGS_NONE,
524                                 supp_handlers[sig],
525                                 NULL,
526                                 NULL);
527         }
528
529         INFO("Successfully register Supplicant DBus signal filters");
530
531 #if defined TIZEN_DEBUG_DISABLE
532         dumpservice_subscription_id = g_dbus_connection_signal_subscribe(
533                         connection,
534                         /*
535                          * Sender => For testing purpose made NULL
536                          *WPA_SUPPLICANT,
537                          */
538                         NULL,
539                         DUMP_SERVICE_INTERFACE,
540                         DUMP_SIGNAL,
541                         NULL,
542                         NULL,
543                         G_DBUS_SIGNAL_FLAGS_NONE,
544                         __netconfig_dumpservice_handler,
545                         NULL,
546                         NULL);
547
548         INFO("Successfully register Dumpservice DBus signal filter");
549 #endif
550         /* In case ConnMan precedes this signal register,
551          * net-config should update the default connected profile.
552          */
553         netconfig_update_default();
554 }
555
556 void netconfig_deregister_signal(void)
557 {
558         GDBusConnection *connection = NULL;
559         int signal;
560         SuppSigArrayIndex sig;
561         connection = netconfig_gdbus_get_connection();
562         if (!connection) {
563                 ERR("Already de-registered. Nothing to be done");
564                 return;
565         }
566
567         for (signal = 0; signal < TOTAL_CONN_SIGNALS; signal++) {
568                 if (conn_subscription_ids[signal]) {
569                         g_dbus_connection_signal_unsubscribe(connection,
570                                                 conn_subscription_ids[signal]);
571                 }
572         }
573
574         for (sig = SIG_INTERFACE_REMOVED; sig < SIG_MAX; sig++) {
575                 if (supp_subscription_ids[sig]) {
576                         g_dbus_connection_signal_unsubscribe(connection,
577                                                 supp_subscription_ids[sig]);
578                 }
579         }
580
581         g_dbus_connection_signal_unsubscribe(connection,
582                         dumpservice_subscription_id);
583 }