Below changes are applied
[framework/connectivity/mobileap-agent.git] / src / mobileap_common.c
1 /*
2  * mobileap-agent
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the License);
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <stdio.h>
19 #include <glib.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28
29 #include <dbus/dbus.h>
30 #include <dbus/dbus-glib.h>
31 #include <dbus/dbus-glib-lowlevel.h>
32
33 #include "mobileap_notification.h"
34 #include "mobileap_common.h"
35
36 #define MOBILEAP_OBJECT_GET_CLASS(obj) \
37         (G_TYPE_INSTANCE_GET_CLASS ((obj), \
38         MOBILEAP_TYPE_OBJECT , MobileAPObjectClass))
39
40 extern DBusConnection *mobileap_conn;
41
42 static GSList *station_list = NULL;
43
44 gint _slist_find_station_by_interface(gconstpointer a, gconstpointer b)
45 {
46         mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
47         mobile_ap_type_e interface = (mobile_ap_type_e)b;
48
49         return si->interface - interface;
50 }
51
52 gint _slist_find_station_by_mac(gconstpointer a, gconstpointer b)
53 {
54         mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
55         const char *mac = (const char *)b;
56
57         return g_ascii_strcasecmp(si->mac, mac);
58 }
59
60 gint _slist_find_station_by_ip_addr(gconstpointer a, gconstpointer b)
61 {
62         mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
63         const char *ip_addr = (const char *)b;
64
65         return g_ascii_strcasecmp(si->ip, ip_addr);
66 }
67
68 void _emit_mobileap_dbus_signal(MobileAPObject *obj,
69                                 mobile_ap_sig_e num, const gchar *message)
70 {
71         MobileAPObjectClass *klass = MOBILEAP_OBJECT_GET_CLASS(obj);
72
73         DBG("Emitting signal id [%d], with message [%s]\n", num, message);
74         g_signal_emit(obj, klass->signals[num], 0, message);
75 }
76
77 void _send_dbus_station_info(const char *member, mobile_ap_station_info_t *info)
78 {
79         if (mobileap_conn == NULL)
80                 return;
81
82         if (member == NULL || info == NULL) {
83                 ERR("Invalid param\n");
84                 return;
85         }
86
87         DBusMessage *msg = NULL;
88         char *ip = info->ip;
89         char *mac = info->mac;
90         char *hostname = info->hostname;
91
92         msg = dbus_message_new_signal("/MobileAP",
93                         "com.samsung.mobileap",
94                         SIGNAL_NAME_DHCP_STATUS);
95         if (!msg) {
96                 ERR("Unable to allocate D-Bus signal\n");
97                 return;
98         }
99
100         if (!dbus_message_append_args(msg,
101                                 DBUS_TYPE_STRING, &member,
102                                 DBUS_TYPE_UINT32, &info->interface,
103                                 DBUS_TYPE_STRING, &ip,
104                                 DBUS_TYPE_STRING, &mac,
105                                 DBUS_TYPE_STRING, &hostname,
106                                 DBUS_TYPE_INVALID)) {
107                 ERR("Event sending failed\n");
108                 dbus_message_unref(msg);
109                 return;
110         }
111
112         dbus_connection_send(mobileap_conn, msg, NULL);
113         dbus_message_unref(msg);
114
115         return;
116 }
117
118
119 void _update_station_count(int count)
120 {
121         static int prev_cnt = 0;
122         char str[MH_NOTI_STR_MAX] = {0, };
123
124         if (prev_cnt == count) {
125                 DBG("No need to update\n");
126                 return;
127         }
128
129         DBG("Update the number of station : %d\n", count);
130         if (vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_CONNECTED_DEVICE,
131                                 count) < 0) {
132                 ERR("Error setting up vconf\n");
133                 return;
134         }
135
136         if (count == 0) {
137                 prev_cnt = 0;
138                 _delete_connected_noti();
139                 return;
140         }
141
142         snprintf(str, MH_NOTI_STR_MAX, MH_NOTI_STR, count);
143         if (prev_cnt == 0) {
144                 DBG("Create notification\n");
145                 _create_connected_noti(str, MH_NOTI_TITLE, MH_NOTI_ICON_PATH);
146         } else {
147                 DBG("Update notification\n");
148                 _update_connected_noti(str);
149         }
150
151         prev_cnt = count;
152         return;
153 }
154
155 int _add_station_info(mobile_ap_station_info_t *info)
156 {
157         if (info == NULL) {
158                 ERR("Invalid param\n");
159                 return MOBILE_AP_ERROR_INVALID_PARAM;
160         }
161
162         guint count;
163         GSList *l = NULL;
164         mobile_ap_station_info_t *si = NULL;
165         int i = 0;
166
167         if (_get_station_info(info->mac, _slist_find_station_by_mac, &si) ==
168                         MOBILE_AP_ERROR_NONE) {
169                 DBG("Already exist station : %s\n", info->mac);
170                 return MOBILE_AP_ERROR_INTERNAL;
171         }
172
173         station_list = g_slist_append(station_list, info);
174         for (l = station_list; l != NULL; l = g_slist_next(l)) {
175                 si = (mobile_ap_station_info_t *)l->data;
176                 DBG("[%d] interface : %d\n", i, si->interface);
177                 DBG("[%d] station MAC : %s\n", i, si->mac);
178                 DBG("[%d] station Hostname : %s\n", i, si->hostname);
179                 DBG("[%d] station IP : %s\n", i, si->ip);
180                 i++;
181         }
182
183         count = g_slist_length(station_list);
184         _update_station_count(count);
185
186         return MOBILE_AP_ERROR_NONE;
187 }
188
189 int _remove_station_info(gconstpointer data, GCompareFunc func)
190 {
191         if (func == NULL) {
192                 ERR("Invalid param\n");
193                 return MOBILE_AP_ERROR_INVALID_PARAM;
194         }
195
196         if (station_list == NULL) {
197                 ERR("There is no station\n");
198                 return MOBILE_AP_ERROR_INTERNAL;
199         }
200
201         GSList *l = NULL;
202         mobile_ap_station_info_t *si = NULL;
203         int count;
204
205         l = g_slist_find_custom(station_list, data, func);
206         if (!l) {
207                 ERR("Not found\n");
208                 return MOBILE_AP_ERROR_INTERNAL;
209         }
210
211         si = (mobile_ap_station_info_t *)l->data;
212         DBG("Remove station MAC : %s\n", si->mac);
213         station_list = g_slist_delete_link(station_list, l);
214         _send_dbus_station_info("DhcpLeaseDeleted", si);
215         g_free(si);
216
217         count = g_slist_length(station_list);
218         _update_station_count(count);
219
220         return MOBILE_AP_ERROR_NONE;
221 }
222
223 int _remove_station_info_all(mobile_ap_type_e type)
224 {
225         if (station_list == NULL) {
226                 return MOBILE_AP_ERROR_NONE;
227         }
228
229         GSList *l = station_list;
230         GSList *temp_l = NULL;
231         mobile_ap_station_info_t *si = NULL;
232         int count;
233
234         while (l) {
235                 si = (mobile_ap_station_info_t *)l->data;
236                 DBG("interface : %d\n", si->interface);
237                 if (si->interface != type) {
238                         l = g_slist_next(l);
239                         continue;
240                 }
241
242                 DBG("Remove station MAC : %s\n", si->mac);
243                 _send_dbus_station_info("DhcpLeaseDeleted", si);
244                 g_free(si);
245
246                 temp_l = l;
247                 l = g_slist_next(l);
248                 station_list = g_slist_delete_link(station_list, temp_l);
249         }
250
251         count = g_slist_length(station_list);
252         _update_station_count(count);
253
254         return MOBILE_AP_ERROR_NONE;
255 }
256
257 int _get_station_info(gconstpointer data, GCompareFunc func,
258                 mobile_ap_station_info_t **si)
259 {
260         if (func == NULL || si == NULL) {
261                 ERR("Invalid param\n");
262                 return MOBILE_AP_ERROR_INVALID_PARAM;
263         }
264
265         if (station_list == NULL) {
266                 ERR("There is no station\n");
267                 return MOBILE_AP_ERROR_INTERNAL;
268         }
269
270         GSList *l = NULL;
271         mobile_ap_station_info_t *node = NULL;
272
273         l = g_slist_find_custom(station_list, data, func);
274         if (!l) {
275                 ERR("Not found\n");
276                 return MOBILE_AP_ERROR_INTERNAL;
277         }
278
279         node = l->data;
280         DBG("Found station : %s\n", node->mac);
281         *si = node;
282
283         return MOBILE_AP_ERROR_NONE;
284 }
285
286 int _get_station_count(gconstpointer data, GCompareFunc func, int *count)
287 {
288         if (count == NULL) {
289                 ERR("Invalid param\n");
290                 return MOBILE_AP_ERROR_INVALID_PARAM;
291         }
292
293         GSList *l = station_list;
294         int _count = 0;
295
296         for (_count = 0; l != NULL; _count++, l = g_slist_next(l)) {
297                 l = g_slist_find_custom(l, data, func);
298                 if (l == NULL)
299                         break;
300         }
301
302         *count = _count;
303         DBG("Station count : %d\n", *count);
304
305         return MOBILE_AP_ERROR_NONE;
306 }
307
308 int _station_info_foreach(GFunc func, void *user_data)
309 {
310         if (func == NULL) {
311                 ERR("Invalid param\n");
312                 return MOBILE_AP_ERROR_INVALID_PARAM;
313         }
314
315         g_slist_foreach(station_list, func, user_data);
316
317         return MOBILE_AP_ERROR_NONE;
318 }
319
320 int _add_data_usage_rule(const char *src, const char *dest)
321 {
322         if (src == NULL || src[0] == '\0' ||
323                         dest == NULL || dest[0] == '\0' ||
324                         g_strcmp0(src, dest) == 0) {
325                 ERR("Invalid parameter\n");
326                 return MOBILE_AP_ERROR_INVALID_PARAM;
327         }
328
329         char cmd[MAX_BUF_SIZE] = {0, };
330
331         snprintf(cmd, sizeof(cmd), "%s -A FORWARD "FORWARD_RULE,
332                         IPTABLES, src, dest);
333         DBG("ADD IPTABLES RULE : %s\n", cmd);
334         if (_execute_command(cmd)) {
335                 ERR("iptables failed : %s\n", cmd);
336                 return MOBILE_AP_ERROR_INTERNAL;
337         }
338
339         snprintf(cmd, sizeof(cmd), "%s -A FORWARD "FORWARD_RULE,
340                         IPTABLES, dest, src);
341         DBG("ADD IPTABLES RULE : %s\n", cmd);
342         if (_execute_command(cmd)) {
343                 ERR("iptables failed : %s\n", cmd);
344                 return MOBILE_AP_ERROR_INTERNAL;
345         }
346
347         return MOBILE_AP_ERROR_NONE;
348 }
349
350 int _del_data_usage_rule(const char *src, const char *dest)
351 {
352         if (src == NULL || src[0] == '\0' ||
353                         dest == NULL || dest[0] == '\0' ||
354                         g_strcmp0(src, dest) == 0) {
355                 ERR("Invalid parameter\n");
356                 return MOBILE_AP_ERROR_INVALID_PARAM;
357         }
358
359         char cmd[MAX_BUF_SIZE] = {0, };
360
361         snprintf(cmd, sizeof(cmd), "%s -D FORWARD "FORWARD_RULE,
362                         IPTABLES, src, dest);
363         DBG("REMOVE IPTABLES RULE : %s\n", cmd);
364         if (_execute_command(cmd)) {
365                 ERR("iptables failed : %s\n", cmd);
366                 return MOBILE_AP_ERROR_INTERNAL;
367         }
368
369         snprintf(cmd, sizeof(cmd), "%s -D FORWARD "FORWARD_RULE,
370                         IPTABLES, dest, src);
371         DBG("REMOVE IPTABLES RULE : %s\n", cmd);
372         if (_execute_command(cmd)) {
373                 ERR("iptables failed : %s\n", cmd);
374                 return MOBILE_AP_ERROR_INTERNAL;
375         }
376
377         return MOBILE_AP_ERROR_NONE;
378 }
379
380 int _get_data_usage(const char *src, const char *dest,
381                 unsigned long long *tx, unsigned long long *rx)
382 {
383         if (src == NULL || src[0] == '\0' ||
384                         dest == NULL || dest[0] == '\0' ||
385                         tx == NULL || rx == NULL) {
386                 ERR("Invalid parameter\n");
387                 return MOBILE_AP_ERROR_INVALID_PARAM;
388         }
389
390         char cmd[MAX_BUF_SIZE] = {0, };
391         char buf[MAX_BUF_SIZE] = {0, };
392         FILE *fp = NULL;
393
394         /* Tx : Src. -> Dest. */
395         snprintf(cmd, sizeof(cmd),
396                         "%s -L FORWARD -vx | %s \"%s[ ]*%s\" | %s '{ print $2 }' > %s",
397                         IPTABLES, GREP, src, dest, AWK, DATA_USAGE_FILE);
398         DBG("GET DATA USAGE : %s\n", cmd);
399         if (system(cmd) < 0) {
400                 ERR("\"cmd\" is failed\n");
401         }
402
403         /* Rx : Dest. -> Src. */
404         snprintf(cmd, sizeof(cmd),
405                         "%s -L FORWARD -vx | %s \"%s[ ]*%s\" | %s '{ print $2 }' >> %s",
406                         IPTABLES, GREP, dest, src, AWK, DATA_USAGE_FILE);
407         DBG("GET DATA USAGE : %s\n", cmd);
408         if (system(cmd) < 0) {
409                 ERR("\"cmd\" is failed\n");
410         }
411
412         fp = fopen(DATA_USAGE_FILE, "r");
413         if (fp == NULL) {
414                 ERR("%s open failed\n", DATA_USAGE_FILE);
415                 ERR("%s\n", strerror(errno));
416                 return MOBILE_AP_ERROR_INTERNAL;
417         }
418
419         if (fgets(buf, sizeof(buf), fp) == NULL)
420                 *tx = 0LL;
421         else
422                 *tx = atoll(buf);
423         DBG("Tx(%s -> %s) : %llu\n", src, dest, *tx);
424
425         if (fgets(buf, sizeof(buf), fp) == NULL)
426                 *rx = 0LL;
427         else
428                 *rx = atoll(buf);
429         DBG("Rx(%s -> %s) : %llu\n", dest, src, *rx);
430
431         fclose(fp);
432         unlink(DATA_USAGE_FILE);
433
434         return MOBILE_AP_ERROR_NONE;
435 }
436
437 int _execute_command(const char *cmd)
438 {
439         if (cmd == NULL) {
440                 ERR("Invalid param\n");
441                 return EXIT_FAILURE;
442         }
443
444         int status = 0;
445         int exit_status = 0;
446         pid_t pid = 0;
447         gchar **args = NULL;
448
449         DBG("cmd : %s\n", cmd);
450
451         args = g_strsplit_set(cmd, " ", -1);
452         if (!args) {
453                 ERR("g_strsplit_set failed\n");
454                 return EXIT_FAILURE;
455         }
456
457         if ((pid = fork()) < 0) {
458                 ERR("fork failed\n");
459                 return EXIT_FAILURE;
460         }
461
462         if (!pid) {
463                 if (execv(args[0], args)) {
464                         ERR("execl failed\n");
465                 }
466
467                 ERR("Should never get here!\n");
468                 return EXIT_FAILURE;
469         } else {
470                 DBG("child pid : %d\n", pid);
471
472                 /* Need to add timeout */
473                 waitpid(pid, &status, 0);
474                 g_strfreev(args);
475
476                 if (WIFEXITED(status)) {
477                         exit_status = WEXITSTATUS(status);
478                         if (exit_status) {
479                                 ERR("child return : %d\n", exit_status);
480                                 return EXIT_FAILURE;
481                         }
482                         DBG("child terminated normally\n");
483                         return EXIT_SUCCESS;
484                 } else {
485                         ERR("child is terminated without exit\n");
486                         return EXIT_FAILURE;
487                 }
488         }
489 }
490
491 int _get_tethering_type_from_ip(const char *ip, mobile_ap_type_e *type)
492 {
493         if (ip == NULL || type == NULL) {
494                 ERR("Invalid param\n");
495                 return MOBILE_AP_ERROR_INVALID_PARAM;
496         }
497
498         static gboolean is_init = FALSE;
499         static in_addr_t subnet_wifi;
500         static in_addr_t subnet_bt_min;
501         static in_addr_t subnet_bt_max;
502         static in_addr_t subnet_usb;
503
504         struct in_addr addr;
505         in_addr_t subnet;
506
507         if (inet_aton(ip, &addr) == 0) {
508                 ERR("Address : %s is invalid\n", ip);
509                 return MOBILE_AP_ERROR_INVALID_PARAM;
510         }
511         subnet = inet_netof(addr);
512
513         if (is_init == FALSE) {
514                 addr.s_addr = htonl(IP_ADDRESS_WIFI);
515                 subnet_wifi = inet_netof(addr);
516
517                 addr.s_addr = htonl(IP_ADDRESS_BT_1);
518                 subnet_bt_min = inet_netof(addr);
519
520                 addr.s_addr = htonl(IP_ADDRESS_BT_7);
521                 subnet_bt_max = inet_netof(addr);
522
523                 addr.s_addr = htonl(IP_ADDRESS_USB);
524                 subnet_usb = inet_netof(addr);
525                 is_init = TRUE;
526         }
527
528         if (subnet == subnet_wifi) {
529                 *type = MOBILE_AP_TYPE_WIFI;
530                 return MOBILE_AP_ERROR_NONE;
531         } else if (subnet >= subnet_bt_min && subnet <= subnet_bt_max) {
532                 *type = MOBILE_AP_TYPE_BT;
533                 return MOBILE_AP_ERROR_NONE;
534         } else if (subnet == subnet_usb) {
535                 *type = MOBILE_AP_TYPE_USB;
536                 return MOBILE_AP_ERROR_NONE;
537         }
538
539         ERR("Tethering type cannot be decided from %s\n", ip);
540         return MOBILE_AP_ERROR_INVALID_PARAM;
541 }