Initialize Tizen 2.3
[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 TETHERING_OBJECT_GET_CLASS(obj) \
37         (G_TYPE_INSTANCE_GET_CLASS ((obj), \
38         TETHERING_TYPE_OBJECT , TetheringObjectClass))
39
40 extern DBusConnection *tethering_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(TetheringObject *obj,
69                                 mobile_ap_sig_e num, const gchar *message)
70 {
71         TetheringObjectClass *klass = TETHERING_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 (tethering_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(TETHERING_SERVICE_OBJECT_PATH,
93                         TETHERING_SERVICE_INTERFACE,
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_UINT32, &info->tm,
107                                 DBUS_TYPE_INVALID)) {
108                 ERR("Event sending failed\n");
109                 dbus_message_unref(msg);
110                 return;
111         }
112
113         dbus_connection_send(tethering_conn, msg, NULL);
114         dbus_message_unref(msg);
115
116         return;
117 }
118
119
120 void _update_station_count(int count)
121 {
122         static int prev_cnt = 0;
123         char str[MH_NOTI_STR_MAX] = {0, };
124
125         if (prev_cnt == count) {
126                 DBG("No need to update\n");
127                 return;
128         }
129
130         DBG("Update the number of station : %d\n", count);
131         if (vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_CONNECTED_DEVICE,
132                                 count) < 0) {
133                 ERR("Error setting up vconf\n");
134                 return;
135         }
136
137         if (count == 0) {
138                 prev_cnt = 0;
139                 _delete_connected_noti();
140                 return;
141         }
142
143         snprintf(str, MH_NOTI_STR_MAX, MH_NOTI_STR, count);
144         if (prev_cnt == 0) {
145                 DBG("Create notification\n");
146                 _create_connected_noti(str, MH_NOTI_TITLE, MH_NOTI_ICON_PATH);
147         } else {
148                 DBG("Update notification\n");
149                 _update_connected_noti(str);
150         }
151
152         prev_cnt = count;
153         return;
154 }
155
156 int _add_station_info(mobile_ap_station_info_t *info)
157 {
158         if (info == NULL) {
159                 ERR("Invalid param\n");
160                 return MOBILE_AP_ERROR_INVALID_PARAM;
161         }
162
163         guint count;
164         GSList *l = NULL;
165         mobile_ap_station_info_t *si = NULL;
166         int i = 0;
167
168         if (_get_station_info(info->mac, _slist_find_station_by_mac, &si) ==
169                         MOBILE_AP_ERROR_NONE) {
170                 DBG("Already exist station : %s\n", info->mac);
171                 return MOBILE_AP_ERROR_INTERNAL;
172         }
173
174         station_list = g_slist_append(station_list, info);
175         for (l = station_list; l != NULL; l = g_slist_next(l)) {
176                 si = (mobile_ap_station_info_t *)l->data;
177                 DBG("[%d] interface : %d\n", i, si->interface);
178                 DBG("[%d] station MAC : %s\n", i, si->mac);
179                 DBG("[%d] station Hostname : %s\n", i, si->hostname);
180                 DBG("[%d] station IP : %s\n", i, si->ip);
181                 DBG("[%d] station connected time : %d\n", i, si->tm);
182                 i++;
183         }
184
185         count = g_slist_length(station_list);
186         _update_station_count(count);
187
188         return MOBILE_AP_ERROR_NONE;
189 }
190
191 int _remove_station_info(gconstpointer data, GCompareFunc func)
192 {
193         if (func == NULL) {
194                 ERR("Invalid param\n");
195                 return MOBILE_AP_ERROR_INVALID_PARAM;
196         }
197
198         if (station_list == NULL) {
199                 ERR("There is no station\n");
200                 return MOBILE_AP_ERROR_INTERNAL;
201         }
202
203         GSList *l = NULL;
204         mobile_ap_station_info_t *si = NULL;
205         int count;
206
207         l = g_slist_find_custom(station_list, data, func);
208         if (!l) {
209                 ERR("Not found\n");
210                 return MOBILE_AP_ERROR_INTERNAL;
211         }
212
213         si = (mobile_ap_station_info_t *)l->data;
214         DBG("Remove station MAC : %s\n", si->mac);
215         station_list = g_slist_delete_link(station_list, l);
216         _send_dbus_station_info("DhcpLeaseDeleted", si);
217         g_free(si);
218
219         count = g_slist_length(station_list);
220         _update_station_count(count);
221
222         return MOBILE_AP_ERROR_NONE;
223 }
224
225 int _remove_station_info_all(mobile_ap_type_e type)
226 {
227         if (station_list == NULL) {
228                 return MOBILE_AP_ERROR_NONE;
229         }
230
231         GSList *l = station_list;
232         GSList *temp_l = NULL;
233         mobile_ap_station_info_t *si = NULL;
234         int count;
235
236         while (l) {
237                 si = (mobile_ap_station_info_t *)l->data;
238                 DBG("interface : %d\n", si->interface);
239                 if (si->interface != type) {
240                         l = g_slist_next(l);
241                         continue;
242                 }
243
244                 DBG("Remove station MAC : %s\n", si->mac);
245                 _send_dbus_station_info("DhcpLeaseDeleted", si);
246                 g_free(si);
247
248                 temp_l = l;
249                 l = g_slist_next(l);
250                 station_list = g_slist_delete_link(station_list, temp_l);
251         }
252
253         count = g_slist_length(station_list);
254         _update_station_count(count);
255
256         return MOBILE_AP_ERROR_NONE;
257 }
258
259 int _get_station_info(gconstpointer data, GCompareFunc func,
260                 mobile_ap_station_info_t **si)
261 {
262         if (func == NULL || si == NULL) {
263                 ERR("Invalid param\n");
264                 return MOBILE_AP_ERROR_INVALID_PARAM;
265         }
266
267         if (station_list == NULL) {
268                 ERR("There is no station\n");
269                 return MOBILE_AP_ERROR_INTERNAL;
270         }
271
272         GSList *l = NULL;
273         mobile_ap_station_info_t *node = NULL;
274
275         l = g_slist_find_custom(station_list, data, func);
276         if (!l) {
277                 ERR("Not found\n");
278                 return MOBILE_AP_ERROR_INTERNAL;
279         }
280
281         node = l->data;
282         DBG("Found station : %s\n", node->mac);
283         *si = node;
284
285         return MOBILE_AP_ERROR_NONE;
286 }
287
288 int _get_station_count(gconstpointer data, GCompareFunc func, int *count)
289 {
290         if (count == NULL) {
291                 ERR("Invalid param\n");
292                 return MOBILE_AP_ERROR_INVALID_PARAM;
293         }
294
295         GSList *l = station_list;
296         int _count = 0;
297
298         for (_count = 0; l != NULL; _count++, l = g_slist_next(l)) {
299                 l = g_slist_find_custom(l, data, func);
300                 if (l == NULL)
301                         break;
302         }
303
304         *count = _count;
305         DBG("Station count : %d\n", *count);
306
307         return MOBILE_AP_ERROR_NONE;
308 }
309
310 int _station_info_foreach(GFunc func, void *user_data)
311 {
312         if (func == NULL) {
313                 ERR("Invalid param\n");
314                 return MOBILE_AP_ERROR_INVALID_PARAM;
315         }
316
317         g_slist_foreach(station_list, func, user_data);
318
319         return MOBILE_AP_ERROR_NONE;
320 }
321
322 int _add_data_usage_rule(const char *src, const char *dest)
323 {
324         if (src == NULL || src[0] == '\0' ||
325                         dest == NULL || dest[0] == '\0' ||
326                         g_strcmp0(src, dest) == 0) {
327                 ERR("Invalid parameter\n");
328                 return MOBILE_AP_ERROR_INVALID_PARAM;
329         }
330
331         char cmd[MAX_BUF_SIZE] = {0, };
332
333         snprintf(cmd, sizeof(cmd), "%s -A FORWARD "FORWARD_RULE,
334                         IPTABLES, src, dest);
335         DBG("ADD IPTABLES RULE : %s\n", cmd);
336         if (_execute_command(cmd)) {
337                 ERR("iptables failed : %s\n", cmd);
338                 return MOBILE_AP_ERROR_INTERNAL;
339         }
340
341         snprintf(cmd, sizeof(cmd), "%s -A FORWARD "FORWARD_RULE,
342                         IPTABLES, dest, src);
343         DBG("ADD IPTABLES RULE : %s\n", cmd);
344         if (_execute_command(cmd)) {
345                 ERR("iptables failed : %s\n", cmd);
346                 return MOBILE_AP_ERROR_INTERNAL;
347         }
348
349         return MOBILE_AP_ERROR_NONE;
350 }
351
352 int _del_data_usage_rule(const char *src, const char *dest)
353 {
354         if (src == NULL || src[0] == '\0' ||
355                         dest == NULL || dest[0] == '\0' ||
356                         g_strcmp0(src, dest) == 0) {
357                 ERR("Invalid parameter\n");
358                 return MOBILE_AP_ERROR_INVALID_PARAM;
359         }
360
361         char cmd[MAX_BUF_SIZE] = {0, };
362
363         snprintf(cmd, sizeof(cmd), "%s -D FORWARD "FORWARD_RULE,
364                         IPTABLES, src, dest);
365         DBG("REMOVE IPTABLES RULE : %s\n", cmd);
366         if (_execute_command(cmd)) {
367                 ERR("iptables failed : %s\n", cmd);
368                 return MOBILE_AP_ERROR_INTERNAL;
369         }
370
371         snprintf(cmd, sizeof(cmd), "%s -D FORWARD "FORWARD_RULE,
372                         IPTABLES, dest, src);
373         DBG("REMOVE IPTABLES RULE : %s\n", cmd);
374         if (_execute_command(cmd)) {
375                 ERR("iptables failed : %s\n", cmd);
376                 return MOBILE_AP_ERROR_INTERNAL;
377         }
378
379         return MOBILE_AP_ERROR_NONE;
380 }
381
382 int _get_data_usage(const char *src, const char *dest,
383                 unsigned long long *tx, unsigned long long *rx)
384 {
385         if (src == NULL || src[0] == '\0' ||
386                         dest == NULL || dest[0] == '\0' ||
387                         tx == NULL || rx == NULL) {
388                 ERR("Invalid parameter\n");
389                 return MOBILE_AP_ERROR_INVALID_PARAM;
390         }
391
392         char cmd[MAX_BUF_SIZE] = {0, };
393         char buf[MAX_BUF_SIZE] = {0, };
394         FILE *fp = NULL;
395
396         /* Tx : Src. -> Dest. */
397         snprintf(cmd, sizeof(cmd),
398                         "%s -L FORWARD -vx | %s \"%s[ ]*%s\" | %s '{ print $2 }' > %s",
399                         IPTABLES, GREP, src, dest, AWK, DATA_USAGE_FILE);
400         if (system(cmd) < 0) {
401                 ERR("\"cmd\" is failed\n");
402         }
403
404         /* Rx : Dest. -> Src. */
405         snprintf(cmd, sizeof(cmd),
406                         "%s -L FORWARD -vx | %s \"%s[ ]*%s\" | %s '{ print $2 }' >> %s",
407                         IPTABLES, GREP, dest, src, AWK, DATA_USAGE_FILE);
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
424         if (fgets(buf, sizeof(buf), fp) == NULL)
425                 *rx = 0LL;
426         else
427                 *rx = atoll(buf);
428
429         fclose(fp);
430         unlink(DATA_USAGE_FILE);
431
432         return MOBILE_AP_ERROR_NONE;
433 }
434
435 int _execute_command(const char *cmd)
436 {
437         if (cmd == NULL) {
438                 ERR("Invalid param\n");
439                 return EXIT_FAILURE;
440         }
441
442         int status = 0;
443         int exit_status = 0;
444         pid_t pid = 0;
445         gchar **args = NULL;
446
447         DBG("cmd : %s\n", cmd);
448
449         args = g_strsplit_set(cmd, " ", -1);
450         if (!args) {
451                 ERR("g_strsplit_set failed\n");
452                 return EXIT_FAILURE;
453         }
454
455         if ((pid = fork()) < 0) {
456                 ERR("fork failed\n");
457                 return EXIT_FAILURE;
458         }
459
460         if (!pid) {
461                 if (execv(args[0], args)) {
462                         ERR("execl failed\n");
463                 }
464
465                 ERR("Should never get here!\n");
466                 return EXIT_FAILURE;
467         } else {
468                 DBG("child pid : %d\n", pid);
469
470                 /* Need to add timeout */
471                 waitpid(pid, &status, 0);
472                 g_strfreev(args);
473
474                 if (WIFEXITED(status)) {
475                         exit_status = WEXITSTATUS(status);
476                         if (exit_status) {
477                                 ERR("child return : %d\n", exit_status);
478                                 return EXIT_FAILURE;
479                         }
480                         DBG("child terminated normally\n");
481                         return EXIT_SUCCESS;
482                 } else {
483                         ERR("child is terminated without exit\n");
484                         return EXIT_FAILURE;
485                 }
486         }
487 }
488
489 int _get_tethering_type_from_ip(const char *ip, mobile_ap_type_e *type)
490 {
491         if (ip == NULL || type == NULL) {
492                 ERR("Invalid param\n");
493                 return MOBILE_AP_ERROR_INVALID_PARAM;
494         }
495
496         static gboolean is_init = FALSE;
497         static in_addr_t subnet_wifi;
498         static in_addr_t subnet_bt_min;
499         static in_addr_t subnet_bt_max;
500         static in_addr_t subnet_usb;
501
502         struct in_addr addr;
503         in_addr_t subnet;
504
505         if (inet_aton(ip, &addr) == 0) {
506                 ERR("Address : %s is invalid\n", ip);
507                 return MOBILE_AP_ERROR_INVALID_PARAM;
508         }
509         subnet = inet_netof(addr);
510
511         if (is_init == FALSE) {
512                 addr.s_addr = htonl(IP_ADDRESS_WIFI);
513                 subnet_wifi = inet_netof(addr);
514
515                 addr.s_addr = htonl(IP_ADDRESS_BT_1);
516                 subnet_bt_min = inet_netof(addr);
517
518                 addr.s_addr = htonl(IP_ADDRESS_BT_7);
519                 subnet_bt_max = inet_netof(addr);
520
521                 addr.s_addr = htonl(IP_ADDRESS_USB);
522                 subnet_usb = inet_netof(addr);
523                 is_init = TRUE;
524         }
525
526         if (subnet == subnet_wifi) {
527                 *type = MOBILE_AP_TYPE_WIFI;
528                 return MOBILE_AP_ERROR_NONE;
529         } else if (subnet >= subnet_bt_min && subnet <= subnet_bt_max) {
530                 *type = MOBILE_AP_TYPE_BT;
531                 return MOBILE_AP_ERROR_NONE;
532         } else if (subnet == subnet_usb) {
533                 *type = MOBILE_AP_TYPE_USB;
534                 return MOBILE_AP_ERROR_NONE;
535         }
536
537         ERR("Tethering type cannot be decided from %s\n", ip);
538         return MOBILE_AP_ERROR_INVALID_PARAM;
539 }