4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hocheol Seo <hocheol.seo@samsung.com>,
7 * Injun Yang <injun.yang@samsung.com>,
8 * Seungyoun Ju <sy39.ju@samsung.com>
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
14 * http://www.apache.org/licenses/LICENSE-2.0
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.
29 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
35 #include <dbus/dbus.h>
36 #include <dbus/dbus-glib.h>
37 #include <dbus/dbus-glib-lowlevel.h>
39 #include "mobileap_notification.h"
40 #include "mobileap_common.h"
42 #define MOBILEAP_OBJECT_GET_CLASS(obj) \
43 (G_TYPE_INSTANCE_GET_CLASS ((obj), \
44 MOBILEAP_TYPE_OBJECT , MobileAPObjectClass))
46 extern DBusConnection *mobileap_conn;
48 static GSList *station_list = NULL;;
50 gint _slist_find_station_by_interface(gconstpointer a, gconstpointer b)
52 mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
53 mobile_ap_type_e interface = (mobile_ap_type_e)b;
55 return si->interface - interface;
58 gint _slist_find_station_by_mac(gconstpointer a, gconstpointer b)
60 mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
61 const char *mac = (const char *)b;
63 return g_ascii_strcasecmp(si->mac, mac);
66 void _emit_mobileap_dbus_signal(MobileAPObject *obj,
67 mobile_ap_sig_e num, const gchar *message)
69 MobileAPObjectClass *klass = MOBILEAP_OBJECT_GET_CLASS(obj);
71 DBG("Emitting signal id [%d], with message [%s]\n", num, message);
72 g_signal_emit(obj, klass->signals[num], 0, message);
75 void _send_dbus_station_info(const char *member, mobile_ap_station_info_t *info)
77 if (mobileap_conn == NULL)
80 if (member == NULL || info == NULL) {
81 ERR("Invalid param\n");
85 DBusMessage *msg = NULL;
87 char *mac = info->mac;
88 char *hostname = info->hostname;
90 msg = dbus_message_new_signal("/MobileAP",
91 "com.samsung.mobileap",
92 SIGNAL_NAME_DHCP_STATUS);
94 ERR("Unable to allocate D-Bus signal\n");
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);
110 dbus_connection_send(mobileap_conn, msg, NULL);
111 dbus_message_unref(msg);
117 void _update_station_count(int count)
119 static int prev_cnt = 0;
120 char str[MH_NOTI_STR_MAX] = {0, };
122 if (prev_cnt == count) {
123 DBG("No need to update\n");
127 DBG("Update the number of station : %d\n", count);
128 if (vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_CONNECTED_DEVICE,
130 ERR("Error setting up vconf\n");
136 _delete_notification();
140 snprintf(str, MH_NOTI_STR_MAX, MH_NOTI_STR, count);
142 DBG("Create notification\n");
143 _create_notification(str, MH_NOTI_TITLE, MH_NOTI_ICON_PATH);
145 DBG("Update notification\n");
146 _update_notification(str);
153 int _add_station_info(mobile_ap_station_info_t *info)
156 ERR("Invalid param\n");
157 return MOBILE_AP_ERROR_INVALID_PARAM;
162 mobile_ap_station_info_t *si = NULL;
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);
175 count = g_slist_length(station_list);
176 _update_station_count(count);
178 return MOBILE_AP_ERROR_NONE;
181 int _remove_station_info(gconstpointer data, GCompareFunc func)
184 ERR("Invalid param\n");
185 return MOBILE_AP_ERROR_INVALID_PARAM;
188 if (station_list == NULL) {
189 ERR("There is no station\n");
190 return MOBILE_AP_ERROR_INTERNAL;
194 mobile_ap_station_info_t *si = NULL;
197 l = g_slist_find_custom(station_list, data, func);
200 return MOBILE_AP_ERROR_INTERNAL;
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);
209 count = g_slist_length(station_list);
210 _update_station_count(count);
212 return MOBILE_AP_ERROR_NONE;
215 int _remove_station_info_all(mobile_ap_type_e type)
217 if (station_list == NULL) {
218 return MOBILE_AP_ERROR_NONE;
221 GSList *l = station_list;
222 GSList *temp_l = NULL;
223 mobile_ap_station_info_t *si = NULL;
227 si = (mobile_ap_station_info_t *)l->data;
228 DBG("interface : %d\n", si->interface);
229 if (si->interface != type) {
234 DBG("Remove station MAC : %s\n", si->mac);
235 _send_dbus_station_info("DhcpLeaseDeleted", si);
240 station_list = g_slist_delete_link(station_list, temp_l);
243 count = g_slist_length(station_list);
244 _update_station_count(count);
246 return MOBILE_AP_ERROR_NONE;
249 int _get_station_info(gconstpointer data, GCompareFunc func,
250 mobile_ap_station_info_t **si)
252 if (func == NULL || si == NULL) {
253 ERR("Invalid param\n");
254 return MOBILE_AP_ERROR_INVALID_PARAM;
257 if (station_list == NULL) {
258 ERR("There is no station\n");
259 return MOBILE_AP_ERROR_INTERNAL;
263 mobile_ap_station_info_t *node = NULL;
265 l = g_slist_find_custom(station_list, data, func);
268 return MOBILE_AP_ERROR_INTERNAL;
272 DBG("Found station : %s\n", node->mac);
275 return MOBILE_AP_ERROR_NONE;
278 int _get_station_count(int *count)
281 ERR("Invalid param\n");
282 return MOBILE_AP_ERROR_INVALID_PARAM;
285 *count = g_slist_length(station_list);
287 return MOBILE_AP_ERROR_NONE;
290 int _station_info_foreach(GFunc func, void *user_data)
293 ERR("Invalid param\n");
294 return MOBILE_AP_ERROR_INVALID_PARAM;
297 g_slist_foreach(station_list, func, user_data);
299 return MOBILE_AP_ERROR_NONE;
302 int _add_data_usage_rule(const char *src, const char *dest)
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;
311 char cmd[MAX_BUF_SIZE] = {0, };
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;
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;
329 return MOBILE_AP_ERROR_NONE;
332 int _del_data_usage_rule(const char *src, const char *dest)
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;
341 char cmd[MAX_BUF_SIZE] = {0, };
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;
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;
359 return MOBILE_AP_ERROR_NONE;
362 int _get_data_usage(const char *src, const char *dest,
363 unsigned long long *tx, unsigned long long *rx)
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;
372 char cmd[MAX_BUF_SIZE] = {0, };
373 char buf[MAX_BUF_SIZE] = {0, };
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");
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");
394 fp = fopen(DATA_USAGE_FILE, "r");
396 ERR("%s open failed\n", DATA_USAGE_FILE);
397 ERR("%s\n", strerror(errno));
398 return MOBILE_AP_ERROR_INTERNAL;
401 if (fgets(buf, sizeof(buf), fp) == NULL)
405 DBG("Tx(%s -> %s) : %llu\n", src, dest, *tx);
407 if (fgets(buf, sizeof(buf), fp) == NULL)
411 DBG("Rx(%s -> %s) : %llu\n", dest, src, *rx);
414 unlink(DATA_USAGE_FILE);
416 return MOBILE_AP_ERROR_NONE;
419 int _execute_command(const char *cmd)
422 ERR("Invalid param\n");
431 DBG("cmd : %s\n", cmd);
433 args = g_strsplit_set(cmd, " ", -1);
435 ERR("g_strsplit_set failed\n");
439 if ((pid = fork()) < 0) {
440 ERR("fork failed\n");
445 if (execv(args[0], args)) {
446 ERR("execl failed\n");
449 ERR("Should never get here!\n");
452 DBG("child pid : %d\n", pid);
454 /* Need to add timeout */
455 waitpid(pid, &status, 0);
458 if (WIFEXITED(status)) {
459 exit_status = WEXITSTATUS(status);
461 ERR("child return : %d\n", exit_status);
464 DBG("child terminated normally\n");
467 ERR("child is terminated without exit\n");
473 int _get_tethering_type_from_ip(const char *ip, mobile_ap_type_e *type)
475 if (ip == NULL || type == NULL) {
476 ERR("Invalid param\n");
477 return MOBILE_AP_ERROR_INVALID_PARAM;
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;
489 if (inet_aton(ip, &addr) == 0) {
490 ERR("Address : %s is invalid\n", ip);
491 return MOBILE_AP_ERROR_INVALID_PARAM;
493 subnet = inet_netof(addr);
495 if (is_init == FALSE) {
496 addr.s_addr = htonl(IP_ADDRESS_WIFI);
497 subnet_wifi = inet_netof(addr);
499 addr.s_addr = htonl(IP_ADDRESS_BT_1);
500 subnet_bt_min = inet_netof(addr);
502 addr.s_addr = htonl(IP_ADDRESS_BT_7);
503 subnet_bt_max = inet_netof(addr);
505 addr.s_addr = htonl(IP_ADDRESS_USB);
506 subnet_usb = inet_netof(addr);
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;
521 ERR("Tethering type cannot be decided from %s\n", ip);
522 return MOBILE_AP_ERROR_INVALID_PARAM;