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"
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 stc_connection_s *g_default_connection = NULL;
55 GSList *g_connection_list = NULL;
56 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)
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("==================================================");
226 static void __print_tether_connection_info(void)
228 STC_LOGI("============= tethering connection info ============");
229 STC_LOGI("mode [%u]", g_default_connection->tether_state ? TRUE : FALSE);
230 STC_LOGI("type [%d]", g_default_connection->tether_iface.type);
231 STC_LOGI("ifname [%s]", g_default_connection->tether_iface.ifname);
232 STC_LOGI("====================================================");
235 static gboolean __is_cellular_internet_profile(const char *profile)
237 const char internet_suffix[] = "_1";
242 if (g_str_has_prefix(profile, CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX)
244 char *suffix = strrchr(profile, '_');
245 if (g_strcmp0(suffix, internet_suffix) == 0)
252 static gboolean __is_cellular_profile(const char *profile)
257 return g_str_has_prefix(profile, //LCOV_EXCL_LINE
258 CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX);
261 static gboolean __is_wifi_profile(const char *profile)
266 return g_str_has_prefix(profile, //LCOV_EXCL_LINE
267 CONNMAN_WIFI_SERVICE_PROFILE_PREFIX);
270 static gboolean __is_ethernet_profile(const char *profile)
275 return g_str_has_prefix(profile, //LCOV_EXCL_LINE
276 CONNMAN_ETHERNET_SERVICE_PROFILE_PREFIX);
279 static gboolean __is_bluetooth_profile(const char *profile)
284 return g_str_has_prefix(profile, //LCOV_EXCL_LINE
285 CONNMAN_BLUETOOTH_SERVICE_PROFILE_PREFIX);
288 static gboolean __is_connected(GVariantIter *array)
290 gboolean is_connected = FALSE;
291 GVariant *variant = NULL;
294 while (g_variant_iter_loop(array, "{sv}", &key, &variant)) {
295 if (g_strcmp0(key, "State") != 0)
298 if (g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) {
299 const gchar *state = NULL;
301 state = g_variant_get_string(variant, NULL);
302 if (g_strcmp0(state, "ready") == 0 ||
303 g_strcmp0(state, "online") == 0)
308 g_variant_unref(variant);
315 static void __get_connection_info(GDBusConnection *connection,
316 stc_connection_s *conn, const char *object_path)
318 GVariant *message = NULL;
319 GVariantIter *iter = NULL;
320 GVariant *variant = NULL;
323 if (object_path == NULL) {
324 STC_LOGI("Object path is NULL, so information not available.");
328 message = stc_manager_gdbus_call_sync(connection,
331 CONNMAN_SERVICE_INTERFACE,
332 "GetProperties", NULL);
333 if (message == NULL) {
334 STC_LOGE("Failed to get services informations"); //LCOV_EXCL_LINE
335 goto done; //LCOV_EXCL_LINE
338 g_variant_get(message, "(a{sv})", &iter);
340 STC_LOGE("Profile %s doesn't exist", object_path); //LCOV_EXCL_LINE
341 goto done; //LCOV_EXCL_LINE
344 while (g_variant_iter_loop(iter, "{sv}", &key, &variant)) {
345 if (g_strcmp0(key, "Ethernet") == 0) {
346 GVariantIter *iter1 = NULL;
347 GVariant *variant1 = NULL;
350 g_variant_get(variant, "a{sv}", &iter1);
352 continue; //LCOV_EXCL_LINE
354 while (g_variant_iter_loop(iter1, "{sv}", &key1,
356 if (g_strcmp0(key1, "Interface") == 0) {
358 g_variant_get_string(variant1,
360 conn->ifname = g_strdup(value);
364 g_variant_iter_free(iter1);
366 } else if (g_strcmp0(key, "Roaming") == 0) {
367 gboolean roaming = 0;
369 if (g_variant_is_of_type(variant,
370 G_VARIANT_TYPE_BOOLEAN)) {
371 roaming = g_variant_get_boolean(variant);
372 conn->roaming = roaming;
379 g_variant_iter_free(iter);
382 g_variant_unref(message);
387 static stc_error_e __get_connected_profiles(GDBusConnection *connection)
389 GVariant *message = NULL;
390 GVariantIter *iter = NULL;
393 stc_connection_s *conn;
394 gboolean default_conn = TRUE;
396 message = stc_manager_gdbus_call_sync(connection,
398 CONNMAN_MANAGER_PATH,
399 CONNMAN_MANAGER_INTERFACE,
400 "GetServices", NULL);
401 if (message == NULL) {
402 STC_LOGE("Failed to get profiles"); //LCOV_EXCL_LINE
403 return STC_ERROR_FAIL; //LCOV_EXCL_LINE
406 g_slist_free_full(g_connection_list, __conn_list_free);
408 g_variant_get(message, "(a(oa{sv}))", &iter);
409 while (g_variant_iter_loop(iter, "(oa{sv})", &object_path, &next)) {
410 if (object_path == NULL)
411 continue; //LCOV_EXCL_LINE
413 if (__is_cellular_profile(object_path) &&
414 !__is_cellular_internet_profile(object_path))
417 if (__is_connected(next) == TRUE) {
418 conn = MALLOC0(stc_connection_s, 1);
422 conn->path = g_strdup(object_path);
423 conn->roaming = FALSE;
425 if (__is_cellular_profile(conn->path)) {
426 conn->type = STC_IFACE_DATACALL;
427 __telephony_update_default_modem_subscriber_id(connection, conn);
428 } else if (__is_wifi_profile(conn->path)) {
429 conn->type = STC_IFACE_WIFI;
430 } else if (__is_ethernet_profile(conn->path)) {
431 conn->type = STC_IFACE_WIRED;
432 } else if (__is_bluetooth_profile(conn->path)) {
433 conn->type = STC_IFACE_BLUETOOTH;
435 conn->type = STC_IFACE_UNKNOWN;
438 __get_connection_info(connection, conn, conn->path);
439 __print_connection_info(conn);
441 if (default_conn == TRUE) {
442 g_default_connection = conn;
443 default_conn = FALSE;
446 g_connection_list = g_slist_append(g_connection_list, conn);
449 g_variant_iter_free(next);
454 g_variant_iter_free(iter);
455 g_variant_unref(message);
457 g_slist_foreach(g_connection_list, __update_monitor_by_conn, NULL);
458 stc_firewall_update();
460 return STC_ERROR_NONE;
463 static stc_error_e __get_default_connection(GDBusConnection *connection)
465 GVariant *message = NULL;
466 GVariantIter *iter = NULL;
470 message = stc_manager_gdbus_call_sync(connection,
472 CONNMAN_MANAGER_PATH,
473 CONNMAN_MANAGER_INTERFACE,
474 "GetServices", NULL);
475 if (message == NULL) {
476 STC_LOGE("Failed to get profiles"); //LCOV_EXCL_LINE
477 return STC_ERROR_FAIL; //LCOV_EXCL_LINE
480 g_variant_get(message, "(a(oa{sv}))", &iter);
481 while (g_variant_iter_loop(iter, "(oa{sv})", &object_path, &next)) {
482 if (object_path == NULL)
483 continue; //LCOV_EXCL_LINE
485 if (__is_cellular_profile(object_path) &&
486 !__is_cellular_internet_profile(object_path))
489 if (__is_connected(next) == TRUE) {
490 GSList *comp = g_slist_find_custom(g_connection_list,
491 object_path, __conn_list_comp);
492 if (comp && comp->data)
493 g_default_connection = comp->data;
499 g_variant_iter_free(iter);
500 g_variant_unref(message);
502 return STC_ERROR_NONE;
505 static void __append_connected_profile(GDBusConnection *connection,
508 stc_connection_s *conn;
510 conn = MALLOC0(stc_connection_s, 1);
514 conn->path = g_strdup(path);
515 conn->roaming = FALSE;
517 if (__is_cellular_profile(conn->path)) {
518 conn->type = STC_IFACE_DATACALL;
519 __telephony_update_default_modem_subscriber_id(connection, conn);
520 } else if (__is_wifi_profile(conn->path)) {
521 conn->type = STC_IFACE_WIFI;
522 } else if (__is_ethernet_profile(conn->path)) {
523 conn->type = STC_IFACE_WIRED;
524 } else if (__is_bluetooth_profile(conn->path)) {
525 conn->type = STC_IFACE_BLUETOOTH;
527 conn->type = STC_IFACE_UNKNOWN;
530 __get_connection_info(connection, conn, conn->path);
531 __print_connection_info(conn);
533 g_connection_list = g_slist_append(g_connection_list, conn);
535 stc_monitor_add_by_connection(conn);
536 stc_firewall_update();
538 __get_default_connection(connection);
541 static void __remove_disconnected_profile(GDBusConnection *connection,
542 stc_connection_s *conn)
544 __print_connection_info(conn);
546 stc_monitor_remove_by_connection(conn);
548 g_connection_list = g_slist_remove(g_connection_list, conn);
550 __get_default_connection(connection);
554 FREE(conn->tether_iface.ifname);
558 static void __vconf_key_callback(keynode_t *node, void *user_data)
563 STC_LOGE("Invalid parameter");
567 if (g_default_connection == NULL)
570 if (vconf_keynode_get_type(node) != VCONF_TYPE_INT) {
571 STC_LOGE("Invalid vconf key type");
575 vconf_key = vconf_keynode_get_int(node);
577 /* Check the tethering type */
579 case VCONFKEY_MOBILE_HOTSPOT_MODE_USB:
580 STC_LOGI("Hotspot mode USB type !");
581 g_default_connection->tether_state = TRUE;
582 g_default_connection->tether_iface.ifname = g_strdup(TETHERING_USB_IF);
583 g_default_connection->tether_iface.type = STC_IFACE_USB;
585 case VCONFKEY_MOBILE_HOTSPOT_MODE_WIFI:
586 STC_LOGI("Hotspot mode Wi-Fi type !");
587 g_default_connection->tether_state = TRUE;
588 g_default_connection->tether_iface.ifname = g_strdup(TETHERING_WIFI_IF);
589 g_default_connection->tether_iface.type = STC_IFACE_WIFI;
591 case VCONFKEY_MOBILE_HOTSPOT_MODE_BT:
592 STC_LOGI("Hotspot mode Bluetooth type !");
593 g_default_connection->tether_state = TRUE;
594 g_default_connection->tether_iface.ifname = g_strdup(TETHERING_BT_IF);
595 g_default_connection->tether_iface.type = STC_IFACE_BLUETOOTH;
597 case VCONFKEY_MOBILE_HOTSPOT_MODE_P2P:
598 STC_LOGI("Hotspot mode P2P type !");
599 g_default_connection->tether_state = TRUE;
600 g_default_connection->tether_iface.ifname = g_strdup(TETHERING_P2P_IF);
601 g_default_connection->tether_iface.type = STC_IFACE_P2P;
603 case VCONFKEY_MOBILE_HOTSPOT_MODE_NONE:
604 STC_LOGI("Hotspot mode none");
605 g_default_connection->tether_state = FALSE;
608 STC_LOGE("Unknown Hotspot mode type !");
612 /* add monitoring for tethering if active found */
613 if (g_default_connection->tether_state == TRUE && g_default_connection->tether_iface.ifname) {
614 __print_tether_connection_info();
615 stc_monitor_update_by_connection(&g_default_connection);
616 stc_firewall_update();
617 STC_LOGI("Data monitoring started for tethering iface !");
621 /* remove monitoring for tethering if in-active found */
622 if (g_default_connection->tether_state == FALSE && g_default_connection->tether_iface.ifname) {
623 stc_monitor_update_by_connection(&g_default_connection);
624 g_free(g_default_connection->tether_iface.ifname);
625 g_default_connection->tether_iface.ifname = NULL;
626 g_default_connection->tether_iface.type = STC_IFACE_UNKNOWN;
627 STC_LOGI("Data monitoring stopped for tethering iface !");
632 static void _service_signal_cb(GDBusConnection *connection,
633 const gchar *name, const gchar *path,
634 const gchar *interface, const gchar *sig,
635 GVariant *param, gpointer user_data)
637 gchar *sigvalue = NULL;
638 GVariant *variant = NULL;
639 stc_s *stc = (stc_s *)stc_get_manager();
640 ret_msg_if(stc == NULL, "failed to get stc data");
642 if (path == NULL || param == NULL)
645 g_variant_get(param, "(sv)", &sigvalue, &variant);
646 if (sigvalue == NULL)
649 if (g_strcmp0(sig, CONNMAN_SIGNAL_PROPERTY_CHANGED) != 0)
652 if (g_strcmp0(sigvalue, "State") == 0 &&
653 g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) {
654 const gchar *state = NULL;
656 state = g_variant_get_string(variant, NULL);
657 if (g_strcmp0(state, "ready") == 0 ||
658 g_strcmp0(state, "online") == 0) {
659 GSList *comp = g_slist_find_custom(g_connection_list,
660 path, __conn_list_comp);
662 __append_connected_profile(stc->connection, path);
663 } else if (g_strcmp0(state, "idle") == 0 ||
664 g_strcmp0(state, "disconnect") == 0) {
665 GSList *comp = g_slist_find_custom(g_connection_list,
666 path, __conn_list_comp);
667 if (comp && comp->data)
668 __remove_disconnected_profile(stc->connection, comp->data);
670 } else if (g_strcmp0(sigvalue, "Roaming") == 0) {
672 GSList *comp = g_slist_find_custom(g_connection_list,
673 path, __conn_list_comp);
676 stc_connection_s *conn = comp->data;
677 gboolean roaming = 0;
679 if (g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN)) {
680 roaming = g_variant_get_boolean(variant);
681 conn->roaming = roaming;
693 g_variant_unref(variant);
698 stc_error_e stc_plugin_monitor_connection_init(stc_s *stc)
701 ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data");
703 __get_connected_profiles(stc->connection);
704 g_connection_sub_id =
705 stc_manager_gdbus_subscribe_signal(stc->connection,
707 CONNMAN_SERVICE_INTERFACE,
708 CONNMAN_SIGNAL_PROPERTY_CHANGED,
710 G_DBUS_SIGNAL_FLAGS_NONE,
714 ret = vconf_notify_key_changed(VCONFKEY_MOBILE_HOTSPOT_MODE, __vconf_key_callback, NULL);
716 STC_LOGE("vconf_notify_key_changed failed: %d", ret);
718 STC_LOGI("Successfully subscribed connman [%s] signal", CONNMAN_SIGNAL_PROPERTY_CHANGED);
719 return STC_ERROR_NONE;
722 stc_error_e stc_plugin_monitor_connection_deinit(stc_s *stc)
724 ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data");
726 stc_manager_gdbus_unsubscribe_signal(stc->connection,
727 g_connection_sub_id);
729 g_slist_free_full(g_connection_list, __conn_list_free);
731 return STC_ERROR_NONE;
734 GSList *stc_get_connection_list(void)
736 return g_connection_list;