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.
23 #include <dbus/dbus.h>
24 #include <dbus/dbus-glib.h>
25 #include <dbus/dbus-glib-lowlevel.h>
31 #include <net_connection.h>
33 #include "mobileap_agent.h"
34 #include "mobileap_handler.h"
35 #include "mobileap_common.h"
36 #include "mobileap_bluetooth.h"
37 #include "mobileap_wifi.h"
38 #include "mobileap_usb.h"
39 #include "mobileap_network.h"
41 GType tethering_object_get_type(void);
42 #define TETHERING_TYPE_OBJECT (tethering_object_get_type())
43 G_DEFINE_TYPE(TetheringObject, tethering_object, G_TYPE_OBJECT)
45 GMainLoop *mainloop = NULL;
46 int mobileap_state = MOBILE_AP_STATE_NONE;
47 DBusConnection *tethering_conn = NULL;
49 gboolean tethering_init(TetheringObject *obj, GError **error);
50 gboolean tethering_deinit(TetheringObject *obj, GError **error);
51 gboolean tethering_disable(TetheringObject *obj, DBusGMethodInvocation *context);
52 gboolean tethering_get_station_info(TetheringObject *obj,
53 DBusGMethodInvocation *context);
54 gboolean tethering_get_data_packet_usage(TetheringObject *obj,
55 DBusGMethodInvocation *context);
56 gboolean tethering_set_ip_forward_status(TetheringObject *obj,
57 gint forward_mode, DBusGMethodInvocation *context);
58 gboolean tethering_get_ip_forward_status(TetheringObject *obj, gint *forward_mode);
60 #include "tethering-server-stub.h"
64 static void tethering_object_init(TetheringObject *obj)
67 g_assert(obj != NULL);
69 obj->bt_context = NULL;
70 obj->usb_context = NULL;
71 obj->bt_device = NULL;
74 obj->transfer_check_count = 0;
77 static void tethering_object_finalize(GObject *obj)
81 G_OBJECT_CLASS(tethering_object_parent_class)->finalize(obj);
84 static void tethering_object_class_init(TetheringObjectClass *klass)
86 GObjectClass *object_class = (GObjectClass *)klass;
87 const gchar *signalNames[E_SIGNAL_MAX] = {
88 SIGNAL_NAME_NET_CLOSED,
89 SIGNAL_NAME_STA_CONNECT,
90 SIGNAL_NAME_STA_DISCONNECT,
91 SIGNAL_NAME_WIFI_TETHER_ON,
92 SIGNAL_NAME_WIFI_TETHER_OFF,
93 SIGNAL_NAME_USB_TETHER_ON,
94 SIGNAL_NAME_USB_TETHER_OFF,
95 SIGNAL_NAME_BT_TETHER_ON,
96 SIGNAL_NAME_BT_TETHER_OFF,
97 SIGNAL_NAME_NO_DATA_TIMEOUT,
98 SIGNAL_NAME_LOW_BATTERY_MODE,
99 SIGNAL_NAME_FLIGHT_MODE,
100 SIGNAL_NAME_SECURITY_TYPE_CHANGED,
101 SIGNAL_NAME_SSID_VISIBILITY_CHANGED,
102 SIGNAL_NAME_PASSPHRASE_CHANGED
107 g_assert(klass != NULL);
109 object_class->finalize = tethering_object_finalize;
111 DBG("Creating signals\n");
113 for (i = 0; i < E_SIGNAL_MAX; i++) {
116 signalId = g_signal_new(signalNames[i],
117 G_OBJECT_CLASS_TYPE(klass),
120 g_cclosure_marshal_VOID__STRING,
121 G_TYPE_NONE, 1, G_TYPE_STRING);
122 klass->signals[i] = signalId;
125 DBG("Binding to GLib/D-Bus\n");
127 dbus_g_object_type_install_info(TETHERING_TYPE_OBJECT,
128 &dbus_glib_tethering_object_info);
131 static void __add_station_info_to_array(gpointer data, gpointer user_data)
133 mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)data;
134 GPtrArray *array = (GPtrArray *)user_data;
135 GValue value = {0, {{0}}};
137 g_value_init(&value, DBUS_STRUCT_STATIONS);
138 g_value_take_boxed(&value,
139 dbus_g_type_specialized_construct(DBUS_STRUCT_STATIONS));
140 dbus_g_type_struct_set(&value, 0, si->interface, 1, si->ip,
141 2, si->mac, 3, si->hostname, 4, (guint)(si->tm), G_MAXUINT);
142 g_ptr_array_add(array, g_value_get_boxed(&value));
145 gboolean _mobileap_set_state(int state)
149 DBG("Before mobileap_state : %d\n", mobileap_state);
150 mobileap_state |= state;
151 DBG("After mobileap_state : %d\n", mobileap_state);
153 vconf_ret = vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_MODE, mobileap_state);
154 if (vconf_ret != 0) {
155 ERR("vconf_set_int is failed : %d\n", vconf_ret);
162 gboolean _mobileap_is_disabled(void)
164 return mobileap_state ? FALSE : TRUE;
167 gboolean _mobileap_is_enabled(int state)
169 return (mobileap_state & state) ? TRUE : FALSE;
172 gboolean _mobileap_is_enabled_by_type(mobile_ap_type_e type)
175 case MOBILE_AP_TYPE_WIFI:
176 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
180 case MOBILE_AP_TYPE_BT:
181 if (_mobileap_is_enabled(MOBILE_AP_STATE_BT))
185 case MOBILE_AP_TYPE_USB:
186 if (_mobileap_is_enabled(MOBILE_AP_STATE_USB))
191 ERR("Unknow type : %d\n", type);
198 gboolean _mobileap_clear_state(int state)
202 DBG("Before mobileap_state : %d\n", mobileap_state);
203 mobileap_state &= (~state);
204 DBG("After mobileap_state : %d\n", mobileap_state);
206 vconf_ret = vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_MODE, mobileap_state);
207 if (vconf_ret != 0) {
208 ERR("vconf_set_int is failed : %d\n", vconf_ret);
215 static void __block_device_sleep(void)
219 ret = pm_lock_state(LCD_OFF, STAY_CUR_STATE, 0);
222 ERR("PM control [ERROR] result = %d\n", ret);
224 DBG("PM control [SUCCESS]\n");
227 static void __unblock_device_sleep(void)
231 ret = pm_unlock_state(LCD_OFF, PM_SLEEP_MARGIN);
233 ERR("PM control [ERROR] result = %d\n", ret);
235 DBG("PM control [SUCCESS]\n");
238 gboolean _init_tethering(TetheringObject *obj)
240 DBG("obj->init_count: %d\n", obj->init_count);
242 if (obj->init_count > 0) {
243 DBG("Already env. is initialized for tethering: %d\n",
251 __block_device_sleep();
253 DBG("Open network\n");
256 DBG("Run DHCP server\n");
257 _mh_core_execute_dhcp_server();
262 gboolean _deinit_tethering(TetheringObject *obj)
264 DBG("obj->init_count: %d\n", obj->init_count);
266 if (obj->init_count > 1) {
267 DBG("Already deinitialized\n");
270 } else if (obj->init_count <= 0) {
271 ERR("Already deinitialized\n");
278 DBG("Terminate DHCP / IPTABLES\n");
279 _mh_core_terminate_dhcp_server();
281 __unblock_device_sleep();
286 gboolean tethering_init(TetheringObject *obj, GError **error)
288 DBG("There are [%d] references\n", ++ref_agent);
293 gboolean tethering_deinit(TetheringObject *obj, GError **error)
295 if (--ref_agent <= 0 && _mobileap_is_disabled() &&
296 !_is_trying_network_operation()) {
297 DBG("Terminate mobileap-agent\n");
298 g_main_loop_quit(mainloop);
301 DBG("There are [%d] references\n", ref_agent);
306 gboolean tethering_disable(TetheringObject *obj, DBusGMethodInvocation *context)
308 int ret = MOBILE_AP_ERROR_NONE;
311 g_assert(obj != NULL);
312 g_assert(context != NULL);
314 if (_mobileap_is_disabled()) {
315 ERR("Mobile hotspot has not been enabled\n");
316 ret = MOBILE_AP_ERROR_NOT_ENABLED;
317 dbus_g_method_return(context, MOBILE_AP_DISABLE_CFM, ret);
321 _disable_wifi_tethering(obj);
322 _disable_bt_tethering(obj);
323 _disable_usb_tethering(obj);
325 dbus_g_method_return(context, MOBILE_AP_DISABLE_CFM, ret);
330 gboolean tethering_get_station_info(TetheringObject *obj,
331 DBusGMethodInvocation *context)
335 GPtrArray *array = g_ptr_array_new();
337 g_assert(obj != NULL);
338 g_assert(context != NULL);
340 _station_info_foreach(__add_station_info_to_array, array);
342 dbus_g_method_return(context, MOBILE_AP_GET_STATION_INFO_CFM, array);
343 g_ptr_array_free(array, TRUE);
350 gboolean tethering_get_data_packet_usage(TetheringObject *obj,
351 DBusGMethodInvocation *context)
353 char *if_name = NULL;
354 unsigned long long wifi_tx_bytes = 0;
355 unsigned long long wifi_rx_bytes = 0;
356 unsigned long long bt_tx_bytes = 0;
357 unsigned long long bt_rx_bytes = 0;
358 unsigned long long usb_tx_bytes = 0;
359 unsigned long long usb_rx_bytes = 0;
360 unsigned long long tx_bytes = 0;
361 unsigned long long rx_bytes = 0;
363 if (_get_network_interface_name(&if_name) == FALSE) {
364 ERR("No network interface\n");
365 dbus_g_method_return(context, MOBILE_AP_GET_DATA_PACKET_USAGE_CFM,
370 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
371 _get_data_usage(WIFI_IF, if_name,
372 &wifi_tx_bytes, &wifi_rx_bytes);
374 if (_mobileap_is_enabled(MOBILE_AP_STATE_BT))
375 _get_data_usage(BT_IF_ALL, if_name,
376 &bt_tx_bytes, &bt_rx_bytes);
378 if (_mobileap_is_enabled(MOBILE_AP_STATE_USB))
379 _get_data_usage(USB_IF, if_name,
380 &usb_tx_bytes, &usb_rx_bytes);
383 tx_bytes = wifi_tx_bytes + bt_tx_bytes + usb_tx_bytes;
384 rx_bytes = wifi_rx_bytes + bt_rx_bytes + usb_rx_bytes;
386 dbus_g_method_return(context, MOBILE_AP_GET_DATA_PACKET_USAGE_CFM,
392 gboolean tethering_set_ip_forward_status(TetheringObject *obj,
393 gint forward_mode, DBusGMethodInvocation *context)
395 g_assert(obj != NULL);
399 if (forward_mode == 0) {
400 ret = _unset_masquerade();
402 ret = _set_masquerade();
405 dbus_g_method_return(context, ret);
410 gboolean tethering_get_ip_forward_status(TetheringObject *obj, gint *forward_mode)
412 g_assert(obj != NULL);
416 char value[2] = {0, };
418 fd = open(IP_FORWARD, O_RDONLY);
420 ERR("open failed\n");
424 ret = read(fd, value, sizeof(value));
426 ERR("read is failed\n");
432 *forward_mode = atoi(value);
438 static DBusHandlerResult __dnsmasq_signal_filter(DBusConnection *conn,
439 DBusMessage *msg, void *user_data)
442 ERR("Invalid param\n");
443 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
446 char *ip_addr = NULL;
449 char *bt_remote_device_name = NULL;
451 mobile_ap_type_e type = MOBILE_AP_TYPE_MAX;
452 TetheringObject *obj = (TetheringObject *)user_data;
453 mobile_ap_station_info_t *info = NULL;
457 dbus_error_init(&error);
458 if (dbus_message_is_signal(msg, DNSMASQ_DBUS_INTERFACE,
460 if (!dbus_message_get_args(msg, &error,
461 DBUS_TYPE_STRING, &ip_addr,
462 DBUS_TYPE_STRING, &mac,
463 DBUS_TYPE_STRING, &name,
464 DBUS_TYPE_INVALID)) {
465 ERR("Cannot read message, cause: %s\n", error.message);
466 dbus_error_free(&error);
467 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
469 DBG("DhcpConnected signal : %s %s %s\n", ip_addr, mac, name);
471 if (_get_tethering_type_from_ip(ip_addr, &type) != MOBILE_AP_ERROR_NONE)
472 return DBUS_HANDLER_RESULT_HANDLED;
474 if (_mobileap_is_enabled_by_type(type) == FALSE) {
475 DBG("Tethering[%d] is disabled. Ignore ACK\n", type);
476 return DBUS_HANDLER_RESULT_HANDLED;
479 info = (mobile_ap_station_info_t *)malloc(sizeof(mobile_ap_station_info_t));
481 ERR("malloc failed\n");
482 return DBUS_HANDLER_RESULT_HANDLED;
485 info->interface = type;
486 g_strlcpy(info->ip, ip_addr, sizeof(info->ip));
487 g_strlcpy(info->mac, mac, sizeof(info->mac));
488 if (type == MOBILE_AP_TYPE_WIFI || type == MOBILE_AP_TYPE_USB) {
490 g_strlcpy(info->hostname,
491 MOBILE_AP_NAME_UNKNOWN,
492 sizeof(info->hostname));
494 g_strlcpy(info->hostname, name,
495 sizeof(info->hostname));
496 } else if (type == MOBILE_AP_TYPE_BT) {
497 _bt_get_remote_device_name(obj, mac, &bt_remote_device_name);
498 if (bt_remote_device_name == NULL)
499 g_strlcpy(info->hostname,
500 MOBILE_AP_NAME_UNKNOWN,
501 sizeof(info->hostname));
503 g_strlcpy(info->hostname, bt_remote_device_name,
504 sizeof(info->hostname));
505 free(bt_remote_device_name);
511 if (_add_station_info(info) != MOBILE_AP_ERROR_NONE) {
513 return DBUS_HANDLER_RESULT_HANDLED;
516 _get_station_count((gconstpointer)type,
517 _slist_find_station_by_interface, &n_station);
519 _stop_timeout_cb(type);
521 _send_dbus_station_info("DhcpConnected", info);
523 return DBUS_HANDLER_RESULT_HANDLED;
524 } else if (dbus_message_is_signal(msg, DNSMASQ_DBUS_INTERFACE,
525 "DhcpLeaseDeleted")) {
526 if (!dbus_message_get_args(msg, &error,
527 DBUS_TYPE_STRING, &ip_addr,
528 DBUS_TYPE_STRING, &mac,
529 DBUS_TYPE_STRING, &name,
530 DBUS_TYPE_INVALID)) {
531 ERR("Cannot read message, cause: %s\n", error.message);
532 dbus_error_free(&error);
533 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
536 DBG("DhcpLeaseDeleted signal : %s %s %s\n", ip_addr, mac, name);
538 _remove_station_info(ip_addr, _slist_find_station_by_ip_addr);
540 return DBUS_HANDLER_RESULT_HANDLED;
543 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
546 int main(int argc, char **argv)
548 TetheringObject *tethering_obj = NULL;
549 DBusError dbus_error;
550 char *rule = "type='signal',interface='"DNSMASQ_DBUS_INTERFACE"'";
551 DBusGConnection *tethering_bus = NULL;
552 DBusGProxy *tethering_bus_proxy = NULL;
554 GError *error = NULL;
555 int mobileap_vconf_key = VCONFKEY_MOBILE_HOTSPOT_MODE_NONE;
557 #if !GLIB_CHECK_VERSION(2,35,0)
561 if (vconf_get_int(VCONFKEY_MOBILE_HOTSPOT_MODE, &mobileap_vconf_key)) {
562 ERR("vconf_get_int FAIL\n");
563 mobileap_state = MOBILE_AP_STATE_NONE;
565 ERR("vconf_get_int OK(mobileap_vconf_key value is %d)\n",
567 mobileap_state = mobileap_vconf_key;
570 mainloop = g_main_loop_new(NULL, FALSE);
571 if (mainloop == NULL) {
572 ERR("Couldn't create GMainLoop\n");
576 tethering_bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
578 ERR("Couldn't connect to system bus[%s]\n", error->message);
582 tethering_conn = dbus_g_connection_get_connection(tethering_bus);
584 DBG("Registering the well-known name (%s)\n", TETHERING_SERVICE_NAME);
586 tethering_bus_proxy = dbus_g_proxy_new_for_name(tethering_bus,
587 DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
588 if (tethering_bus_proxy == NULL) {
589 ERR("Failed to get a proxy for D-Bus\n");
593 if (!dbus_g_proxy_call(tethering_bus_proxy,
597 TETHERING_SERVICE_NAME,
598 G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &result, G_TYPE_INVALID)) {
599 ERR("D-Bus.RequestName RPC failed[%s]\n", error->message);
604 ERR("Failed to get the primary well-known name.\n");
608 g_object_unref(tethering_bus_proxy);
609 tethering_bus_proxy = NULL;
611 tethering_obj = g_object_new(TETHERING_TYPE_OBJECT, NULL);
612 if (tethering_obj == NULL) {
613 ERR("Failed to create one MobileAP instance.\n");
617 /* Registering it on the D-Bus */
618 dbus_g_connection_register_g_object(tethering_bus,
619 TETHERING_SERVICE_OBJECT_PATH, G_OBJECT(tethering_obj));
621 DBG("Ready to serve requests.\n");
624 _register_wifi_station_handler();
625 _register_vconf_cb((void *)tethering_obj);
627 dbus_error_init(&dbus_error);
628 dbus_bus_add_match(tethering_conn, rule, &dbus_error);
629 if (dbus_error_is_set(&dbus_error)) {
630 ERR("Cannot add D-BUS match rule, cause: %s", dbus_error.message);
631 dbus_error_free(&dbus_error);
635 DBG("Listening to D-BUS signals from dnsmasq");
636 dbus_connection_add_filter(tethering_conn, __dnsmasq_signal_filter, tethering_obj, NULL);
638 g_main_loop_run(mainloop);
640 _unregister_vconf_cb((void *)tethering_obj);
644 ERR("Terminate the mobileap-agent\n");
647 dbus_g_connection_unref(tethering_bus);
648 if (tethering_bus_proxy)
649 g_object_unref(tethering_bus_proxy);
651 g_object_unref(tethering_obj);