Update for tizen_2.1
[framework/connectivity/mobileap-agent.git] / src / mobileap_common.c
1 /*
2  *  mobileap-agent
3  *
4  * Copyright 2012-2013  Samsung Electronics Co., Ltd
5  *
6  * Licensed under the Flora License, Version 1.1 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://floralicense.org/license
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <stdio.h>
21 #include <glib.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30
31 #include <dbus/dbus.h>
32 #include <dbus/dbus-glib.h>
33 #include <dbus/dbus-glib-lowlevel.h>
34
35 #include "mobileap_notification.h"
36 #include "mobileap_common.h"
37
38 #define TETHERING_OBJECT_GET_CLASS(obj) \
39         (G_TYPE_INSTANCE_GET_CLASS ((obj), \
40         TETHERING_TYPE_OBJECT , TetheringObjectClass))
41
42 extern DBusConnection *tethering_conn;
43
44 static GSList *station_list = NULL;
45
46 gint _slist_find_station_by_interface(gconstpointer a, gconstpointer b)
47 {
48         mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
49         mobile_ap_type_e interface = (mobile_ap_type_e)b;
50
51         return si->interface - interface;
52 }
53
54 gint _slist_find_station_by_mac(gconstpointer a, gconstpointer b)
55 {
56         mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
57         const char *mac = (const char *)b;
58
59         return g_ascii_strcasecmp(si->mac, mac);
60 }
61
62 gint _slist_find_station_by_ip_addr(gconstpointer a, gconstpointer b)
63 {
64         mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
65         const char *ip_addr = (const char *)b;
66
67         return g_ascii_strcasecmp(si->ip, ip_addr);
68 }
69
70 void _emit_mobileap_dbus_signal(TetheringObject *obj,
71                                 mobile_ap_sig_e num, const gchar *message)
72 {
73         TetheringObjectClass *klass = TETHERING_OBJECT_GET_CLASS(obj);
74
75         DBG("Emitting signal id [%d], with message [%s]\n", num, message);
76         g_signal_emit(obj, klass->signals[num], 0, message);
77 }
78
79 void _send_dbus_station_info(const char *member, mobile_ap_station_info_t *info)
80 {
81         if (tethering_conn == NULL)
82                 return;
83
84         if (member == NULL || info == NULL) {
85                 ERR("Invalid param\n");
86                 return;
87         }
88
89         DBusMessage *msg = NULL;
90         char *ip = info->ip;
91         char *mac = info->mac;
92         char *hostname = info->hostname;
93
94         msg = dbus_message_new_signal(TETHERING_SERVICE_OBJECT_PATH,
95                         TETHERING_SERVICE_INTERFACE,
96                         SIGNAL_NAME_DHCP_STATUS);
97         if (!msg) {
98                 ERR("Unable to allocate D-Bus signal\n");
99                 return;
100         }
101
102         if (!dbus_message_append_args(msg,
103                                 DBUS_TYPE_STRING, &member,
104                                 DBUS_TYPE_UINT32, &info->interface,
105                                 DBUS_TYPE_STRING, &ip,
106                                 DBUS_TYPE_STRING, &mac,
107                                 DBUS_TYPE_STRING, &hostname,
108                                 DBUS_TYPE_UINT32, &info->tm,
109                                 DBUS_TYPE_INVALID)) {
110                 ERR("Event sending failed\n");
111                 dbus_message_unref(msg);
112                 return;
113         }
114
115         dbus_connection_send(tethering_conn, msg, NULL);
116         dbus_message_unref(msg);
117
118         return;
119 }
120
121
122 void _update_station_count(int count)
123 {
124         static int prev_cnt = 0;
125         char str[MH_NOTI_STR_MAX] = {0, };
126
127         if (prev_cnt == count) {
128                 DBG("No need to update\n");
129                 return;
130         }
131
132         DBG("Update the number of station : %d\n", count);
133         if (vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_CONNECTED_DEVICE,
134                                 count) < 0) {
135                 ERR("Error setting up vconf\n");
136                 return;
137         }
138
139         if (count == 0) {
140                 prev_cnt = 0;
141                 _delete_connected_noti();
142                 return;
143         }
144
145         snprintf(str, MH_NOTI_STR_MAX, MH_NOTI_STR, count);
146         if (prev_cnt == 0) {
147                 DBG("Create notification\n");
148                 _create_connected_noti(str, MH_NOTI_TITLE, MH_NOTI_ICON_PATH);
149         } else {
150                 DBG("Update notification\n");
151                 _update_connected_noti(str);
152         }
153
154         prev_cnt = count;
155         return;
156 }
157
158 int _add_station_info(mobile_ap_station_info_t *info)
159 {
160         if (info == NULL) {
161                 ERR("Invalid param\n");
162                 return MOBILE_AP_ERROR_INVALID_PARAM;
163         }
164
165         guint count;
166         GSList *l = NULL;
167         mobile_ap_station_info_t *si = NULL;
168         int i = 0;
169
170         if (_get_station_info(info->mac, _slist_find_station_by_mac, &si) ==
171                         MOBILE_AP_ERROR_NONE) {
172                 DBG("Already exist station : %s\n", info->mac);
173                 return MOBILE_AP_ERROR_INTERNAL;
174         }
175
176         station_list = g_slist_append(station_list, info);
177         for (l = station_list; l != NULL; l = g_slist_next(l)) {
178                 si = (mobile_ap_station_info_t *)l->data;
179                 DBG("[%d] interface : %d\n", i, si->interface);
180                 DBG("[%d] station MAC : %s\n", i, si->mac);
181                 DBG("[%d] station Hostname : %s\n", i, si->hostname);
182                 DBG("[%d] station IP : %s\n", i, si->ip);
183                 DBG("[%d] station connected time : %d\n", i, si->tm);
184                 i++;
185         }
186
187         count = g_slist_length(station_list);
188         _update_station_count(count);
189
190         return MOBILE_AP_ERROR_NONE;
191 }
192
193 int _remove_station_info(gconstpointer data, GCompareFunc func)
194 {
195         if (func == NULL) {
196                 ERR("Invalid param\n");
197                 return MOBILE_AP_ERROR_INVALID_PARAM;
198         }
199
200         if (station_list == NULL) {
201                 ERR("There is no station\n");
202                 return MOBILE_AP_ERROR_INTERNAL;
203         }
204
205         GSList *l = NULL;
206         mobile_ap_station_info_t *si = NULL;
207         int count;
208
209         l = g_slist_find_custom(station_list, data, func);
210         if (!l) {
211                 ERR("Not found\n");
212                 return MOBILE_AP_ERROR_INTERNAL;
213         }
214
215         si = (mobile_ap_station_info_t *)l->data;
216         DBG("Remove station MAC : %s\n", si->mac);
217         station_list = g_slist_delete_link(station_list, l);
218         _send_dbus_station_info("DhcpLeaseDeleted", si);
219         g_free(si);
220
221         count = g_slist_length(station_list);
222         _update_station_count(count);
223
224         return MOBILE_AP_ERROR_NONE;
225 }
226
227 int _remove_station_info_all(mobile_ap_type_e type)
228 {
229         if (station_list == NULL) {
230                 return MOBILE_AP_ERROR_NONE;
231         }
232
233         GSList *l = station_list;
234         GSList *temp_l = NULL;
235         mobile_ap_station_info_t *si = NULL;
236         int count;
237
238         while (l) {
239                 si = (mobile_ap_station_info_t *)l->data;
240                 DBG("interface : %d\n", si->interface);
241                 if (si->interface != type) {
242                         l = g_slist_next(l);
243                         continue;
244                 }
245
246                 DBG("Remove station MAC : %s\n", si->mac);
247                 _send_dbus_station_info("DhcpLeaseDeleted", si);
248                 g_free(si);
249
250                 temp_l = l;
251                 l = g_slist_next(l);
252                 station_list = g_slist_delete_link(station_list, temp_l);
253         }
254
255         count = g_slist_length(station_list);
256         _update_station_count(count);
257
258         return MOBILE_AP_ERROR_NONE;
259 }
260
261 int _get_station_info(gconstpointer data, GCompareFunc func,
262                 mobile_ap_station_info_t **si)
263 {
264         if (func == NULL || si == NULL) {
265                 ERR("Invalid param\n");
266                 return MOBILE_AP_ERROR_INVALID_PARAM;
267         }
268
269         if (station_list == NULL) {
270                 ERR("There is no station\n");
271                 return MOBILE_AP_ERROR_INTERNAL;
272         }
273
274         GSList *l = NULL;
275         mobile_ap_station_info_t *node = NULL;
276
277         l = g_slist_find_custom(station_list, data, func);
278         if (!l) {
279                 ERR("Not found\n");
280                 return MOBILE_AP_ERROR_INTERNAL;
281         }
282
283         node = l->data;
284         DBG("Found station : %s\n", node->mac);
285         *si = node;
286
287         return MOBILE_AP_ERROR_NONE;
288 }
289
290 int _get_station_count(gconstpointer data, GCompareFunc func, int *count)
291 {
292         if (count == NULL) {
293                 ERR("Invalid param\n");
294                 return MOBILE_AP_ERROR_INVALID_PARAM;
295         }
296
297         GSList *l = station_list;
298         int _count = 0;
299
300         for (_count = 0; l != NULL; _count++, l = g_slist_next(l)) {
301                 l = g_slist_find_custom(l, data, func);
302                 if (l == NULL)
303                         break;
304         }
305
306         *count = _count;
307         DBG("Station count : %d\n", *count);
308
309         return MOBILE_AP_ERROR_NONE;
310 }
311
312 int _station_info_foreach(GFunc func, void *user_data)
313 {
314         if (func == NULL) {
315                 ERR("Invalid param\n");
316                 return MOBILE_AP_ERROR_INVALID_PARAM;
317         }
318
319         g_slist_foreach(station_list, func, user_data);
320
321         return MOBILE_AP_ERROR_NONE;
322 }
323
324 int _add_data_usage_rule(const char *src, const char *dest)
325 {
326         if (src == NULL || src[0] == '\0' ||
327                         dest == NULL || dest[0] == '\0' ||
328                         g_strcmp0(src, dest) == 0) {
329                 ERR("Invalid parameter\n");
330                 return MOBILE_AP_ERROR_INVALID_PARAM;
331         }
332
333         char cmd[MAX_BUF_SIZE] = {0, };
334
335         snprintf(cmd, sizeof(cmd), "%s -A FORWARD "FORWARD_RULE,
336                         IPTABLES, src, dest);
337         DBG("ADD IPTABLES RULE : %s\n", cmd);
338         if (_execute_command(cmd)) {
339                 ERR("iptables failed : %s\n", cmd);
340                 return MOBILE_AP_ERROR_INTERNAL;
341         }
342
343         snprintf(cmd, sizeof(cmd), "%s -A FORWARD "FORWARD_RULE,
344                         IPTABLES, dest, src);
345         DBG("ADD IPTABLES RULE : %s\n", cmd);
346         if (_execute_command(cmd)) {
347                 ERR("iptables failed : %s\n", cmd);
348                 return MOBILE_AP_ERROR_INTERNAL;
349         }
350
351         return MOBILE_AP_ERROR_NONE;
352 }
353
354 int _del_data_usage_rule(const char *src, const char *dest)
355 {
356         if (src == NULL || src[0] == '\0' ||
357                         dest == NULL || dest[0] == '\0' ||
358                         g_strcmp0(src, dest) == 0) {
359                 ERR("Invalid parameter\n");
360                 return MOBILE_AP_ERROR_INVALID_PARAM;
361         }
362
363         char cmd[MAX_BUF_SIZE] = {0, };
364
365         snprintf(cmd, sizeof(cmd), "%s -D FORWARD "FORWARD_RULE,
366                         IPTABLES, src, dest);
367         DBG("REMOVE IPTABLES RULE : %s\n", cmd);
368         if (_execute_command(cmd)) {
369                 ERR("iptables failed : %s\n", cmd);
370                 return MOBILE_AP_ERROR_INTERNAL;
371         }
372
373         snprintf(cmd, sizeof(cmd), "%s -D FORWARD "FORWARD_RULE,
374                         IPTABLES, dest, src);
375         DBG("REMOVE IPTABLES RULE : %s\n", cmd);
376         if (_execute_command(cmd)) {
377                 ERR("iptables failed : %s\n", cmd);
378                 return MOBILE_AP_ERROR_INTERNAL;
379         }
380
381         return MOBILE_AP_ERROR_NONE;
382 }
383
384 int _get_data_usage(const char *src, const char *dest,
385                 unsigned long long *tx, unsigned long long *rx)
386 {
387         if (src == NULL || src[0] == '\0' ||
388                         dest == NULL || dest[0] == '\0' ||
389                         tx == NULL || rx == NULL) {
390                 ERR("Invalid parameter\n");
391                 return MOBILE_AP_ERROR_INVALID_PARAM;
392         }
393
394         char cmd[MAX_BUF_SIZE] = {0, };
395         char buf[MAX_BUF_SIZE] = {0, };
396         FILE *fp = NULL;
397
398         /* Tx : Src. -> Dest. */
399         snprintf(cmd, sizeof(cmd),
400                         "%s -L FORWARD -vx | %s \"%s[ ]*%s\" | %s '{ print $2 }' > %s",
401                         IPTABLES, GREP, src, dest, AWK, DATA_USAGE_FILE);
402         if (system(cmd) < 0) {
403                 ERR("\"cmd\" is failed\n");
404         }
405
406         /* Rx : Dest. -> Src. */
407         snprintf(cmd, sizeof(cmd),
408                         "%s -L FORWARD -vx | %s \"%s[ ]*%s\" | %s '{ print $2 }' >> %s",
409                         IPTABLES, GREP, dest, src, AWK, DATA_USAGE_FILE);
410         if (system(cmd) < 0) {
411                 ERR("\"cmd\" is failed\n");
412         }
413
414         fp = fopen(DATA_USAGE_FILE, "r");
415         if (fp == NULL) {
416                 ERR("%s open failed\n", DATA_USAGE_FILE);
417                 ERR("%s\n", strerror(errno));
418                 return MOBILE_AP_ERROR_INTERNAL;
419         }
420
421         if (fgets(buf, sizeof(buf), fp) == NULL)
422                 *tx = 0LL;
423         else
424                 *tx = atoll(buf);
425
426         if (fgets(buf, sizeof(buf), fp) == NULL)
427                 *rx = 0LL;
428         else
429                 *rx = atoll(buf);
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 }