4 * Copyright 2012-2013 Samsung Electronics Co., Ltd
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
10 * http://floralicense.org/license
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.
25 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
31 #include <dbus/dbus.h>
32 #include <dbus/dbus-glib.h>
33 #include <dbus/dbus-glib-lowlevel.h>
35 #include "mobileap_notification.h"
36 #include "mobileap_common.h"
38 #define TETHERING_OBJECT_GET_CLASS(obj) \
39 (G_TYPE_INSTANCE_GET_CLASS ((obj), \
40 TETHERING_TYPE_OBJECT , TetheringObjectClass))
42 extern DBusConnection *tethering_conn;
44 static GSList *station_list = NULL;
46 gint _slist_find_station_by_interface(gconstpointer a, gconstpointer b)
48 mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
49 mobile_ap_type_e interface = (mobile_ap_type_e)b;
51 return si->interface - interface;
54 gint _slist_find_station_by_mac(gconstpointer a, gconstpointer b)
56 mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
57 const char *mac = (const char *)b;
59 return g_ascii_strcasecmp(si->mac, mac);
62 gint _slist_find_station_by_ip_addr(gconstpointer a, gconstpointer b)
64 mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
65 const char *ip_addr = (const char *)b;
67 return g_ascii_strcasecmp(si->ip, ip_addr);
70 void _emit_mobileap_dbus_signal(TetheringObject *obj,
71 mobile_ap_sig_e num, const gchar *message)
73 TetheringObjectClass *klass = TETHERING_OBJECT_GET_CLASS(obj);
75 DBG("Emitting signal id [%d], with message [%s]\n", num, message);
76 g_signal_emit(obj, klass->signals[num], 0, message);
79 void _send_dbus_station_info(const char *member, mobile_ap_station_info_t *info)
81 if (tethering_conn == NULL)
84 if (member == NULL || info == NULL) {
85 ERR("Invalid param\n");
89 DBusMessage *msg = NULL;
91 char *mac = info->mac;
92 char *hostname = info->hostname;
94 msg = dbus_message_new_signal(TETHERING_SERVICE_OBJECT_PATH,
95 TETHERING_SERVICE_INTERFACE,
96 SIGNAL_NAME_DHCP_STATUS);
98 ERR("Unable to allocate D-Bus signal\n");
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);
115 dbus_connection_send(tethering_conn, msg, NULL);
116 dbus_message_unref(msg);
122 void _update_station_count(int count)
124 static int prev_cnt = 0;
125 char str[MH_NOTI_STR_MAX] = {0, };
127 if (prev_cnt == count) {
128 DBG("No need to update\n");
132 DBG("Update the number of station : %d\n", count);
133 if (vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_CONNECTED_DEVICE,
135 ERR("Error setting up vconf\n");
141 _delete_connected_noti();
145 snprintf(str, MH_NOTI_STR_MAX, MH_NOTI_STR, count);
147 DBG("Create notification\n");
148 _create_connected_noti(str, MH_NOTI_TITLE, MH_NOTI_ICON_PATH);
150 DBG("Update notification\n");
151 _update_connected_noti(str);
158 int _add_station_info(mobile_ap_station_info_t *info)
161 ERR("Invalid param\n");
162 return MOBILE_AP_ERROR_INVALID_PARAM;
167 mobile_ap_station_info_t *si = NULL;
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;
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);
187 count = g_slist_length(station_list);
188 _update_station_count(count);
190 return MOBILE_AP_ERROR_NONE;
193 int _remove_station_info(gconstpointer data, GCompareFunc func)
196 ERR("Invalid param\n");
197 return MOBILE_AP_ERROR_INVALID_PARAM;
200 if (station_list == NULL) {
201 ERR("There is no station\n");
202 return MOBILE_AP_ERROR_INTERNAL;
206 mobile_ap_station_info_t *si = NULL;
209 l = g_slist_find_custom(station_list, data, func);
212 return MOBILE_AP_ERROR_INTERNAL;
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);
221 count = g_slist_length(station_list);
222 _update_station_count(count);
224 return MOBILE_AP_ERROR_NONE;
227 int _remove_station_info_all(mobile_ap_type_e type)
229 if (station_list == NULL) {
230 return MOBILE_AP_ERROR_NONE;
233 GSList *l = station_list;
234 GSList *temp_l = NULL;
235 mobile_ap_station_info_t *si = NULL;
239 si = (mobile_ap_station_info_t *)l->data;
240 DBG("interface : %d\n", si->interface);
241 if (si->interface != type) {
246 DBG("Remove station MAC : %s\n", si->mac);
247 _send_dbus_station_info("DhcpLeaseDeleted", si);
252 station_list = g_slist_delete_link(station_list, temp_l);
255 count = g_slist_length(station_list);
256 _update_station_count(count);
258 return MOBILE_AP_ERROR_NONE;
261 int _get_station_info(gconstpointer data, GCompareFunc func,
262 mobile_ap_station_info_t **si)
264 if (func == NULL || si == NULL) {
265 ERR("Invalid param\n");
266 return MOBILE_AP_ERROR_INVALID_PARAM;
269 if (station_list == NULL) {
270 ERR("There is no station\n");
271 return MOBILE_AP_ERROR_INTERNAL;
275 mobile_ap_station_info_t *node = NULL;
277 l = g_slist_find_custom(station_list, data, func);
280 return MOBILE_AP_ERROR_INTERNAL;
284 DBG("Found station : %s\n", node->mac);
287 return MOBILE_AP_ERROR_NONE;
290 int _get_station_count(gconstpointer data, GCompareFunc func, int *count)
293 ERR("Invalid param\n");
294 return MOBILE_AP_ERROR_INVALID_PARAM;
297 GSList *l = station_list;
300 for (_count = 0; l != NULL; _count++, l = g_slist_next(l)) {
301 l = g_slist_find_custom(l, data, func);
307 DBG("Station count : %d\n", *count);
309 return MOBILE_AP_ERROR_NONE;
312 int _station_info_foreach(GFunc func, void *user_data)
315 ERR("Invalid param\n");
316 return MOBILE_AP_ERROR_INVALID_PARAM;
319 g_slist_foreach(station_list, func, user_data);
321 return MOBILE_AP_ERROR_NONE;
324 int _add_data_usage_rule(const char *src, const char *dest)
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;
333 char cmd[MAX_BUF_SIZE] = {0, };
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;
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;
351 return MOBILE_AP_ERROR_NONE;
354 int _del_data_usage_rule(const char *src, const char *dest)
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;
363 char cmd[MAX_BUF_SIZE] = {0, };
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;
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;
381 return MOBILE_AP_ERROR_NONE;
384 int _get_data_usage(const char *src, const char *dest,
385 unsigned long long *tx, unsigned long long *rx)
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;
394 char cmd[MAX_BUF_SIZE] = {0, };
395 char buf[MAX_BUF_SIZE] = {0, };
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");
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");
414 fp = fopen(DATA_USAGE_FILE, "r");
416 ERR("%s open failed\n", DATA_USAGE_FILE);
417 ERR("%s\n", strerror(errno));
418 return MOBILE_AP_ERROR_INTERNAL;
421 if (fgets(buf, sizeof(buf), fp) == NULL)
426 if (fgets(buf, sizeof(buf), fp) == NULL)
432 unlink(DATA_USAGE_FILE);
434 return MOBILE_AP_ERROR_NONE;
437 int _execute_command(const char *cmd)
440 ERR("Invalid param\n");
449 DBG("cmd : %s\n", cmd);
451 args = g_strsplit_set(cmd, " ", -1);
453 ERR("g_strsplit_set failed\n");
457 if ((pid = fork()) < 0) {
458 ERR("fork failed\n");
463 if (execv(args[0], args)) {
464 ERR("execl failed\n");
467 ERR("Should never get here!\n");
470 DBG("child pid : %d\n", pid);
472 /* Need to add timeout */
473 waitpid(pid, &status, 0);
476 if (WIFEXITED(status)) {
477 exit_status = WEXITSTATUS(status);
479 ERR("child return : %d\n", exit_status);
482 DBG("child terminated normally\n");
485 ERR("child is terminated without exit\n");
491 int _get_tethering_type_from_ip(const char *ip, mobile_ap_type_e *type)
493 if (ip == NULL || type == NULL) {
494 ERR("Invalid param\n");
495 return MOBILE_AP_ERROR_INVALID_PARAM;
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;
507 if (inet_aton(ip, &addr) == 0) {
508 ERR("Address : %s is invalid\n", ip);
509 return MOBILE_AP_ERROR_INVALID_PARAM;
511 subnet = inet_netof(addr);
513 if (is_init == FALSE) {
514 addr.s_addr = htonl(IP_ADDRESS_WIFI);
515 subnet_wifi = inet_netof(addr);
517 addr.s_addr = htonl(IP_ADDRESS_BT_1);
518 subnet_bt_min = inet_netof(addr);
520 addr.s_addr = htonl(IP_ADDRESS_BT_7);
521 subnet_bt_max = inet_netof(addr);
523 addr.s_addr = htonl(IP_ADDRESS_USB);
524 subnet_usb = inet_netof(addr);
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;
539 ERR("Tethering type cannot be decided from %s\n", ip);
540 return MOBILE_AP_ERROR_INVALID_PARAM;