Fixed some svaces
[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-manager-gdbus.h"
22 #include "stc-default-connection.h"
23
24 /* connman service dbus details */
25 #define CONNMAN_SERVICE                          "net.connman"
26 #define CONNMAN_PATH                             "/net/connman"
27
28 #define CONNMAN_MANAGER_PATH                     "/"
29 #define CONNMAN_MANAGER_INTERFACE                CONNMAN_SERVICE ".Manager"
30 #define CONNMAN_SERVICE_INTERFACE                CONNMAN_SERVICE ".Service"
31
32 #define CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX  CONNMAN_PATH "/service/cellular_"
33 #define CONNMAN_WIFI_SERVICE_PROFILE_PREFIX      CONNMAN_PATH "/service/wifi_"
34 #define CONNMAN_ETHERNET_SERVICE_PROFILE_PREFIX  CONNMAN_PATH "/service/ethernet_"
35 #define CONNMAN_BLUETOOTH_SERVICE_PROFILE_PREFIX CONNMAN_PATH "/service/bluetooth_"
36
37 #define CONNMAN_SIGNAL_PROPERTY_CHANGED          "PropertyChanged"
38
39 /* telephony service dbus details */
40 #define TELEPHONY_SERVICE                        "org.tizen.telephony"
41 #define TELEPHONY_DEFAULT_PATH                   "/org/tizen/telephony"
42
43 #define TELEPHONY_SERVICE_MANAGER                TELEPHONY_SERVICE".Manager"
44 #define TELEPHONY_SIM_INTERFACE                  TELEPHONY_SERVICE".Sim"
45
46 #define TELEPHONY_GET_MODEMS                     "GetModems"
47 #define TELEPHONY_GET_IMSI                       "GetIMSI"
48
49 #define SIM_SLOT_SINGLE 1
50
51 #define VCONF_TELEPHONY_DEFAULT_DATA_SERVICE     "db/telephony/dualsim/default_data_service"
52
53 default_connection_s g_default_connection;
54 guint g_default_connection_sub_id = 0;
55
56 static int __telephony_get_current_sim(void)
57 {
58         int sim_slot_count = 0;
59         int current_sim = 0;
60
61         if (vconf_get_int(VCONFKEY_TELEPHONY_SIM_SLOT_COUNT, &sim_slot_count) != 0) {
62                 STC_LOGD("failed to get sim slot count"); //LCOV_EXCL_LINE
63                 return -1; //LCOV_EXCL_LINE
64         }
65
66         if (sim_slot_count == SIM_SLOT_SINGLE) {
67                STC_LOGD("It's single sim model"); //LCOV_EXCL_LINE
68                return current_sim; //LCOV_EXCL_LINE
69         }
70
71         if (vconf_get_int(VCONF_TELEPHONY_DEFAULT_DATA_SERVICE, &current_sim) != 0) {
72                 STC_LOGD("failed to get default data service = %d\n", //LCOV_EXCL_LINE
73                          current_sim);
74                 return -1; //LCOV_EXCL_LINE
75         }
76
77         return current_sim;
78 }
79
80 static void __make_imsi_to_subscriber_id(char *imsi)
81 {
82         int i = 0;
83         SHA256_CTX ctx;
84         unsigned char md[SHA256_DIGEST_LENGTH];
85
86         SHA256_Init(&ctx);
87         SHA256_Update(&ctx, imsi, strlen(imsi));
88         SHA256_Final(md, &ctx);
89
90         for (i = 0; i < SHA256_DIGEST_LENGTH; ++i)
91                 snprintf(g_default_connection.subscriber_id + (i * 2), 3, "%02x", md[i]);
92 }
93
94 static void __telephony_get_modem_subscriber_id(GDBusConnection *connection,
95                                        const char *default_modem_name)
96 {
97         GVariant *message = NULL;
98         char tel_path[MAX_PATH_LENGTH];
99         char imsi[IMSI_LENGTH];
100         const char *plmn = NULL;
101         int plmn_len = 0;
102         const char *msin = NULL;
103         int msin_len = 0;
104
105         snprintf(tel_path, sizeof(tel_path), "%s/%s", TELEPHONY_DEFAULT_PATH,
106                  default_modem_name);
107         message = stc_manager_gdbus_call_sync(connection,
108                                               TELEPHONY_SERVICE,
109                                               tel_path,
110                                               TELEPHONY_SIM_INTERFACE,
111                                               TELEPHONY_GET_IMSI,
112                                               NULL);
113         if (message == NULL) {
114                 STC_LOGE("Failed to get services informations"); //LCOV_EXCL_LINE
115                 goto done; //LCOV_EXCL_LINE
116         }
117
118         DEBUG_PARAMS(message);
119         DEBUG_PARAM_TYPE(message);
120         g_variant_get(message, "(&s&s)", &plmn, &msin);
121         if (plmn)
122                 plmn_len = strlen(plmn);
123         if (msin)
124                 msin_len = strlen(msin);
125
126         if (msin_len + plmn_len >= IMSI_LENGTH) {
127                 STC_LOGD("Incorrect length of mobile subscriber identifier + net id"); //LCOV_EXCL_LINE
128                 goto done; //LCOV_EXCL_LINE
129         }
130
131         snprintf(imsi, IMSI_LENGTH, "%s%s", plmn, msin);
132         __make_imsi_to_subscriber_id(imsi);
133
134 done:
135         g_variant_unref(message);
136         return;
137 }
138
139 static void __telephony_update_default_modem_subscriber_id(GDBusConnection *connection)
140 {
141         GVariant *message = NULL;
142         GVariantIter *iter = NULL;
143         gchar *default_modem_name = NULL;
144         gchar *modem_name = NULL;
145         int current_sim = __telephony_get_current_sim();
146
147         if (current_sim < 0) {
148                 STC_LOGI("Sim not found"); //LCOV_EXCL_LINE
149                 return; //LCOV_EXCL_LINE
150         }
151
152         message = stc_manager_gdbus_call_sync(connection,
153                                               TELEPHONY_SERVICE,
154                                               TELEPHONY_DEFAULT_PATH,
155                                               TELEPHONY_SERVICE_MANAGER,
156                                               TELEPHONY_GET_MODEMS,
157                                               NULL);
158         if (message == NULL) {
159                 STC_LOGE("Failed to get services informations"); //LCOV_EXCL_LINE
160                 return; //LCOV_EXCL_LINE
161         }
162
163         g_variant_get(message, "(as)", &iter);
164         DEBUG_PARAMS(message);
165         DEBUG_PARAM_TYPE(message);
166         while (g_variant_iter_loop(iter, "s", &modem_name)) {
167                 if (current_sim == 0) {
168                         default_modem_name = g_strdup(modem_name);
169                         FREE(modem_name);
170                         break;
171                 }
172                 current_sim--; //LCOV_EXCL_LINE
173         }
174
175         __telephony_get_modem_subscriber_id(connection, default_modem_name);
176
177         FREE(default_modem_name);
178         g_variant_iter_free(iter);
179         g_variant_unref(message);
180         return;
181 }
182
183 static void __print_default_connection_info(void)
184 {
185         STC_LOGI("============= default connection info ============");
186         STC_LOGI("path    [%s]", g_default_connection.path);
187         STC_LOGI("type    [%d]", g_default_connection.type);
188         STC_LOGI("ifname  [%s]", g_default_connection.ifname);
189         STC_LOGI("roaming [%u]", g_default_connection.roaming ? TRUE : FALSE);
190         if (g_default_connection.type == STC_IFACE_DATACALL)
191                 STC_LOGI("sub_id  [%s]", g_default_connection.subscriber_id);
192         STC_LOGI("==================================================");
193 }
194
195 static void __reset_default_connection_data(void)
196 {
197         FREE(g_default_connection.path);
198         FREE(g_default_connection.ifname);
199         g_default_connection.type = STC_IFACE_UNKNOWN;
200         g_default_connection.roaming = FALSE;
201 }
202
203 static gboolean __is_cellular_internet_profile(const char *profile)
204 {
205         const char internet_suffix[] = "_1";
206
207         if (profile == NULL)
208                 return FALSE;
209
210         if (g_str_has_prefix(profile, CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX)
211             == TRUE) {
212                 char *suffix = strrchr(profile, '_');
213                 if (g_strcmp0(suffix, internet_suffix) == 0)
214                         return TRUE;
215         }
216
217         return FALSE;
218 }
219
220 static gboolean __is_cellular_profile(const char *profile)
221 {
222         if (profile == NULL)
223                 return FALSE;
224
225         return g_str_has_prefix(profile, //LCOV_EXCL_LINE
226                                 CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX);
227 }
228
229 static gboolean __is_wifi_profile(const char *profile)
230 {
231         if (profile == NULL)
232                 return FALSE;
233
234         return g_str_has_prefix(profile, //LCOV_EXCL_LINE
235                                 CONNMAN_WIFI_SERVICE_PROFILE_PREFIX);
236 }
237
238 static gboolean __is_ethernet_profile(const char *profile)
239 {
240         if (profile == NULL)
241                 return FALSE;
242
243         return g_str_has_prefix(profile, //LCOV_EXCL_LINE
244                                 CONNMAN_ETHERNET_SERVICE_PROFILE_PREFIX);
245 }
246
247 static gboolean __is_bluetooth_profile(const char *profile)
248 {
249         if (profile == NULL)
250                 return FALSE;
251
252         return g_str_has_prefix(profile, //LCOV_EXCL_LINE
253                                 CONNMAN_BLUETOOTH_SERVICE_PROFILE_PREFIX);
254 }
255
256 static gboolean __is_connected(GVariantIter *array)
257 {
258         gboolean is_connected = FALSE;
259         GVariant *variant = NULL;
260         gchar *key = NULL;
261
262         while (g_variant_iter_loop(array, "{sv}", &key, &variant)) {
263                 if (g_strcmp0(key, "State") != 0)
264                         continue;
265
266                 if (g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) {
267                         const gchar *state = NULL;
268
269                         state = g_variant_get_string(variant, NULL);
270                         if (g_strcmp0(state, "ready") == 0 ||
271                             g_strcmp0(state, "online") == 0)
272                                 is_connected = TRUE;
273                 }
274
275                 g_free(key);
276                 g_variant_unref(variant);
277                 break;
278         }
279
280         return is_connected;
281 }
282
283 static void __get_default_connection_info(GDBusConnection *connection,
284                                           const char *object_path)
285 {
286         GVariant *message = NULL;
287         GVariantIter *iter = NULL;
288         GVariant *variant = NULL;
289         gchar *key = NULL;
290
291         if (object_path == NULL) {
292                 STC_LOGI("Object path is NULL, so information not available.");
293                 return;
294         }
295
296         message = stc_manager_gdbus_call_sync(connection,
297                                               CONNMAN_SERVICE,
298                                               object_path,
299                                               CONNMAN_SERVICE_INTERFACE,
300                                               "GetProperties", NULL);
301         if (message == NULL) {
302                 STC_LOGE("Failed to get services informations"); //LCOV_EXCL_LINE
303                 goto done; //LCOV_EXCL_LINE
304         }
305
306         g_variant_get(message, "(a{sv})", &iter);
307         if (iter == NULL) {
308                 STC_LOGE("Profile %s doesn't exist", object_path); //LCOV_EXCL_LINE
309                 goto done; //LCOV_EXCL_LINE
310         }
311
312         while (g_variant_iter_loop(iter, "{sv}", &key, &variant)) {
313                 if (g_strcmp0(key, "Ethernet") == 0) {
314                         GVariantIter *iter1 = NULL;
315                         GVariant *variant1 = NULL;
316                         gchar *key1 = NULL;
317
318                         g_variant_get(variant, "a{sv}", &iter1);
319                         if (iter1 == NULL)
320                                 continue; //LCOV_EXCL_LINE
321
322                         while (g_variant_iter_loop(iter1, "{sv}", &key1,
323                                                    &variant1)) {
324                                 if (g_strcmp0(key1, "Interface") == 0) {
325                                         const gchar *value =
326                                                 g_variant_get_string(variant1,
327                                                                      NULL);
328                                         g_default_connection.ifname =
329                                                 g_strdup(value);
330                                 }
331                         }
332
333                         g_variant_iter_free(iter1);
334
335                 } else if (g_strcmp0(key, "Roaming") == 0) {
336                         gboolean roaming = 0;
337
338                         if (g_variant_is_of_type(variant,
339                                                  G_VARIANT_TYPE_BOOLEAN)) {
340                                 roaming = g_variant_get_boolean(variant);
341                                 g_default_connection.roaming = roaming;
342                         }
343                 }
344         }
345
346 done:
347         if (iter)
348                 g_variant_iter_free(iter);
349
350         if (message)
351                 g_variant_unref(message);
352
353         return;
354 }
355
356 static stc_error_e __get_default_profile(GDBusConnection *connection)
357 {
358         GVariant *message = NULL;
359         GVariantIter *iter = NULL;
360         GVariantIter *next;
361         gchar *object_path;
362
363         message = stc_manager_gdbus_call_sync(connection,
364                                               CONNMAN_SERVICE,
365                                               CONNMAN_MANAGER_PATH,
366                                               CONNMAN_MANAGER_INTERFACE,
367                                               "GetServices", NULL);
368         if (message == NULL) {
369                 STC_LOGE("Failed to get profiles"); //LCOV_EXCL_LINE
370                 return STC_ERROR_FAIL; //LCOV_EXCL_LINE
371         }
372
373         g_variant_get(message, "(a(oa{sv}))", &iter);
374         while (g_variant_iter_loop(iter, "(oa{sv})", &object_path, &next)) {
375                 if (object_path == NULL)
376                         continue; //LCOV_EXCL_LINE
377
378                 if (__is_cellular_profile(object_path) &&
379                     !__is_cellular_internet_profile(object_path))
380                         continue;
381
382                 if (__is_connected(next) == TRUE) {
383                         /* reset old default connection data */
384                         FREE(g_default_connection.path);
385                         FREE(g_default_connection.ifname);
386                         g_default_connection.type = STC_IFACE_UNKNOWN;
387                         g_default_connection.roaming = FALSE;
388
389                         g_default_connection.path = g_strdup(object_path);
390                         g_free(object_path);
391                         g_variant_iter_free(next);
392                         break;
393                 }
394         }
395
396         g_variant_iter_free(iter);
397         g_variant_unref(message);
398
399         if (__is_cellular_profile(g_default_connection.path)) {
400                 g_default_connection.type = STC_IFACE_DATACALL; //LCOV_EXCL_LINE
401                 __telephony_update_default_modem_subscriber_id(connection); //LCOV_EXCL_LINE
402         } else if (__is_wifi_profile(g_default_connection.path)) {
403                 g_default_connection.type = STC_IFACE_WIFI; //LCOV_EXCL_LINE
404         } else if (__is_ethernet_profile(g_default_connection.path)) {
405                 g_default_connection.type = STC_IFACE_WIRED; //LCOV_EXCL_LINE
406         } else if (__is_bluetooth_profile(g_default_connection.path)) {
407                 g_default_connection.type = STC_IFACE_BLUETOOTH; //LCOV_EXCL_LINE
408         } else {
409                 g_default_connection.type = STC_IFACE_UNKNOWN; //LCOV_EXCL_LINE
410         }
411
412         __get_default_connection_info(connection, g_default_connection.path);
413
414         __print_default_connection_info();
415
416         stc_monitor_update_rstn_by_default_connection(&g_default_connection);
417
418         return STC_ERROR_NONE;
419 }
420
421 static void _service_signal_cb(GDBusConnection *conn,
422                                const gchar *name, const gchar *path,
423                                const gchar *interface, const gchar *sig,
424                                GVariant *param, gpointer user_data)
425 {
426         gchar *sigvalue = NULL;
427         GVariant *variant = NULL;
428         stc_s *stc = (stc_s *)stc_get_manager();
429         ret_msg_if(stc == NULL, "failed to get stc data");
430
431         if (path == NULL || param == NULL)
432                 goto done;
433
434         g_variant_get(param, "(sv)", &sigvalue, &variant);
435         if (sigvalue == NULL)
436                 goto done;
437
438         if (g_strcmp0(sig, CONNMAN_SIGNAL_PROPERTY_CHANGED) != 0)
439                 goto done;
440
441         if (g_strcmp0(sigvalue, "State") == 0 &&
442             g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) {
443                 const gchar *state = NULL;
444
445                 state = g_variant_get_string(variant, NULL);
446                 if (g_strcmp0(state, "ready") == 0 ||
447                     g_strcmp0(state, "online") == 0) {
448                         if (g_strcmp0(g_default_connection.path, path)) {
449                                 __reset_default_connection_data();
450                                 __get_default_profile(stc->connection);
451                         }
452                 } else {
453                         if (g_strcmp0(g_default_connection.path, path) == 0) {
454                                 __reset_default_connection_data(); //LCOV_EXCL_LINE
455                                 __get_default_profile(stc->connection); //LCOV_EXCL_LINE
456                         }
457                 }
458         } else if (g_strcmp0(sigvalue, "Roaming") == 0) {
459                 //LCOV_EXCL_START
460                 if (g_strcmp0(g_default_connection.path, path) == 0) {
461                         gboolean roaming = 0;
462
463                         if (g_variant_is_of_type(variant,
464                                                  G_VARIANT_TYPE_BOOLEAN)) {
465                                 roaming = g_variant_get_boolean(variant);
466                                 g_default_connection.roaming = roaming;
467                         }
468                 }
469                 //LCOV_EXCL_STOP
470         } else {
471                 ;//Do nothing
472         }
473 done:
474         if (sigvalue)
475                 g_free(sigvalue);
476
477         if (variant)
478                 g_variant_unref(variant);
479
480         return;
481 }
482
483 stc_error_e stc_default_connection_monitor_init(stc_s *stc)
484 {
485         ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data");
486
487         __get_default_profile(stc->connection);
488         g_default_connection_sub_id =
489                 stc_manager_gdbus_subscribe_signal(stc->connection,
490                                                    CONNMAN_SERVICE,
491                                                    CONNMAN_SERVICE_INTERFACE,
492                                                    CONNMAN_SIGNAL_PROPERTY_CHANGED,
493                                                    NULL, NULL,
494                                                    G_DBUS_SIGNAL_FLAGS_NONE,
495                                                    _service_signal_cb,
496                                                    NULL, NULL);
497
498         STC_LOGI("Successfully subscribed connman [%s] signal", CONNMAN_SIGNAL_PROPERTY_CHANGED);
499         return STC_ERROR_NONE;
500 }
501
502 stc_error_e stc_default_connection_monitor_deinit(stc_s *stc)
503 {
504         ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data");
505
506         stc_manager_gdbus_unsubscribe_signal(stc->connection,
507                                              g_default_connection_sub_id);
508         FREE(g_default_connection.path);
509         FREE(g_default_connection.ifname);
510         return STC_ERROR_NONE;
511 }
512
513 gchar *stc_default_connection_get_ifname(void)
514 {
515         return g_strdup(g_default_connection.ifname);
516 }
517
518 default_connection_s *stc_get_default_connection(void)
519 {
520         return &g_default_connection;
521 }