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