3 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
29 #include <dbus/dbus.h>
31 #include "mobileap_notification.h"
32 #include "mobileap_common.h"
34 static GSList *station_list = NULL;
36 gint _slist_find_station_by_interface(gconstpointer a, gconstpointer b)
38 mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
39 mobile_ap_type_e interface = (mobile_ap_type_e)b;
41 return si->interface - interface;
44 gint _slist_find_station_by_mac(gconstpointer a, gconstpointer b)
46 mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
47 const char *mac = (const char *)b;
49 return g_ascii_strcasecmp(si->mac, mac);
52 gint _slist_find_station_by_ip_addr(gconstpointer a, gconstpointer b)
54 mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
55 const char *ip_addr = (const char *)b;
57 return g_ascii_strcasecmp(si->ip, ip_addr);
60 void _send_dbus_station_info(const char *member, mobile_ap_station_info_t *info)
64 if (member == NULL || info == NULL) {
65 ERR("Invalid param\n");
68 Tethering *obj = _get_tethering_obj();
70 ERR("tethering object is null\n");
73 DBG("signal is %s", member);
74 tethering_emit_dhcp_status(obj, member, info->interface, info->ip, info->mac,
75 info->hostname, info->tm);
79 void _update_station_count(int count)
81 static int prev_cnt = 0;
82 char icon_path[MH_NOTI_PATH_MAX] = {0, };
87 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) {
91 if (prev_cnt == count) {
95 if (vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_CONNECTED_DEVICE,
97 ERR("Error setting up vconf\n");
103 _delete_connected_noti();
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);
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) {
120 g_strlcpy(icon_path, MH_NOTI_ICON_GENERAL, sizeof(icon_path));
124 _create_connected_noti(count, icon_path);
126 _update_connected_noti(count, icon_path);
133 int _add_station_info(mobile_ap_station_info_t *info)
136 ERR("Invalid param\n");
137 return MOBILE_AP_ERROR_INVALID_PARAM;
142 mobile_ap_station_info_t *si = NULL;
145 if (_get_station_info(info->mac, _slist_find_station_by_mac, &si) ==
146 MOBILE_AP_ERROR_NONE) {
148 return MOBILE_AP_ERROR_INTERNAL;
151 if (g_strcmp0(si->hostname, info->hostname) == 0 &&
152 g_strcmp0(si->ip, info->ip) == 0) {
153 return MOBILE_AP_ERROR_INTERNAL;
156 _remove_station_info(si->mac, _slist_find_station_by_mac);
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);
170 count = g_slist_length(station_list);
171 _update_station_count(count);
173 return MOBILE_AP_ERROR_NONE;
176 int _remove_station_info(gconstpointer data, GCompareFunc func)
179 ERR("Invalid param\n");
180 return MOBILE_AP_ERROR_INVALID_PARAM;
183 if (station_list == NULL) {
184 ERR("There is no station\n");
185 return MOBILE_AP_ERROR_INTERNAL;
189 mobile_ap_station_info_t *si = NULL;
192 l = g_slist_find_custom(station_list, data, func);
195 return MOBILE_AP_ERROR_INTERNAL;
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);
205 count = g_slist_length(station_list);
206 _update_station_count(count);
208 return MOBILE_AP_ERROR_NONE;
211 int _remove_station_info_all(mobile_ap_type_e type)
213 if (station_list == NULL) {
214 return MOBILE_AP_ERROR_NONE;
217 GSList *l = station_list;
218 GSList *temp_l = NULL;
219 mobile_ap_station_info_t *si = NULL;
222 _flush_dhcp_ack_timer();
225 si = (mobile_ap_station_info_t *)l->data;
226 if (si->interface != type) {
231 SDBG("Remove station MAC : %s\n", si->mac);
232 _send_dbus_station_info("DhcpLeaseDeleted", si);
233 g_free(si->hostname);
238 station_list = g_slist_delete_link(station_list, temp_l);
241 count = g_slist_length(station_list);
242 _update_station_count(count);
244 return MOBILE_AP_ERROR_NONE;
247 int _get_station_info(gconstpointer data, GCompareFunc func,
248 mobile_ap_station_info_t **si)
250 if (func == NULL || si == NULL) {
251 ERR("Invalid param\n");
252 return MOBILE_AP_ERROR_INVALID_PARAM;
255 if (station_list == NULL) {
256 ERR("There is no station\n");
257 return MOBILE_AP_ERROR_INTERNAL;
261 mobile_ap_station_info_t *node = NULL;
263 l = g_slist_find_custom(station_list, data, func);
266 return MOBILE_AP_ERROR_INTERNAL;
270 SDBG("Found station : %s\n", node->mac);
273 return MOBILE_AP_ERROR_NONE;
276 int _get_station_count(gconstpointer data, GCompareFunc func, int *count)
279 ERR("Invalid param\n");
280 return MOBILE_AP_ERROR_INVALID_PARAM;
283 GSList *l = station_list;
286 for (_count = 0; l != NULL; _count++, l = g_slist_next(l)) {
287 l = g_slist_find_custom(l, data, func);
294 return MOBILE_AP_ERROR_NONE;
297 GVariant * _station_info_foreach()
300 GVariant *params = NULL;
301 GVariantBuilder *inner_builder;
302 GVariantBuilder *outer_builder;
303 mobile_ap_station_info_t *st = NULL;
305 outer_builder = g_variant_builder_new(G_VARIANT_TYPE ("a(a{sv})"));
307 for (l = station_list; l != NULL; l = g_slist_next(l)) {
308 st = (mobile_ap_station_info_t *)l->data;
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));
318 g_variant_builder_add(inner_builder, "{sv}", "Name",
319 g_variant_new_string(st->hostname));
321 g_variant_builder_add(inner_builder, "{sv}", "Time",
322 g_variant_new_int32(st->tm));
324 g_variant_builder_add(outer_builder, "(@a{sv})", g_variant_builder_end(inner_builder));
326 g_variant_builder_unref(inner_builder);
329 params = g_variant_new("(@a(a{sv}))", g_variant_builder_end(outer_builder));
330 if (params == NULL) {
331 ERR("params IS NULL\n");
333 SDBG("outer builder print %s", g_variant_print(params, TRUE));
335 g_variant_builder_unref(outer_builder);
339 int _add_interface_routing(const char *interface, const in_addr_t gateway)
341 if (interface == NULL || interface[0] == '\0') {
342 ERR("Invalid parameter\n");
343 return MOBILE_AP_ERROR_INVALID_PARAM;
346 char cmd[MAX_BUF_SIZE] = {0, };
351 addr.s_addr = htonl(gateway);
353 subnet = inet_netof(addr);
354 addr = inet_makeaddr(subnet, 0);
355 interface_gw = inet_ntoa(addr);
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;
364 return MOBILE_AP_ERROR_NONE;
367 int _del_interface_routing(const char *interface, const in_addr_t gateway)
369 if (interface == NULL || interface[0] == '\0') {
370 ERR("Invalid parameter\n");
371 return MOBILE_AP_ERROR_INVALID_PARAM;
374 char cmd[MAX_BUF_SIZE] = {0, };
379 addr.s_addr = htonl(gateway);
381 subnet = inet_netof(addr);
382 addr = inet_makeaddr(subnet, 0);
383 interface_gw = inet_ntoa(addr);
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;
392 return MOBILE_AP_ERROR_NONE;
395 int _add_routing_rule(const char *interface)
397 if (interface == NULL || interface[0] == '\0') {
398 ERR("Invalid parameter\n");
399 return MOBILE_AP_ERROR_INVALID_PARAM;
402 char cmd[MAX_BUF_SIZE] = {0, };
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;
411 return MOBILE_AP_ERROR_NONE;
414 int _del_routing_rule(const char *interface)
416 if (interface == NULL || interface[0] == '\0') {
417 ERR("Invalid parameter\n");
418 return MOBILE_AP_ERROR_INVALID_PARAM;
421 char cmd[MAX_BUF_SIZE] = {0, };
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;
430 return MOBILE_AP_ERROR_NONE;
433 int _flush_ip_address(const char *interface)
435 if (interface == NULL || interface[0] == '\0') {
436 ERR("Invalid parameter\n");
437 return MOBILE_AP_ERROR_INVALID_PARAM;
440 char cmd[MAX_BUF_SIZE] = {0, };
442 snprintf(cmd, sizeof(cmd), "%s addr flush dev %s",
444 if (_execute_command(cmd)) {
445 ERR("cmd failed : %s\n", cmd);
446 return MOBILE_AP_ERROR_INTERNAL;
449 return MOBILE_AP_ERROR_NONE;
452 int _execute_command(const char *cmd)
455 ERR("Invalid param\n");
464 SDBG("CMD : %s\n", cmd);
466 args = g_strsplit_set(cmd, " ", -1);
468 ERR("g_strsplit_set failed\n");
472 if ((pid = fork()) < 0) {
473 ERR("fork failed\n");
478 if (execv(args[0], args)) {
479 ERR("execl failed\n");
482 ERR("Should never get here!\n");
485 /* Need to add timeout */
486 waitpid(pid, &status, 0);
489 if (WIFEXITED(status)) {
490 exit_status = WEXITSTATUS(status);
492 ERR("child return : %d\n", exit_status);
497 ERR("child is terminated without exit\n");
503 int _get_tethering_type_from_ip(const char *ip, mobile_ap_type_e *type)
505 if (ip == NULL || type == NULL) {
506 ERR("Invalid param\n");
507 return MOBILE_AP_ERROR_INVALID_PARAM;
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;
519 if (inet_aton(ip, &addr) == 0) {
520 SERR("Address : %s is invalid\n", ip);
521 return MOBILE_AP_ERROR_INVALID_PARAM;
523 subnet = inet_netof(addr);
525 if (is_init == FALSE) {
526 addr.s_addr = htonl(IP_ADDRESS_WIFI);
527 subnet_wifi = inet_netof(addr);
529 addr.s_addr = htonl(IP_ADDRESS_BT_1);
530 subnet_bt_min = inet_netof(addr);
532 addr.s_addr = htonl(IP_ADDRESS_BT_7);
533 subnet_bt_max = inet_netof(addr);
535 addr.s_addr = htonl(IP_ADDRESS_USB);
536 subnet_usb = inet_netof(addr);
540 if (subnet == subnet_wifi) {
541 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
542 *type = MOBILE_AP_TYPE_WIFI;
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;
554 SERR("Tethering type cannot be decided from %s\n", ip);
556 return MOBILE_AP_ERROR_INVALID_PARAM;