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>
30 #include <dbus/dbus-glib.h>
31 #include <dbus/dbus-glib-lowlevel.h>
33 #include "mobileap_notification.h"
34 #include "mobileap_common.h"
36 #define TETHERING_OBJECT_GET_CLASS(obj) \
37 (G_TYPE_INSTANCE_GET_CLASS ((obj), \
38 TETHERING_TYPE_OBJECT , TetheringObjectClass))
40 extern DBusConnection *tethering_conn;
42 static GSList *station_list = NULL;
44 gint _slist_find_station_by_interface(gconstpointer a, gconstpointer b)
46 mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
47 mobile_ap_type_e interface = (mobile_ap_type_e)b;
49 return si->interface - interface;
52 gint _slist_find_station_by_mac(gconstpointer a, gconstpointer b)
54 mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
55 const char *mac = (const char *)b;
57 return g_ascii_strcasecmp(si->mac, mac);
60 gint _slist_find_station_by_ip_addr(gconstpointer a, gconstpointer b)
62 mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
63 const char *ip_addr = (const char *)b;
65 return g_ascii_strcasecmp(si->ip, ip_addr);
68 void _emit_mobileap_dbus_signal(TetheringObject *obj,
69 mobile_ap_sig_e num, const gchar *message)
71 TetheringObjectClass *klass = TETHERING_OBJECT_GET_CLASS(obj);
73 DBG("Emitting signal id [%d], with message [%s]\n", num, message);
74 g_signal_emit(obj, klass->signals[num], 0, message);
77 void _send_dbus_station_info(const char *member, mobile_ap_station_info_t *info)
79 if (tethering_conn == NULL)
82 if (member == NULL || info == NULL) {
83 ERR("Invalid param\n");
87 DBusMessage *msg = NULL;
89 char *mac = info->mac;
90 char *hostname = info->hostname;
92 msg = dbus_message_new_signal(TETHERING_SERVICE_OBJECT_PATH,
93 TETHERING_SERVICE_INTERFACE,
94 SIGNAL_NAME_DHCP_STATUS);
96 ERR("Unable to allocate D-Bus signal\n");
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);
113 dbus_connection_send(tethering_conn, msg, NULL);
114 dbus_message_unref(msg);
120 void _update_station_count(int count)
122 static int prev_cnt = 0;
123 char str[MH_NOTI_STR_MAX] = {0, };
125 if (prev_cnt == count) {
126 DBG("No need to update\n");
130 DBG("Update the number of station : %d\n", count);
131 if (vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_CONNECTED_DEVICE,
133 ERR("Error setting up vconf\n");
139 _delete_connected_noti();
143 snprintf(str, MH_NOTI_STR_MAX, MH_NOTI_STR, count);
145 DBG("Create notification\n");
146 _create_connected_noti(str, MH_NOTI_TITLE, MH_NOTI_ICON_PATH);
148 DBG("Update notification\n");
149 _update_connected_noti(str);
156 int _add_station_info(mobile_ap_station_info_t *info)
159 ERR("Invalid param\n");
160 return MOBILE_AP_ERROR_INVALID_PARAM;
165 mobile_ap_station_info_t *si = NULL;
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;
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);
185 count = g_slist_length(station_list);
186 _update_station_count(count);
188 return MOBILE_AP_ERROR_NONE;
191 int _remove_station_info(gconstpointer data, GCompareFunc func)
194 ERR("Invalid param\n");
195 return MOBILE_AP_ERROR_INVALID_PARAM;
198 if (station_list == NULL) {
199 ERR("There is no station\n");
200 return MOBILE_AP_ERROR_INTERNAL;
204 mobile_ap_station_info_t *si = NULL;
207 l = g_slist_find_custom(station_list, data, func);
210 return MOBILE_AP_ERROR_INTERNAL;
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);
219 count = g_slist_length(station_list);
220 _update_station_count(count);
222 return MOBILE_AP_ERROR_NONE;
225 int _remove_station_info_all(mobile_ap_type_e type)
227 if (station_list == NULL) {
228 return MOBILE_AP_ERROR_NONE;
231 GSList *l = station_list;
232 GSList *temp_l = NULL;
233 mobile_ap_station_info_t *si = NULL;
237 si = (mobile_ap_station_info_t *)l->data;
238 DBG("interface : %d\n", si->interface);
239 if (si->interface != type) {
244 DBG("Remove station MAC : %s\n", si->mac);
245 _send_dbus_station_info("DhcpLeaseDeleted", si);
250 station_list = g_slist_delete_link(station_list, temp_l);
253 count = g_slist_length(station_list);
254 _update_station_count(count);
256 return MOBILE_AP_ERROR_NONE;
259 int _get_station_info(gconstpointer data, GCompareFunc func,
260 mobile_ap_station_info_t **si)
262 if (func == NULL || si == NULL) {
263 ERR("Invalid param\n");
264 return MOBILE_AP_ERROR_INVALID_PARAM;
267 if (station_list == NULL) {
268 ERR("There is no station\n");
269 return MOBILE_AP_ERROR_INTERNAL;
273 mobile_ap_station_info_t *node = NULL;
275 l = g_slist_find_custom(station_list, data, func);
278 return MOBILE_AP_ERROR_INTERNAL;
282 DBG("Found station : %s\n", node->mac);
285 return MOBILE_AP_ERROR_NONE;
288 int _get_station_count(gconstpointer data, GCompareFunc func, int *count)
291 ERR("Invalid param\n");
292 return MOBILE_AP_ERROR_INVALID_PARAM;
295 GSList *l = station_list;
298 for (_count = 0; l != NULL; _count++, l = g_slist_next(l)) {
299 l = g_slist_find_custom(l, data, func);
305 DBG("Station count : %d\n", *count);
307 return MOBILE_AP_ERROR_NONE;
310 int _station_info_foreach(GFunc func, void *user_data)
313 ERR("Invalid param\n");
314 return MOBILE_AP_ERROR_INVALID_PARAM;
317 g_slist_foreach(station_list, func, user_data);
319 return MOBILE_AP_ERROR_NONE;
322 int _add_data_usage_rule(const char *src, const char *dest)
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;
331 char cmd[MAX_BUF_SIZE] = {0, };
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;
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;
349 return MOBILE_AP_ERROR_NONE;
352 int _del_data_usage_rule(const char *src, const char *dest)
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;
361 char cmd[MAX_BUF_SIZE] = {0, };
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;
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;
379 return MOBILE_AP_ERROR_NONE;
382 int _get_data_usage(const char *src, const char *dest,
383 unsigned long long *tx, unsigned long long *rx)
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;
392 char cmd[MAX_BUF_SIZE] = {0, };
393 char buf[MAX_BUF_SIZE] = {0, };
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");
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");
412 fp = fopen(DATA_USAGE_FILE, "r");
414 ERR("%s open failed\n", DATA_USAGE_FILE);
415 ERR("%s\n", strerror(errno));
416 return MOBILE_AP_ERROR_INTERNAL;
419 if (fgets(buf, sizeof(buf), fp) == NULL)
424 if (fgets(buf, sizeof(buf), fp) == NULL)
430 unlink(DATA_USAGE_FILE);
432 return MOBILE_AP_ERROR_NONE;
435 int _execute_command(const char *cmd)
438 ERR("Invalid param\n");
447 DBG("cmd : %s\n", cmd);
449 args = g_strsplit_set(cmd, " ", -1);
451 ERR("g_strsplit_set failed\n");
455 if ((pid = fork()) < 0) {
456 ERR("fork failed\n");
461 if (execv(args[0], args)) {
462 ERR("execl failed\n");
465 ERR("Should never get here!\n");
468 DBG("child pid : %d\n", pid);
470 /* Need to add timeout */
471 waitpid(pid, &status, 0);
474 if (WIFEXITED(status)) {
475 exit_status = WEXITSTATUS(status);
477 ERR("child return : %d\n", exit_status);
480 DBG("child terminated normally\n");
483 ERR("child is terminated without exit\n");
489 int _get_tethering_type_from_ip(const char *ip, mobile_ap_type_e *type)
491 if (ip == NULL || type == NULL) {
492 ERR("Invalid param\n");
493 return MOBILE_AP_ERROR_INVALID_PARAM;
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;
505 if (inet_aton(ip, &addr) == 0) {
506 ERR("Address : %s is invalid\n", ip);
507 return MOBILE_AP_ERROR_INVALID_PARAM;
509 subnet = inet_netof(addr);
511 if (is_init == FALSE) {
512 addr.s_addr = htonl(IP_ADDRESS_WIFI);
513 subnet_wifi = inet_netof(addr);
515 addr.s_addr = htonl(IP_ADDRESS_BT_1);
516 subnet_bt_min = inet_netof(addr);
518 addr.s_addr = htonl(IP_ADDRESS_BT_7);
519 subnet_bt_max = inet_netof(addr);
521 addr.s_addr = htonl(IP_ADDRESS_USB);
522 subnet_usb = inet_netof(addr);
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;
537 ERR("Tethering type cannot be decided from %s\n", ip);
538 return MOBILE_AP_ERROR_INVALID_PARAM;