[Fix] Use localtime_r() instead of localtime()
[platform/core/connectivity/stc-manager.git] / src / monitor / stc-default-connection.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <vconf/vconf.h>
18 #include <openssl/sha.h>
19
20 #include "stc-monitor.h"
21 #include "stc-firewall.h"
22 #include "stc-manager-gdbus.h"
23 #include "stc-default-connection.h"
24
25 /* connman service dbus details */
26 #define CONNMAN_SERVICE                          "net.connman"
27 #define CONNMAN_PATH                             "/net/connman"
28
29 #define CONNMAN_MANAGER_PATH                     "/"
30 #define CONNMAN_MANAGER_INTERFACE                CONNMAN_SERVICE ".Manager"
31 #define CONNMAN_SERVICE_INTERFACE                CONNMAN_SERVICE ".Service"
32
33 #define CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX  CONNMAN_PATH "/service/cellular_"
34 #define CONNMAN_WIFI_SERVICE_PROFILE_PREFIX      CONNMAN_PATH "/service/wifi_"
35 #define CONNMAN_ETHERNET_SERVICE_PROFILE_PREFIX  CONNMAN_PATH "/service/ethernet_"
36 #define CONNMAN_BLUETOOTH_SERVICE_PROFILE_PREFIX CONNMAN_PATH "/service/bluetooth_"
37
38 #define CONNMAN_SIGNAL_PROPERTY_CHANGED          "PropertyChanged"
39
40 /* telephony service dbus details */
41 #define TELEPHONY_SERVICE                        "org.tizen.telephony"
42 #define TELEPHONY_DEFAULT_PATH                   "/org/tizen/telephony"
43
44 #define TELEPHONY_SERVICE_MANAGER                TELEPHONY_SERVICE".Manager"
45 #define TELEPHONY_SIM_INTERFACE                  TELEPHONY_SERVICE".Sim"
46
47 #define TELEPHONY_GET_MODEMS                     "GetModems"
48 #define TELEPHONY_GET_IMSI                       "GetIMSI"
49
50 #define SIM_SLOT_SINGLE 1
51
52 #define VCONF_TELEPHONY_DEFAULT_DATA_SERVICE     "db/telephony/dualsim/default_data_service"
53
54 default_connection_s g_default_connection;
55 guint g_default_connection_sub_id = 0;
56
57 static int __telephony_get_current_sim(void)
58 {
59         int sim_slot_count = 0;
60         int current_sim = 0;
61
62         if (vconf_get_int(VCONFKEY_TELEPHONY_SIM_SLOT_COUNT, &sim_slot_count) != 0) {
63                 STC_LOGD("failed to get sim slot count"); //LCOV_EXCL_LINE
64                 return -1; //LCOV_EXCL_LINE
65         }
66
67         if (sim_slot_count == SIM_SLOT_SINGLE) {
68                STC_LOGD("It's single sim model"); //LCOV_EXCL_LINE
69                return current_sim; //LCOV_EXCL_LINE
70         }
71
72         if (vconf_get_int(VCONF_TELEPHONY_DEFAULT_DATA_SERVICE, &current_sim) != 0) {
73                 STC_LOGD("failed to get default data service = %d\n", //LCOV_EXCL_LINE
74                          current_sim);
75                 return -1; //LCOV_EXCL_LINE
76         }
77
78         return current_sim;
79 }
80
81 static void __make_imsi_to_subscriber_id(char *imsi)
82 {
83         int i = 0;
84         SHA256_CTX ctx;
85         unsigned char md[SHA256_DIGEST_LENGTH];
86
87         SHA256_Init(&ctx);
88         SHA256_Update(&ctx, imsi, strlen(imsi));
89         SHA256_Final(md, &ctx);
90
91         for (i = 0; i < SHA256_DIGEST_LENGTH; ++i)
92                 snprintf(g_default_connection.subscriber_id + (i * 2), 3, "%02x", md[i]);
93 }
94
95 static void __telephony_get_modem_subscriber_id(GDBusConnection *connection,
96                                        const char *default_modem_name)
97 {
98         GVariant *message = NULL;
99         char tel_path[MAX_PATH_LENGTH];
100         char imsi[IMSI_LENGTH];
101         const char *plmn = NULL;
102         int plmn_len = 0;
103         const char *msin = NULL;
104         int msin_len = 0;
105
106         snprintf(tel_path, sizeof(tel_path), "%s/%s", TELEPHONY_DEFAULT_PATH,
107                  default_modem_name);
108         message = stc_manager_gdbus_call_sync(connection,
109                                               TELEPHONY_SERVICE,
110                                               tel_path,
111                                               TELEPHONY_SIM_INTERFACE,
112                                               TELEPHONY_GET_IMSI,
113                                               NULL);
114         if (message == NULL) {
115                 STC_LOGE("Failed to get services informations"); //LCOV_EXCL_LINE
116                 goto done; //LCOV_EXCL_LINE
117         }
118
119         DEBUG_PARAMS(message);
120         DEBUG_PARAM_TYPE(message);
121         g_variant_get(message, "(&s&s)", &plmn, &msin);
122         if (plmn)
123                 plmn_len = strlen(plmn);
124         if (msin)
125                 msin_len = strlen(msin);
126
127         if (msin_len + plmn_len >= IMSI_LENGTH) {
128                 STC_LOGD("Incorrect length of mobile subscriber identifier + net id"); //LCOV_EXCL_LINE
129                 goto done; //LCOV_EXCL_LINE
130         }
131
132         snprintf(imsi, IMSI_LENGTH, "%s%s", plmn, msin);
133         __make_imsi_to_subscriber_id(imsi);
134
135 done:
136         g_variant_unref(message);
137         return;
138 }
139
140 static void __telephony_update_default_modem_subscriber_id(GDBusConnection *connection)
141 {
142         GVariant *message = NULL;
143         GVariantIter *iter = NULL;
144         gchar *default_modem_name = NULL;
145         gchar *modem_name = NULL;
146         int current_sim = __telephony_get_current_sim();
147
148         if (current_sim < 0) {
149                 STC_LOGI("Sim not found"); //LCOV_EXCL_LINE
150                 return; //LCOV_EXCL_LINE
151         }
152
153         message = stc_manager_gdbus_call_sync(connection,
154                                               TELEPHONY_SERVICE,
155                                               TELEPHONY_DEFAULT_PATH,
156                                               TELEPHONY_SERVICE_MANAGER,
157                                               TELEPHONY_GET_MODEMS,
158                                               NULL);
159         if (message == NULL) {
160                 STC_LOGE("Failed to get services informations"); //LCOV_EXCL_LINE
161                 return; //LCOV_EXCL_LINE
162         }
163
164         g_variant_get(message, "(as)", &iter);
165         DEBUG_PARAMS(message);
166         DEBUG_PARAM_TYPE(message);
167         while (g_variant_iter_loop(iter, "s", &modem_name)) {
168                 if (current_sim == 0) {
169                         default_modem_name = g_strdup(modem_name);
170                         FREE(modem_name);
171                         break;
172                 }
173                 current_sim--; //LCOV_EXCL_LINE
174         }
175
176         __telephony_get_modem_subscriber_id(connection, default_modem_name);
177
178         FREE(default_modem_name);
179         g_variant_iter_free(iter);
180         g_variant_unref(message);
181         return;
182 }
183
184 static void __print_default_connection_info(void)
185 {
186         STC_LOGI("============= default connection info ============");
187         STC_LOGI("path    [%s]", g_default_connection.path);
188         STC_LOGI("type    [%d]", g_default_connection.type);
189         STC_LOGI("ifname  [%s]", g_default_connection.ifname);
190         STC_LOGI("roaming [%u]", g_default_connection.roaming ? TRUE : FALSE);
191         if (g_default_connection.type == STC_IFACE_DATACALL)
192                 STC_LOGI("sub_id  [%s]", g_default_connection.subscriber_id);
193         STC_LOGI("==================================================");
194 }
195
196 static void __print_tether_connection_info(void)
197 {
198         STC_LOGI("============= tethering connection info ============");
199         STC_LOGI("mode    [%u]", g_default_connection.tether_state ? TRUE : FALSE);
200         STC_LOGI("type    [%d]", g_default_connection.tether_iface.type);
201         STC_LOGI("ifname  [%s]", g_default_connection.tether_iface.ifname);
202         STC_LOGI("====================================================");
203 }
204
205 static void __reset_default_connection_data(void)
206 {
207         FREE(g_default_connection.path);
208         FREE(g_default_connection.ifname);
209         FREE(g_default_connection.tether_iface.ifname);
210         g_default_connection.type = STC_IFACE_UNKNOWN;
211         g_default_connection.roaming = FALSE;
212         g_default_connection.tether_iface.type = STC_IFACE_UNKNOWN;
213         g_default_connection.tether_state = FALSE;
214 }
215
216 static gboolean __is_cellular_internet_profile(const char *profile)
217 {
218         const char internet_suffix[] = "_1";
219
220         if (profile == NULL)
221                 return FALSE;
222
223         if (g_str_has_prefix(profile, CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX)
224             == TRUE) {
225                 char *suffix = strrchr(profile, '_');
226                 if (g_strcmp0(suffix, internet_suffix) == 0)
227                         return TRUE;
228         }
229
230         return FALSE;
231 }
232
233 static gboolean __is_cellular_profile(const char *profile)
234 {
235         if (profile == NULL)
236                 return FALSE;
237
238         return g_str_has_prefix(profile, //LCOV_EXCL_LINE
239                                 CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX);
240 }
241
242 static gboolean __is_wifi_profile(const char *profile)
243 {
244         if (profile == NULL)
245                 return FALSE;
246
247         return g_str_has_prefix(profile, //LCOV_EXCL_LINE
248                                 CONNMAN_WIFI_SERVICE_PROFILE_PREFIX);
249 }
250
251 static gboolean __is_ethernet_profile(const char *profile)
252 {
253         if (profile == NULL)
254                 return FALSE;
255
256         return g_str_has_prefix(profile, //LCOV_EXCL_LINE
257                                 CONNMAN_ETHERNET_SERVICE_PROFILE_PREFIX);
258 }
259
260 static gboolean __is_bluetooth_profile(const char *profile)
261 {
262         if (profile == NULL)
263                 return FALSE;
264
265         return g_str_has_prefix(profile, //LCOV_EXCL_LINE
266                                 CONNMAN_BLUETOOTH_SERVICE_PROFILE_PREFIX);
267 }
268
269 static gboolean __is_connected(GVariantIter *array)
270 {
271         gboolean is_connected = FALSE;
272         GVariant *variant = NULL;
273         gchar *key = NULL;
274
275         while (g_variant_iter_loop(array, "{sv}", &key, &variant)) {
276                 if (g_strcmp0(key, "State") != 0)
277                         continue;
278
279                 if (g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) {
280                         const gchar *state = NULL;
281
282                         state = g_variant_get_string(variant, NULL);
283                         if (g_strcmp0(state, "ready") == 0 ||
284                             g_strcmp0(state, "online") == 0)
285                                 is_connected = TRUE;
286                 }
287
288                 g_free(key);
289                 g_variant_unref(variant);
290                 break;
291         }
292
293         return is_connected;
294 }
295
296 static void __get_default_connection_info(GDBusConnection *connection,
297                                           const char *object_path)
298 {
299         GVariant *message = NULL;
300         GVariantIter *iter = NULL;
301         GVariant *variant = NULL;
302         gchar *key = NULL;
303
304         if (object_path == NULL) {
305                 STC_LOGI("Object path is NULL, so information not available.");
306                 return;
307         }
308
309         message = stc_manager_gdbus_call_sync(connection,
310                                               CONNMAN_SERVICE,
311                                               object_path,
312                                               CONNMAN_SERVICE_INTERFACE,
313                                               "GetProperties", NULL);
314         if (message == NULL) {
315                 STC_LOGE("Failed to get services informations"); //LCOV_EXCL_LINE
316                 goto done; //LCOV_EXCL_LINE
317         }
318
319         g_variant_get(message, "(a{sv})", &iter);
320         if (iter == NULL) {
321                 STC_LOGE("Profile %s doesn't exist", object_path); //LCOV_EXCL_LINE
322                 goto done; //LCOV_EXCL_LINE
323         }
324
325         while (g_variant_iter_loop(iter, "{sv}", &key, &variant)) {
326                 if (g_strcmp0(key, "Ethernet") == 0) {
327                         GVariantIter *iter1 = NULL;
328                         GVariant *variant1 = NULL;
329                         gchar *key1 = NULL;
330
331                         g_variant_get(variant, "a{sv}", &iter1);
332                         if (iter1 == NULL)
333                                 continue; //LCOV_EXCL_LINE
334
335                         while (g_variant_iter_loop(iter1, "{sv}", &key1,
336                                                    &variant1)) {
337                                 if (g_strcmp0(key1, "Interface") == 0) {
338                                         const gchar *value =
339                                                 g_variant_get_string(variant1,
340                                                                      NULL);
341                                         g_default_connection.ifname =
342                                                 g_strdup(value);
343                                 }
344                         }
345
346                         g_variant_iter_free(iter1);
347
348                 } else if (g_strcmp0(key, "Roaming") == 0) {
349                         gboolean roaming = 0;
350
351                         if (g_variant_is_of_type(variant,
352                                                  G_VARIANT_TYPE_BOOLEAN)) {
353                                 roaming = g_variant_get_boolean(variant);
354                                 g_default_connection.roaming = roaming;
355                         }
356                 }
357         }
358
359 done:
360         if (iter)
361                 g_variant_iter_free(iter);
362
363         if (message)
364                 g_variant_unref(message);
365
366         return;
367 }
368
369 static stc_error_e __get_default_profile(GDBusConnection *connection)
370 {
371         GVariant *message = NULL;
372         GVariantIter *iter = NULL;
373         GVariantIter *next;
374         gchar *object_path;
375
376         message = stc_manager_gdbus_call_sync(connection,
377                                               CONNMAN_SERVICE,
378                                               CONNMAN_MANAGER_PATH,
379                                               CONNMAN_MANAGER_INTERFACE,
380                                               "GetServices", NULL);
381         if (message == NULL) {
382                 STC_LOGE("Failed to get profiles"); //LCOV_EXCL_LINE
383                 return STC_ERROR_FAIL; //LCOV_EXCL_LINE
384         }
385
386         g_variant_get(message, "(a(oa{sv}))", &iter);
387         while (g_variant_iter_loop(iter, "(oa{sv})", &object_path, &next)) {
388                 if (object_path == NULL)
389                         continue; //LCOV_EXCL_LINE
390
391                 if (__is_cellular_profile(object_path) &&
392                     !__is_cellular_internet_profile(object_path))
393                         continue;
394
395                 if (__is_connected(next) == TRUE) {
396                         /* reset old default connection data */
397                         FREE(g_default_connection.path);
398                         FREE(g_default_connection.ifname);
399                         g_default_connection.type = STC_IFACE_UNKNOWN;
400                         g_default_connection.roaming = FALSE;
401
402                         g_default_connection.path = g_strdup(object_path);
403                         g_free(object_path);
404                         g_variant_iter_free(next);
405                         break;
406                 }
407         }
408
409         g_variant_iter_free(iter);
410         g_variant_unref(message);
411
412         if (__is_cellular_profile(g_default_connection.path)) {
413                 g_default_connection.type = STC_IFACE_DATACALL; //LCOV_EXCL_LINE
414                 __telephony_update_default_modem_subscriber_id(connection); //LCOV_EXCL_LINE
415         } else if (__is_wifi_profile(g_default_connection.path)) {
416                 g_default_connection.type = STC_IFACE_WIFI; //LCOV_EXCL_LINE
417         } else if (__is_ethernet_profile(g_default_connection.path)) {
418                 g_default_connection.type = STC_IFACE_WIRED; //LCOV_EXCL_LINE
419         } else if (__is_bluetooth_profile(g_default_connection.path)) {
420                 g_default_connection.type = STC_IFACE_BLUETOOTH; //LCOV_EXCL_LINE
421         } else {
422                 g_default_connection.type = STC_IFACE_UNKNOWN; //LCOV_EXCL_LINE
423         }
424
425         __get_default_connection_info(connection, g_default_connection.path);
426
427         __print_default_connection_info();
428
429         stc_monitor_update_rstn_by_default_connection(&g_default_connection);
430         stc_firewall_update();
431
432         return STC_ERROR_NONE;
433 }
434
435 static void _service_signal_cb(GDBusConnection *conn,
436                                const gchar *name, const gchar *path,
437                                const gchar *interface, const gchar *sig,
438                                GVariant *param, gpointer user_data)
439 {
440         gchar *sigvalue = NULL;
441         GVariant *variant = NULL;
442         stc_s *stc = (stc_s *)stc_get_manager();
443         ret_msg_if(stc == NULL, "failed to get stc data");
444
445         if (path == NULL || param == NULL)
446                 goto done;
447
448         g_variant_get(param, "(sv)", &sigvalue, &variant);
449         if (sigvalue == NULL)
450                 goto done;
451
452         if (g_strcmp0(sig, CONNMAN_SIGNAL_PROPERTY_CHANGED) != 0)
453                 goto done;
454
455         if (g_strcmp0(sigvalue, "State") == 0 &&
456             g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) {
457                 const gchar *state = NULL;
458
459                 state = g_variant_get_string(variant, NULL);
460                 if (g_strcmp0(state, "ready") == 0 ||
461                     g_strcmp0(state, "online") == 0) {
462                         if (g_strcmp0(g_default_connection.path, path)) {
463                                 __reset_default_connection_data();
464                                 __get_default_profile(stc->connection);
465                         }
466                 } else {
467                         if (g_strcmp0(g_default_connection.path, path) == 0) {
468                                 __reset_default_connection_data(); //LCOV_EXCL_LINE
469                                 __get_default_profile(stc->connection); //LCOV_EXCL_LINE
470                         }
471                 }
472         } else if (g_strcmp0(sigvalue, "Roaming") == 0) {
473                 //LCOV_EXCL_START
474                 if (g_strcmp0(g_default_connection.path, path) == 0) {
475                         gboolean roaming = 0;
476
477                         if (g_variant_is_of_type(variant,
478                                                  G_VARIANT_TYPE_BOOLEAN)) {
479                                 roaming = g_variant_get_boolean(variant);
480                                 g_default_connection.roaming = roaming;
481                         }
482                 }
483                 //LCOV_EXCL_STOP
484         } else {
485                 ;//Do nothing
486         }
487 done:
488         if (sigvalue)
489                 g_free(sigvalue);
490
491         if (variant)
492                 g_variant_unref(variant);
493
494         return;
495 }
496
497 static void __vconf_key_callback(keynode_t *node, void *user_data)
498 {
499         int vconf_key;
500
501         if (node == NULL) {
502                 STC_LOGE("Invalid parameter");
503                 return;
504         }
505
506         if (vconf_keynode_get_type(node) != VCONF_TYPE_INT) {
507                 STC_LOGE("Invalid vconf key type");
508                 return;
509         }
510
511         vconf_key = vconf_keynode_get_int(node);
512
513         /* Check the tethering type */
514         switch (vconf_key) {
515         case VCONFKEY_MOBILE_HOTSPOT_MODE_USB:
516                 STC_LOGI("Hotspot mode USB type !");
517                 g_default_connection.tether_state = TRUE;
518                 g_default_connection.tether_iface.ifname = g_strdup(TETHERING_USB_IF);
519                 g_default_connection.tether_iface.type = STC_IFACE_USB;
520                 break;
521         case VCONFKEY_MOBILE_HOTSPOT_MODE_WIFI:
522                 STC_LOGI("Hotspot mode Wi-Fi type !");
523                 g_default_connection.tether_state = TRUE;
524                 g_default_connection.tether_iface.ifname = g_strdup(TETHERING_WIFI_IF);
525                 g_default_connection.tether_iface.type = STC_IFACE_WIFI;
526                 break;
527         case VCONFKEY_MOBILE_HOTSPOT_MODE_BT:
528                 STC_LOGI("Hotspot mode Bluetooth type !");
529                 g_default_connection.tether_state = TRUE;
530                 g_default_connection.tether_iface.ifname = g_strdup(TETHERING_BT_IF);
531                 g_default_connection.tether_iface.type = STC_IFACE_BLUETOOTH;
532                 break;
533         case VCONFKEY_MOBILE_HOTSPOT_MODE_P2P:
534                 STC_LOGI("Hotspot mode P2P type !");
535                 g_default_connection.tether_state = TRUE;
536                 g_default_connection.tether_iface.ifname = g_strdup(TETHERING_P2P_IF);
537                 g_default_connection.tether_iface.type = STC_IFACE_P2P;
538                 break;
539         case VCONFKEY_MOBILE_HOTSPOT_MODE_NONE:
540                 STC_LOGI("Hotspot mode none");
541                 g_default_connection.tether_state = FALSE;
542                 break;
543         default:
544                 STC_LOGE("Unknown Hotspot mode type !");
545                 break;
546         }
547
548         /* add monitoring for tethering if active found */
549         if (g_default_connection.tether_state == TRUE && g_default_connection.tether_iface.ifname) {
550                 __print_tether_connection_info();
551                 stc_monitor_update_rstn_by_default_connection(&g_default_connection);
552                 stc_firewall_update();
553                 STC_LOGI("Data monitoring started for tethering iface !");
554                 return;
555         }
556
557         /* remove monitoring for tethering if in-active found */
558         if (g_default_connection.tether_state == FALSE && g_default_connection.tether_iface.ifname) {
559                 stc_monitor_update_rstn_by_default_connection(&g_default_connection);
560                 g_free(g_default_connection.tether_iface.ifname);
561                 g_default_connection.tether_iface.ifname = NULL;
562                 g_default_connection.tether_iface.type = STC_IFACE_UNKNOWN;
563                 STC_LOGI("Data monitoring stopped for tethering iface !");
564                 return;
565         }
566 }
567
568 stc_error_e stc_default_connection_monitor_init(stc_s *stc)
569 {
570         int ret;
571         ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data");
572
573         __get_default_profile(stc->connection);
574         g_default_connection_sub_id =
575                 stc_manager_gdbus_subscribe_signal(stc->connection,
576                                                    CONNMAN_SERVICE,
577                                                    CONNMAN_SERVICE_INTERFACE,
578                                                    CONNMAN_SIGNAL_PROPERTY_CHANGED,
579                                                    NULL, NULL,
580                                                    G_DBUS_SIGNAL_FLAGS_NONE,
581                                                    _service_signal_cb,
582                                                    NULL, NULL);
583
584         ret = vconf_notify_key_changed(VCONFKEY_MOBILE_HOTSPOT_MODE, __vconf_key_callback, NULL);
585         if (ret < 0)
586                 STC_LOGE("vconf_notify_key_changed failed: %d", ret);
587
588         STC_LOGI("Successfully subscribed connman [%s] signal", CONNMAN_SIGNAL_PROPERTY_CHANGED);
589         return STC_ERROR_NONE;
590 }
591
592 stc_error_e stc_default_connection_monitor_deinit(stc_s *stc)
593 {
594         ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data");
595
596         stc_manager_gdbus_unsubscribe_signal(stc->connection,
597                                              g_default_connection_sub_id);
598         FREE(g_default_connection.path);
599         FREE(g_default_connection.ifname);
600         return STC_ERROR_NONE;
601 }
602
603 gchar *stc_default_connection_get_ifname(void)
604 {
605         return g_strdup(g_default_connection.ifname);
606 }
607
608 default_connection_s *stc_get_default_connection(void)
609 {
610         return &g_default_connection;
611 }