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 MOBILEAP_OBJECT_GET_CLASS(obj) \
37 (G_TYPE_INSTANCE_GET_CLASS ((obj), \
38 MOBILEAP_TYPE_OBJECT , MobileAPObjectClass))
40 extern DBusConnection *mobileap_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(MobileAPObject *obj,
69 mobile_ap_sig_e num, const gchar *message)
71 MobileAPObjectClass *klass = MOBILEAP_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 (mobileap_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("/MobileAP",
93 "com.samsung.mobileap",
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_INVALID)) {
107 ERR("Event sending failed\n");
108 dbus_message_unref(msg);
112 dbus_connection_send(mobileap_conn, msg, NULL);
113 dbus_message_unref(msg);
119 void _update_station_count(int count)
121 static int prev_cnt = 0;
122 char str[MH_NOTI_STR_MAX] = {0, };
124 if (prev_cnt == count) {
125 DBG("No need to update\n");
129 DBG("Update the number of station : %d\n", count);
130 if (vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_CONNECTED_DEVICE,
132 ERR("Error setting up vconf\n");
138 _delete_connected_noti();
142 snprintf(str, MH_NOTI_STR_MAX, MH_NOTI_STR, count);
144 DBG("Create notification\n");
145 _create_connected_noti(str, MH_NOTI_TITLE, MH_NOTI_ICON_PATH);
147 DBG("Update notification\n");
148 _update_connected_noti(str);
155 int _add_station_info(mobile_ap_station_info_t *info)
158 ERR("Invalid param\n");
159 return MOBILE_AP_ERROR_INVALID_PARAM;
164 mobile_ap_station_info_t *si = NULL;
167 if (_get_station_info(info->mac, _slist_find_station_by_mac, &si) ==
168 MOBILE_AP_ERROR_NONE) {
169 DBG("Already exist station : %s\n", info->mac);
170 return MOBILE_AP_ERROR_INTERNAL;
173 station_list = g_slist_append(station_list, info);
174 for (l = station_list; l != NULL; l = g_slist_next(l)) {
175 si = (mobile_ap_station_info_t *)l->data;
176 DBG("[%d] interface : %d\n", i, si->interface);
177 DBG("[%d] station MAC : %s\n", i, si->mac);
178 DBG("[%d] station Hostname : %s\n", i, si->hostname);
179 DBG("[%d] station IP : %s\n", i, si->ip);
183 count = g_slist_length(station_list);
184 _update_station_count(count);
186 return MOBILE_AP_ERROR_NONE;
189 int _remove_station_info(gconstpointer data, GCompareFunc func)
192 ERR("Invalid param\n");
193 return MOBILE_AP_ERROR_INVALID_PARAM;
196 if (station_list == NULL) {
197 ERR("There is no station\n");
198 return MOBILE_AP_ERROR_INTERNAL;
202 mobile_ap_station_info_t *si = NULL;
205 l = g_slist_find_custom(station_list, data, func);
208 return MOBILE_AP_ERROR_INTERNAL;
211 si = (mobile_ap_station_info_t *)l->data;
212 DBG("Remove station MAC : %s\n", si->mac);
213 station_list = g_slist_delete_link(station_list, l);
214 _send_dbus_station_info("DhcpLeaseDeleted", si);
217 count = g_slist_length(station_list);
218 _update_station_count(count);
220 return MOBILE_AP_ERROR_NONE;
223 int _remove_station_info_all(mobile_ap_type_e type)
225 if (station_list == NULL) {
226 return MOBILE_AP_ERROR_NONE;
229 GSList *l = station_list;
230 GSList *temp_l = NULL;
231 mobile_ap_station_info_t *si = NULL;
235 si = (mobile_ap_station_info_t *)l->data;
236 DBG("interface : %d\n", si->interface);
237 if (si->interface != type) {
242 DBG("Remove station MAC : %s\n", si->mac);
243 _send_dbus_station_info("DhcpLeaseDeleted", si);
248 station_list = g_slist_delete_link(station_list, temp_l);
251 count = g_slist_length(station_list);
252 _update_station_count(count);
254 return MOBILE_AP_ERROR_NONE;
257 int _get_station_info(gconstpointer data, GCompareFunc func,
258 mobile_ap_station_info_t **si)
260 if (func == NULL || si == NULL) {
261 ERR("Invalid param\n");
262 return MOBILE_AP_ERROR_INVALID_PARAM;
265 if (station_list == NULL) {
266 ERR("There is no station\n");
267 return MOBILE_AP_ERROR_INTERNAL;
271 mobile_ap_station_info_t *node = NULL;
273 l = g_slist_find_custom(station_list, data, func);
276 return MOBILE_AP_ERROR_INTERNAL;
280 DBG("Found station : %s\n", node->mac);
283 return MOBILE_AP_ERROR_NONE;
286 int _get_station_count(gconstpointer data, GCompareFunc func, int *count)
289 ERR("Invalid param\n");
290 return MOBILE_AP_ERROR_INVALID_PARAM;
293 GSList *l = station_list;
296 for (_count = 0; l != NULL; _count++, l = g_slist_next(l)) {
297 l = g_slist_find_custom(l, data, func);
303 DBG("Station count : %d\n", *count);
305 return MOBILE_AP_ERROR_NONE;
308 int _station_info_foreach(GFunc func, void *user_data)
311 ERR("Invalid param\n");
312 return MOBILE_AP_ERROR_INVALID_PARAM;
315 g_slist_foreach(station_list, func, user_data);
317 return MOBILE_AP_ERROR_NONE;
320 int _add_data_usage_rule(const char *src, const char *dest)
322 if (src == NULL || src[0] == '\0' ||
323 dest == NULL || dest[0] == '\0' ||
324 g_strcmp0(src, dest) == 0) {
325 ERR("Invalid parameter\n");
326 return MOBILE_AP_ERROR_INVALID_PARAM;
329 char cmd[MAX_BUF_SIZE] = {0, };
331 snprintf(cmd, sizeof(cmd), "%s -A FORWARD "FORWARD_RULE,
332 IPTABLES, src, dest);
333 DBG("ADD IPTABLES RULE : %s\n", cmd);
334 if (_execute_command(cmd)) {
335 ERR("iptables failed : %s\n", cmd);
336 return MOBILE_AP_ERROR_INTERNAL;
339 snprintf(cmd, sizeof(cmd), "%s -A FORWARD "FORWARD_RULE,
340 IPTABLES, dest, src);
341 DBG("ADD IPTABLES RULE : %s\n", cmd);
342 if (_execute_command(cmd)) {
343 ERR("iptables failed : %s\n", cmd);
344 return MOBILE_AP_ERROR_INTERNAL;
347 return MOBILE_AP_ERROR_NONE;
350 int _del_data_usage_rule(const char *src, const char *dest)
352 if (src == NULL || src[0] == '\0' ||
353 dest == NULL || dest[0] == '\0' ||
354 g_strcmp0(src, dest) == 0) {
355 ERR("Invalid parameter\n");
356 return MOBILE_AP_ERROR_INVALID_PARAM;
359 char cmd[MAX_BUF_SIZE] = {0, };
361 snprintf(cmd, sizeof(cmd), "%s -D FORWARD "FORWARD_RULE,
362 IPTABLES, src, dest);
363 DBG("REMOVE IPTABLES RULE : %s\n", cmd);
364 if (_execute_command(cmd)) {
365 ERR("iptables failed : %s\n", cmd);
366 return MOBILE_AP_ERROR_INTERNAL;
369 snprintf(cmd, sizeof(cmd), "%s -D FORWARD "FORWARD_RULE,
370 IPTABLES, dest, src);
371 DBG("REMOVE IPTABLES RULE : %s\n", cmd);
372 if (_execute_command(cmd)) {
373 ERR("iptables failed : %s\n", cmd);
374 return MOBILE_AP_ERROR_INTERNAL;
377 return MOBILE_AP_ERROR_NONE;
380 int _get_data_usage(const char *src, const char *dest,
381 unsigned long long *tx, unsigned long long *rx)
383 if (src == NULL || src[0] == '\0' ||
384 dest == NULL || dest[0] == '\0' ||
385 tx == NULL || rx == NULL) {
386 ERR("Invalid parameter\n");
387 return MOBILE_AP_ERROR_INVALID_PARAM;
390 char cmd[MAX_BUF_SIZE] = {0, };
391 char buf[MAX_BUF_SIZE] = {0, };
394 /* Tx : Src. -> Dest. */
395 snprintf(cmd, sizeof(cmd),
396 "%s -L FORWARD -vx | %s \"%s[ ]*%s\" | %s '{ print $2 }' > %s",
397 IPTABLES, GREP, src, dest, AWK, DATA_USAGE_FILE);
398 DBG("GET DATA USAGE : %s\n", cmd);
399 if (system(cmd) < 0) {
400 ERR("\"cmd\" is failed\n");
403 /* Rx : Dest. -> Src. */
404 snprintf(cmd, sizeof(cmd),
405 "%s -L FORWARD -vx | %s \"%s[ ]*%s\" | %s '{ print $2 }' >> %s",
406 IPTABLES, GREP, dest, src, AWK, DATA_USAGE_FILE);
407 DBG("GET DATA USAGE : %s\n", cmd);
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)
423 DBG("Tx(%s -> %s) : %llu\n", src, dest, *tx);
425 if (fgets(buf, sizeof(buf), fp) == NULL)
429 DBG("Rx(%s -> %s) : %llu\n", dest, src, *rx);
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;