2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <vconf/vconf.h>
18 #include <openssl/sha.h>
20 #include "stc-firewall.h"
21 #include "stc-manager-gdbus.h"
22 #include "stc-plugin-monitor.h"
23 #include "stc-plugin-monitor-connection.h"
24 #include "stc-manager-plugin-firewall.h"
26 /* connman service dbus details */
27 #define CONNMAN_SERVICE "net.connman"
28 #define CONNMAN_PATH "/net/connman"
30 #define CONNMAN_MANAGER_PATH "/"
31 #define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager"
32 #define CONNMAN_SERVICE_INTERFACE CONNMAN_SERVICE ".Service"
34 #define CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX CONNMAN_PATH "/service/cellular_"
35 #define CONNMAN_WIFI_SERVICE_PROFILE_PREFIX CONNMAN_PATH "/service/wifi_"
36 #define CONNMAN_ETHERNET_SERVICE_PROFILE_PREFIX CONNMAN_PATH "/service/ethernet_"
37 #define CONNMAN_BLUETOOTH_SERVICE_PROFILE_PREFIX CONNMAN_PATH "/service/bluetooth_"
39 #define CONNMAN_SIGNAL_PROPERTY_CHANGED "PropertyChanged"
41 /* telephony service dbus details */
42 #define TELEPHONY_SERVICE "org.tizen.telephony"
43 #define TELEPHONY_DEFAULT_PATH "/org/tizen/telephony"
45 #define TELEPHONY_SERVICE_MANAGER TELEPHONY_SERVICE".Manager"
46 #define TELEPHONY_SIM_INTERFACE TELEPHONY_SERVICE".Sim"
48 #define TELEPHONY_GET_MODEMS "GetModems"
49 #define TELEPHONY_GET_IMSI "GetIMSI"
51 #define SIM_SLOT_SINGLE 1
53 #define VCONF_TELEPHONY_DEFAULT_DATA_SERVICE "db/telephony/dualsim/default_data_service"
55 stc_connection_s *g_default_connection = NULL;
56 GSList *g_connection_list = NULL;
57 guint g_connection_sub_id = 0;
59 static void __conn_list_free(gpointer value)
61 stc_connection_s *conn = (stc_connection_s *)value;
65 FREE(conn->tether_iface.ifname);
69 static gint __conn_list_comp(gconstpointer a, gconstpointer b)
71 stc_connection_s *conn = (stc_connection_s *)a;
72 char *path = (char *)b;
74 if (g_strcmp0(conn->path, path) == 0)
80 static void __update_monitor_by_conn(gpointer data, gpointer user_data)
82 stc_connection_s *conn = (stc_connection_s *)data;
84 stc_monitor_update_by_connection(conn);
87 static int __telephony_get_current_sim(void)
89 int sim_slot_count = 0;
92 if (vconf_get_int(VCONFKEY_TELEPHONY_SIM_SLOT_COUNT, &sim_slot_count) != 0) {
93 STC_LOGD("failed to get sim slot count"); //LCOV_EXCL_LINE
94 return -1; //LCOV_EXCL_LINE
97 if (sim_slot_count == SIM_SLOT_SINGLE) {
98 STC_LOGD("It's single sim model"); //LCOV_EXCL_LINE
99 return current_sim; //LCOV_EXCL_LINE
102 if (vconf_get_int(VCONF_TELEPHONY_DEFAULT_DATA_SERVICE, ¤t_sim) != 0) {
103 STC_LOGD("failed to get default data service = %d\n", //LCOV_EXCL_LINE
105 return -1; //LCOV_EXCL_LINE
111 static void __make_imsi_to_subscriber_id(stc_connection_s *conn, char *imsi)
115 unsigned char md[SHA256_DIGEST_LENGTH];
118 SHA256_Update(&ctx, imsi, strlen(imsi));
119 SHA256_Final(md, &ctx);
121 for (i = 0; i < SHA256_DIGEST_LENGTH; ++i)
122 snprintf(conn->subscriber_id + (i * 2), 3, "%02x", md[i]);
125 static void __telephony_get_modem_subscriber_id(GDBusConnection *connection,
126 stc_connection_s *conn, const char *default_modem_name)
128 GVariant *message = NULL;
129 char tel_path[MAX_PATH_LENGTH];
130 char imsi[IMSI_LENGTH];
131 const char *plmn = NULL;
133 const char *msin = NULL;
136 snprintf(tel_path, sizeof(tel_path), "%s/%s", TELEPHONY_DEFAULT_PATH,
138 message = stc_manager_gdbus_call_sync(connection,
141 TELEPHONY_SIM_INTERFACE,
144 if (message == NULL) {
145 STC_LOGE("Failed to get services informations"); //LCOV_EXCL_LINE
146 goto done; //LCOV_EXCL_LINE
149 DEBUG_PARAMS(message);
150 DEBUG_PARAM_TYPE(message);
151 g_variant_get(message, "(&s&s)", &plmn, &msin);
153 plmn_len = strlen(plmn);
155 msin_len = strlen(msin);
157 if (msin_len + plmn_len >= IMSI_LENGTH) {
158 STC_LOGD("Incorrect length of mobile subscriber identifier + net id"); //LCOV_EXCL_LINE
159 goto done; //LCOV_EXCL_LINE
162 snprintf(imsi, IMSI_LENGTH, "%s%s", plmn, msin);
163 __make_imsi_to_subscriber_id(conn, imsi);
166 g_variant_unref(message);
170 static void __telephony_update_default_modem_subscriber_id(GDBusConnection *connection,
171 stc_connection_s *conn)
173 GVariant *message = NULL;
174 GVariantIter *iter = NULL;
175 gchar *default_modem_name = NULL;
176 gchar *modem_name = NULL;
177 int current_sim = __telephony_get_current_sim();
179 if (current_sim < 0) {
180 STC_LOGI("Sim not found"); //LCOV_EXCL_LINE
181 return; //LCOV_EXCL_LINE
184 message = stc_manager_gdbus_call_sync(connection,
186 TELEPHONY_DEFAULT_PATH,
187 TELEPHONY_SERVICE_MANAGER,
188 TELEPHONY_GET_MODEMS,
190 if (message == NULL) {
191 STC_LOGE("Failed to get services informations"); //LCOV_EXCL_LINE
192 return; //LCOV_EXCL_LINE
195 g_variant_get(message, "(as)", &iter);
196 DEBUG_PARAMS(message);
197 DEBUG_PARAM_TYPE(message);
198 while (g_variant_iter_loop(iter, "s", &modem_name)) {
199 if (current_sim == 0) {
200 default_modem_name = g_strdup(modem_name);
204 current_sim--; //LCOV_EXCL_LINE
207 __telephony_get_modem_subscriber_id(connection, conn, default_modem_name);
209 FREE(default_modem_name);
210 g_variant_iter_free(iter);
211 g_variant_unref(message);
215 static void __print_connection_info(stc_connection_s *conn)
217 STC_LOGI("============= connection info ============");
218 STC_LOGI("path [%s]", conn->path);
219 STC_LOGI("type [%d]", conn->type);
220 STC_LOGI("ifname [%s]", conn->ifname);
221 STC_LOGI("roaming [%u]", conn->roaming ? TRUE : FALSE);
222 if (conn->type == STC_IFACE_DATACALL)
223 STC_LOGI("sub_id [%s]", conn->subscriber_id);
224 STC_LOGI("==================================================");
227 static void __print_tether_connection_info(void)
229 STC_LOGI("============= tethering connection info ============");
230 STC_LOGI("mode [%u]", g_default_connection->tether_state ? TRUE : FALSE);
231 STC_LOGI("type [%d]", g_default_connection->tether_iface.type);
232 STC_LOGI("ifname [%s]", g_default_connection->tether_iface.ifname);
233 STC_LOGI("====================================================");
236 static gboolean __is_cellular_internet_profile(const char *profile)
238 const char internet_suffix[] = "_1";
243 if (g_str_has_prefix(profile, CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX)
245 char *suffix = strrchr(profile, '_');
246 if (g_strcmp0(suffix, internet_suffix) == 0)
253 static gboolean __is_cellular_profile(const char *profile)
258 return g_str_has_prefix(profile, //LCOV_EXCL_LINE
259 CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX);
262 static gboolean __is_wifi_profile(const char *profile)
267 return g_str_has_prefix(profile, //LCOV_EXCL_LINE
268 CONNMAN_WIFI_SERVICE_PROFILE_PREFIX);
271 static gboolean __is_ethernet_profile(const char *profile)
276 return g_str_has_prefix(profile, //LCOV_EXCL_LINE
277 CONNMAN_ETHERNET_SERVICE_PROFILE_PREFIX);
280 static gboolean __is_bluetooth_profile(const char *profile)
285 return g_str_has_prefix(profile, //LCOV_EXCL_LINE
286 CONNMAN_BLUETOOTH_SERVICE_PROFILE_PREFIX);
289 static gboolean __is_connected(GVariantIter *array)
291 gboolean is_connected = FALSE;
292 GVariant *variant = NULL;
295 while (g_variant_iter_loop(array, "{sv}", &key, &variant)) {
296 if (g_strcmp0(key, "State") != 0)
299 if (g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) {
300 const gchar *state = NULL;
302 state = g_variant_get_string(variant, NULL);
303 if (g_strcmp0(state, "ready") == 0 ||
304 g_strcmp0(state, "online") == 0)
309 g_variant_unref(variant);
316 static void __get_connection_info(GDBusConnection *connection,
317 stc_connection_s *conn, const char *object_path)
319 GVariant *message = NULL;
320 GVariantIter *iter = NULL;
321 GVariant *variant = NULL;
324 if (object_path == NULL) {
325 STC_LOGI("Object path is NULL, so information not available.");
329 message = stc_manager_gdbus_call_sync(connection,
332 CONNMAN_SERVICE_INTERFACE,
333 "GetProperties", NULL);
334 if (message == NULL) {
335 STC_LOGE("Failed to get services informations"); //LCOV_EXCL_LINE
336 goto done; //LCOV_EXCL_LINE
339 g_variant_get(message, "(a{sv})", &iter);
341 STC_LOGE("Profile %s doesn't exist", object_path); //LCOV_EXCL_LINE
342 goto done; //LCOV_EXCL_LINE
345 while (g_variant_iter_loop(iter, "{sv}", &key, &variant)) {
346 if (g_strcmp0(key, "Ethernet") == 0) {
347 GVariantIter *iter1 = NULL;
348 GVariant *variant1 = NULL;
351 g_variant_get(variant, "a{sv}", &iter1);
353 continue; //LCOV_EXCL_LINE
355 while (g_variant_iter_loop(iter1, "{sv}", &key1,
357 if (g_strcmp0(key1, "Interface") == 0) {
359 g_variant_get_string(variant1,
361 conn->ifname = g_strdup(value);
365 g_variant_iter_free(iter1);
367 } else if (g_strcmp0(key, "Roaming") == 0) {
368 gboolean roaming = 0;
370 if (g_variant_is_of_type(variant,
371 G_VARIANT_TYPE_BOOLEAN)) {
372 roaming = g_variant_get_boolean(variant);
373 conn->roaming = roaming;
380 g_variant_iter_free(iter);
383 g_variant_unref(message);
388 static stc_error_e __get_connected_profiles(GDBusConnection *connection)
390 GVariant *message = NULL;
391 GVariantIter *iter = NULL;
394 stc_connection_s *conn;
395 gboolean default_conn = TRUE;
397 message = stc_manager_gdbus_call_sync(connection,
399 CONNMAN_MANAGER_PATH,
400 CONNMAN_MANAGER_INTERFACE,
401 "GetServices", NULL);
402 if (message == NULL) {
403 STC_LOGE("Failed to get profiles"); //LCOV_EXCL_LINE
404 return STC_ERROR_FAIL; //LCOV_EXCL_LINE
407 g_slist_free_full(g_connection_list, __conn_list_free);
409 g_variant_get(message, "(a(oa{sv}))", &iter);
410 while (g_variant_iter_loop(iter, "(oa{sv})", &object_path, &next)) {
411 if (object_path == NULL)
412 continue; //LCOV_EXCL_LINE
414 if (__is_cellular_profile(object_path) &&
415 !__is_cellular_internet_profile(object_path))
418 if (__is_connected(next) == TRUE) {
419 conn = MALLOC0(stc_connection_s, 1);
423 conn->path = g_strdup(object_path);
424 conn->roaming = FALSE;
426 if (__is_cellular_profile(conn->path)) {
427 conn->type = STC_IFACE_DATACALL;
428 __telephony_update_default_modem_subscriber_id(connection, conn);
429 } else if (__is_wifi_profile(conn->path)) {
430 conn->type = STC_IFACE_WIFI;
431 } else if (__is_ethernet_profile(conn->path)) {
432 conn->type = STC_IFACE_WIRED;
433 } else if (__is_bluetooth_profile(conn->path)) {
434 conn->type = STC_IFACE_BLUETOOTH;
436 conn->type = STC_IFACE_UNKNOWN;
439 __get_connection_info(connection, conn, conn->path);
440 __print_connection_info(conn);
442 if (default_conn == TRUE) {
443 g_default_connection = conn;
444 default_conn = FALSE;
447 g_connection_list = g_slist_append(g_connection_list, conn);
450 g_variant_iter_free(next);
455 g_variant_iter_free(iter);
456 g_variant_unref(message);
458 g_slist_foreach(g_connection_list, __update_monitor_by_conn, NULL);
459 stc_plugin_firewall_update();
461 return STC_ERROR_NONE;
464 static stc_error_e __get_default_connection(GDBusConnection *connection)
466 GVariant *message = NULL;
467 GVariantIter *iter = NULL;
471 message = stc_manager_gdbus_call_sync(connection,
473 CONNMAN_MANAGER_PATH,
474 CONNMAN_MANAGER_INTERFACE,
475 "GetServices", NULL);
476 if (message == NULL) {
477 STC_LOGE("Failed to get profiles"); //LCOV_EXCL_LINE
478 return STC_ERROR_FAIL; //LCOV_EXCL_LINE
481 g_variant_get(message, "(a(oa{sv}))", &iter);
482 while (g_variant_iter_loop(iter, "(oa{sv})", &object_path, &next)) {
483 if (object_path == NULL)
484 continue; //LCOV_EXCL_LINE
486 if (__is_cellular_profile(object_path) &&
487 !__is_cellular_internet_profile(object_path))
490 if (__is_connected(next) == TRUE) {
491 GSList *comp = g_slist_find_custom(g_connection_list,
492 object_path, __conn_list_comp);
493 if (comp && comp->data)
494 g_default_connection = comp->data;
500 g_variant_iter_free(iter);
501 g_variant_unref(message);
503 return STC_ERROR_NONE;
506 static void __append_connected_profile(GDBusConnection *connection,
509 stc_connection_s *conn;
511 conn = MALLOC0(stc_connection_s, 1);
515 conn->path = g_strdup(path);
516 conn->roaming = FALSE;
518 if (__is_cellular_profile(conn->path)) {
519 conn->type = STC_IFACE_DATACALL;
520 __telephony_update_default_modem_subscriber_id(connection, conn);
521 } else if (__is_wifi_profile(conn->path)) {
522 conn->type = STC_IFACE_WIFI;
523 } else if (__is_ethernet_profile(conn->path)) {
524 conn->type = STC_IFACE_WIRED;
525 } else if (__is_bluetooth_profile(conn->path)) {
526 conn->type = STC_IFACE_BLUETOOTH;
528 conn->type = STC_IFACE_UNKNOWN;
531 __get_connection_info(connection, conn, conn->path);
532 __print_connection_info(conn);
534 g_connection_list = g_slist_append(g_connection_list, conn);
536 stc_monitor_add_by_connection(conn);
537 stc_plugin_firewall_update();
539 __get_default_connection(connection);
542 static void __remove_disconnected_profile(GDBusConnection *connection,
543 stc_connection_s *conn)
545 __print_connection_info(conn);
547 stc_monitor_remove_by_connection(conn);
549 g_connection_list = g_slist_remove(g_connection_list, conn);
551 __get_default_connection(connection);
555 FREE(conn->tether_iface.ifname);
559 static void __vconf_key_callback(keynode_t *node, void *user_data)
564 STC_LOGE("Invalid parameter");
568 if (g_default_connection == NULL)
571 if (vconf_keynode_get_type(node) != VCONF_TYPE_INT) {
572 STC_LOGE("Invalid vconf key type");
576 vconf_key = vconf_keynode_get_int(node);
578 /* Check the tethering type */
580 case VCONFKEY_MOBILE_HOTSPOT_MODE_USB:
581 STC_LOGI("Hotspot mode USB type !");
582 g_default_connection->tether_state = TRUE;
583 g_default_connection->tether_iface.ifname = g_strdup(TETHERING_USB_IF);
584 g_default_connection->tether_iface.type = STC_IFACE_USB;
586 case VCONFKEY_MOBILE_HOTSPOT_MODE_WIFI:
587 STC_LOGI("Hotspot mode Wi-Fi type !");
588 g_default_connection->tether_state = TRUE;
589 g_default_connection->tether_iface.ifname = g_strdup(TETHERING_WIFI_IF);
590 g_default_connection->tether_iface.type = STC_IFACE_WIFI;
592 case VCONFKEY_MOBILE_HOTSPOT_MODE_BT:
593 STC_LOGI("Hotspot mode Bluetooth type !");
594 g_default_connection->tether_state = TRUE;
595 g_default_connection->tether_iface.ifname = g_strdup(TETHERING_BT_IF);
596 g_default_connection->tether_iface.type = STC_IFACE_BLUETOOTH;
598 case VCONFKEY_MOBILE_HOTSPOT_MODE_P2P:
599 STC_LOGI("Hotspot mode P2P type !");
600 g_default_connection->tether_state = TRUE;
601 g_default_connection->tether_iface.ifname = g_strdup(TETHERING_P2P_IF);
602 g_default_connection->tether_iface.type = STC_IFACE_P2P;
604 case VCONFKEY_MOBILE_HOTSPOT_MODE_NONE:
605 STC_LOGI("Hotspot mode none");
606 g_default_connection->tether_state = FALSE;
609 STC_LOGE("Unknown Hotspot mode type !");
613 /* add monitoring for tethering if active found */
614 if (g_default_connection->tether_state == TRUE && g_default_connection->tether_iface.ifname) {
615 __print_tether_connection_info();
616 stc_monitor_update_by_connection(&g_default_connection);
617 stc_plugin_firewall_update();
618 STC_LOGI("Data monitoring started for tethering iface !");
622 /* remove monitoring for tethering if in-active found */
623 if (g_default_connection->tether_state == FALSE && g_default_connection->tether_iface.ifname) {
624 stc_monitor_update_by_connection(&g_default_connection);
625 g_free(g_default_connection->tether_iface.ifname);
626 g_default_connection->tether_iface.ifname = NULL;
627 g_default_connection->tether_iface.type = STC_IFACE_UNKNOWN;
628 STC_LOGI("Data monitoring stopped for tethering iface !");
633 static void _service_signal_cb(GDBusConnection *connection,
634 const gchar *name, const gchar *path,
635 const gchar *interface, const gchar *sig,
636 GVariant *param, gpointer user_data)
638 gchar *sigvalue = NULL;
639 GVariant *variant = NULL;
640 stc_s *stc = (stc_s *)stc_get_manager();
641 ret_msg_if(stc == NULL, "failed to get stc data");
643 if (path == NULL || param == NULL)
646 g_variant_get(param, "(sv)", &sigvalue, &variant);
647 if (sigvalue == NULL)
650 if (g_strcmp0(sig, CONNMAN_SIGNAL_PROPERTY_CHANGED) != 0)
653 if (g_strcmp0(sigvalue, "State") == 0 &&
654 g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) {
655 const gchar *state = NULL;
657 state = g_variant_get_string(variant, NULL);
658 if (g_strcmp0(state, "ready") == 0 ||
659 g_strcmp0(state, "online") == 0) {
660 GSList *comp = g_slist_find_custom(g_connection_list,
661 path, __conn_list_comp);
663 __append_connected_profile(stc->connection, path);
664 } else if (g_strcmp0(state, "idle") == 0 ||
665 g_strcmp0(state, "disconnect") == 0) {
666 GSList *comp = g_slist_find_custom(g_connection_list,
667 path, __conn_list_comp);
668 if (comp && comp->data)
669 __remove_disconnected_profile(stc->connection, comp->data);
671 } else if (g_strcmp0(sigvalue, "Roaming") == 0) {
673 GSList *comp = g_slist_find_custom(g_connection_list,
674 path, __conn_list_comp);
677 stc_connection_s *conn = comp->data;
678 gboolean roaming = 0;
680 if (g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN)) {
681 roaming = g_variant_get_boolean(variant);
682 conn->roaming = roaming;
694 g_variant_unref(variant);
699 stc_error_e stc_plugin_monitor_connection_init(stc_s *stc)
702 ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data");
704 __get_connected_profiles(stc->connection);
705 g_connection_sub_id =
706 stc_manager_gdbus_subscribe_signal(stc->connection,
708 CONNMAN_SERVICE_INTERFACE,
709 CONNMAN_SIGNAL_PROPERTY_CHANGED,
711 G_DBUS_SIGNAL_FLAGS_NONE,
715 ret = vconf_notify_key_changed(VCONFKEY_MOBILE_HOTSPOT_MODE, __vconf_key_callback, NULL);
717 STC_LOGE("vconf_notify_key_changed failed: %d", ret);
719 STC_LOGI("Successfully subscribed connman [%s] signal", CONNMAN_SIGNAL_PROPERTY_CHANGED);
720 return STC_ERROR_NONE;
723 stc_error_e stc_plugin_monitor_connection_deinit(stc_s *stc)
725 ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data");
727 stc_manager_gdbus_unsubscribe_signal(stc->connection,
728 g_connection_sub_id);
730 g_slist_free_full(g_connection_list, __conn_list_free);
732 return STC_ERROR_NONE;
735 GSList *stc_get_connection_list(void)
737 return g_connection_list;