5270aed9d2dc5d5bf00e16c29c487a24696b7ab2
[platform/core/connectivity/stc-manager.git] / plugin / tether / stc-plugin-tether.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 <stdbool.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <glib.h>
25
26 #include "stc-monitor.h"
27 #include "stc-plugin-tether.h"
28
29 static GSList *station_list = NULL;
30 static GDBusConnection *connection = NULL;
31 static GCancellable *cancellable = NULL;
32 static int g_mobileap_signal_sub_id = 0;
33
34 static stc_error_e add_station_monitor(gchar *pkg_id, gchar *app_id,
35                          const char *mac)
36 {
37         int ret;
38         stc_app_value_s app_value;
39
40         if (pkg_id == NULL || app_id == NULL || mac == NULL) {
41                 STC_LOGE("invalid station station info");
42                 return STC_ERROR_INVALID_PARAMETER;
43         }
44
45         memset(&app_value, 0, sizeof(stc_app_value_s));
46         app_value.pkg_id = g_strdup(pkg_id);
47         app_value.app_id = g_strconcat(app_id, STC_TETHERING_APP_SUFFIX, NULL);
48         app_value.type = STC_APP_TYPE_TETHERING;
49         app_value.processes = NULL;
50         g_strlcpy(app_value.mac, mac, STATION_MAC_STR_LEN);
51
52         ret = stc_monitor_app_add(STC_UNKNOWN_CLASSID, app_id, pkg_id, app_value);
53         FREE(app_value.pkg_id);
54         FREE(app_value.app_id);
55         return ret;
56 }
57
58 static stc_error_e remove_station_monitor(gchar *pkg_id, gchar *app_id)
59 {
60         int ret;
61         char *sta_app_id;
62
63         if (pkg_id == NULL || app_id == NULL) {
64                 STC_LOGE("invalid station station info");
65                 return STC_ERROR_INVALID_PARAMETER;
66         }
67
68         sta_app_id = g_strconcat(app_id, STC_TETHERING_APP_SUFFIX, NULL);
69
70         ret = stc_monitor_app_remove(STC_UNKNOWN_CLASSID, sta_app_id);
71
72         FREE(sta_app_id);
73         return ret;
74 }
75
76 static int _compare_sta_by_mac_func(gconstpointer a,
77                 gconstpointer b)
78 {
79         tether_sta_info_s *si = (tether_sta_info_s *)a;
80         return g_ascii_strcasecmp(si->mac, (const char *)b);
81 }
82
83 static int _compare_sta_by_classid_func(gconstpointer a,
84                 gconstpointer b)
85 {
86         tether_sta_info_s *si = (tether_sta_info_s *)a;
87         int *classid = (int *)b;
88         return si->classid - *classid;
89 }
90
91 static int _get_station_info(gconstpointer data, GCompareFunc func,
92                 tether_sta_info_s **si)
93 {
94         GSList *list = station_list;
95         tether_sta_info_s *info = NULL;
96
97         if (func == NULL || si == NULL)
98                 return -1;
99
100         if (!list)
101                 return -1;
102
103         list = g_slist_find_custom(list, data, func);
104         if (list == NULL)
105                 return -1;
106
107         info = list->data;
108         *si = info;
109         return 0;
110 }
111
112 static void _remove_station_info(gconstpointer data, GCompareFunc func)
113 {
114         GSList *list = station_list;
115         tether_sta_info_s *info = NULL;
116         if (func == NULL)
117                 return;
118
119         if (!list)
120                 return;
121
122         list = g_slist_find_custom(list, data, func);
123         if (list == NULL)
124                 return;
125
126         info = (tether_sta_info_s *)list->data;
127         STC_LOGI("STA-REMOVED: (%s) (%s) (%s)", info->ip, info->mac, info->name);
128
129         /* remove tethering client from monitoring */
130         remove_station_monitor(info->mac, info->station_id);
131
132         g_free(info->station_id);
133         g_free(info);
134
135         station_list = g_slist_delete_link(station_list, list);
136 }
137
138 static void _add_station_info(tether_sta_info_s *info)
139 {
140         tether_sta_info_s *tmp = NULL;
141         if (info == NULL) {
142                 STC_LOGE("info is NULL");
143                 return;
144         }
145
146         if (_get_station_info(info->mac, _compare_sta_by_mac_func, &tmp) == 0) {
147                 if (!g_strcmp0(tmp->name, info->name) && !g_strcmp0(tmp->ip, info->ip))
148                         return;
149
150                 /* Remove the station if dhcp info changed. */
151                 _remove_station_info(info->mac, _compare_sta_by_mac_func);
152         }
153
154         station_list = g_slist_prepend(station_list, info);
155         STC_LOGI("STA-ADDED: (%s) (%s) (%s)", info->ip, info->mac, info->name);
156
157         /* add tethering client for monitoring data usage */
158         info->station_id = g_strdup_printf("%s_%s", info->mac, info->name);
159         add_station_monitor(info->mac, info->station_id, info->mac);
160 }
161
162 static void _mobileap_signal_cb(GDBusConnection *conn,
163                                const gchar *name, const gchar *path,
164                                const gchar *interface, const gchar *sig,
165                                GVariant *param, gpointer user_data)
166 {
167         int type;
168         int tm;
169         char *ip = NULL;
170         char *mac = NULL;
171         char *hostname = NULL;
172         char *state = NULL;
173         tether_sta_info_s *sta = NULL;
174
175         ret_msg_if(sig == NULL, "signal name NULL");
176         ret_msg_if(param == NULL, "param NULL");
177
178         STC_LOGI("%s interface(%s)", sig, interface);
179
180         g_variant_get(param, "(susssu)", &state, &type, &ip, &mac, &hostname, &tm);
181         STC_LOGI("%s: ip(%s) mac(%s) name(%s) tm(%d)", state, ip, mac, hostname, tm);
182
183         if (!g_strcmp0(state, "DhcpConnected")) {
184                 sta = (tether_sta_info_s *)g_malloc0(sizeof(tether_sta_info_s));
185                 if (sta == NULL) {
186                         STC_LOGE("g_malloc0 failed");
187                         return;
188                 }
189
190                 g_strlcpy(sta->ip, ip, INET_ADDRSTRLEN);
191                 g_strlcpy(sta->mac, mac, STATION_MAC_STR_LEN);
192                 g_strlcpy(sta->name, hostname, STATION_STR_HOSTNAME_LEN);
193                 _add_station_info(sta);
194         } else if (!g_strcmp0(state, "DhcpLeaseDeleted")) {
195                 _remove_station_info(mac, _compare_sta_by_mac_func);
196         }
197
198         g_free(state);
199         g_free(ip);
200         g_free(mac);
201         g_free(hostname);
202 }
203
204 stc_error_e tether_plugin_get_station_ip(const char *mac, char *ip)
205 {
206         tether_sta_info_s *tmp = NULL;
207
208         if (mac == NULL || ip == NULL)
209                 return STC_ERROR_FAIL;
210
211         if (_get_station_info((gconstpointer)mac,
212                                 _compare_sta_by_mac_func, &tmp) != 0) {
213                 STC_LOGE("mac(%s) not found", mac);
214                 return STC_ERROR_FAIL;
215         }
216
217         g_strlcpy(ip, tmp->ip, INET_ADDRSTRLEN);
218         return STC_ERROR_NONE;
219 }
220
221 stc_error_e tether_plugin_get_station_by_classid(const int classid, char *mac)
222 {
223         tether_sta_info_s *tmp = NULL;
224         int classid_value = classid;
225
226         if (mac == NULL)
227                 return STC_ERROR_FAIL;
228
229         if (_get_station_info((gconstpointer)&classid_value,
230                                 _compare_sta_by_classid_func, &tmp) != 0) {
231                 STC_LOGE("classid(%d) not found", classid);
232                 return STC_ERROR_FAIL;
233         }
234
235         g_strlcpy(mac, tmp->mac, STATION_MAC_STR_LEN);
236         return STC_ERROR_NONE;
237 }
238
239 stc_error_e tether_plugin_set_station_classid(const char *mac, int classid)
240 {
241         tether_sta_info_s *tmp = NULL;
242
243         if (mac == NULL) {
244                 STC_LOGE("invalid param");
245                 return STC_ERROR_FAIL;
246         }
247
248         if (_get_station_info((gconstpointer)mac,
249                                 _compare_sta_by_mac_func, &tmp) != 0) {
250                 STC_LOGE("mac(%s) not found", mac);
251                 return STC_ERROR_FAIL;
252         }
253
254         if (tmp)
255                 tmp->classid = classid;
256
257         return STC_ERROR_NONE;
258 }
259
260 int tether_plugin_init(void)
261 {
262         GError *error = NULL;
263
264         if (connection)
265                 return 0;
266
267         connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
268         if (!connection) {
269                 g_error_free(error);
270                 return -1;
271         }
272
273         cancellable = g_cancellable_new();
274
275         g_mobileap_signal_sub_id = g_dbus_connection_signal_subscribe(connection,
276                                                    NULL,
277                                                    TETHERING_SERVICE_INTERFACE,
278                                                    SIGNAL_NAME_DHCP_STATUS,
279                                                    NULL, NULL,
280                                                    G_DBUS_SIGNAL_FLAGS_NONE,
281                                                    _mobileap_signal_cb,
282                                                    NULL, NULL);
283
284         STC_LOGI("tether plugin initialised");
285         return 0;
286 }
287
288 void tether_plugin_deinit(void)
289 {
290         if (!connection)
291                 return;
292
293         g_object_unref(connection);
294         g_object_unref(cancellable);
295         connection = NULL;
296         cancellable = NULL;
297         STC_LOGI("tether plugin deinitialised");
298 }
299
300 API stc_plugin_tether_s tether_plugin = {
301         .init = tether_plugin_init,
302         .deinit = tether_plugin_deinit,
303         .get_station_ip = tether_plugin_get_station_ip,
304         .get_station_by_classid = tether_plugin_get_station_by_classid,
305         .set_station_classid = tether_plugin_set_station_classid
306 };