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.
19 #include <dbus/dbus.h>
20 #include <dbus/dbus-glib.h>
21 #include <dbus/dbus-glib-lowlevel.h>
27 #include <net_connection.h>
29 #include "mobileap_agent.h"
30 #include "mobileap_handler.h"
31 #include "mobileap_common.h"
32 #include "mobileap_bluetooth.h"
33 #include "mobileap_wifi.h"
34 #include "mobileap_usb.h"
35 #include "mobileap_network.h"
37 GType tethering_object_get_type(void);
38 #define TETHERING_TYPE_OBJECT (tethering_object_get_type())
39 G_DEFINE_TYPE(TetheringObject, tethering_object, G_TYPE_OBJECT)
41 GMainLoop *mainloop = NULL;
42 int mobileap_state = MOBILE_AP_STATE_NONE;
43 DBusConnection *tethering_conn = NULL;
45 gboolean tethering_deinit(TetheringObject *obj, GError **error);
46 gboolean tethering_disable(TetheringObject *obj, DBusGMethodInvocation *context);
47 gboolean tethering_get_station_info(TetheringObject *obj,
48 DBusGMethodInvocation *context);
49 gboolean tethering_get_data_packet_usage(TetheringObject *obj,
50 DBusGMethodInvocation *context);
51 #include "tethering-server-stub.h"
53 static void tethering_object_init(TetheringObject *obj)
56 g_assert(obj != NULL);
58 obj->bt_context = NULL;
59 obj->usb_context = NULL;
60 obj->bt_device = NULL;
63 obj->transfer_check_count = 0;
66 static void tethering_object_finalize(GObject *obj)
70 G_OBJECT_CLASS(tethering_object_parent_class)->finalize(obj);
73 static void tethering_object_class_init(TetheringObjectClass *klass)
75 GObjectClass *object_class = (GObjectClass *)klass;
76 const gchar *signalNames[E_SIGNAL_MAX] = {
77 SIGNAL_NAME_NET_CLOSED,
78 SIGNAL_NAME_STA_CONNECT,
79 SIGNAL_NAME_STA_DISCONNECT,
80 SIGNAL_NAME_WIFI_TETHER_ON,
81 SIGNAL_NAME_WIFI_TETHER_OFF,
82 SIGNAL_NAME_USB_TETHER_ON,
83 SIGNAL_NAME_USB_TETHER_OFF,
84 SIGNAL_NAME_BT_TETHER_ON,
85 SIGNAL_NAME_BT_TETHER_OFF,
86 SIGNAL_NAME_NO_DATA_TIMEOUT,
87 SIGNAL_NAME_LOW_BATTERY_MODE,
88 SIGNAL_NAME_FLIGHT_MODE,
89 SIGNAL_NAME_SECURITY_TYPE_CHANGED,
90 SIGNAL_NAME_SSID_VISIBILITY_CHANGED,
91 SIGNAL_NAME_PASSPHRASE_CHANGED
96 g_assert(klass != NULL);
98 object_class->finalize = tethering_object_finalize;
100 DBG("Creating signals\n");
102 for (i = 0; i < E_SIGNAL_MAX; i++) {
105 signalId = g_signal_new(signalNames[i],
106 G_OBJECT_CLASS_TYPE(klass),
109 g_cclosure_marshal_VOID__STRING,
110 G_TYPE_NONE, 1, G_TYPE_STRING);
111 klass->signals[i] = signalId;
114 DBG("Binding to GLib/D-Bus\n");
116 dbus_g_object_type_install_info(TETHERING_TYPE_OBJECT,
117 &dbus_glib_tethering_object_info);
120 static void __add_station_info_to_array(gpointer data, gpointer user_data)
122 mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)data;
123 GPtrArray *array = (GPtrArray *)user_data;
124 GValue value = {0, {{0}}};
126 g_value_init(&value, DBUS_STRUCT_STATIONS);
127 g_value_take_boxed(&value,
128 dbus_g_type_specialized_construct(DBUS_STRUCT_STATIONS));
129 dbus_g_type_struct_set(&value, 0, si->interface, 1, si->ip,
130 2, si->mac, 3, si->hostname, G_MAXUINT);
131 g_ptr_array_add(array, g_value_get_boxed(&value));
134 gboolean _mobileap_set_state(int state)
138 DBG("Before mobileap_state : %d\n", mobileap_state);
139 mobileap_state |= state;
140 DBG("After mobileap_state : %d\n", mobileap_state);
142 vconf_ret = vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_MODE, mobileap_state);
143 if (vconf_ret != 0) {
144 ERR("vconf_set_int is failed : %d\n", vconf_ret);
151 gboolean _mobileap_is_disabled(void)
153 return mobileap_state ? FALSE : TRUE;
156 gboolean _mobileap_is_enabled(int state)
158 return (mobileap_state & state) ? TRUE : FALSE;
161 gboolean _mobileap_is_enabled_by_type(mobile_ap_type_e type)
164 case MOBILE_AP_TYPE_WIFI:
165 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
169 case MOBILE_AP_TYPE_BT:
170 if (_mobileap_is_enabled(MOBILE_AP_STATE_BT))
174 case MOBILE_AP_TYPE_USB:
175 if (_mobileap_is_enabled(MOBILE_AP_STATE_USB))
180 ERR("Unknow type : %d\n", type);
187 gboolean _mobileap_clear_state(int state)
191 DBG("Before mobileap_state : %d\n", mobileap_state);
192 mobileap_state &= (~state);
193 DBG("After mobileap_state : %d\n", mobileap_state);
195 vconf_ret = vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_MODE, mobileap_state);
196 if (vconf_ret != 0) {
197 ERR("vconf_set_int is failed : %d\n", vconf_ret);
204 static void __block_device_sleep(void)
208 ret = pm_lock_state(LCD_OFF, STAY_CUR_STATE, 0);
210 ERR("PM control [ERROR] result = %d\n", ret);
212 DBG("PM control [SUCCESS]\n");
215 static void __unblock_device_sleep(void)
219 ret = pm_unlock_state(LCD_OFF, PM_SLEEP_MARGIN);
221 ERR("PM control [ERROR] result = %d\n", ret);
223 DBG("PM control [SUCCESS]\n");
226 gboolean _init_tethering(TetheringObject *obj)
228 DBG("obj->init_count: %d\n", obj->init_count);
230 if (obj->init_count > 0) {
231 DBG("Already env. is initialized for tethering: %d\n",
239 __block_device_sleep();
241 DBG("Open network\n");
244 DBG("Run DHCP server\n");
245 _mh_core_execute_dhcp_server();
250 gboolean _deinit_tethering(TetheringObject *obj)
252 DBG("obj->init_count: %d\n", obj->init_count);
254 if (obj->init_count > 1) {
255 DBG("Already deinitialized\n");
258 } else if (obj->init_count <= 0) {
259 ERR("Already deinitialized\n");
266 DBG("Terminate DHCP / IPTABLES\n");
267 _mh_core_terminate_dhcp_server();
269 __unblock_device_sleep();
275 gboolean tethering_deinit(TetheringObject *obj, GError **error)
278 g_assert(obj != NULL);
280 if (_mobileap_is_disabled()) {
281 DBG("Mobile AP is not activated, so we quit the mobileap-agent.\n");
282 g_main_loop_quit(mainloop);
288 gboolean tethering_disable(TetheringObject *obj, DBusGMethodInvocation *context)
290 int ret = MOBILE_AP_ERROR_NONE;
293 g_assert(obj != NULL);
294 g_assert(context != NULL);
296 if (_mobileap_is_disabled()) {
297 ERR("Mobile hotspot has not been enabled\n");
298 ret = MOBILE_AP_ERROR_NOT_ENABLED;
299 dbus_g_method_return(context, MOBILE_AP_DISABLE_CFM, ret);
303 _disable_wifi_tethering(obj);
304 _disable_bt_tethering(obj);
305 _disable_usb_tethering(obj);
307 dbus_g_method_return(context, MOBILE_AP_DISABLE_CFM, ret);
312 gboolean tethering_get_station_info(TetheringObject *obj,
313 DBusGMethodInvocation *context)
317 GPtrArray *array = g_ptr_array_new();
319 g_assert(obj != NULL);
320 g_assert(context != NULL);
322 _station_info_foreach(__add_station_info_to_array, array);
324 dbus_g_method_return(context, MOBILE_AP_GET_STATION_INFO_CFM, array);
325 g_ptr_array_free(array, TRUE);
332 gboolean tethering_get_data_packet_usage(TetheringObject *obj,
333 DBusGMethodInvocation *context)
335 char *if_name = NULL;
336 unsigned long long wifi_tx_bytes = 0;
337 unsigned long long wifi_rx_bytes = 0;
338 unsigned long long bt_tx_bytes = 0;
339 unsigned long long bt_rx_bytes = 0;
340 unsigned long long usb_tx_bytes = 0;
341 unsigned long long usb_rx_bytes = 0;
342 unsigned long long tx_bytes = 0;
343 unsigned long long rx_bytes = 0;
345 if (_get_network_interface_name(&if_name) == FALSE) {
346 ERR("No network interface\n");
347 dbus_g_method_return(context, MOBILE_AP_GET_DATA_PACKET_USAGE_CFM,
352 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
353 _get_data_usage(WIFI_IF, if_name,
354 &wifi_tx_bytes, &wifi_rx_bytes);
356 if (_mobileap_is_enabled(MOBILE_AP_STATE_BT))
357 _get_data_usage(BT_IF_ALL, if_name,
358 &bt_tx_bytes, &bt_rx_bytes);
360 if (_mobileap_is_enabled(MOBILE_AP_STATE_USB))
361 _get_data_usage(USB_IF, if_name,
362 &usb_tx_bytes, &usb_rx_bytes);
365 tx_bytes = wifi_tx_bytes + bt_tx_bytes + usb_tx_bytes;
366 rx_bytes = wifi_rx_bytes + bt_rx_bytes + usb_rx_bytes;
368 dbus_g_method_return(context, MOBILE_AP_GET_DATA_PACKET_USAGE_CFM,
375 static DBusHandlerResult __dnsmasq_signal_filter(DBusConnection *conn,
376 DBusMessage *msg, void *user_data)
379 ERR("Invalid param\n");
380 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
383 char *ip_addr = NULL;
386 char *bt_remote_device_name = NULL;
388 mobile_ap_type_e type = MOBILE_AP_TYPE_MAX;
389 TetheringObject *obj = (TetheringObject *)user_data;
390 mobile_ap_station_info_t *info = NULL;
393 dbus_error_init(&error);
394 if (dbus_message_is_signal(msg, DNSMASQ_DBUS_INTERFACE,
396 if (!dbus_message_get_args(msg, &error,
397 DBUS_TYPE_STRING, &ip_addr,
398 DBUS_TYPE_STRING, &mac,
399 DBUS_TYPE_STRING, &name,
400 DBUS_TYPE_INVALID)) {
401 ERR("Cannot read message, cause: %s\n", error.message);
402 dbus_error_free(&error);
403 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
405 DBG("DhcpConnected signal : %s %s %s\n", ip_addr, mac, name);
407 if (_get_tethering_type_from_ip(ip_addr, &type) != MOBILE_AP_ERROR_NONE)
408 return DBUS_HANDLER_RESULT_HANDLED;
410 if (_mobileap_is_enabled_by_type(type) == FALSE) {
411 DBG("Tethering[%d] is disabled. Ignore ACK\n", type);
412 return DBUS_HANDLER_RESULT_HANDLED;
415 info = (mobile_ap_station_info_t *)malloc(sizeof(mobile_ap_station_info_t));
417 ERR("malloc failed\n");
418 return DBUS_HANDLER_RESULT_HANDLED;
421 info->interface = type;
422 g_strlcpy(info->ip, ip_addr, sizeof(info->ip));
423 g_strlcpy(info->mac, mac, sizeof(info->mac));
424 if (type == MOBILE_AP_TYPE_WIFI || type == MOBILE_AP_TYPE_USB) {
426 g_strlcpy(info->hostname,
427 MOBILE_AP_NAME_UNKNOWN,
428 sizeof(info->hostname));
430 g_strlcpy(info->hostname, name,
431 sizeof(info->hostname));
432 } else if (type == MOBILE_AP_TYPE_BT) {
433 _bt_get_remote_device_name(obj, mac, &bt_remote_device_name);
434 if (bt_remote_device_name == NULL)
435 g_strlcpy(info->hostname,
436 MOBILE_AP_NAME_UNKNOWN,
437 sizeof(info->hostname));
439 g_strlcpy(info->hostname, bt_remote_device_name,
440 sizeof(info->hostname));
441 free(bt_remote_device_name);
445 if (_add_station_info(info) != MOBILE_AP_ERROR_NONE) {
447 return DBUS_HANDLER_RESULT_HANDLED;
450 _get_station_count((gconstpointer)type,
451 _slist_find_station_by_interface, &n_station);
453 _stop_timeout_cb(type);
455 _send_dbus_station_info("DhcpConnected", info);
457 return DBUS_HANDLER_RESULT_HANDLED;
458 } else if (dbus_message_is_signal(msg, DNSMASQ_DBUS_INTERFACE,
459 "DhcpLeaseDeleted")) {
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;
470 DBG("DhcpLeaseDeleted signal : %s %s %s\n", ip_addr, mac, name);
472 _remove_station_info(ip_addr, _slist_find_station_by_ip_addr);
474 return DBUS_HANDLER_RESULT_HANDLED;
477 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
480 int main(int argc, char **argv)
482 TetheringObject *tethering_obj = NULL;
483 DBusError dbus_error;
484 char *rule = "type='signal',interface='"DNSMASQ_DBUS_INTERFACE"'";
485 DBusGConnection *tethering_bus = NULL;
486 DBusGProxy *tethering_bus_proxy = NULL;
488 GError *error = NULL;
489 int mobileap_vconf_key = VCONFKEY_MOBILE_HOTSPOT_MODE_NONE;
493 if (vconf_get_int(VCONFKEY_MOBILE_HOTSPOT_MODE, &mobileap_vconf_key)) {
494 ERR("vconf_get_int FAIL\n");
495 mobileap_state = MOBILE_AP_STATE_NONE;
497 ERR("vconf_get_int OK(mobileap_vconf_key value is %d)\n",
499 mobileap_state = mobileap_vconf_key;
502 mainloop = g_main_loop_new(NULL, FALSE);
503 if (mainloop == NULL) {
504 ERR("Couldn't create GMainLoop\n");
508 tethering_bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
510 ERR("Couldn't connect to system bus[%s]\n", error->message);
514 tethering_conn = dbus_g_connection_get_connection(tethering_bus);
516 DBG("Registering the well-known name (%s)\n", TETHERING_SERVICE_NAME);
518 tethering_bus_proxy = dbus_g_proxy_new_for_name(tethering_bus,
519 DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
520 if (tethering_bus_proxy == NULL) {
521 ERR("Failed to get a proxy for D-Bus\n");
525 if (!dbus_g_proxy_call(tethering_bus_proxy,
529 TETHERING_SERVICE_NAME,
530 G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &result, G_TYPE_INVALID)) {
531 ERR("D-Bus.RequestName RPC failed[%s]\n", error->message);
536 ERR("Failed to get the primary well-known name.\n");
540 g_object_unref(tethering_bus_proxy);
541 tethering_bus_proxy = NULL;
543 tethering_obj = g_object_new(TETHERING_TYPE_OBJECT, NULL);
544 if (tethering_obj == NULL) {
545 ERR("Failed to create one MobileAP instance.\n");
549 /* Registering it on the D-Bus */
550 dbus_g_connection_register_g_object(tethering_bus,
551 TETHERING_SERVICE_OBJECT_PATH, G_OBJECT(tethering_obj));
553 DBG("Ready to serve requests.\n");
556 _register_wifi_station_handler();
557 _register_vconf_cb((void *)tethering_obj);
559 dbus_error_init(&dbus_error);
560 dbus_bus_add_match(tethering_conn, rule, &dbus_error);
561 if (dbus_error_is_set(&dbus_error)) {
562 ERR("Cannot add D-BUS match rule, cause: %s", dbus_error.message);
563 dbus_error_free(&dbus_error);
567 DBG("Listening to D-BUS signals from dnsmasq");
568 dbus_connection_add_filter(tethering_conn, __dnsmasq_signal_filter, tethering_obj, NULL);
570 g_main_loop_run(mainloop);
572 _unregister_vconf_cb((void *)tethering_obj);
576 ERR("Terminate the mobileap-agent\n");
579 dbus_g_connection_unref(tethering_bus);
580 if (tethering_bus_proxy)
581 g_object_unref(tethering_bus_proxy);
583 g_object_unref(tethering_obj);