tizen 2.4 release
[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
31 #include "mobileap_notification.h"
32 #include "mobileap_common.h"
33
34 static GSList *station_list = NULL;
35
36 gint _slist_find_station_by_interface(gconstpointer a, gconstpointer b)
37 {
38         mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
39         mobile_ap_type_e interface = (mobile_ap_type_e)b;
40
41         return si->interface - interface;
42 }
43
44 gint _slist_find_station_by_mac(gconstpointer a, gconstpointer b)
45 {
46         mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
47         const char *mac = (const char *)b;
48
49         return g_ascii_strcasecmp(si->mac, mac);
50 }
51
52 gint _slist_find_station_by_ip_addr(gconstpointer a, gconstpointer b)
53 {
54         mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
55         const char *ip_addr = (const char *)b;
56
57         return g_ascii_strcasecmp(si->ip, ip_addr);
58 }
59
60 void _send_dbus_station_info(const char *member, mobile_ap_station_info_t *info)
61 {
62
63         DBG("+\n");
64         if (member == NULL || info == NULL) {
65                 ERR("Invalid param\n");
66                 return;
67         }
68         Tethering *obj = _get_tethering_obj();
69         if (obj == NULL) {
70                 ERR("tethering object is null\n");
71                 return;
72         }
73         DBG("signal is   %s", member);
74         tethering_emit_dhcp_status(obj, member, info->interface, info->ip, info->mac,
75                         info->hostname, info->tm);
76         DBG("-\n");
77 }
78
79 void _update_station_count(int count)
80 {
81         static int prev_cnt = 0;
82         char icon_path[MH_NOTI_PATH_MAX] = {0, };
83         int wifi_count = 0;
84         int bt_count = 0;
85         int usb_count = 0;
86
87         if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) {
88                 return;
89         }
90
91         if (prev_cnt == count) {
92                 return;
93         }
94
95         if (vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_CONNECTED_DEVICE,
96                                 count) < 0) {
97                 ERR("Error setting up vconf\n");
98                 return;
99         }
100
101         if (count == 0) {
102                 prev_cnt = 0;
103                 _delete_connected_noti();
104                 return;
105         }
106
107         _get_station_count((gconstpointer)MOBILE_AP_TYPE_WIFI, _slist_find_station_by_interface, &wifi_count);
108         _get_station_count((gconstpointer)MOBILE_AP_TYPE_BT, _slist_find_station_by_interface, &bt_count);
109         _get_station_count((gconstpointer)MOBILE_AP_TYPE_USB, _slist_find_station_by_interface, &usb_count);
110
111         if (wifi_count > 0 && bt_count == 0 && usb_count == 0) {
112                 g_strlcpy(icon_path, MH_NOTI_ICON_WIFI, sizeof(icon_path));
113         } else if (wifi_count == 0 && bt_count > 0 && usb_count == 0) {
114                 g_strlcpy(icon_path, MH_NOTI_ICON_BT, sizeof(icon_path));
115         } else if (wifi_count == 0 && bt_count == 0 && usb_count > 0) {
116                 g_strlcpy(icon_path, MH_NOTI_ICON_USB, sizeof(icon_path));
117         } else if (wifi_count == 0 && bt_count == 0 && usb_count == 0) {
118                 return;
119         } else {
120                 g_strlcpy(icon_path, MH_NOTI_ICON_GENERAL, sizeof(icon_path));
121         }
122
123         if (prev_cnt == 0) {
124                 _create_connected_noti(count, icon_path);
125         } else {
126                 _update_connected_noti(count, icon_path);
127         }
128
129         prev_cnt = count;
130         return;
131 }
132
133 int _add_station_info(mobile_ap_station_info_t *info)
134 {
135         if (info == NULL) {
136                 ERR("Invalid param\n");
137                 return MOBILE_AP_ERROR_INVALID_PARAM;
138         }
139
140         guint count;
141         GSList *l = NULL;
142         mobile_ap_station_info_t *si = NULL;
143         int i = 0;
144
145         if (_get_station_info(info->mac, _slist_find_station_by_mac, &si) ==
146                         MOBILE_AP_ERROR_NONE) {
147                 if (!si) {
148                         return MOBILE_AP_ERROR_INTERNAL;
149                 }
150
151                 if (g_strcmp0(si->hostname, info->hostname) == 0 &&
152                                 g_strcmp0(si->ip, info->ip) == 0) {
153                         return MOBILE_AP_ERROR_INTERNAL;
154                 }
155
156                 _remove_station_info(si->mac, _slist_find_station_by_mac);
157         }
158
159         station_list = g_slist_append(station_list, info);
160         for (l = station_list; l != NULL; l = g_slist_next(l)) {
161                 si = (mobile_ap_station_info_t *)l->data;
162                 SDBG("[%d] interface : %d\n", i, si->interface);
163                 SDBG("[%d] station MAC : %s\n", i, si->mac);
164                 SDBG("[%d] station Hostname : %s\n", i, si->hostname);
165                 SDBG("[%d] station IP : %s\n", i, si->ip);
166                 SDBG("[%d] station connected time : %d\n", i, si->tm);
167                 i++;
168         }
169
170         count = g_slist_length(station_list);
171         _update_station_count(count);
172
173         return MOBILE_AP_ERROR_NONE;
174 }
175
176 int _remove_station_info(gconstpointer data, GCompareFunc func)
177 {
178         if (func == NULL) {
179                 ERR("Invalid param\n");
180                 return MOBILE_AP_ERROR_INVALID_PARAM;
181         }
182
183         if (station_list == NULL) {
184                 ERR("There is no station\n");
185                 return MOBILE_AP_ERROR_INTERNAL;
186         }
187
188         GSList *l = NULL;
189         mobile_ap_station_info_t *si = NULL;
190         int count;
191
192         l = g_slist_find_custom(station_list, data, func);
193         if (!l) {
194                 ERR("Not found\n");
195                 return MOBILE_AP_ERROR_INTERNAL;
196         }
197
198         si = (mobile_ap_station_info_t *)l->data;
199         SDBG("Remove station MAC : %s\n", si->mac);
200         station_list = g_slist_delete_link(station_list, l);
201         _send_dbus_station_info("DhcpLeaseDeleted", si);
202         g_free(si->hostname);
203         g_free(si);
204
205         count = g_slist_length(station_list);
206         _update_station_count(count);
207
208         return MOBILE_AP_ERROR_NONE;
209 }
210
211 int _remove_station_info_all(mobile_ap_type_e type)
212 {
213         if (station_list == NULL) {
214                 return MOBILE_AP_ERROR_NONE;
215         }
216
217         GSList *l = station_list;
218         GSList *temp_l = NULL;
219         mobile_ap_station_info_t *si = NULL;
220         int count;
221
222         _flush_dhcp_ack_timer();
223
224         while (l) {
225                 si = (mobile_ap_station_info_t *)l->data;
226                 if (si->interface != type) {
227                         l = g_slist_next(l);
228                         continue;
229                 }
230
231                 SDBG("Remove station MAC : %s\n", si->mac);
232                 _send_dbus_station_info("DhcpLeaseDeleted", si);
233                 g_free(si->hostname);
234                 g_free(si);
235
236                 temp_l = l;
237                 l = g_slist_next(l);
238                 station_list = g_slist_delete_link(station_list, temp_l);
239         }
240
241         count = g_slist_length(station_list);
242         _update_station_count(count);
243
244         return MOBILE_AP_ERROR_NONE;
245 }
246
247 int _get_station_info(gconstpointer data, GCompareFunc func,
248                 mobile_ap_station_info_t **si)
249 {
250         if (func == NULL || si == NULL) {
251                 ERR("Invalid param\n");
252                 return MOBILE_AP_ERROR_INVALID_PARAM;
253         }
254
255         if (station_list == NULL) {
256                 ERR("There is no station\n");
257                 return MOBILE_AP_ERROR_INTERNAL;
258         }
259
260         GSList *l = NULL;
261         mobile_ap_station_info_t *node = NULL;
262
263         l = g_slist_find_custom(station_list, data, func);
264         if (!l) {
265                 ERR("Not found\n");
266                 return MOBILE_AP_ERROR_INTERNAL;
267         }
268
269         node = l->data;
270         SDBG("Found station : %s\n", node->mac);
271         *si = node;
272
273         return MOBILE_AP_ERROR_NONE;
274 }
275
276 int _get_station_count(gconstpointer data, GCompareFunc func, int *count)
277 {
278         if (count == NULL) {
279                 ERR("Invalid param\n");
280                 return MOBILE_AP_ERROR_INVALID_PARAM;
281         }
282
283         GSList *l = station_list;
284         int _count = 0;
285
286         for (_count = 0; l != NULL; _count++, l = g_slist_next(l)) {
287                 l = g_slist_find_custom(l, data, func);
288                 if (l == NULL)
289                         break;
290         }
291
292         *count = _count;
293
294         return MOBILE_AP_ERROR_NONE;
295 }
296
297 GVariant * _station_info_foreach()
298 {
299         GSList *l = NULL;
300         GVariant *params = NULL;
301         GVariantBuilder *inner_builder;
302         GVariantBuilder *outer_builder;
303         mobile_ap_station_info_t *st = NULL;
304
305         outer_builder = g_variant_builder_new(G_VARIANT_TYPE ("a(a{sv})"));
306
307         for (l = station_list; l != NULL; l = g_slist_next(l)) {
308                 st = (mobile_ap_station_info_t *)l->data;
309
310                 inner_builder = g_variant_builder_new(G_VARIANT_TYPE ("a{sv}"));
311                 g_variant_builder_add(inner_builder, "{sv}", "Type",
312                                         g_variant_new_int32(st->interface));
313                 g_variant_builder_add(inner_builder, "{sv}", "IP",
314                                         g_variant_new_string(st->ip));
315                 g_variant_builder_add(inner_builder, "{sv}", "MAC",
316                                         g_variant_new_string(st->mac));
317                 if (st->hostname) {
318                         g_variant_builder_add(inner_builder, "{sv}", "Name",
319                                                 g_variant_new_string(st->hostname));
320                 }
321                 g_variant_builder_add(inner_builder, "{sv}", "Time",
322                                         g_variant_new_int32(st->tm));
323
324                 g_variant_builder_add(outer_builder, "(@a{sv})", g_variant_builder_end(inner_builder));
325
326                 g_variant_builder_unref(inner_builder);
327         }
328
329         params = g_variant_new("(@a(a{sv}))", g_variant_builder_end(outer_builder));
330         if (params == NULL) {
331                 ERR("params IS NULL\n");
332         } else {
333                 SDBG("outer builder print  %s", g_variant_print(params, TRUE));
334         }
335         g_variant_builder_unref(outer_builder);
336         return params;
337 }
338
339 int _add_interface_routing(const char *interface, const in_addr_t gateway)
340 {
341         if (interface == NULL || interface[0] == '\0') {
342                 ERR("Invalid parameter\n");
343                 return MOBILE_AP_ERROR_INVALID_PARAM;
344         }
345
346         char cmd[MAX_BUF_SIZE] = {0, };
347         struct in_addr addr;
348         char *interface_gw;
349         in_addr_t subnet;
350
351         addr.s_addr = htonl(gateway);
352
353         subnet = inet_netof(addr);
354         addr = inet_makeaddr(subnet, 0);
355         interface_gw = inet_ntoa(addr);
356
357         snprintf(cmd, sizeof(cmd), "%s route add "INTERFACE_ROUTING,
358                         IP_CMD, interface_gw, TETHERING_ROUTING_TABLE, interface);
359         if (_execute_command(cmd)) {
360                 ERR("cmd failed : %s\n", cmd);
361                 return MOBILE_AP_ERROR_INTERNAL;
362         }
363
364         return MOBILE_AP_ERROR_NONE;
365 }
366
367 int _del_interface_routing(const char *interface, const in_addr_t gateway)
368 {
369         if (interface == NULL || interface[0] == '\0') {
370                 ERR("Invalid parameter\n");
371                 return MOBILE_AP_ERROR_INVALID_PARAM;
372         }
373
374         char cmd[MAX_BUF_SIZE] = {0, };
375         struct in_addr addr;
376         char *interface_gw;
377         in_addr_t subnet;
378
379         addr.s_addr = htonl(gateway);
380
381         subnet = inet_netof(addr);
382         addr = inet_makeaddr(subnet, 0);
383         interface_gw = inet_ntoa(addr);
384
385         snprintf(cmd, sizeof(cmd), "%s route del "INTERFACE_ROUTING,
386                         IP_CMD, interface_gw, TETHERING_ROUTING_TABLE, interface);
387         if (_execute_command(cmd)) {
388                 ERR("cmd failed : %s\n", cmd);
389                 return MOBILE_AP_ERROR_INTERNAL;
390         }
391
392         return MOBILE_AP_ERROR_NONE;
393 }
394
395 int _add_routing_rule(const char *interface)
396 {
397         if (interface == NULL || interface[0] == '\0') {
398                 ERR("Invalid parameter\n");
399                 return MOBILE_AP_ERROR_INVALID_PARAM;
400         }
401
402         char cmd[MAX_BUF_SIZE] = {0, };
403
404         snprintf(cmd, sizeof(cmd), "%s rule add "SRC_ROUTING_RULE,
405                         IP_CMD, interface, TETHERING_ROUTING_TABLE);
406         if (_execute_command(cmd)) {
407                 ERR("cmd failed : %s\n", cmd);
408                 return MOBILE_AP_ERROR_INTERNAL;
409         }
410
411         return MOBILE_AP_ERROR_NONE;
412 }
413
414 int _del_routing_rule(const char *interface)
415 {
416         if (interface == NULL || interface[0] == '\0') {
417                 ERR("Invalid parameter\n");
418                 return MOBILE_AP_ERROR_INVALID_PARAM;
419         }
420
421         char cmd[MAX_BUF_SIZE] = {0, };
422
423         snprintf(cmd, sizeof(cmd), "%s rule del "SRC_ROUTING_RULE,
424                         IP_CMD, interface, TETHERING_ROUTING_TABLE);
425         if (_execute_command(cmd)) {
426                 ERR("cmd failed : %s\n", cmd);
427                 return MOBILE_AP_ERROR_INTERNAL;
428         }
429
430         return MOBILE_AP_ERROR_NONE;
431 }
432
433 int _flush_ip_address(const char *interface)
434 {
435         if (interface == NULL || interface[0] == '\0') {
436                 ERR("Invalid parameter\n");
437                 return MOBILE_AP_ERROR_INVALID_PARAM;
438         }
439
440         char cmd[MAX_BUF_SIZE] = {0, };
441
442         snprintf(cmd, sizeof(cmd), "%s addr flush dev %s",
443                         IP_CMD, interface);
444         if (_execute_command(cmd)) {
445                 ERR("cmd failed : %s\n", cmd);
446                 return MOBILE_AP_ERROR_INTERNAL;
447         }
448
449         return MOBILE_AP_ERROR_NONE;
450 }
451
452 int _execute_command(const char *cmd)
453 {
454         if (cmd == NULL) {
455                 ERR("Invalid param\n");
456                 return EXIT_FAILURE;
457         }
458
459         int status = 0;
460         int exit_status = 0;
461         pid_t pid = 0;
462         gchar **args = NULL;
463
464         SDBG("CMD : %s\n", cmd);
465
466         args = g_strsplit_set(cmd, " ", -1);
467         if (!args) {
468                 ERR("g_strsplit_set failed\n");
469                 return EXIT_FAILURE;
470         }
471
472         if ((pid = fork()) < 0) {
473                 ERR("fork failed\n");
474                 return EXIT_FAILURE;
475         }
476
477         if (!pid) {
478                 if (execv(args[0], args)) {
479                         ERR("execl failed\n");
480                 }
481
482                 ERR("Should never get here!\n");
483                 return EXIT_FAILURE;
484         } else {
485                 /* Need to add timeout */
486                 waitpid(pid, &status, 0);
487                 g_strfreev(args);
488
489                 if (WIFEXITED(status)) {
490                         exit_status = WEXITSTATUS(status);
491                         if (exit_status) {
492                                 ERR("child return : %d\n", exit_status);
493                                 return EXIT_FAILURE;
494                         }
495                         return EXIT_SUCCESS;
496                 } else {
497                         ERR("child is terminated without exit\n");
498                         return EXIT_FAILURE;
499                 }
500         }
501 }
502
503 int _get_tethering_type_from_ip(const char *ip, mobile_ap_type_e *type)
504 {
505         if (ip == NULL || type == NULL) {
506                 ERR("Invalid param\n");
507                 return MOBILE_AP_ERROR_INVALID_PARAM;
508         }
509
510         static gboolean is_init = FALSE;
511         static in_addr_t subnet_wifi;
512         static in_addr_t subnet_bt_min;
513         static in_addr_t subnet_bt_max;
514         static in_addr_t subnet_usb;
515
516         struct in_addr addr;
517         in_addr_t subnet;
518
519         if (inet_aton(ip, &addr) == 0) {
520                 SERR("Address : %s is invalid\n", ip);
521                 return MOBILE_AP_ERROR_INVALID_PARAM;
522         }
523         subnet = inet_netof(addr);
524
525         if (is_init == FALSE) {
526                 addr.s_addr = htonl(IP_ADDRESS_WIFI);
527                 subnet_wifi = inet_netof(addr);
528
529                 addr.s_addr = htonl(IP_ADDRESS_BT_1);
530                 subnet_bt_min = inet_netof(addr);
531
532                 addr.s_addr = htonl(IP_ADDRESS_BT_7);
533                 subnet_bt_max = inet_netof(addr);
534
535                 addr.s_addr = htonl(IP_ADDRESS_USB);
536                 subnet_usb = inet_netof(addr);
537                 is_init = TRUE;
538         }
539
540         if (subnet == subnet_wifi) {
541                 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
542                         *type = MOBILE_AP_TYPE_WIFI;
543                 else
544                         *type = MOBILE_AP_TYPE_WIFI_AP;
545                 return MOBILE_AP_ERROR_NONE;
546         } else if (subnet >= subnet_bt_min && subnet <= subnet_bt_max) {
547                 *type = MOBILE_AP_TYPE_BT;
548                 return MOBILE_AP_ERROR_NONE;
549         } else if (subnet == subnet_usb) {
550                 *type = MOBILE_AP_TYPE_USB;
551                 return MOBILE_AP_ERROR_NONE;
552         }
553
554         SERR("Tethering type cannot be decided from %s\n", ip);
555
556         return MOBILE_AP_ERROR_INVALID_PARAM;
557 }