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 <openssl/sha.h>
19 #include "stc-gdbus.h"
20 #include "stc-firewall.h"
21 #include "stc-plugin-firewall.h"
22 #include "stcplugin-monitor.h"
23 #include "stcplugin-monitor-connection.h"
25 /* connman service dbus details */
26 #define CONNMAN_SERVICE "net.connman"
27 #define CONNMAN_PATH "/net/connman"
29 #define CONNMAN_MANAGER_PATH "/"
30 #define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager"
31 #define CONNMAN_SERVICE_INTERFACE CONNMAN_SERVICE ".Service"
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_"
38 #define CONNMAN_SIGNAL_PROPERTY_CHANGED "PropertyChanged"
40 /* telephony service dbus details */
41 #define TELEPHONY_SERVICE "org.tizen.telephony"
42 #define TELEPHONY_DEFAULT_PATH "/org/tizen/telephony"
44 #define TELEPHONY_SERVICE_MANAGER TELEPHONY_SERVICE".Manager"
45 #define TELEPHONY_SIM_INTERFACE TELEPHONY_SERVICE".Sim"
47 #define TELEPHONY_GET_MODEMS "GetModems"
48 #define TELEPHONY_GET_IMSI "GetIMSI"
50 #define SIM_SLOT_SINGLE 1
52 #define VCONF_TELEPHONY_DEFAULT_DATA_SERVICE "db/telephony/dualsim/default_data_service"
54 static stc_connection_s *g_default_connection = NULL;
55 static GSList *g_connection_list = NULL;
56 static guint g_connection_sub_id = 0;
58 static void __conn_list_free(gpointer value)
60 stc_connection_s *conn = (stc_connection_s *)value;
64 FREE(conn->tether_iface.ifname);
68 static gint __conn_list_comp(gconstpointer a, gconstpointer b)
70 stc_connection_s *conn = (stc_connection_s *)a;
71 char *path = (char *)b;
73 if (g_strcmp0(conn->path, path) == 0)
79 static void __update_monitor_by_conn(gpointer data, gpointer user_data)
81 stc_connection_s *conn = (stc_connection_s *)data;
83 stc_monitor_update_by_connection(conn);
86 static int __telephony_get_current_sim(void)
88 int sim_slot_count = 0;
91 if (vconf_get_int(VCONFKEY_TELEPHONY_SIM_SLOT_COUNT, &sim_slot_count) != 0) {
92 STC_LOGD("failed to get sim slot count"); //LCOV_EXCL_LINE
93 return -1; //LCOV_EXCL_LINE
96 if (sim_slot_count == SIM_SLOT_SINGLE) {
97 STC_LOGD("It's single sim model"); //LCOV_EXCL_LINE
98 return current_sim; //LCOV_EXCL_LINE
101 if (vconf_get_int(VCONF_TELEPHONY_DEFAULT_DATA_SERVICE, ¤t_sim) != 0) {
102 STC_LOGD("failed to get default data service = %d\n", //LCOV_EXCL_LINE
104 return -1; //LCOV_EXCL_LINE
110 static void __make_imsi_to_subscriber_id(stc_connection_s *conn, char *imsi)
114 unsigned char md[SHA256_DIGEST_LENGTH];
117 SHA256_Update(&ctx, imsi, strlen(imsi));
118 SHA256_Final(md, &ctx);
120 for (i = 0; i < SHA256_DIGEST_LENGTH; ++i)
121 snprintf(conn->subscriber_id + (i * 2), 3, "%02x", md[i]);
124 static void __telephony_get_modem_subscriber_id(GDBusConnection *connection,
125 stc_connection_s *conn, const char *default_modem_name)
127 GVariant *message = NULL;
128 char tel_path[MAX_PATH_LENGTH];
129 char imsi[IMSI_LENGTH];
130 const char *plmn = NULL;
132 const char *msin = NULL;
135 snprintf(tel_path, sizeof(tel_path), "%s/%s", TELEPHONY_DEFAULT_PATH,
137 message = stc_manager_gdbus_call_sync(connection,
140 TELEPHONY_SIM_INTERFACE,
143 if (message == NULL) {
144 STC_LOGE("Failed to get services informations"); //LCOV_EXCL_LINE
145 goto done; //LCOV_EXCL_LINE
148 DEBUG_PARAMS(message);
149 DEBUG_PARAM_TYPE(message);
150 g_variant_get(message, "(&s&s)", &plmn, &msin);
152 plmn_len = strlen(plmn);
154 msin_len = strlen(msin);
156 if (msin_len + plmn_len >= IMSI_LENGTH) {
157 STC_LOGD("Incorrect length of mobile subscriber identifier + net id"); //LCOV_EXCL_LINE
158 goto done; //LCOV_EXCL_LINE
161 snprintf(imsi, IMSI_LENGTH, "%s%s", plmn, msin);
162 __make_imsi_to_subscriber_id(conn, imsi);
165 g_variant_unref(message);
169 static void __telephony_update_default_modem_subscriber_id(GDBusConnection *connection,
170 stc_connection_s *conn)
172 GVariant *message = NULL;
173 GVariantIter *iter = NULL;
174 gchar *default_modem_name = NULL;
175 gchar *modem_name = NULL;
176 int current_sim = __telephony_get_current_sim();
178 if (current_sim < 0) {
179 STC_LOGI("Sim not found"); //LCOV_EXCL_LINE
180 return; //LCOV_EXCL_LINE
183 message = stc_manager_gdbus_call_sync(connection,
185 TELEPHONY_DEFAULT_PATH,
186 TELEPHONY_SERVICE_MANAGER,
187 TELEPHONY_GET_MODEMS,
189 if (message == NULL) {
190 STC_LOGE("Failed to get services informations"); //LCOV_EXCL_LINE
191 return; //LCOV_EXCL_LINE
194 g_variant_get(message, "(as)", &iter);
195 DEBUG_PARAMS(message);
196 DEBUG_PARAM_TYPE(message);
197 while (g_variant_iter_loop(iter, "s", &modem_name)) {
198 if (current_sim == 0) {
199 default_modem_name = g_strdup(modem_name);
203 current_sim--; //LCOV_EXCL_LINE
206 __telephony_get_modem_subscriber_id(connection, conn, default_modem_name);
208 FREE(default_modem_name);
209 g_variant_iter_free(iter);
210 g_variant_unref(message);
214 static void __print_connection_info(stc_connection_s *conn, const char *state)
216 STC_LOGI("============= connection info ============");
217 STC_LOGI("path [%s]", conn->path);
218 STC_LOGI("type [%d]", conn->type);
219 STC_LOGI("ifname [%s]", conn->ifname);
220 STC_LOGI("roaming [%u]", conn->roaming ? TRUE : FALSE);
221 if (conn->type == STC_IFACE_DATACALL)
222 STC_LOGI("sub_id [%s]", conn->subscriber_id);
223 STC_LOGI("state [%s]", state);
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, "connected");
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);
451 g_variant_iter_free(iter);
452 g_variant_unref(message);
454 g_slist_foreach(g_connection_list, __update_monitor_by_conn, NULL);
455 stc_plugin_firewall_update();
457 return STC_ERROR_NONE;
460 static stc_error_e __get_default_connection(GDBusConnection *connection)
462 GVariant *message = NULL;
463 GVariantIter *iter = NULL;
467 message = stc_manager_gdbus_call_sync(connection,
469 CONNMAN_MANAGER_PATH,
470 CONNMAN_MANAGER_INTERFACE,
471 "GetServices", NULL);
472 if (message == NULL) {
473 STC_LOGE("Failed to get profiles"); //LCOV_EXCL_LINE
474 return STC_ERROR_FAIL; //LCOV_EXCL_LINE
477 g_variant_get(message, "(a(oa{sv}))", &iter);
478 while (g_variant_iter_loop(iter, "(oa{sv})", &object_path, &next)) {
479 if (object_path == NULL)
480 continue; //LCOV_EXCL_LINE
482 if (__is_cellular_profile(object_path) &&
483 !__is_cellular_internet_profile(object_path))
486 if (__is_connected(next) == TRUE) {
487 GSList *comp = g_slist_find_custom(g_connection_list,
488 object_path, __conn_list_comp);
489 if (comp && comp->data)
490 g_default_connection = comp->data;
493 g_variant_iter_free(next);
498 g_variant_iter_free(iter);
499 g_variant_unref(message);
501 return STC_ERROR_NONE;
504 static void __append_connected_profile(GDBusConnection *connection,
507 stc_connection_s *conn;
509 conn = MALLOC0(stc_connection_s, 1);
513 conn->path = g_strdup(path);
514 conn->roaming = FALSE;
516 if (__is_cellular_profile(conn->path)) {
517 conn->type = STC_IFACE_DATACALL;
518 __telephony_update_default_modem_subscriber_id(connection, conn);
519 } else if (__is_wifi_profile(conn->path)) {
520 conn->type = STC_IFACE_WIFI;
521 } else if (__is_ethernet_profile(conn->path)) {
522 conn->type = STC_IFACE_WIRED;
523 } else if (__is_bluetooth_profile(conn->path)) {
524 conn->type = STC_IFACE_BLUETOOTH;
526 conn->type = STC_IFACE_UNKNOWN;
529 __get_connection_info(connection, conn, conn->path);
530 __print_connection_info(conn, "connected");
532 g_connection_list = g_slist_append(g_connection_list, conn);
534 stc_monitor_add_by_connection(conn);
535 stc_plugin_firewall_update();
537 __get_default_connection(connection);
540 static void __remove_disconnected_profile(GDBusConnection *connection,
541 stc_connection_s *conn)
543 __print_connection_info(conn, "disconnected");
545 stc_monitor_remove_by_connection(conn);
547 g_connection_list = g_slist_remove(g_connection_list, conn);
549 __get_default_connection(connection);
553 FREE(conn->tether_iface.ifname);
557 static void __vconf_key_callback(keynode_t *node, void *user_data)
562 STC_LOGE("Invalid parameter");
566 if (g_default_connection == NULL)
569 if (vconf_keynode_get_type(node) != VCONF_TYPE_INT) {
570 STC_LOGE("Invalid vconf key type");
574 vconf_key = vconf_keynode_get_int(node);
576 /* Check the tethering type */
578 case VCONFKEY_MOBILE_HOTSPOT_MODE_USB:
579 STC_LOGI("Hotspot mode USB type !");
580 g_default_connection->tether_state = TRUE;
581 g_default_connection->tether_iface.ifname = g_strdup(TETHERING_USB_IF);
582 g_default_connection->tether_iface.type = STC_IFACE_USB;
584 case VCONFKEY_MOBILE_HOTSPOT_MODE_WIFI:
585 STC_LOGI("Hotspot mode Wi-Fi type !");
586 g_default_connection->tether_state = TRUE;
587 g_default_connection->tether_iface.ifname = g_strdup(TETHERING_WIFI_IF);
588 g_default_connection->tether_iface.type = STC_IFACE_WIFI;
590 case VCONFKEY_MOBILE_HOTSPOT_MODE_BT:
591 STC_LOGI("Hotspot mode Bluetooth type !");
592 g_default_connection->tether_state = TRUE;
593 g_default_connection->tether_iface.ifname = g_strdup(TETHERING_BT_IF);
594 g_default_connection->tether_iface.type = STC_IFACE_BLUETOOTH;
596 case VCONFKEY_MOBILE_HOTSPOT_MODE_P2P:
597 STC_LOGI("Hotspot mode P2P type !");
598 g_default_connection->tether_state = TRUE;
599 g_default_connection->tether_iface.ifname = g_strdup(TETHERING_P2P_IF);
600 g_default_connection->tether_iface.type = STC_IFACE_P2P;
602 case VCONFKEY_MOBILE_HOTSPOT_MODE_NONE:
603 STC_LOGI("Hotspot mode none");
604 g_default_connection->tether_state = FALSE;
607 STC_LOGE("Unknown Hotspot mode type !");
611 /* add monitoring for tethering if active found */
612 if (g_default_connection->tether_state == TRUE && g_default_connection->tether_iface.ifname) {
613 __print_tether_connection_info();
614 stc_monitor_update_by_connection(g_default_connection);
615 stc_plugin_firewall_update();
616 STC_LOGI("Data monitoring started for tethering iface !");
620 /* remove monitoring for tethering if in-active found */
621 if (g_default_connection->tether_state == FALSE && g_default_connection->tether_iface.ifname) {
622 stc_monitor_update_by_connection(g_default_connection);
623 g_free(g_default_connection->tether_iface.ifname);
624 g_default_connection->tether_iface.ifname = NULL;
625 g_default_connection->tether_iface.type = STC_IFACE_UNKNOWN;
626 STC_LOGI("Data monitoring stopped for tethering iface !");
631 static void _service_signal_cb(GDBusConnection *connection,
632 const gchar *name, const gchar *path,
633 const gchar *interface, const gchar *sig,
634 GVariant *param, gpointer user_data)
636 gchar *sigvalue = NULL;
637 GVariant *variant = NULL;
638 stc_s *stc = (stc_s *)stc_get_manager();
639 ret_msg_if(stc == NULL, "failed to get stc data");
641 if (path == NULL || param == NULL)
644 g_variant_get(param, "(sv)", &sigvalue, &variant);
645 if (sigvalue == NULL)
648 if (g_strcmp0(sig, CONNMAN_SIGNAL_PROPERTY_CHANGED) != 0)
651 if (g_strcmp0(sigvalue, "State") == 0 &&
652 g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) {
653 const gchar *state = NULL;
655 state = g_variant_get_string(variant, NULL);
656 if (g_strcmp0(state, "ready") == 0 ||
657 g_strcmp0(state, "online") == 0) {
658 GSList *comp = g_slist_find_custom(g_connection_list,
659 path, __conn_list_comp);
661 __append_connected_profile(stc->connection, path);
662 } else if (g_strcmp0(state, "idle") == 0 ||
663 g_strcmp0(state, "disconnect") == 0) {
664 GSList *comp = g_slist_find_custom(g_connection_list,
665 path, __conn_list_comp);
666 if (comp && comp->data)
667 __remove_disconnected_profile(stc->connection, comp->data);
669 } else if (g_strcmp0(sigvalue, "Roaming") == 0) {
671 GSList *comp = g_slist_find_custom(g_connection_list,
672 path, __conn_list_comp);
675 stc_connection_s *conn = comp->data;
676 gboolean roaming = 0;
678 if (g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN)) {
679 roaming = g_variant_get_boolean(variant);
680 conn->roaming = roaming;
692 g_variant_unref(variant);
697 stc_error_e stc_plugin_monitor_connection_init(stc_s *stc)
700 ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data");
702 __get_connected_profiles(stc->connection);
703 g_connection_sub_id =
704 stc_manager_gdbus_subscribe_signal(stc->connection,
706 CONNMAN_SERVICE_INTERFACE,
707 CONNMAN_SIGNAL_PROPERTY_CHANGED,
709 G_DBUS_SIGNAL_FLAGS_NONE,
713 ret = vconf_notify_key_changed(VCONFKEY_MOBILE_HOTSPOT_MODE, __vconf_key_callback, NULL);
715 STC_LOGE("vconf_notify_key_changed failed: %d", ret);
717 STC_LOGI("Successfully subscribed connman [%s] signal", CONNMAN_SIGNAL_PROPERTY_CHANGED);
718 return STC_ERROR_NONE;
721 stc_error_e stc_plugin_monitor_connection_deinit(stc_s *stc)
723 ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data");
725 stc_manager_gdbus_unsubscribe_signal(stc->connection,
726 g_connection_sub_id);
728 g_slist_free_full(g_connection_list, __conn_list_free);
730 return STC_ERROR_NONE;
733 GSList *stc_get_connection_list(void)
735 return g_connection_list;