Tizen 2.1 base
authorJinkun Jang <jinkun.jang@samsung.com>
Tue, 12 Mar 2013 16:47:25 +0000 (01:47 +0900)
committerJinkun Jang <jinkun.jang@samsung.com>
Tue, 12 Mar 2013 16:47:25 +0000 (01:47 +0900)
26 files changed:
AUTHORS [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
LICENSE.APLv2.0 [new file with mode: 0644]
NOTICE [new file with mode: 0644]
include/mobileap.h [new file with mode: 0644]
include/mobileap_agent.h [new file with mode: 0644]
include/mobileap_bluetooth.h [new file with mode: 0644]
include/mobileap_common.h [new file with mode: 0644]
include/mobileap_handler.h [new file with mode: 0644]
include/mobileap_network.h [new file with mode: 0644]
include/mobileap_notification.h [new file with mode: 0644]
include/mobileap_usb.h [new file with mode: 0644]
include/mobileap_wifi.h [new file with mode: 0644]
include/tethering-dbus-interface.xml [new file with mode: 0644]
mobileap-agent.manifest [new file with mode: 0644]
packaging/mobileap-agent.spec [new file with mode: 0644]
packaging/org.tizen.tethering.service [new file with mode: 0644]
src/mobileap_agent.c [new file with mode: 0644]
src/mobileap_bluetooth.c [new file with mode: 0644]
src/mobileap_common.c [new file with mode: 0644]
src/mobileap_handler.c [new file with mode: 0644]
src/mobileap_main.c [new file with mode: 0644]
src/mobileap_network.c [new file with mode: 0644]
src/mobileap_notification.c [new file with mode: 0644]
src/mobileap_usb.c [new file with mode: 0644]
src/mobileap_wifi.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..4d93362
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+Hocheol Seo <hocheol.seo at samsung dot com>
+Injun Yang <injun.yang at samsung dot com>
+Seungyoun Ju <sy39.ju at samsung dot com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..306d414
--- /dev/null
@@ -0,0 +1,65 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(mobileap-agent C)
+
+SET(SRCS src/mobileap_agent.c
+       src/mobileap_main.c
+       src/mobileap_wifi.c
+       src/mobileap_usb.c
+       src/mobileap_bluetooth.c
+       src/mobileap_handler.c
+       src/mobileap_common.c
+       src/mobileap_notification.c
+       src/mobileap_network.c
+)
+
+SET(APP_VENDOR "samsung")
+SET(APP_NAME mobileap-agent)
+SET(APP_DIR /usr/bin)
+SET(INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include)
+
+IF("${CMAKE_BUILD_TYPE}" STREQUAL "")
+       SET(CMAKE_BUILD_TYPE "Release")
+ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "")
+
+IF("${CMAKE_BUILD_TYPE}" STREQUAL "Private")
+       SET(CMAKE_BUILD_TYPE "Release")
+       ADD_DEFINITIONS("-D__PRIVATE_CODE__")
+       SET(PRIVATE_REQUIRED_PKGS "mdm kies-control-point")
+ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "Private")
+MESSAGE("Build type: ${CMAKE_BUILD_TYPE}")
+
+INCLUDE_DIRECTORIES(${INCLUDE_DIR})
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkgs REQUIRED dlog dbus-glib-1 pmapi vconf notification libssl secure-storage capi-network-connection capi-network-bluetooth ${PRIVATE_REQUIRED_PKGS})
+FOREACH(flag ${pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+
+FIND_PROGRAM(UNAME NAMES uname)
+EXEC_PROGRAM("${UNAME}" ARGS "-m" OUTPUT_VARIABLE "ARCH")
+IF("${ARCH}" STREQUAL "arm")
+       ADD_DEFINITIONS("-DTARGET")
+       MESSAGE("add -DTARGET")
+ENDIF("${ARCH}" STREQUAL "arm")
+
+FIND_PROGRAM(DBUS_BINDING_TOOL NAMES dbus-binding-tool)
+EXEC_PROGRAM("${DBUS_BINDING_TOOL}" ARGS "--prefix=tethering ${INCLUDE_DIR}/tethering-dbus-interface.xml --mode=glib-server --output=${INCLUDE_DIR}/tethering-server-stub.h")
+
+ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
+ADD_DEFINITIONS("-DVENDOR=\"${APP_VENDOR}\"")
+ADD_DEFINITIONS("-DAPPNAME=\"${APP_NAME}\"")
+ADD_DEFINITIONS("-DAPP_DIR=\"${APP_DIR}\"")
+
+SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed")
+
+ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS})
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/org.tizen.tethering.service DESTINATION share/dbus-1/services)
+
diff --git a/LICENSE.APLv2.0 b/LICENSE.APLv2.0
new file mode 100644 (file)
index 0000000..d645695
--- /dev/null
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/NOTICE b/NOTICE
new file mode 100644 (file)
index 0000000..ccdad52
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,3 @@
+Copyright (c) Samsung Electronics Co., Ltd. All rights reserved.
+Except as noted, this software is licensed under Apache License, Version 2.
+Please, see the LICENSE file for Apache License terms and conditions.
diff --git a/include/mobileap.h b/include/mobileap.h
new file mode 100644 (file)
index 0000000..5d144a8
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOBILEAP_INTERNAL_H__
+#define __MOBILEAP_INTERNAL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Client / Agent common */
+#define DBUS_STRUCT_UINT_STRING (dbus_g_type_get_struct ("GValueArray", \
+                       G_TYPE_UINT, G_TYPE_STRING, G_TYPE_INVALID))
+
+#define DBUS_STRUCT_STATIONS (dbus_g_type_get_struct ("GValueArray", \
+                       G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, \
+                       G_TYPE_STRING, G_TYPE_INVALID))
+
+#define DBUS_STRUCT_STATION (dbus_g_type_get_struct ("GValueArray", \
+                       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, \
+                       G_TYPE_INVALID))
+
+#define DBUS_STRUCT_INTERFACE (dbus_g_type_get_struct ("GValueArray", \
+                       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, \
+                       G_TYPE_STRING, G_TYPE_INVALID))
+
+
+#define TETHERING_SERVICE_OBJECT_PATH  "/Tethering"
+#define TETHERING_SERVICE_NAME         "org.tizen.tethering"
+#define TETHERING_SERVICE_INTERFACE    "org.tizen.tethering"
+
+#define SIGNAL_NAME_NET_CLOSED         "net_closed"
+#define SIGNAL_NAME_STA_CONNECT                "sta_connected"
+#define SIGNAL_NAME_STA_DISCONNECT     "sta_disconnected"
+#define SIGNAL_NAME_WIFI_TETHER_ON     "wifi_on"
+#define SIGNAL_NAME_WIFI_TETHER_OFF    "wifi_off"
+#define SIGNAL_NAME_USB_TETHER_ON      "usb_on"
+#define SIGNAL_NAME_USB_TETHER_OFF     "usb_off"
+#define SIGNAL_NAME_BT_TETHER_ON       "bluetooth_on"
+#define SIGNAL_NAME_BT_TETHER_OFF      "bluetooth_off"
+#define SIGNAL_NAME_NO_DATA_TIMEOUT    "no_data_timeout"
+#define SIGNAL_NAME_LOW_BATTERY_MODE   "low_batt_mode"
+#define SIGNAL_NAME_FLIGHT_MODE                "flight_mode"
+#define SIGNAL_NAME_DHCP_STATUS                "dhcp_status"
+#define SIGNAL_NAME_SECURITY_TYPE_CHANGED      "security_type_changed"
+#define SIGNAL_NAME_SSID_VISIBILITY_CHANGED    "ssid_visibility_changed"
+#define SIGNAL_NAME_PASSPHRASE_CHANGED         "passphrase_changed"
+
+#define SIGNAL_MSG_NOT_AVAIL_INTERFACE "Interface is not available"
+#define SIGNAL_MSG_TIMEOUT             "There is no connection for a while"
+#define SIGNAL_MSG_SSID_VISIBLE                "ssid_visible"
+#define SIGNAL_MSG_SSID_HIDE           "ssid_hide"
+
+#define DNSMASQ_LEASES_FILE            "/var/lib/misc/dnsmasq.leases"
+#define IP_USB_SUBNET                  "192.168.129"
+
+typedef enum {
+       E_SIGNAL_NET_CLOSED,
+       E_SIGNAL_STA_CONNECT,
+       E_SIGNAL_STA_DISCONNECT,
+       E_SIGNAL_WIFI_TETHER_ON,
+       E_SIGNAL_WIFI_TETHER_OFF,
+       E_SIGNAL_USB_TETHER_ON,
+       E_SIGNAL_USB_TETHER_OFF,
+       E_SIGNAL_BT_TETHER_ON,
+       E_SIGNAL_BT_TETHER_OFF,
+       E_SIGNAL_NO_DATA_TIMEOUT,
+       E_SIGNAL_LOW_BATTERY_MODE,
+       E_SIGNAL_FLIGHT_MODE,
+       E_SIGNAL_SECURITY_TYPE_CHANGED,
+       E_SIGNAL_SSID_VISIBILITY_CHANGED,
+       E_SIGNAL_PASSPHRASE_CHANGED,
+       E_SIGNAL_MAX
+} mobile_ap_sig_e;
+
+/**
+* WiFi tethering configuration
+*/
+#define MOBILE_AP_WIFI_CHANNEL         7       /**< Channel number */
+#define MOBILE_AP_WIFI_BSSID_LEN       6       /**< BSSID Length */
+#define MOBILE_AP_WIFI_SSID_MAX_LEN    31      /**< Maximum length of ssid */
+#define MOBILE_AP_WIFI_KEY_MIN_LEN     8       /**< Minimum length of wifi key */
+#define MOBILE_AP_WIFI_KEY_MAX_LEN     63      /**< Maximum length of wifi key */
+
+/**
+* Common configuration
+*/
+#define MOBILE_AP_MAX_WIFI_STA         8
+#define MOBILE_AP_MAX_BT_STA           7
+#define MOBILE_AP_MAX_USB_STA          1
+#define MOBILE_AP_MAX_CONNECTED_STA    16      /**< Maximum connected station. 8(Wi-Fi) + 7(BT) + 1(USB) */
+
+#define MOBILE_AP_STR_INFO_LEN         20      /**< length of the ip or mac address*/
+#define MOBILE_AP_STR_HOSTNAME_LEN     32      /**< length of the hostname */
+#define MOBILE_AP_NAME_UNKNOWN         "UNKNOWN"
+
+/**
+* Mobile AP error code
+*/
+typedef enum {
+       MOBILE_AP_ERROR_NONE,                   /**< No error */
+       MOBILE_AP_ERROR_RESOURCE,               /**< Socket creation error, file open error */
+       MOBILE_AP_ERROR_INTERNAL,               /**< Driver related error */
+       MOBILE_AP_ERROR_INVALID_PARAM,          /**< Invalid parameter */
+       MOBILE_AP_ERROR_ALREADY_ENABLED,        /**< Mobile AP is already ON */
+       MOBILE_AP_ERROR_NOT_ENABLED,            /**< Mobile AP is not ON, so cannot be disabled */
+       MOBILE_AP_ERROR_NET_OPEN,               /**< PDP network open error */
+       MOBILE_AP_ERROR_NET_CLOSE,              /**< PDP network close error */
+       MOBILE_AP_ERROR_DHCP,                   /**< DHCP error */
+       MOBILE_AP_ERROR_IN_PROGRESS,            /**< Request is in progress */
+       MOBILE_AP_ERROR_NOT_PERMITTED,          /**< Operation is not permitted */
+
+       MOBILE_AP_ERROR_MAX
+} mobile_ap_error_code_e;
+
+/**
+* Event type on callback
+*/
+typedef enum {
+       MOBILE_AP_ENABLE_CFM,                   /* mobile_ap_enable() */
+       MOBILE_AP_DISABLE_CFM,                  /* mobile_ap_disable() */
+
+       MOBILE_AP_ENABLE_WIFI_TETHERING_CFM,    /* mobile_ap_enable_wifi_tethering() */
+       MOBILE_AP_DISABLE_WIFI_TETHERING_CFM,   /* mobile_ap_disable_wifi_tethering() */
+       MOBILE_AP_CHANGE_WIFI_CONFIG_CFM,       /* mobile_ap_change_wifi_config() */
+
+       MOBILE_AP_ENABLE_USB_TETHERING_CFM,     /* mobile_ap_enable_usb_tethering() */
+       MOBILE_AP_DISABLE_USB_TETHERING_CFM,    /* mobile_ap_disable_usb_tethering() */
+
+       MOBILE_AP_ENABLE_BT_TETHERING_CFM,      /* mobile_ap_enable_bt_tethering() */
+       MOBILE_AP_DISABLE_BT_TETHERING_CFM,     /* mobile_ap_disable_bt_tethering() */
+
+       MOBILE_AP_GET_STATION_INFO_CFM,         /* mobile_ap_get_station_info() */
+       MOBILE_AP_GET_DATA_PACKET_USAGE_CFM,    /* mobile_ap_get_data_packet_usage() */
+
+       MOBILE_AP_DISABLED_IND,                 /* Turning off tethering service indication */
+
+       MOBILE_AP_ENABLED_WIFI_TETHERING_IND,   /* Turning on WiFi tethering indication */
+       MOBILE_AP_DISABLED_WIFI_TETHERING_IND,  /* Turning off WiFi tethering indication */
+
+       MOBILE_AP_ENABLED_USB_TETHERING_IND,    /* Turning on USB tethering indication */
+       MOBILE_AP_DISABLED_USB_TETHERING_IND,   /* Turning off USB tethering indication */
+
+       MOBILE_AP_ENABLED_BT_TETHERING_IND,     /* Turning on BT tethering indication */
+       MOBILE_AP_DISABLED_BT_TETHERING_IND,    /* Turning off BT tethering indication */
+
+       MOBILE_AP_STATION_CONNECT_IND,          /* Station connection indication */
+       MOBILE_AP_STATION_DISCONNECT_IND,       /* Station disconnection indication */
+       MOBILE_AP_USB_STATION_CONNECT_IND,
+
+       MOBILE_AP_MAX_EVENT,
+} mobile_ap_event_e;
+
+typedef enum {
+       MOBILE_AP_TYPE_WIFI,
+       MOBILE_AP_TYPE_USB,
+       MOBILE_AP_TYPE_BT,
+       MOBILE_AP_TYPE_MAX,
+} mobile_ap_type_e;
+
+typedef struct {
+       unsigned long long pdp_tx_bytes;        /**< packet data transmitted */
+       unsigned long long pdp_rx_bytes;        /**< packet data received */
+} mobile_ap_data_packet_usage_t;
+
+typedef struct {
+       mobile_ap_type_e interface;                     /**< interface type */
+       char ip[MOBILE_AP_STR_INFO_LEN];                /**< assigned IP address */
+       char mac[MOBILE_AP_STR_INFO_LEN];               /**< MAC Address */
+       char hostname[MOBILE_AP_STR_HOSTNAME_LEN];      /**< alphanumeric name */
+} mobile_ap_station_info_t;
+
+typedef struct {
+       mobile_ap_type_e interface;                     /**< interface type */
+       char interface_name[MOBILE_AP_STR_INFO_LEN];            /**< interface alphanumeric name */
+       char ip_address[MOBILE_AP_STR_INFO_LEN];                /**< assigned ip addresss to interface */
+       char gateway_address[MOBILE_AP_STR_INFO_LEN];   /**< gateway address of interface */
+       char subnet_mask[MOBILE_AP_STR_INFO_LEN];       /**< subnet mask of interface */
+} mobile_ap_interface_info_t;
+
+typedef struct {
+       unsigned short number;                  /**< Number of connected device */
+       mobile_ap_station_info_t sta_info[MOBILE_AP_MAX_CONNECTED_STA];
+} mobile_ap_device_info_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MOBILEAP_INTERNAL_H__ */
diff --git a/include/mobileap_agent.h b/include/mobileap_agent.h
new file mode 100644 (file)
index 0000000..2344166
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOBILEAP_AGENT_H__
+#define __MOBILEAP_AGENT_H__
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <dlog.h>
+#include <vconf.h>
+#include <netinet/in.h>
+
+#include "mobileap.h"
+
+#define MH_MID "mh_agent"
+#define DBG(fmt, args...) LOG(LOG_DEBUG, MH_MID, "[%s()][Ln:%d] "fmt, \
+                                       __func__, __LINE__, ##args)
+#define ERR(fmt, args...) LOG(LOG_ERROR, MH_MID, "[%s()][Ln:%d] "fmt, \
+                                               __func__, __LINE__, ##args)
+
+#define DRIVER_DELAY           250000  /* micro seconds */
+
+#define IF_BUF_LEN             32
+#define NET_BUF_LEN            12
+#define INTERFACE_NAME_LEN     12
+#define SECURITY_TYPE_LEN      32
+
+/* Network Interface */
+#define IP_SUBNET_MASK         "255.255.255.0"
+
+#define WIFI_IF                        "wlan0"
+#define IP_ADDRESS_WIFI                0xC0A83D02      /* 192.168.61.2 */
+
+#define SOFTAP_IF              "wl0.1"
+#define IP_ADDRESS_SOFTAP      0xC0A83D01      /* 192.168.61.1 */
+
+#define USB_IF                 "usb0"
+#define IP_ADDRESS_USB         0xC0A88103      /* 192.168.129.3 */
+
+#define BT_IF_PREFIX           "bnep"
+#define BT_IF_ALL              BT_IF_PREFIX"+"
+#define IP_ADDRESS_BT_1                0xC0A88201      /* 192.168.130.1 */
+#define IP_ADDRESS_BT_2                0xC0A88301      /* 192.168.131.1 */
+#define IP_ADDRESS_BT_3                0xC0A88401      /* 192.168.132.1 */
+#define IP_ADDRESS_BT_4                0xC0A88501      /* 192.168.133.1 */
+#define IP_ADDRESS_BT_5                0xC0A88601      /* 192.168.134.1 */
+#define IP_ADDRESS_BT_6                0xC0A88701      /* 192.168.135.1 */
+#define IP_ADDRESS_BT_7                0xC0A88801      /* 192.168.136.1 */
+
+#define RET_FAILURE            (-1)
+#define RET_SUCCESS            (0)
+#define MAX_BUF_SIZE           (256u)
+
+#define DNSMASQ_CONF_LEN       1024
+#define DNSMASQ_CONF   "dhcp-range=192.168.61.3,192.168.61.150,255.255.255.0\n" \
+                       "dhcp-range=192.168.130.2,192.168.130.150,255.255.255.0\n" \
+                       "dhcp-range=192.168.131.2,192.168.131.150,255.255.255.0\n" \
+                       "dhcp-range=192.168.132.2,192.168.132.150,255.255.255.0\n" \
+                       "dhcp-range=192.168.133.2,192.168.133.150,255.255.255.0\n" \
+                       "dhcp-range=192.168.134.2,192.168.134.150,255.255.255.0\n" \
+                       "dhcp-range=192.168.135.2,192.168.135.150,255.255.255.0\n" \
+                       "dhcp-range=192.168.136.2,192.168.136.150,255.255.255.0\n" \
+                       "dhcp-range=192.168.137.2,192.168.137.150,255.255.255.0\n" \
+                       "dhcp-range=set:blue,192.168.129.4,192.168.129.150,255.255.255.0\n"\
+                       "enable-dbus\n" \
+                       "dhcp-option=tag:blue,option:router,192.168.129.3\n"
+#define DNSMASQ_CONF_FILE      "/tmp/dnsmasq.conf"
+
+/* Start of hostapd configuration */
+#define MH_CTRL_INTF           "/tmp/mh_wpa_ctrl"
+#define MH_MONITOR_INTF                "/tmp/mh_wpa_monitor"
+
+#define HOSTAPD_BIN            "/usr/sbin/hostapd"
+#define HOSTAPD_ENTROPY_FILE   "/opt/var/lib/misc/hostapd.bin"
+#define HOSTAPD_CONF_FILE      "/opt/var/lib/misc/hostapd.conf"
+#define HOSTAPD_CTRL_INTF_DIR  "/opt/var/lib/misc/hostapd"
+#define HOSTAPD_CONF_LEN       1024
+#define HOSTAPD_CONF           "interface=%s\n" \
+                               "driver=nl80211\n" \
+                               "ctrl_interface=%s\n" \
+                               "ssid=%s\n" \
+                               "channel=%d\n" \
+                               "ignore_broadcast_ssid=%d\n" \
+                               "max_num_sta=%d\n" \
+                               "%s\n"
+#define HOSTAPD_DEBUG_FILE     "/tmp/hostapd.log"
+#define HOSTAPD_REQ_MAX_LEN    128
+#define HOSTAPD_RETRY_MAX      5
+#define HOSTAPD_RETRY_DELAY    500000  /* us */
+#define HOSTAPD_STA_DISCONN    "AP-STA-DISCONNECTED "  /* from wpa_ctrl.h */
+#define HOSTAPD_MONITOR_ATTACH "ATTACH"
+#define HOSTAPD_MONITOR_DETACH "DETACH"
+/* End of hostapd configuration */
+
+#define WLAN_SCRIPT    "/usr/bin/wlan.sh"
+
+#define IP_FORWARD     "/proc/sys/net/ipv4/ip_forward"
+#define IPTABLES       "/usr/sbin/iptables"
+#define GREP           "/bin/grep"
+#define AWK            "/usr/bin/awk"
+#define DATA_USAGE_FILE        "/tmp/tethering_data_usage.txt"
+#define MASQUERADE_RULE                "-o %s -j MASQUERADE"
+#define DNS_ORDER              1
+#define TCP_DNS_FORWARD_RULE   "-i %s -p tcp --dport 53 -j DNAT --to %s:53"
+#define UDP_DNS_FORWARD_RULE   "-i %s -p udp --dport 53 -j DNAT --to %s:53"
+#define FORWARD_RULE           "-i %s -o %s"
+
+#define MOBILE_AP_STATE_NONE   0
+#define MOBILE_AP_STATE_WIFI   1
+#define MOBILE_AP_STATE_USB    2
+#define MOBILE_AP_STATE_BT     4
+#define MOBILE_AP_STATE_ALL    7
+
+#define DNSMASQ_DBUS_INTERFACE "uk.org.thekelleys.dnsmasq"
+
+#define PROC_NET_DEV                   "/proc/net/dev"
+#define TETHERING_CONN_TIMEOUT         (1200000)       /* 20 Mins */
+#define CHECK_NET_STATE_RETRY_COUNT    5
+#define PSK_ITERATION_COUNT            4096
+
+typedef struct {
+       /* The parent class object state. */
+       GObject parent;
+
+       /* instance member */
+       DBusGMethodInvocation *bt_context;
+       DBusGMethodInvocation *usb_context;
+       guint source_id;
+       GSList *bt_device;
+
+       int init_count;
+       int hide_mode;
+       int transfer_check_count;
+       unsigned long long rx_bytes;
+       unsigned long long tx_bytes;
+
+       char ssid[MOBILE_AP_WIFI_SSID_MAX_LEN + 1];
+       char key[MOBILE_AP_WIFI_KEY_MAX_LEN + 1];
+       char security_type[SECURITY_TYPE_LEN];
+} TetheringObject;
+
+typedef struct {
+       /* The parent class state. */
+       GObjectClass parent;
+
+       /* class member */
+       guint signals[E_SIGNAL_MAX];
+} TetheringObjectClass;
+
+typedef struct {
+       unsigned int number;    /* Number of connected device */
+                               /* BSSID list of connected device */
+       char bssid[MOBILE_AP_MAX_WIFI_STA][MOBILE_AP_STR_INFO_LEN];
+} softap_device_info_t;
+
+typedef struct {
+       const char *key;
+       vconf_callback_fn cb;
+       int *value;
+} vconf_reg_t;
+
+
+typedef enum {
+       MOBILE_AP_DRV_INTERFACE_NONE,
+       MOBILE_AP_WEXT,
+       MOBILE_AP_NL80211,
+} mobile_ap_drv_interface_e;
+
+/* ssid : 32  key : 64 */
+int _mh_core_enable_softap(const char *ssid, const char *security,
+               const char *key, int hide_mode);
+int _mh_core_disable_softap(void);
+int _mh_core_get_device_info(softap_device_info_t *di);
+int _mh_core_execute_dhcp_server(void);
+int _mh_core_terminate_dhcp_server(void);
+int _mh_core_enable_masquerade(const char *ext_if);
+int _mh_core_disable_masquerade(const char *ext_if);
+void _mh_core_add_data_to_array(GPtrArray *array, guint type, gchar *dev_name);
+int _mh_core_set_ip_address(const char *if_name, const in_addr_t ip);
+
+
+gboolean _init_tethering(TetheringObject *obj);
+gboolean _deinit_tethering(TetheringObject *obj);
+gboolean _mobileap_clear_state(int state);
+
+
+gboolean _mobileap_is_disabled(void);
+gboolean _mobileap_is_enabled(int state);
+gboolean _mobileap_is_enabled_by_type(mobile_ap_type_e type);
+gboolean _mobileap_set_state(int state);
+
+#endif
diff --git a/include/mobileap_bluetooth.h b/include/mobileap_bluetooth.h
new file mode 100644 (file)
index 0000000..f890d8c
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOBILEAP_BLUETOOTH_H__
+#define __MOBILEAP_BLUETOOTH_H__
+
+#include "mobileap_agent.h"
+
+void _bt_get_remote_device_name(TetheringObject *obj, const char *mac, char **name);
+mobile_ap_error_code_e _disable_bt_tethering(TetheringObject *obj);
+
+gboolean tethering_enable_bt_tethering(TetheringObject *obj,
+               DBusGMethodInvocation *context);
+gboolean tethering_disable_bt_tethering(TetheringObject *obj,
+               DBusGMethodInvocation *context);
+
+#endif
diff --git a/include/mobileap_common.h b/include/mobileap_common.h
new file mode 100644 (file)
index 0000000..be0cbaf
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOBILEAP_COMMON_H__
+#define __MOBILEAP_COMMON_H__
+
+#include <glib.h>
+
+#include "mobileap_agent.h"
+
+/* Need translation */
+#define MH_NOTI_STR    "Connected device (%d)"
+#define MH_NOTI_TITLE  "Tethering"
+
+gint _slist_find_station_by_interface(gconstpointer a, gconstpointer b);
+gint _slist_find_station_by_mac(gconstpointer a, gconstpointer b);
+gint _slist_find_station_by_ip_addr(gconstpointer a, gconstpointer b);
+
+void _emit_mobileap_dbus_signal(TetheringObject *obj,
+               mobile_ap_sig_e num, const gchar *message);
+void _send_dbus_station_info(const char *member,
+               mobile_ap_station_info_t *info);
+void _update_station_count(int count);
+int _add_station_info(mobile_ap_station_info_t *info);
+int _remove_station_info(gconstpointer data, GCompareFunc func);
+int _remove_station_info_all(mobile_ap_type_e type);
+int _get_station_info(gconstpointer data, GCompareFunc func,
+               mobile_ap_station_info_t **si);
+int _get_station_count(gconstpointer data, GCompareFunc func, int *count);
+int _station_info_foreach(GFunc func, void *user_data);
+int _add_data_usage_rule(const char *src, const char *dest);
+int _del_data_usage_rule(const char *src, const char *dest);
+int _get_data_usage(const char *src, const char *dest, unsigned long long *tx, unsigned long long *rx);
+int _execute_command(const char *cmd);
+int _get_tethering_type_from_ip(const char *ip, mobile_ap_type_e *type);
+
+#endif
diff --git a/include/mobileap_handler.h b/include/mobileap_handler.h
new file mode 100644 (file)
index 0000000..c1bc03b
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOBILEAP_HANDLER_H__
+#define __MOBILEAP_HANDLER_H__
+
+void _register_vconf_cb(void *user_data);
+void _unregister_vconf_cb(void *user_data);
+
+void _init_timeout_cb(mobile_ap_type_e type, void *user_data);
+void _start_timeout_cb(mobile_ap_type_e type);
+void _stop_timeout_cb(mobile_ap_type_e type);
+void _deinit_timeout_cb(mobile_ap_type_e type);
+
+
+#endif
diff --git a/include/mobileap_network.h b/include/mobileap_network.h
new file mode 100644 (file)
index 0000000..985797f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOBILEAP_NETWORK_H__
+#define __MOBILEAP_NETWORK_H__
+
+#include <glib.h>
+
+gboolean _get_network_interface_name(char **if_name);
+gboolean _set_masquerade(void);
+gboolean _unset_masquerade(void);
+gboolean _open_network(void);
+gboolean _close_network(void);
+gboolean _init_network(void *user_data);
+gboolean _deinit_network(void);
+
+#endif
diff --git a/include/mobileap_notification.h b/include/mobileap_notification.h
new file mode 100644 (file)
index 0000000..35a6273
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOBILEAP_NOTIFICATION_H__
+#define __MOBILEAP_NOTIFICATION_H__
+
+#include <notification.h>
+
+#define MH_NOTI_STR_MAX                50
+#define MH_NOTI_ICON_PATH      "/usr/apps/org.tizen.tethering/res/images/Q02_Notification_MobileAP.png"
+
+int _create_timeout_noti(const char *content, const char *title,
+               const char *icon_path);
+
+int _create_connected_noti(const char *content, const char *title,
+               const char *icon_path);
+int _update_connected_noti(const char *content);
+int _delete_connected_noti(void);
+
+#endif
diff --git a/include/mobileap_usb.h b/include/mobileap_usb.h
new file mode 100644 (file)
index 0000000..9acc5e6
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOBILEAP_USB_H__
+#define __MOBILEAP_USB_H__
+
+#include "mobileap_agent.h"
+
+
+mobile_ap_error_code_e _disable_usb_tethering(TetheringObject *obj);
+
+gboolean tethering_enable_usb_tethering(TetheringObject *obj,
+                                               DBusGMethodInvocation *context);
+gboolean tethering_disable_usb_tethering(TetheringObject *obj,
+                                               DBusGMethodInvocation *context);
+gboolean tethering_get_usb_station_info(TetheringObject *obj,
+                                               DBusGMethodInvocation *context);
+gboolean tethering_get_usb_interface_info(TetheringObject *obj,
+                                               DBusGMethodInvocation *context);
+
+#endif
diff --git a/include/mobileap_wifi.h b/include/mobileap_wifi.h
new file mode 100644 (file)
index 0000000..d64a595
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOBILEAP_WIFI_H__
+#define __MOBILEAP_WIFI_H__
+
+#include "mobileap_agent.h"
+
+#define SOFTAP_SECURITY_TYPE_OPEN_STR          "open"
+#define SOFTAP_SECURITY_TYPE_WPA2_PSK_STR      "wpa2-psk"
+#define SOFTAP_PASSPHRASE_PATH                 "wifi_tethering.txt"
+
+typedef enum {
+       SOFTAP_SECURITY_TYPE_OPEN,
+       SOFTAP_SECURITY_TYPE_WPA2_PSK,
+} softap_security_type_e;
+
+void _register_wifi_station_handler(void);
+void _add_wifi_device_to_array(softap_device_info_t *di, GPtrArray *array);
+mobile_ap_error_code_e _disable_wifi_tethering(TetheringObject *obj);
+
+/* Dbus method */
+gboolean tethering_enable_wifi_tethering(TetheringObject *obj, gchar *ssid,
+               gchar *key, gint hide_mode,
+               DBusGMethodInvocation *context);
+
+gboolean tethering_disable_wifi_tethering(TetheringObject *obj,
+               DBusGMethodInvocation *context);
+
+gboolean tethering_get_wifi_tethering_hide_mode(TetheringObject *obj,
+               DBusGMethodInvocation *context);
+
+gboolean tethering_set_wifi_tethering_hide_mode(TetheringObject *obj,
+               gint hide_mode, DBusGMethodInvocation *context);
+
+gboolean tethering_get_wifi_tethering_ssid(TetheringObject *obj,
+               DBusGMethodInvocation *context);
+
+gboolean tethering_get_wifi_tethering_security_type(TetheringObject *obj,
+               DBusGMethodInvocation *context);
+
+gboolean tethering_set_wifi_tethering_security_type(TetheringObject *obj,
+               gchar *security_type, DBusGMethodInvocation *context);
+
+gboolean tethering_get_wifi_tethering_passphrase(TetheringObject *obj,
+               DBusGMethodInvocation *context);
+
+gboolean tethering_set_wifi_tethering_passphrase(TetheringObject *obj,
+               gchar *passphrase, guint len, DBusGMethodInvocation *context);
+#endif /* __MOBILEAP_WIFI_H__ */
diff --git a/include/tethering-dbus-interface.xml b/include/tethering-dbus-interface.xml
new file mode 100644 (file)
index 0000000..0d5231e
--- /dev/null
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!DOCTYPE node PUBLIC
+       "-//freedesktop//DTD D-Bus Object Introspection 1.0//EN"
+       "http://standards.freedesktop.org/dbus/1.0/introspect.dtd">
+
+<node>
+       <interface name="org.tizen.tethering">
+
+               <!-- Method definitions -->
+
+               <method name="deinit">
+               </method>
+
+               <method name="disable">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="u" name="type" direction="out"/>
+                       <arg type="u" name="result" direction="out"/>
+               </method>
+
+               <method name="enable_wifi_tethering">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="s" name="ssid" direction="in"/>
+                       <arg type="s" name="key" direction="in"/>
+                       <arg type="i" name="visibility" direction="in"/>
+                       <arg type="u" name="type" direction="out"/>
+                       <arg type="u" name="result" direction="out"/>
+               </method>
+
+               <method name="disable_wifi_tethering">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="u" name="type" direction="out"/>
+                       <arg type="u" name="result" direction="out"/>
+               </method>
+
+               <method name="enable_bt_tethering">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="u" name="type" direction="out"/>
+                       <arg type="u" name="result" direction="out"/>
+               </method>
+
+               <method name="disable_bt_tethering">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="u" name="type" direction="out"/>
+                       <arg type="u" name="result" direction="out"/>
+               </method>
+
+               <method name="enable_usb_tethering">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="u" name="type" direction="out"/>
+                       <arg type="u" name="result" direction="out"/>
+               </method>
+
+               <method name="disable_usb_tethering">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="u" name="type" direction="out"/>
+                       <arg type="u" name="result" direction="out"/>
+               </method>
+
+               <method name="get_station_info">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="u" name="type" direction="out"/>
+                       <arg type="a(usss)" name="station" direction="out"/>
+               </method>
+
+               <method name="get_usb_station_info">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="a(sss)" name="usb_station" direction="out"/>
+               </method>
+
+               <method name="get_data_packet_usage">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="u" name="type" direction="out"/>
+                       <arg type="t" name="rx_data" direction="out"/>
+                       <arg type="t" name="tx_data" direction="out"/>
+               </method>
+
+               <method name="get_usb_interface_info">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="a(ssss)" name="interface" direction="out"/>
+               </method>
+
+               <method name="get_wifi_tethering_hide_mode">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="i" name="hide_mode" direction="out"/>
+               </method>
+
+               <method name="set_wifi_tethering_hide_mode">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="i" name="hide_mode" direction="in"/>
+               </method>
+
+               <method name="get_wifi_tethering_ssid">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="s" name="ssid" direction="out"/>
+               </method>
+
+               <method name="get_wifi_tethering_security_type">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="s" name="security_type" direction="out"/>
+               </method>
+
+               <method name="set_wifi_tethering_security_type">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="s" name="security_type" direction="in"/>
+               </method>
+
+               <method name="get_wifi_tethering_passphrase">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="s" name="passphrase" direction="out"/>
+                       <arg type="u" name="len" direction="out"/>
+               </method>
+
+               <method name="set_wifi_tethering_passphrase">
+                       <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+                       <arg type="s" name="passphrase" direction="in"/>
+                       <arg type="u" name="len" direction="in"/>
+               </method>
+
+               <!-- Signal (D-Bus) definitions -->
+               <signal name="net_closed">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+               <signal name="sta_connected">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+               <signal name="sta_disconnected">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+               <signal name="wifi_on">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+               <signal name="wifi_off">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+               <signal name="usb_on">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+               <signal name="usb_off">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+               <signal name="bluetooth_on">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+               <signal name="bluetooth_off">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+               <signal name="no_data_timeout">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+               <signal name="low_batt_mode">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+               <signal name="flight_mode">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+               <signal name="dhcp_status">
+                       <arg type="s" name="member" direction="out"/>
+                       <arg type="s" name="ip" direction="out"/>
+                       <arg type="s" name="mac" direction="out"/>
+                       <arg type="s" name="name" direction="out"/>
+               </signal>
+
+               <signal name="security_type_changed">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+               <signal name="ssid_visibility_changed">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+               <signal name="passphrase_changed">
+                       <arg type="s" name="arg1" direction="out"/>
+               </signal>
+
+       </interface>
+</node>
+
diff --git a/mobileap-agent.manifest b/mobileap-agent.manifest
new file mode 100644 (file)
index 0000000..75b0fa5
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+    <request>
+        <domain name="_"/>
+    </request>
+</manifest>
diff --git a/packaging/mobileap-agent.spec b/packaging/mobileap-agent.spec
new file mode 100644 (file)
index 0000000..28f2607
--- /dev/null
@@ -0,0 +1,160 @@
+Name:       mobileap-agent
+Summary:    Mobile AP daemon for setting tethering environments
+Version:    0.1.83
+Release:    1
+Group:      TO_BE/FILLED_IN
+License:    Apache License Version 2.0
+Source0:    %{name}-%{version}.tar.gz
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(dbus-glib-1)
+BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(gthread-2.0)
+BuildRequires: pkgconfig(pmapi)
+BuildRequires: pkgconfig(vconf)
+BuildRequires: pkgconfig(notification)
+BuildRequires: pkgconfig(libssl)
+BuildRequires: pkgconfig(secure-storage)
+BuildRequires: pkgconfig(capi-network-connection)
+BuildRequires: pkgconfig(capi-network-bluetooth)
+BuildRequires: cmake
+Requires(post): /usr/bin/vconftool
+Requires: iptables
+Requires: dnsmasq
+%description
+Mobile AP daemon for setting tethering environments
+
+%prep
+%setup -q
+
+%build
+export CFLAGS+=" -fpie"
+CFLAGS="${CFLAGS}" cmake . -DCMAKE_INSTALL_PREFIX="%{_prefix}"
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+%post
+/usr/bin/vconftool set -t int memory/mobile_hotspot/connected_device "0" -u 0 -i -f
+/usr/bin/vconftool set -t int memory/mobile_hotspot/mode "0" -u 0 -i -f
+/usr/bin/vconftool set -t int db/mobile_hotspot/security "0" -u 0 -f
+/usr/bin/vconftool set -t int db/mobile_hotspot/hide "0" -u 0 -f
+
+%files
+%manifest mobileap-agent.manifest
+%defattr(-,root,root,-)
+/usr/share/dbus-1/services/org.tizen.tethering.service
+%{_bindir}/mobileap-agent
+
+%changelog
+* Mon Jan 28 2013 Seungyoun Ju <sy39.ju@samsung.com> 0.1.83-1
+- Remove unrequired log
+
+* Thu Jan 24 2013 Seungyoun Ju <sy39.ju@samsung.com> 0.1.82-1
+- Indications for Wi-Fi tethering setting change are added
+- DNS Forward and Use of Tethering cellular profile are removed
+- Dbus service / interface / object names are changed
+
+* Mon Jan 14 2013 Seungyoun Ju <sy39.ju@samsung.com> 0.1.81-1
+- dhcp lease delete is handled based on IP Address
+- DNS Forward by netfilter is implemented
+- Vconf key for flight mode is changed
+
+* Fri Dec 07 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.80-1
+- Notification API's usage is changed
+- Duplicated station information issue is fixed
+- Improper notification type is used
+- Timeout(Auto disconnection) feature is implemented
+- Notification for timeout event is implemented
+
+* Thu Nov 08 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.79-1
+- Notification's API usage is changed
+
+* Tue Nov 06 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.78-1
+- Unnecessary BT API is removed
+
+* Sat Nov 03 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.77-1
+- Prevent issues are fixed
+
+* Tue Oct 30 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.76-1
+- Vconf enum is changed (SETTING_USB_MOBILE_HOTSPOT -> SETTING_USB_TETHERING_MODE)
+- Private code is separated
+
+* Mon Oct 29 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.75-1
+- Code clean-up and path for notification icon is changed
+
+* Thu Oct 22 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.74-1
+- License is added
+
+* Thu Oct 11 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.73-1
+- Source package name is changed (libmobileap -> mobileap-agent)
+
+* Thu Oct 11 2012 Injun Yang <injun.yang@samsung.com> 0.1.72-1
+- Launch kcp-agent
+
+* Fri Sep 28 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.71-1
+- Fix memory corruption
+
+* Fri Sep 21 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.70-1
+- Manifest file is added for SMACK
+
+* Wed Sep 19 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.69-1
+- The code for Legacy APIs is removed
+
+* Wed Sep 14 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.68-1
+- Bluetooth PAN Managed APIs are applied
+- MDM Phase 2 implementation
+
+* Wed Sep 06 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.67-1
+- Connection Managed APIs are applied
+- Network status is not checked in agent
+
+* Wed Aug 01 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.66-1
+- Wi-Fi tethering setting values are managed here
+- Deprecated APIs from glib-2.3.0 are replaced
+- Notification Icon is changed
+
+* Fri Jul 13 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.65-1
+- Wi-Fi tethering disable / enable issues are fixed
+
+* Fri Jul 06 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.64-1
+- Unnecessary dependency is removed
+
+* Mon Jun 25 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.63-1
+- Data usage is fixed
+
+* Thu May 31 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.62-1
+- Wi-Fi tethering security is implemented
+- API for getting USB interface information is implemented
+
+* Wed May 23 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.61-1
+- Tethering app. dependency is added
+
+* Tue May 22 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.60-1
+- Wi-Fi interface name is changed from eth0 to wlan0
+
+* Tue May 22 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.59-1
+- Below changes are applied
+- Ignore mdm failure case
+- CAPI bugs are fixed
+- Bug of _remove_station_info_all() is fixed
+- Launch tethering applicatoin from notification
+
+* Tue May 08 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.58-1
+- Hostapd control interface is implemented
+
+* Mon Apr 09 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.57-1
+- Unused vconfkey is removed
+
+* Wed Mar 14 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.56-1
+- Export API's are changed
+
+* Mon Feb 06 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.55-2
+- Fix build error
+
+* Mon Feb 06 2012 Seungyoun Ju <sy39.ju@samsung.com> 0.1.55-1
+- Test code is modified
+- Code clean-up
+- Notification is implemented
+- MDM bug fix
diff --git a/packaging/org.tizen.tethering.service b/packaging/org.tizen.tethering.service
new file mode 100644 (file)
index 0000000..8cd9d6f
--- /dev/null
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.tizen.tethering
+Exec=/usr/bin/mobileap-agent
diff --git a/src/mobileap_agent.c b/src/mobileap_agent.c
new file mode 100644 (file)
index 0000000..68f1c67
--- /dev/null
@@ -0,0 +1,1006 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/wireless.h>
+
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+
+#include "mobileap_common.h"
+#include "mobileap_agent.h"
+#include "mobileap_handler.h"
+
+static pid_t dnsmasq_pid = 0;
+static pid_t hostapd_pid = 0;
+static int hostapd_ctrl_fd = 0;
+static int hostapd_monitor_fd = 0;
+static GIOChannel *hostapd_io_channel = NULL;
+static guint hostapd_io_source = 0;
+
+static int __issue_ioctl(int sock_fd, char *if_name, char *cmd, char *buf)
+{
+       int ret_val = MOBILE_AP_ERROR_NONE;
+       struct iwreq iwr;
+
+       memset(buf, 0, MAX_BUF_SIZE);
+       memset(&iwr, 0, sizeof(iwr));
+
+       /* Configure ioctl parameters */
+       g_strlcpy(iwr.ifr_name, if_name, IFNAMSIZ);
+       g_strlcpy(buf, cmd, MAX_BUF_SIZE);
+       iwr.u.data.pointer = buf;
+       iwr.u.data.length = MAX_BUF_SIZE;
+
+       usleep(DRIVER_DELAY);
+
+       /* Issue ioctl */
+       if ((ioctl(sock_fd, SIOCSIWPRIV, &iwr)) < 0) {
+               ERR("ioctl failed...!!!\n");
+               ret_val = MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       return ret_val;
+}
+
+static int __get_psk_hexascii(const char *pass, const unsigned char *salt, char *psk, unsigned int psk_len)
+{
+       if (pass == NULL || salt == NULL || psk == NULL || psk_len == 0) {
+               ERR("Invalid parameter\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       if (psk_len < SHA256_DIGEST_LENGTH * 2 + 1) {
+               ERR("Invalid parameter\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       int i;
+       int d_16;
+       int r_16;
+       unsigned char buf[SHA256_DIGEST_LENGTH] = {0, };
+
+       if (!PKCS5_PBKDF2_HMAC_SHA1(pass, strlen(pass),
+                               salt, strlen((const char *)salt),
+                               PSK_ITERATION_COUNT, sizeof(buf), buf)) {
+               ERR("Getting psk is failed\n");
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
+               d_16 = buf[i] >> 4;
+               r_16 = buf[i] & 0xf;
+
+               psk[i << 1] = d_16 < 10 ? d_16 + '0' : d_16 - 10 + 'a';
+               psk[(i << 1) + 1] = r_16 < 10 ? r_16 + '0' : r_16 - 10 + 'a';
+       }
+       psk[i << 1] = '\0';
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+static int __execute_hostapd(const char *ssid, const char *security,
+               const char *key, int hide_mode)
+{
+       DBG("+\n");
+
+       char psk[2 * SHA256_DIGEST_LENGTH + 1] = {0, };
+       char buf[HOSTAPD_CONF_LEN] = "";
+       char sec_buf[HOSTAPD_CONF_LEN] = "";
+       FILE *fp = NULL;
+       pid_t pid;
+
+       if (security != NULL && !strcmp(security, "wpa2-psk")) {
+               if (__get_psk_hexascii(key, (const unsigned char *)ssid, psk,
+                                       sizeof(psk)) != MOBILE_AP_ERROR_NONE) {
+                       ERR("Getting PSK(Hex ascii type) is failed\n");
+                       return MOBILE_AP_ERROR_INTERNAL;
+               }
+
+               snprintf(sec_buf, HOSTAPD_CONF_LEN,
+                               "\nwpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s",
+                               psk);
+       }
+
+       snprintf(buf, HOSTAPD_CONF_LEN, HOSTAPD_CONF,
+                       WIFI_IF,
+                       HOSTAPD_CTRL_INTF_DIR,
+                       ssid,
+                       MOBILE_AP_WIFI_CHANNEL,
+                       hide_mode ? 2 : 0,
+                       MOBILE_AP_MAX_WIFI_STA,
+                       sec_buf);
+
+       fp = fopen(HOSTAPD_CONF_FILE, "w");
+       if (NULL == fp) {
+               ERR("Could not create the file.\n");
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+       fputs(buf, fp);
+       fclose(fp);
+
+       pid = fork();
+       if (pid < 0) {
+               ERR("fork failed\n");
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+        if (pid == 0) {
+               if (execl(HOSTAPD_BIN, HOSTAPD_BIN, "-e", HOSTAPD_ENTROPY_FILE,
+                                       HOSTAPD_CONF_FILE,
+                                       "-f", HOSTAPD_DEBUG_FILE, "-d",
+                                       (char *)NULL)) {
+                       ERR("execl failed\n");
+               }
+
+               ERR("Should not get here!");
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       hostapd_pid = pid;
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+static int __terminate_hostapd()
+{
+       DBG("+\n");
+
+       if (hostapd_pid == 0) {
+               DBG("There is no hostapd\n");
+               return MOBILE_AP_ERROR_NONE;
+       }
+
+       kill(hostapd_pid, SIGTERM);
+       waitpid(hostapd_pid, NULL, 0);
+       hostapd_pid = 0;
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+/*
+ * number NUM_STA(void)
+ * addr STA-FIRST(void)
+ * addr STA-NEXT(addr)
+ * void DISASSOCIATE(addr)
+ * void READ_WHITELIST(filename)
+ * void SET_MAXCLIENT(number)
+ */
+static int __send_hostapd_req(int fd, const char *req, const int req_len,
+               char *buf, int *buf_len)
+{
+       if (fd < 0 || req == NULL || req_len <= 0 ||
+                       buf == NULL || buf_len == NULL || *buf_len <= 0) {
+               ERR("Invalid param\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       struct timeval tv = {10, 0};
+       fd_set fds;
+       int ret = 0;
+
+       ret = send(fd, req, req_len, 0);
+       if (ret < 0) {
+               ERR("send is failed : %s\n", strerror(errno));
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       while (TRUE) {
+               FD_ZERO(&fds);
+               FD_SET(fd, &fds);
+               ret = select(fd + 1, &fds, NULL, NULL, &tv);
+               if (ret < 0) {
+                       return MOBILE_AP_ERROR_INTERNAL;
+               } else if (ret == 0) {
+                       ERR("There is no response from hostapd\n");
+                       return MOBILE_AP_ERROR_INTERNAL;
+               } else if (!FD_ISSET(fd, &fds)) {
+                       ERR("Unknown case\n");
+                       return MOBILE_AP_ERROR_INTERNAL;
+               }
+
+               ret = recv(fd, buf, (*buf_len) - 1, 0);
+               if (ret < 0) {
+                       ERR("recv is failed\n");
+                       return MOBILE_AP_ERROR_INTERNAL;
+               }
+
+               if (buf[0] == '<') {
+                       DBG("Unsolicited message\n");
+                       continue;
+               }
+
+               *buf_len = ret;
+               buf[ret] = '\0';
+               if (ret == 0) {
+                       ERR("socket is closed\n");
+               }
+
+               break;
+       }
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+static int __open_hostapd_intf(int *fd, const char *intf)
+{
+       if (fd == NULL || intf == NULL) {
+               ERR("fd is NULL\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       DBG("+\n");
+
+       int retry = 0;
+       char ctrl_intf[255] = {0, };
+       struct sockaddr_un src;
+       struct sockaddr_un dest;
+       struct stat stat_buf;
+
+       *fd = socket(PF_UNIX, SOCK_DGRAM, 0);
+       if (*fd < 0) {
+               ERR("socket is failed\n");
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       src.sun_family = AF_UNIX;
+       g_strlcpy(src.sun_path, intf, sizeof(src.sun_path));
+
+       if (stat(src.sun_path, &stat_buf) == 0) {
+               DBG("There is already mh interface. It will be removed\n");
+               unlink(src.sun_path);
+       }
+
+       if (bind(*fd, (struct sockaddr *)&src, sizeof(src)) < 0) {
+               ERR("bind is failed\n");
+               close(*fd);
+               *fd = -1;
+               unlink(src.sun_path);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       snprintf(ctrl_intf, sizeof(ctrl_intf), "%s/%s",
+                       HOSTAPD_CTRL_INTF_DIR, WIFI_IF);
+       dest.sun_family = AF_UNIX;
+       g_strlcpy(dest.sun_path, ctrl_intf, sizeof(dest.sun_path));
+
+       while (connect(*fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
+               DBG("connect is failed : %s\n", strerror(errno));
+               if (++retry >= HOSTAPD_RETRY_MAX)
+                       goto FAIL;
+               usleep(HOSTAPD_RETRY_DELAY);
+       }
+
+       return MOBILE_AP_ERROR_NONE;
+
+FAIL:
+       ERR("Cannot make connection to hostapd\n");
+       close(*fd);
+       *fd = -1;
+       unlink(src.sun_path);
+
+       return MOBILE_AP_ERROR_INTERNAL;
+}
+
+static int __close_hostapd_intf(int *fd)
+{
+       DBG("+\n");
+
+       if (fd == NULL) {
+               ERR("fd is NULL\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       if (*fd > 0)
+               close(*fd);
+       *fd = -1;
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+static gboolean __hostapd_monitor_cb(GIOChannel *source)
+{
+       DBG("+\n");
+
+       char buf[HOSTAPD_REQ_MAX_LEN] = {0, };
+       char *pbuf = NULL;
+       gsize read = 0;
+       int n_station = 0;
+
+#if !GLIB_CHECK_VERSION(2, 31, 0)
+       int ret = 0;
+
+       ret = g_io_channel_read(hostapd_io_channel, buf,
+                       HOSTAPD_REQ_MAX_LEN, &read);
+       if (ret != G_IO_ERROR_NONE) {
+               ERR("g_io_channel_read is failed\n");
+               return FALSE;
+       }
+#else
+       GError *err = NULL;
+
+       g_io_channel_read_chars(hostapd_io_channel, buf,
+                       HOSTAPD_REQ_MAX_LEN, &read, &err);
+       if (err != NULL) {
+               ERR("g_io_channel_read_chars is failed : %s\n", err->message);
+               g_error_free(err);
+               return FALSE;
+       }
+#endif
+
+       buf[read] = '\0';
+       pbuf = strrchr(buf, '\n');
+       if (pbuf != NULL)
+               *pbuf = '\0';
+
+       if (buf[0] == '<' && (pbuf = strchr(buf, '>')) != NULL) {
+               pbuf++;
+       } else {
+               pbuf = buf;
+       }
+
+       DBG("Event : %s\n", pbuf);
+
+       if (!strncmp(pbuf, HOSTAPD_STA_DISCONN, strlen(HOSTAPD_STA_DISCONN))) {
+               pbuf = strchr(pbuf, ' ');
+               if (pbuf == NULL) {
+                       ERR("There is no info. for disconnected station\n");
+                       return TRUE;
+               }
+               pbuf++;
+
+               DBG("Disconnected station MAC : %s\n", pbuf);
+               _remove_station_info(pbuf, _slist_find_station_by_mac);
+
+               _get_station_count((gconstpointer)MOBILE_AP_TYPE_WIFI,
+                               _slist_find_station_by_interface, &n_station);
+               if (n_station == 0)
+                       _start_timeout_cb(MOBILE_AP_TYPE_WIFI);
+
+               return TRUE;
+       } else {
+               DBG("Event is not handled\n");
+       }
+
+       return TRUE;
+}
+
+static int __open_hostapd_monitor(int *fd)
+{
+       if (fd == NULL) {
+               ERR("fd is NULL\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       DBG("+\n");
+
+       char buf[HOSTAPD_REQ_MAX_LEN] = {0, };
+       int buf_len = 0;
+
+       if (__open_hostapd_intf(fd, MH_MONITOR_INTF) != MOBILE_AP_ERROR_NONE) {
+               ERR("__open_hostapd_intf() is failed\n");
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       hostapd_io_channel = g_io_channel_unix_new(*fd);
+       if (hostapd_io_channel == NULL) {
+               ERR("g_io_channel_unix_new is failed\n");
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       g_io_channel_set_encoding(hostapd_io_channel, NULL, NULL);
+       g_io_channel_set_flags(hostapd_io_channel,
+                       G_IO_FLAG_APPEND | G_IO_FLAG_NONBLOCK, NULL);
+
+       hostapd_io_source = g_io_add_watch(hostapd_io_channel, G_IO_IN,
+                       (GIOFunc)__hostapd_monitor_cb, NULL);
+
+       buf_len = sizeof(buf);
+       __send_hostapd_req(*fd, HOSTAPD_MONITOR_ATTACH,
+                       strlen(HOSTAPD_MONITOR_ATTACH), buf, &buf_len);
+       DBG("return : %s\n", buf);
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+static int __close_hostapd_monitor(int *fd)
+{
+       GError *err = NULL;
+       char buf[HOSTAPD_REQ_MAX_LEN] = {0, };
+       int buf_len = 0;
+
+       buf_len = sizeof(buf);
+       __send_hostapd_req(*fd, HOSTAPD_MONITOR_DETACH,
+                       strlen(HOSTAPD_MONITOR_DETACH), buf, &buf_len);
+       DBG("return : %s\n", buf);
+
+       if (hostapd_io_source != 0) {
+               g_source_remove(hostapd_io_source);
+               hostapd_io_source = 0;
+       }
+
+       if (hostapd_io_channel != NULL) {
+               g_io_channel_shutdown(hostapd_io_channel, TRUE, &err);
+               g_io_channel_unref(hostapd_io_channel);
+               hostapd_io_channel = NULL;
+       }
+
+       __close_hostapd_intf(fd);
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+static mobile_ap_drv_interface_e __get_drv_interface(void)
+{
+       static mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
+
+       if (drv_interface != MOBILE_AP_DRV_INTERFACE_NONE) {
+               return drv_interface;
+       }
+
+       const char *drv_rfkill_path = "/sys/devices/platform";
+       const char *wext_drv[] = {
+               "bcm4329-b1", "bcm4330-b0",
+               "bcm4330-b1", "bcm4330-b2",
+               NULL};
+
+       char path[MAX_BUF_SIZE] = { 0 };
+       struct stat stat_buf = { 0 };
+       int fd = 0;
+       int i = 0;
+
+       drv_interface = MOBILE_AP_NL80211;
+
+       for (i = 0; wext_drv[i] != NULL; i++) {
+               snprintf(path, sizeof(path), "%s/%s",
+                               drv_rfkill_path, wext_drv[i]);
+               fd = open(path, O_RDONLY);
+               if (fd < 0)
+                       continue;
+
+               if (fstat(fd, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode)) {
+                       drv_interface = MOBILE_AP_WEXT;
+                       close(fd);
+                       break;
+               }
+
+               close(fd);
+       }
+
+       return drv_interface;
+}
+
+int _mh_core_enable_softap(const char *ssid, const char *security,
+               const char *key, int hide_mode)
+{
+       if (ssid == NULL || security == NULL || key == NULL) {
+               ERR("Invalid param\n");
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       char cmd[MAX_BUF_SIZE];
+       int ret_status = MOBILE_AP_ERROR_NONE;
+       mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
+
+       int sock_fd;
+       char *if_name = WIFI_IF;
+       char buf[MAX_BUF_SIZE] = { 0 };
+
+       snprintf(cmd, sizeof(cmd), "%s softap", WLAN_SCRIPT);
+       if (_execute_command(cmd)) {
+               ERR("execute script failed : %s\n", cmd);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       drv_interface = __get_drv_interface();
+
+       switch (drv_interface) {
+       case MOBILE_AP_WEXT:
+               if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
+                       ERR("Failed to open socket...!!!\n");
+                       ret_status = MOBILE_AP_ERROR_RESOURCE;
+                       break;
+               }
+
+               snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_CFG,"
+                                       "SSID_LEN=%d,SSID=%s,"
+                                       "SEC=%s,KEY_LEN=%d,KEY=%s,CHANNEL=%d,"
+                                       "PREAMBLE=0,MAX_SCB=%d,HIDE=%d,END",
+                                       strlen(ssid), ssid,
+                                       security, strlen(key), key,
+                                       MOBILE_AP_WIFI_CHANNEL,
+                                       MOBILE_AP_MAX_WIFI_STA, hide_mode);
+               ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
+               if (ret_status != MOBILE_AP_ERROR_NONE) {
+                       ERR("__issue_ioctl failed...!!!\n");
+                       close(sock_fd);
+                       break;
+               }
+
+               /* Start broadcasting of BSS. */
+               snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_BSS_START");
+               ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
+               if (ret_status != MOBILE_AP_ERROR_NONE) {
+                       ERR("__issue_ioctl failed...!!!\n");
+                       close(sock_fd);
+                       break;
+               }
+
+               close(sock_fd);
+
+               ret_status = _mh_core_set_ip_address(SOFTAP_IF,
+                               IP_ADDRESS_SOFTAP);
+               if (ret_status != MOBILE_AP_ERROR_NONE) {
+                       ERR("_mh_core_set_ip_address of SOFTAP_IF is failed\n");
+                       break;
+               }
+
+               DBG("Setting softap is OK\n");
+               ret_status = _mh_core_set_ip_address(WIFI_IF,
+                               IP_ADDRESS_WIFI);
+               if (ret_status != MOBILE_AP_ERROR_NONE) {
+                       ERR("_mh_core_set_ip_address of WIFI_IF is failed\n");
+                       break;
+               }
+               break;
+
+       case MOBILE_AP_NL80211:
+               ret_status = _mh_core_set_ip_address(WIFI_IF,
+                               IP_ADDRESS_SOFTAP);
+               if (ret_status != MOBILE_AP_ERROR_NONE) {
+                       ERR("_mh_core_set_ip_address is failed\n");
+                       break;
+               }
+
+               ret_status = __execute_hostapd(ssid, security, key, hide_mode);
+               if (ret_status != MOBILE_AP_ERROR_NONE) {
+                       ERR("__execute_hostapd is failed\n");
+                       break;
+               }
+
+               ret_status = __open_hostapd_intf(&hostapd_ctrl_fd, MH_CTRL_INTF);
+               if (ret_status != MOBILE_AP_ERROR_NONE) {
+                       ERR("__open_hostapd_intf is failed\n");
+                       __terminate_hostapd();
+                       break;
+               }
+
+               ret_status = __open_hostapd_monitor(&hostapd_monitor_fd);
+               if (ret_status != MOBILE_AP_ERROR_NONE) {
+                       ERR("__open_hostapd_monitor is failed\n");
+                       __close_hostapd_intf(&hostapd_ctrl_fd);
+                       __terminate_hostapd();
+                       break;
+               }
+
+               break;
+
+       default:
+               DBG("Unknown driver interface : %d\n", drv_interface);
+               break;
+       }
+
+       if (ret_status != MOBILE_AP_ERROR_NONE) {
+               snprintf(cmd, sizeof(cmd), "%s stop", WLAN_SCRIPT);
+               if (_execute_command(cmd)) {
+                       ERR("execute script failed : %s\n", cmd);
+               }
+       }
+
+       return ret_status;
+}
+
+int _mh_core_disable_softap(void)
+{
+       char cmd[MAX_BUF_SIZE] = { 0 };
+       int ret_status = MOBILE_AP_ERROR_NONE;
+       mobile_ap_drv_interface_e drv_interface = MOBILE_AP_DRV_INTERFACE_NONE;
+
+       int sock_fd = 0;
+       char buf[MAX_BUF_SIZE] = { 0 };
+       char *if_name = WIFI_IF;
+
+       drv_interface = __get_drv_interface();
+
+       switch (drv_interface) {
+       case MOBILE_AP_WEXT:
+               if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
+                       ERR("Failed to open socket...!!!\n");
+                       ret_status = MOBILE_AP_ERROR_RESOURCE;
+                       break;
+               }
+
+               /* Stop broadcasting of BSS. */
+               snprintf(cmd, MAX_BUF_SIZE, "ASCII_CMD=AP_BSS_STOP");
+               ret_status = __issue_ioctl(sock_fd, if_name, cmd, buf);
+               if (ret_status != MOBILE_AP_ERROR_NONE) {
+                       ERR("__issue_ioctl failed...!!!\n");
+                       close(sock_fd);
+                       break;
+               }
+
+               close(sock_fd);
+               break;
+
+       case MOBILE_AP_NL80211:
+               ret_status = __close_hostapd_intf(&hostapd_ctrl_fd);
+               if (ret_status != MOBILE_AP_ERROR_NONE)
+                       ERR("hostapd termination is failed\n");
+
+               ret_status = __close_hostapd_monitor(&hostapd_monitor_fd);
+               if (ret_status != MOBILE_AP_ERROR_NONE)
+                       ERR("hostapd termination is failed\n");
+
+               ret_status = __terminate_hostapd();
+               if (ret_status != MOBILE_AP_ERROR_NONE) {
+                       ERR("hostapd termination is failed\n");
+               }
+               break;
+
+       default:
+               DBG("Unknown driver interface : %d\n", drv_interface);
+               break;
+       }
+
+       snprintf(cmd, sizeof(cmd), "%s stop", WLAN_SCRIPT);
+       if (_execute_command(cmd)) {
+               ERR("execute script failed : %s\n", cmd);
+               ret_status = MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       return ret_status;
+}
+
+static int __get_device_info_by_wext(softap_device_info_t *di)
+{
+       int sock_fd = 0;
+       char *if_name = SOFTAP_IF;
+       char cmd[MAX_BUF_SIZE];
+       char buf[MAX_BUF_SIZE] = { 0 };
+       int ret = MOBILE_AP_ERROR_NONE;
+
+       char *buf_ptr = NULL;
+       int i;
+
+       if ((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
+               ERR("Failed to open socket...!!!\n");
+               di->number = 0;
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       snprintf(cmd, MAX_BUF_SIZE, "AP_GET_STA_LIST");
+       ret = __issue_ioctl(sock_fd, if_name, cmd, buf);
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               ERR("__issue_ioctl failed...!!!\n");
+               di->number = 0;
+               close(sock_fd);
+               return ret;
+       }
+
+       buf_ptr = buf;
+
+       sscanf(buf_ptr, "%02x", &di->number);
+       DBG("connected station : %d\n", di->number);
+
+       buf_ptr += 2;
+       for (i = 0; i < di->number; i++) {
+               unsigned int l_bssid[MOBILE_AP_WIFI_BSSID_LEN];
+               sscanf(buf_ptr, "%02X%02X%02X%02X%02X%02X", &l_bssid[0],
+                                       &l_bssid[1], &l_bssid[2], &l_bssid[3],
+                                       &l_bssid[4], &l_bssid[5]);
+               snprintf(di->bssid[i], MOBILE_AP_STR_INFO_LEN,
+                                       "%02X:%02X:%02X:%02X:%02X:%02X",
+                                       l_bssid[0], l_bssid[1], l_bssid[2],
+                                       l_bssid[3], l_bssid[4], l_bssid[5]);
+
+               DBG("STA[%d] address[%s]\n", i, di->bssid[i]);
+
+               buf_ptr += 12;
+       }
+
+       close(sock_fd);
+
+       return ret;
+}
+
+static int __get_device_info_by_nl80211(softap_device_info_t *di)
+{
+       int ret = 0;
+       int no_of_sta = 0;
+       int buf_len = 0;
+       char req[HOSTAPD_REQ_MAX_LEN] = {0, };
+       char buf[MOBILE_AP_STR_INFO_LEN] = {0, };
+
+       buf_len = sizeof(buf);
+       g_strlcpy(req, "NUM_STA", sizeof(req));
+       ret = __send_hostapd_req(hostapd_ctrl_fd,
+                       req, strlen(req), buf, &buf_len);
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               ERR("__send_hostapd_req is failed : %d\n", ret);
+               return ret;
+       }
+
+       DBG("The number of station : %s\n", buf);
+       if (atoi(buf) == 0) {
+               DBG("There is no station\n");
+               return MOBILE_AP_ERROR_NONE;
+       }
+
+       buf_len = sizeof(buf);
+       g_strlcpy(req, "STA-FIRST", sizeof(req));
+       ret = __send_hostapd_req(hostapd_ctrl_fd,
+                       req, strlen(req), buf, &buf_len);
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               ERR("__send_hostapd_req is failed : %d\n", ret);
+               return ret;
+       }
+
+       do {
+               if (!strncmp(buf, "FAIL", 4)) {
+                       ERR("FAIL is returned\n");
+                       break;
+               }
+
+               if (buf[0] == '\0') {
+                       ERR("NULL string\n");
+                       break;
+               }
+
+               DBG("Station : %s\n", buf);
+               g_strlcpy(di->bssid[no_of_sta++], buf, MOBILE_AP_STR_INFO_LEN);
+
+               buf_len = sizeof(buf);
+               snprintf(req, sizeof(req), "STA-NEXT %s", buf);
+               ret = __send_hostapd_req(hostapd_ctrl_fd,
+                               req, strlen(req), buf, &buf_len);
+       } while (ret == MOBILE_AP_ERROR_NONE);
+
+       di->number = no_of_sta;
+
+       return ret;
+}
+
+int _mh_core_get_device_info(softap_device_info_t *di)
+{
+       if (di == NULL) {
+               ERR("Invalid param\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       int ret = MOBILE_AP_ERROR_NONE;
+
+       switch (__get_drv_interface()) {
+       case MOBILE_AP_WEXT:
+               ret = __get_device_info_by_wext(di);
+               break;
+
+       case MOBILE_AP_NL80211:
+               ret = __get_device_info_by_nl80211(di);
+               break;
+
+       default:
+               ERR("Unknown interface\n");
+               break;
+       }
+
+       return ret;
+}
+
+int _mh_core_execute_dhcp_server(void)
+{
+       char buf[DNSMASQ_CONF_LEN] = "";
+       FILE *fp = NULL;
+       pid_t pid;
+
+       fp = fopen(DNSMASQ_CONF_FILE, "w");
+       if (NULL == fp) {
+               ERR("Could not create the file.\n");
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+       snprintf(buf, DNSMASQ_CONF_LEN, DNSMASQ_CONF);
+       fputs(buf, fp);
+       fclose(fp);
+
+       pid = fork();
+       if (pid < 0) {
+               ERR("fork failed\n");
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       if (pid == 0) {
+               /* -d : Debug mode
+                * -p 0 : DNS off
+                * -C file : Configuration file path
+                */
+               if (execl("/usr/bin/dnsmasq", "/usr/bin/dnsmasq", "-d",
+                                       "-p", "0", "-C", DNSMASQ_CONF_FILE,
+                                       (char *)NULL)) {
+                       ERR("execl failed\n");
+               }
+
+               ERR("Should not get here!");
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       dnsmasq_pid = pid;
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+int _mh_core_terminate_dhcp_server(void)
+{
+       if (dnsmasq_pid == 0) {
+               DBG("There is no dnsmasq\n");
+               return MOBILE_AP_ERROR_NONE;
+       }
+
+       kill(dnsmasq_pid, SIGTERM);
+       waitpid(dnsmasq_pid, NULL, 0);
+       dnsmasq_pid = 0;
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+int _mh_core_enable_masquerade(const char *ext_if)
+{
+       if (ext_if == NULL || strlen(ext_if) == 0) {
+               ERR("ext_if[%s] is invalid\n", ext_if);
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       int fd = -1;
+       char cmd[MAX_BUF_SIZE] = {0, };
+
+       fd = open(IP_FORWARD, O_WRONLY);
+       if (fd < 0) {
+               ERR("open failed\n");
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       if (write(fd, "1", 1) != 1) {
+               ERR("write failed\n");
+               close(fd);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+       close(fd);
+
+       snprintf(cmd, sizeof(cmd), "%s -t nat -A POSTROUTING "MASQUERADE_RULE,
+                       IPTABLES, ext_if);
+       if (_execute_command(cmd)) {
+               ERR("iptables failed : %s\n", cmd);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       _add_data_usage_rule(WIFI_IF, ext_if);
+       _add_data_usage_rule(BT_IF_ALL, ext_if);
+       _add_data_usage_rule(USB_IF, ext_if);
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+int _mh_core_disable_masquerade(const char *ext_if)
+{
+       if (ext_if == NULL || strlen(ext_if) == 0) {
+               ERR("ext_if[%s] is invalid\n", ext_if);
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       int fd = -1;
+       char cmd[MAX_BUF_SIZE] = {0, };
+
+       fd = open(IP_FORWARD, O_WRONLY);
+       if (fd < 0) {
+               ERR("open failed\n");
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       if (write(fd, "0", 1) != 1) {
+               ERR("write failed\n");
+               close(fd);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+       close(fd);
+
+       snprintf(cmd, sizeof(cmd), "%s -t nat -D POSTROUTING "MASQUERADE_RULE,
+                       IPTABLES, ext_if);
+       if (_execute_command(cmd)) {
+               ERR("iptables failed : %s\n", cmd);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       _del_data_usage_rule(WIFI_IF, ext_if);
+       _del_data_usage_rule(BT_IF_ALL, ext_if);
+       _del_data_usage_rule(USB_IF, ext_if);
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+void _mh_core_add_data_to_array(GPtrArray *array, guint type, gchar *dev_name)
+{
+       GValue value = {0, {{0}}};
+
+       g_value_init(&value, DBUS_STRUCT_UINT_STRING);
+       g_value_take_boxed(&value,
+                       dbus_g_type_specialized_construct(DBUS_STRUCT_UINT_STRING));
+       dbus_g_type_struct_set(&value, 0, type, 1, dev_name, G_MAXUINT);
+       g_ptr_array_add(array, g_value_get_boxed(&value));
+}
+
+int _mh_core_set_ip_address(const char *if_name, const in_addr_t ip)
+{
+       struct ifreq ifr;
+       struct sockaddr_in addr;
+       int sock_fd;
+
+       DBG("if_name : %s ip address : 0x%X\n", if_name, ip);
+
+       if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+               ERR("socket open failed!!!\n");
+               perror("ioctl fail");
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       g_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
+
+       memset(&addr, 0, sizeof(struct sockaddr));
+       addr.sin_family = AF_INET;
+       addr.sin_port = 0;
+       addr.sin_addr.s_addr = htonl(ip);
+
+       memcpy(&ifr.ifr_addr, &addr, sizeof(struct sockaddr));
+       if (ioctl(sock_fd, SIOCSIFADDR, &ifr) < 0) {
+               ERR("ioctl failed...!!!\n");
+               perror("ioctl fail");
+               close(sock_fd);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) < 0) {
+               ERR("ioctl failed...!!!\n");
+               perror("ioctl fail");
+               close(sock_fd);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+       if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) < 0) {
+               ERR("ioctl failed...!!!\n");
+               perror("ioctl fail");
+               close(sock_fd);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       close(sock_fd);
+
+       return MOBILE_AP_ERROR_NONE;
+}
diff --git a/src/mobileap_bluetooth.c b/src/mobileap_bluetooth.c
new file mode 100644 (file)
index 0000000..5fac0be
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <bluetooth.h>
+
+#include "mobileap_agent.h"
+#include "mobileap_common.h"
+#include "mobileap_bluetooth.h"
+#include "mobileap_handler.h"
+
+typedef struct {
+       bt_device_info_s *info;
+       char *intf_name;
+       const in_addr_t intf_ip;
+} __bt_remote_device_s;
+
+static __bt_remote_device_s __bt_remote_devices[MOBILE_AP_MAX_BT_STA] = {
+       {NULL, NULL, IP_ADDRESS_BT_1},
+       {NULL, NULL, IP_ADDRESS_BT_2},
+       {NULL, NULL, IP_ADDRESS_BT_3},
+       {NULL, NULL, IP_ADDRESS_BT_4},
+       {NULL, NULL, IP_ADDRESS_BT_5},
+       {NULL, NULL, IP_ADDRESS_BT_6},
+       {NULL, NULL, IP_ADDRESS_BT_7}};
+
+static __bt_remote_device_s *__find_bt_remote(const char *mac)
+{
+       int i;
+
+       for (i = 0; i < MOBILE_AP_MAX_BT_STA; i++) {
+               if (__bt_remote_devices[i].info == NULL)
+                       continue;
+
+               if (!g_ascii_strcasecmp(__bt_remote_devices[i].info->remote_address, mac))
+                       break;
+       }
+
+       if (i == MOBILE_AP_MAX_BT_STA) {
+               ERR("Not found : %s\n", mac);
+               return NULL;
+       }
+
+       return &__bt_remote_devices[i];
+}
+
+static __bt_remote_device_s *__add_bt_remote(bt_device_info_s *info, const char *intf_name)
+{
+       int i;
+
+       for (i = 0; i < MOBILE_AP_MAX_BT_STA; i++) {
+               if (__bt_remote_devices[i].info == NULL)
+                       break;
+       }
+
+       if (i == MOBILE_AP_MAX_BT_STA) {
+               ERR("Too many BT devices are connected\n");
+               return NULL;
+       }
+
+       __bt_remote_devices[i].intf_name = g_strdup(intf_name);
+       if (__bt_remote_devices[i].intf_name == NULL) {
+               ERR("Memory allocation failed\n");
+               return NULL;
+       }
+
+       __bt_remote_devices[i].info = info;
+
+       return &__bt_remote_devices[i];
+}
+
+static gboolean __del_bt_remote(const char *mac)
+{
+       int i;
+
+       for (i = 0; i < MOBILE_AP_MAX_BT_STA; i++) {
+               if (__bt_remote_devices[i].info == NULL)
+                       continue;
+
+               if (!g_ascii_strcasecmp(__bt_remote_devices[i].info->remote_address, mac))
+                       break;
+       }
+
+       if (i == MOBILE_AP_MAX_BT_STA) {
+               ERR("Not found : %s\n", mac);
+               return FALSE;
+       }
+
+        bt_adapter_free_device_info(__bt_remote_devices[i].info);
+        g_free(__bt_remote_devices[i].intf_name);
+
+        __bt_remote_devices[i].info = NULL;
+        __bt_remote_devices[i].intf_name = NULL;
+
+       return TRUE;
+}
+
+static void __del_bt_remote_all(void)
+{
+       int i;
+
+       for (i = 0; i < MOBILE_AP_MAX_BT_STA; i++) {
+               if (__bt_remote_devices[i].info) {
+                       bt_adapter_free_device_info(__bt_remote_devices[i].info);
+                       __bt_remote_devices[i].info = NULL;
+               }
+
+               if (__bt_remote_devices[i].intf_name) {
+                       g_free(__bt_remote_devices[i].intf_name);
+                       __bt_remote_devices[i].intf_name = NULL;
+               }
+       }
+
+       return;
+}
+
+static void __bt_nap_connection_changed(bool connected, const char *remote_address, const char *interface_name, void *user_data)
+{
+       if (remote_address == NULL || interface_name == NULL || user_data == NULL) {
+               ERR("Invalid param\n");
+               return;
+       }
+
+       __bt_remote_device_s *remote;
+       bt_device_info_s *info;
+       int ret;
+       int n_station = 0;
+
+       DBG("Remote address : %s, Interface : %s, %s\n",
+                       remote_address, interface_name,
+                       connected ? "Connected" : "Disconnected");
+
+
+       if (connected) {
+               ret = bt_adapter_get_bonded_device_info(remote_address, &info);
+               if (ret != BT_ERROR_NONE) {
+                       ERR("bt_adapter_get_bonded_device_info is failed : %d\n", ret);
+                       return;
+               }
+
+               remote = __add_bt_remote(info, interface_name);
+               if (remote == NULL) {
+                       ERR("__add_bt_remote is failed\n");
+                        bt_adapter_free_device_info(info);
+                       return;
+               }
+
+               ret = _mh_core_set_ip_address(interface_name, remote->intf_ip);
+               if (ret != MOBILE_AP_ERROR_NONE) {
+                       ERR("Setting ip address error : %d\n", ret);
+               }
+       } else {
+               _remove_station_info(remote_address, _slist_find_station_by_mac);
+               if (__del_bt_remote(remote_address) == FALSE) {
+                       ERR("__del_bt_remote is failed\n");
+               }
+
+               _get_station_count((gconstpointer)MOBILE_AP_TYPE_BT,
+                               _slist_find_station_by_interface, &n_station);
+               if (n_station == 0)
+                       _start_timeout_cb(MOBILE_AP_TYPE_BT);
+       }
+
+       return;
+}
+
+static mobile_ap_error_code_e __activate_bt_nap(TetheringObject *obj)
+{
+       int bt_ret = BT_ERROR_NONE;
+
+       bt_ret = bt_nap_set_connection_state_changed_cb(__bt_nap_connection_changed, (void *)obj);
+       if (bt_ret != BT_ERROR_NONE) {
+               ERR("bt_nap_set_connection_state_changed_cb is failed : %d\n", bt_ret);
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       bt_ret = bt_nap_activate();
+       if (bt_ret != BT_ERROR_NONE && bt_ret != BT_ERROR_ALREADY_DONE) {
+               bt_nap_unset_connection_state_changed_cb();
+               ERR("bt_nap_activate is failed : %d\n", bt_ret);
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+static void __deactivate_bt_nap(void)
+{
+       int bt_ret;
+
+       bt_ret = bt_nap_deactivate();
+       if (bt_ret != BT_ERROR_NONE)
+               ERR("bt_nap_deactivate is failed : %d\n", bt_ret);
+
+       bt_ret = bt_nap_unset_connection_state_changed_cb();
+       if (bt_ret != BT_ERROR_NONE)
+               ERR("bt_nap_unset_connection_state_changed_cb is failed : %d\n", bt_ret);
+
+       return;
+}
+
+static void __bt_adapter_state_changed(int result, bt_adapter_state_e adapter_state, void *user_data)
+{
+       if (user_data == NULL) {
+               ERR("Invalid param\n");
+               return;
+       }
+
+       if (!_mobileap_is_enabled(MOBILE_AP_STATE_BT))
+               return;
+
+       int ret;
+       TetheringObject *obj = (TetheringObject *)user_data;
+       DBusGMethodInvocation *context = obj->bt_context;
+
+       obj->bt_context = NULL;
+       if (result != BT_ERROR_NONE) {
+               ERR("BT Adapter operation is failed : %d\n", result);
+               if (context) {
+                       ret = MOBILE_AP_ERROR_RESOURCE;
+                       dbus_g_method_return(context,
+                                       MOBILE_AP_ENABLE_BT_TETHERING_CFM, ret);
+                       _mobileap_clear_state(MOBILE_AP_STATE_BT);
+               }
+               return;
+       }
+
+       DBG("BT Adapter is %s\n", adapter_state == BT_ADAPTER_ENABLED ?
+                       "enabled" : "disabled");
+       if (adapter_state == BT_ADAPTER_DISABLED) {
+               _disable_bt_tethering(obj);
+               _emit_mobileap_dbus_signal(obj, E_SIGNAL_BT_TETHER_OFF,
+                               SIGNAL_MSG_NOT_AVAIL_INTERFACE);
+               return;
+       }
+
+       ret = __activate_bt_nap(obj);
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               bt_adapter_unset_state_changed_cb();
+               bt_deinitialize();
+               _deinit_tethering(obj);
+               dbus_g_method_return(context,
+                               MOBILE_AP_ENABLE_BT_TETHERING_CFM, ret);
+               _mobileap_clear_state(MOBILE_AP_STATE_BT);
+               return;
+       }
+
+       _emit_mobileap_dbus_signal(obj, E_SIGNAL_BT_TETHER_ON, NULL);
+       if (context)
+               dbus_g_method_return(context,
+                               MOBILE_AP_ENABLE_BT_TETHERING_CFM, ret);
+       return;
+}
+
+void _bt_get_remote_device_name(TetheringObject *obj, const char *mac, char **name)
+{
+       if (obj == NULL || mac == NULL || name == NULL) {
+               ERR("Invalid param\n");
+               return;
+       }
+
+       __bt_remote_device_s *remote = NULL;
+
+       remote = __find_bt_remote(mac);
+       if (remote == NULL)
+               return;
+
+       *name = g_strdup(remote->info->remote_name);
+       if (*name == NULL) {
+               ERR("Memory allocation failed\n");
+               return;
+       }
+
+       return;
+}
+
+mobile_ap_error_code_e _disable_bt_tethering(TetheringObject *obj)
+{
+       int bt_ret;
+
+       if (!_mobileap_is_enabled(MOBILE_AP_STATE_BT)) {
+               ERR("BT tethering has not been enabled\n");
+               return MOBILE_AP_ERROR_NOT_ENABLED;
+       }
+
+       __deactivate_bt_nap();
+
+       bt_ret = bt_adapter_unset_state_changed_cb();
+       if (bt_ret != BT_ERROR_NONE)
+               ERR("bt_adapter_unset_state_changed_cb is failed : %d\n", bt_ret);
+
+       bt_ret = bt_deinitialize();
+       if (bt_ret != BT_ERROR_NONE)
+               ERR("bt_deinitialize is failed : %d\n", bt_ret);
+
+       _remove_station_info_all(MOBILE_AP_TYPE_BT);
+       __del_bt_remote_all();
+       _deinit_timeout_cb(MOBILE_AP_TYPE_BT);
+
+       _deinit_tethering(obj);
+       _mobileap_clear_state(MOBILE_AP_STATE_BT);
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+gboolean tethering_enable_bt_tethering(TetheringObject *obj,
+               DBusGMethodInvocation *context)
+{
+       int ret;
+       int bt_ret;
+       bt_adapter_state_e adapter_state = BT_ADAPTER_DISABLED;
+
+       DBG("+\n");
+
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+
+       if (_mobileap_is_enabled(MOBILE_AP_STATE_BT)) {
+               ERR("Bluetooth tethering is already enabled\n");
+               ret = MOBILE_AP_ERROR_ALREADY_ENABLED;
+               dbus_g_method_return(context,
+                               MOBILE_AP_ENABLE_BT_TETHERING_CFM, ret);
+               return FALSE;
+       }
+
+       if (obj->bt_context != NULL) {
+               ERR("Bluetooth tethering request is progressing\n");
+               ret = MOBILE_AP_ERROR_IN_PROGRESS;
+               dbus_g_method_return(context,
+                               MOBILE_AP_ENABLE_BT_TETHERING_CFM, ret);
+               return FALSE;
+       }
+
+       if (!_mobileap_set_state(MOBILE_AP_STATE_BT)) {
+               ret = MOBILE_AP_ERROR_RESOURCE;
+               goto FAIL;
+       }
+
+       if (!_init_tethering(obj)) {
+               ret = MOBILE_AP_ERROR_RESOURCE;
+               goto FAIL;
+       }
+
+       bt_ret = bt_initialize();
+       if (bt_ret != BT_ERROR_NONE) {
+               ERR("bt_initialize is failed : %d\n", bt_ret);
+               _deinit_tethering(obj);
+               ret = MOBILE_AP_ERROR_RESOURCE;
+               goto FAIL;
+       }
+
+       bt_ret = bt_adapter_set_state_changed_cb(__bt_adapter_state_changed, (void *)obj);
+       if (bt_ret != BT_ERROR_NONE) {
+               ERR("bt_adapter_set_state_changed_cb is failed : %d\n", bt_ret);
+               bt_deinitialize();
+               _deinit_tethering(obj);
+               ret = MOBILE_AP_ERROR_RESOURCE;
+               goto FAIL;
+       }
+
+       bt_ret = bt_adapter_get_state(&adapter_state);
+       if (bt_ret != BT_ERROR_NONE) {
+               ERR("bt_adapter_get_state is failed : %d\n", bt_ret);
+               bt_adapter_unset_state_changed_cb();
+               bt_deinitialize();
+               _deinit_tethering(obj);
+               ret = MOBILE_AP_ERROR_RESOURCE;
+               goto FAIL;
+       }
+
+       if (adapter_state == BT_ADAPTER_DISABLED) {
+               bt_ret = bt_adapter_enable();
+               if (bt_ret != BT_ERROR_NONE) {
+                       ERR("bt_adapter_enable is failed : %d\n", bt_ret);
+                       bt_adapter_unset_state_changed_cb();
+                       bt_deinitialize();
+                       _deinit_tethering(obj);
+                       ret = MOBILE_AP_ERROR_RESOURCE;
+                       goto FAIL;
+               }
+               obj->bt_context = context;
+               return TRUE;
+       }
+
+       ret = __activate_bt_nap(obj);
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               bt_adapter_unset_state_changed_cb();
+               bt_deinitialize();
+               _deinit_tethering(obj);
+               ret = MOBILE_AP_ERROR_RESOURCE;
+               goto FAIL;
+       }
+
+       _init_timeout_cb(MOBILE_AP_TYPE_BT, (void *)obj);
+       _start_timeout_cb(MOBILE_AP_TYPE_BT);
+
+       _emit_mobileap_dbus_signal(obj, E_SIGNAL_BT_TETHER_ON, NULL);
+       dbus_g_method_return(context, MOBILE_AP_ENABLE_BT_TETHERING_CFM, ret);
+       return TRUE;
+
+FAIL:
+       _mobileap_clear_state(MOBILE_AP_STATE_BT);
+       dbus_g_method_return(context, MOBILE_AP_ENABLE_BT_TETHERING_CFM, ret);
+       return FALSE;
+}
+
+
+gboolean tethering_disable_bt_tethering(TetheringObject *obj,
+               DBusGMethodInvocation *context)
+{
+       mobile_ap_error_code_e ret;
+
+       DBG("+\n");
+
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+       ret = _disable_bt_tethering(obj);
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               dbus_g_method_return(context, MOBILE_AP_DISABLE_BT_TETHERING_CFM, ret);
+               return FALSE;
+       }
+
+       _emit_mobileap_dbus_signal(obj, E_SIGNAL_BT_TETHER_OFF, NULL);
+       dbus_g_method_return(context, MOBILE_AP_DISABLE_BT_TETHERING_CFM, ret);
+       return TRUE;
+}
diff --git a/src/mobileap_common.c b/src/mobileap_common.c
new file mode 100644 (file)
index 0000000..41b9f7d
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "mobileap_notification.h"
+#include "mobileap_common.h"
+
+#define TETHERING_OBJECT_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+       TETHERING_TYPE_OBJECT , TetheringObjectClass))
+
+extern DBusConnection *tethering_conn;
+
+static GSList *station_list = NULL;
+
+gint _slist_find_station_by_interface(gconstpointer a, gconstpointer b)
+{
+       mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
+       mobile_ap_type_e interface = (mobile_ap_type_e)b;
+
+       return si->interface - interface;
+}
+
+gint _slist_find_station_by_mac(gconstpointer a, gconstpointer b)
+{
+       mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
+       const char *mac = (const char *)b;
+
+       return g_ascii_strcasecmp(si->mac, mac);
+}
+
+gint _slist_find_station_by_ip_addr(gconstpointer a, gconstpointer b)
+{
+       mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)a;
+       const char *ip_addr = (const char *)b;
+
+       return g_ascii_strcasecmp(si->ip, ip_addr);
+}
+
+void _emit_mobileap_dbus_signal(TetheringObject *obj,
+                               mobile_ap_sig_e num, const gchar *message)
+{
+       TetheringObjectClass *klass = TETHERING_OBJECT_GET_CLASS(obj);
+
+       DBG("Emitting signal id [%d], with message [%s]\n", num, message);
+       g_signal_emit(obj, klass->signals[num], 0, message);
+}
+
+void _send_dbus_station_info(const char *member, mobile_ap_station_info_t *info)
+{
+       if (tethering_conn == NULL)
+               return;
+
+       if (member == NULL || info == NULL) {
+               ERR("Invalid param\n");
+               return;
+       }
+
+       DBusMessage *msg = NULL;
+       char *ip = info->ip;
+       char *mac = info->mac;
+       char *hostname = info->hostname;
+
+       msg = dbus_message_new_signal(TETHERING_SERVICE_OBJECT_PATH,
+                       TETHERING_SERVICE_INTERFACE,
+                       SIGNAL_NAME_DHCP_STATUS);
+       if (!msg) {
+               ERR("Unable to allocate D-Bus signal\n");
+               return;
+       }
+
+       if (!dbus_message_append_args(msg,
+                               DBUS_TYPE_STRING, &member,
+                               DBUS_TYPE_UINT32, &info->interface,
+                               DBUS_TYPE_STRING, &ip,
+                               DBUS_TYPE_STRING, &mac,
+                               DBUS_TYPE_STRING, &hostname,
+                               DBUS_TYPE_INVALID)) {
+               ERR("Event sending failed\n");
+               dbus_message_unref(msg);
+               return;
+       }
+
+       dbus_connection_send(tethering_conn, msg, NULL);
+       dbus_message_unref(msg);
+
+       return;
+}
+
+
+void _update_station_count(int count)
+{
+       static int prev_cnt = 0;
+       char str[MH_NOTI_STR_MAX] = {0, };
+
+       if (prev_cnt == count) {
+               DBG("No need to update\n");
+               return;
+       }
+
+       DBG("Update the number of station : %d\n", count);
+       if (vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_CONNECTED_DEVICE,
+                               count) < 0) {
+               ERR("Error setting up vconf\n");
+               return;
+       }
+
+       if (count == 0) {
+               prev_cnt = 0;
+               _delete_connected_noti();
+               return;
+       }
+
+       snprintf(str, MH_NOTI_STR_MAX, MH_NOTI_STR, count);
+       if (prev_cnt == 0) {
+               DBG("Create notification\n");
+               _create_connected_noti(str, MH_NOTI_TITLE, MH_NOTI_ICON_PATH);
+       } else {
+               DBG("Update notification\n");
+               _update_connected_noti(str);
+       }
+
+       prev_cnt = count;
+       return;
+}
+
+int _add_station_info(mobile_ap_station_info_t *info)
+{
+       if (info == NULL) {
+               ERR("Invalid param\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       guint count;
+       GSList *l = NULL;
+       mobile_ap_station_info_t *si = NULL;
+       int i = 0;
+
+       if (_get_station_info(info->mac, _slist_find_station_by_mac, &si) ==
+                       MOBILE_AP_ERROR_NONE) {
+               DBG("Already exist station : %s\n", info->mac);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       station_list = g_slist_append(station_list, info);
+       for (l = station_list; l != NULL; l = g_slist_next(l)) {
+               si = (mobile_ap_station_info_t *)l->data;
+               DBG("[%d] interface : %d\n", i, si->interface);
+               DBG("[%d] station MAC : %s\n", i, si->mac);
+               DBG("[%d] station Hostname : %s\n", i, si->hostname);
+               DBG("[%d] station IP : %s\n", i, si->ip);
+               i++;
+       }
+
+       count = g_slist_length(station_list);
+       _update_station_count(count);
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+int _remove_station_info(gconstpointer data, GCompareFunc func)
+{
+       if (func == NULL) {
+               ERR("Invalid param\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       if (station_list == NULL) {
+               ERR("There is no station\n");
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       GSList *l = NULL;
+       mobile_ap_station_info_t *si = NULL;
+       int count;
+
+       l = g_slist_find_custom(station_list, data, func);
+       if (!l) {
+               ERR("Not found\n");
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       si = (mobile_ap_station_info_t *)l->data;
+       DBG("Remove station MAC : %s\n", si->mac);
+       station_list = g_slist_delete_link(station_list, l);
+       _send_dbus_station_info("DhcpLeaseDeleted", si);
+       g_free(si);
+
+       count = g_slist_length(station_list);
+       _update_station_count(count);
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+int _remove_station_info_all(mobile_ap_type_e type)
+{
+       if (station_list == NULL) {
+               return MOBILE_AP_ERROR_NONE;
+       }
+
+       GSList *l = station_list;
+       GSList *temp_l = NULL;
+       mobile_ap_station_info_t *si = NULL;
+       int count;
+
+       while (l) {
+               si = (mobile_ap_station_info_t *)l->data;
+               DBG("interface : %d\n", si->interface);
+               if (si->interface != type) {
+                       l = g_slist_next(l);
+                       continue;
+               }
+
+               DBG("Remove station MAC : %s\n", si->mac);
+               _send_dbus_station_info("DhcpLeaseDeleted", si);
+               g_free(si);
+
+               temp_l = l;
+               l = g_slist_next(l);
+               station_list = g_slist_delete_link(station_list, temp_l);
+       }
+
+       count = g_slist_length(station_list);
+       _update_station_count(count);
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+int _get_station_info(gconstpointer data, GCompareFunc func,
+               mobile_ap_station_info_t **si)
+{
+       if (func == NULL || si == NULL) {
+               ERR("Invalid param\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       if (station_list == NULL) {
+               ERR("There is no station\n");
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       GSList *l = NULL;
+       mobile_ap_station_info_t *node = NULL;
+
+       l = g_slist_find_custom(station_list, data, func);
+       if (!l) {
+               ERR("Not found\n");
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       node = l->data;
+       DBG("Found station : %s\n", node->mac);
+       *si = node;
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+int _get_station_count(gconstpointer data, GCompareFunc func, int *count)
+{
+       if (count == NULL) {
+               ERR("Invalid param\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       GSList *l = station_list;
+       int _count = 0;
+
+       for (_count = 0; l != NULL; _count++, l = g_slist_next(l)) {
+               l = g_slist_find_custom(l, data, func);
+               if (l == NULL)
+                       break;
+       }
+
+       *count = _count;
+       DBG("Station count : %d\n", *count);
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+int _station_info_foreach(GFunc func, void *user_data)
+{
+       if (func == NULL) {
+               ERR("Invalid param\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       g_slist_foreach(station_list, func, user_data);
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+int _add_data_usage_rule(const char *src, const char *dest)
+{
+       if (src == NULL || src[0] == '\0' ||
+                       dest == NULL || dest[0] == '\0' ||
+                       g_strcmp0(src, dest) == 0) {
+               ERR("Invalid parameter\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       char cmd[MAX_BUF_SIZE] = {0, };
+
+       snprintf(cmd, sizeof(cmd), "%s -A FORWARD "FORWARD_RULE,
+                       IPTABLES, src, dest);
+       DBG("ADD IPTABLES RULE : %s\n", cmd);
+       if (_execute_command(cmd)) {
+               ERR("iptables failed : %s\n", cmd);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       snprintf(cmd, sizeof(cmd), "%s -A FORWARD "FORWARD_RULE,
+                       IPTABLES, dest, src);
+       DBG("ADD IPTABLES RULE : %s\n", cmd);
+       if (_execute_command(cmd)) {
+               ERR("iptables failed : %s\n", cmd);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+int _del_data_usage_rule(const char *src, const char *dest)
+{
+       if (src == NULL || src[0] == '\0' ||
+                       dest == NULL || dest[0] == '\0' ||
+                       g_strcmp0(src, dest) == 0) {
+               ERR("Invalid parameter\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       char cmd[MAX_BUF_SIZE] = {0, };
+
+       snprintf(cmd, sizeof(cmd), "%s -D FORWARD "FORWARD_RULE,
+                       IPTABLES, src, dest);
+       DBG("REMOVE IPTABLES RULE : %s\n", cmd);
+       if (_execute_command(cmd)) {
+               ERR("iptables failed : %s\n", cmd);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       snprintf(cmd, sizeof(cmd), "%s -D FORWARD "FORWARD_RULE,
+                       IPTABLES, dest, src);
+       DBG("REMOVE IPTABLES RULE : %s\n", cmd);
+       if (_execute_command(cmd)) {
+               ERR("iptables failed : %s\n", cmd);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+int _get_data_usage(const char *src, const char *dest,
+               unsigned long long *tx, unsigned long long *rx)
+{
+       if (src == NULL || src[0] == '\0' ||
+                       dest == NULL || dest[0] == '\0' ||
+                       tx == NULL || rx == NULL) {
+               ERR("Invalid parameter\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       char cmd[MAX_BUF_SIZE] = {0, };
+       char buf[MAX_BUF_SIZE] = {0, };
+       FILE *fp = NULL;
+
+       /* Tx : Src. -> Dest. */
+       snprintf(cmd, sizeof(cmd),
+                       "%s -L FORWARD -vx | %s \"%s[ ]*%s\" | %s '{ print $2 }' > %s",
+                       IPTABLES, GREP, src, dest, AWK, DATA_USAGE_FILE);
+       DBG("GET DATA USAGE : %s\n", cmd);
+       if (system(cmd) < 0) {
+               ERR("\"cmd\" is failed\n");
+       }
+
+       /* Rx : Dest. -> Src. */
+       snprintf(cmd, sizeof(cmd),
+                       "%s -L FORWARD -vx | %s \"%s[ ]*%s\" | %s '{ print $2 }' >> %s",
+                       IPTABLES, GREP, dest, src, AWK, DATA_USAGE_FILE);
+       DBG("GET DATA USAGE : %s\n", cmd);
+       if (system(cmd) < 0) {
+               ERR("\"cmd\" is failed\n");
+       }
+
+       fp = fopen(DATA_USAGE_FILE, "r");
+       if (fp == NULL) {
+               ERR("%s open failed\n", DATA_USAGE_FILE);
+               ERR("%s\n", strerror(errno));
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       if (fgets(buf, sizeof(buf), fp) == NULL)
+               *tx = 0LL;
+       else
+               *tx = atoll(buf);
+       DBG("Tx(%s -> %s) : %llu\n", src, dest, *tx);
+
+       if (fgets(buf, sizeof(buf), fp) == NULL)
+               *rx = 0LL;
+       else
+               *rx = atoll(buf);
+       DBG("Rx(%s -> %s) : %llu\n", dest, src, *rx);
+
+       fclose(fp);
+       unlink(DATA_USAGE_FILE);
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+int _execute_command(const char *cmd)
+{
+       if (cmd == NULL) {
+               ERR("Invalid param\n");
+               return EXIT_FAILURE;
+       }
+
+       int status = 0;
+       int exit_status = 0;
+       pid_t pid = 0;
+       gchar **args = NULL;
+
+       DBG("cmd : %s\n", cmd);
+
+       args = g_strsplit_set(cmd, " ", -1);
+       if (!args) {
+               ERR("g_strsplit_set failed\n");
+               return EXIT_FAILURE;
+       }
+
+       if ((pid = fork()) < 0) {
+               ERR("fork failed\n");
+               return EXIT_FAILURE;
+       }
+
+       if (!pid) {
+               if (execv(args[0], args)) {
+                       ERR("execl failed\n");
+               }
+
+               ERR("Should never get here!\n");
+               return EXIT_FAILURE;
+       } else {
+               DBG("child pid : %d\n", pid);
+
+               /* Need to add timeout */
+               waitpid(pid, &status, 0);
+               g_strfreev(args);
+
+               if (WIFEXITED(status)) {
+                       exit_status = WEXITSTATUS(status);
+                       if (exit_status) {
+                               ERR("child return : %d\n", exit_status);
+                               return EXIT_FAILURE;
+                       }
+                       DBG("child terminated normally\n");
+                       return EXIT_SUCCESS;
+               } else {
+                       ERR("child is terminated without exit\n");
+                       return EXIT_FAILURE;
+               }
+       }
+}
+
+int _get_tethering_type_from_ip(const char *ip, mobile_ap_type_e *type)
+{
+       if (ip == NULL || type == NULL) {
+               ERR("Invalid param\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       static gboolean is_init = FALSE;
+       static in_addr_t subnet_wifi;
+       static in_addr_t subnet_bt_min;
+       static in_addr_t subnet_bt_max;
+       static in_addr_t subnet_usb;
+
+       struct in_addr addr;
+       in_addr_t subnet;
+
+       if (inet_aton(ip, &addr) == 0) {
+               ERR("Address : %s is invalid\n", ip);
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+       subnet = inet_netof(addr);
+
+       if (is_init == FALSE) {
+               addr.s_addr = htonl(IP_ADDRESS_WIFI);
+               subnet_wifi = inet_netof(addr);
+
+               addr.s_addr = htonl(IP_ADDRESS_BT_1);
+               subnet_bt_min = inet_netof(addr);
+
+               addr.s_addr = htonl(IP_ADDRESS_BT_7);
+               subnet_bt_max = inet_netof(addr);
+
+               addr.s_addr = htonl(IP_ADDRESS_USB);
+               subnet_usb = inet_netof(addr);
+               is_init = TRUE;
+       }
+
+       if (subnet == subnet_wifi) {
+               *type = MOBILE_AP_TYPE_WIFI;
+               return MOBILE_AP_ERROR_NONE;
+       } else if (subnet >= subnet_bt_min && subnet <= subnet_bt_max) {
+               *type = MOBILE_AP_TYPE_BT;
+               return MOBILE_AP_ERROR_NONE;
+       } else if (subnet == subnet_usb) {
+               *type = MOBILE_AP_TYPE_USB;
+               return MOBILE_AP_ERROR_NONE;
+       }
+
+       ERR("Tethering type cannot be decided from %s\n", ip);
+       return MOBILE_AP_ERROR_INVALID_PARAM;
+}
diff --git a/src/mobileap_handler.c b/src/mobileap_handler.c
new file mode 100644 (file)
index 0000000..0799cd5
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "mobileap_agent.h"
+#include "mobileap_common.h"
+#include "mobileap_bluetooth.h"
+#include "mobileap_wifi.h"
+#include "mobileap_usb.h"
+#include "mobileap_notification.h"
+
+/* Need translation */
+#define MH_NOTI_TIMEOUT_STR    "Tap for setting"
+#define MH_NOTI_TIMEOUT_TITLE  "Disable tethering by timeout"
+
+typedef struct {
+       guint src_id;
+       GSourceFunc func;
+       void *user_data;
+} sp_timeout_handler_t;
+
+static gboolean __wifi_timeout_cb(gpointer user_data);
+static gboolean __bt_timeout_cb(gpointer user_data);
+
+static sp_timeout_handler_t sp_timeout_handler[MOBILE_AP_TYPE_MAX] = {
+       {0, __wifi_timeout_cb, NULL},
+       {0, NULL, NULL},
+       {0, __bt_timeout_cb, NULL}};
+
+
+
+static void __handle_flight_mode_changed_cb(keynode_t *key, void *data)
+{
+       if (key == NULL) {
+               ERR("Parameter is NULL\n");
+               return;
+       }
+
+       TetheringObject *obj = (TetheringObject *)data;
+       int vconf_key = 0;
+
+       if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) {
+               DBG("Wi-Fi tethering is not enabled\n");
+               return;
+       }
+
+       if (vconf_keynode_get_type(key) != VCONF_TYPE_BOOL) {
+               ERR("Invalid vconf key type\n");
+               return;
+       }
+
+       vconf_key = vconf_keynode_get_bool(key);
+       DBG("key = %s, value = %d(bool)\n",
+                       vconf_keynode_get_name(key), vconf_key);
+
+       if (vconf_key == FALSE)
+               return;
+
+       DBG("Flight mode\n");
+       _disable_wifi_tethering(obj);
+       _emit_mobileap_dbus_signal(obj, E_SIGNAL_FLIGHT_MODE, NULL);
+
+       return;
+}
+
+static void __handle_device_name_changed_cb(keynode_t *key, void *data)
+{
+       if (key == NULL || data == NULL) {
+               ERR("Parameter is NULL\n");
+               return;
+       }
+
+       TetheringObject *obj = (TetheringObject *)data;
+       char *vconf_key = NULL;
+
+       if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) {
+               DBG("Wi-Fi hotspot is not enabled\n");
+               return;
+       }
+
+       if (vconf_keynode_get_type(key) != VCONF_TYPE_STRING) {
+               ERR("Invalid vconf key type\n");
+               return;
+       }
+
+       vconf_key = vconf_keynode_get_str(key);
+       DBG("key = %s, value = %s(str)\n",
+                       vconf_keynode_get_name(key), vconf_key);
+
+       if (g_strcmp0(vconf_key, obj->ssid) == 0) {
+               DBG("ssid is not changed\n");
+       } else {
+               DBG("ssid is changed\n");
+               _disable_wifi_tethering(obj);
+       }
+
+       return;
+}
+
+void _register_vconf_cb(void *user_data)
+{
+       if (user_data == NULL) {
+               ERR("Invalid param\n");
+               return;
+       }
+
+       vconf_reg_t vconf_reg[] = {
+               {VCONFKEY_TELEPHONY_FLIGHT_MODE,
+                       __handle_flight_mode_changed_cb, NULL},
+               {VCONFKEY_SETAPPL_DEVICE_NAME_STR,
+                       __handle_device_name_changed_cb, NULL},
+               {NULL, NULL, NULL}
+       };
+
+       int i = 0;
+       int ret = 0;
+
+       while (vconf_reg[i].key != NULL && vconf_reg[i].cb != NULL) {
+               DBG("Register [%d] : %s\n", i, vconf_reg[i].key);
+               ret = vconf_notify_key_changed(vconf_reg[i].key,
+                                       vconf_reg[i].cb, user_data);
+               if (ret != 0) {
+                       ERR("vconf_notify_key_changed is failed : %d\n", ret);
+               }
+
+               if (vconf_reg[i].value) {
+                       ret = vconf_get_int(vconf_reg[i].key,
+                                       vconf_reg[i].value);
+                       if (ret != 0) {
+                               ERR("vconf_get_int is failed : %d\n", ret);
+                       }
+               }
+
+               i++;
+       }
+
+       return;
+}
+
+void _unregister_vconf_cb(void *user_data)
+{
+       if (user_data == NULL) {
+               ERR("Invalid param\n");
+               return;
+       }
+
+       vconf_reg_t vconf_reg[] = {
+               {VCONFKEY_TELEPHONY_FLIGHT_MODE,
+                       __handle_flight_mode_changed_cb, NULL},
+               {VCONFKEY_SETAPPL_DEVICE_NAME_STR,
+                       __handle_device_name_changed_cb, NULL},
+               {NULL, NULL, NULL}
+       };
+
+       int i = 0;
+       int ret = 0;
+
+       while (vconf_reg[i].key != NULL && vconf_reg[i].cb != NULL) {
+               DBG("Register [%d] : %s\n", i, vconf_reg[i].key);
+               ret = vconf_ignore_key_changed(vconf_reg[i].key,
+                               vconf_reg[i].cb);
+               if (ret != 0) {
+                       ERR("vconf_notify_key_changed is failed : %d\n", ret);
+               }
+
+               i++;
+       }
+
+       return;
+}
+
+static gboolean __wifi_timeout_cb(gpointer data)
+{
+       DBG("+\n");
+       if (data == NULL) {
+               ERR("data is NULL\n");
+               return FALSE;
+       }
+
+       TetheringObject *obj = (TetheringObject *)data;
+
+       if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI) == FALSE) {
+               ERR("There is no conn. via Wi-Fi tethernig. But nothing to do\n");
+               return FALSE;
+       }
+
+       _disable_wifi_tethering(obj);
+       _emit_mobileap_dbus_signal(obj,
+                       E_SIGNAL_WIFI_TETHER_OFF, SIGNAL_MSG_TIMEOUT);
+
+       _create_timeout_noti(MH_NOTI_TIMEOUT_STR, MH_NOTI_TIMEOUT_TITLE,
+                       MH_NOTI_ICON_PATH);
+
+       DBG("-\n");
+       return FALSE;
+}
+
+static gboolean __bt_timeout_cb(gpointer data)
+{
+       DBG("+\n");
+       if (data == NULL) {
+               ERR("data is NULL\n");
+               return FALSE;
+       }
+
+       TetheringObject *obj = (TetheringObject *)data;
+
+       if (_mobileap_is_enabled(MOBILE_AP_STATE_BT) == FALSE) {
+               ERR("There is no conn. via BT tethering. But nothing to do\n");
+               return FALSE;
+       }
+
+       _disable_bt_tethering(obj);
+       _emit_mobileap_dbus_signal(obj,
+                       E_SIGNAL_BT_TETHER_OFF, SIGNAL_MSG_TIMEOUT);
+
+       _create_timeout_noti(MH_NOTI_TIMEOUT_STR, MH_NOTI_TIMEOUT_TITLE,
+                       MH_NOTI_ICON_PATH);
+       DBG("-\n");
+       return FALSE;
+}
+
+void _init_timeout_cb(mobile_ap_type_e type, void *user_data)
+{
+       DBG("+\n");
+       if (sp_timeout_handler[type].func == NULL) {
+               DBG("Not supported timeout : type[%d]\n", type);
+               return;
+       }
+
+       if (user_data == NULL) {
+               ERR("Invalid param\n");
+               return;
+       }
+
+       if (sp_timeout_handler[type].src_id > 0) {
+               DBG("There is already registered timeout source\n");
+               g_source_remove(sp_timeout_handler[type].src_id);
+               sp_timeout_handler[type].src_id = 0;
+       }
+
+       sp_timeout_handler[type].user_data = user_data;
+
+       DBG("-\n");
+       return;
+}
+
+void _start_timeout_cb(mobile_ap_type_e type)
+{
+       DBG("+\n");
+       if (sp_timeout_handler[type].func == NULL) {
+               DBG("Not supported timeout : type[%d]\n", type);
+               return;
+       }
+
+       if (sp_timeout_handler[type].src_id > 0) {
+               ERR("It is not registered or stopped\n");
+               return;
+       }
+
+       sp_timeout_handler[type].src_id = g_timeout_add(TETHERING_CONN_TIMEOUT,
+                       sp_timeout_handler[type].func,
+                       sp_timeout_handler[type].user_data);
+
+       DBG("-\n");
+       return;
+}
+
+void _stop_timeout_cb(mobile_ap_type_e type)
+{
+       DBG("+\n");
+       if (sp_timeout_handler[type].func == NULL) {
+               DBG("Not supported timeout : type[%d]\n", type);
+               return;
+       }
+
+       if (sp_timeout_handler[type].src_id == 0) {
+               ERR("It is not started yet\n");
+               return;
+       }
+
+       g_source_remove(sp_timeout_handler[type].src_id);
+       sp_timeout_handler[type].src_id = 0;
+
+       DBG("-\n");
+       return;
+}
+
+void _deinit_timeout_cb(mobile_ap_type_e type) {
+       DBG("+\n");
+       if (sp_timeout_handler[type].func == NULL) {
+               DBG("Not supported timeout : type[%d]\n", type);
+               return;
+       }
+
+       if (sp_timeout_handler[type].src_id > 0) {
+               g_source_remove(sp_timeout_handler[type].src_id);
+               sp_timeout_handler[type].src_id = 0;
+       }
+
+       sp_timeout_handler[type].user_data = NULL;
+
+       DBG("-\n");
+       return;
+}
+
diff --git a/src/mobileap_main.c b/src/mobileap_main.c
new file mode 100644 (file)
index 0000000..bfb1f8e
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pmapi.h>
+#include <vconf.h>
+#include <net_connection.h>
+
+#include "mobileap_agent.h"
+#include "mobileap_handler.h"
+#include "mobileap_common.h"
+#include "mobileap_bluetooth.h"
+#include "mobileap_wifi.h"
+#include "mobileap_usb.h"
+#include "mobileap_network.h"
+
+GType tethering_object_get_type(void);
+#define TETHERING_TYPE_OBJECT (tethering_object_get_type())
+G_DEFINE_TYPE(TetheringObject, tethering_object, G_TYPE_OBJECT)
+
+GMainLoop *mainloop = NULL;
+int mobileap_state = MOBILE_AP_STATE_NONE;
+DBusConnection *tethering_conn = NULL;
+
+gboolean tethering_deinit(TetheringObject *obj, GError **error);
+gboolean tethering_disable(TetheringObject *obj, DBusGMethodInvocation *context);
+gboolean tethering_get_station_info(TetheringObject *obj,
+               DBusGMethodInvocation *context);
+gboolean tethering_get_data_packet_usage(TetheringObject *obj,
+               DBusGMethodInvocation *context);
+#include "tethering-server-stub.h"
+
+static void tethering_object_init(TetheringObject *obj)
+{
+       DBG("+\n");
+       g_assert(obj != NULL);
+
+       obj->bt_context = NULL;
+       obj->usb_context = NULL;
+       obj->bt_device = NULL;
+       obj->rx_bytes = 0;
+       obj->tx_bytes = 0;
+       obj->transfer_check_count = 0;
+}
+
+static void tethering_object_finalize(GObject *obj)
+{
+       DBG("+\n");
+
+       G_OBJECT_CLASS(tethering_object_parent_class)->finalize(obj);
+}
+
+static void tethering_object_class_init(TetheringObjectClass *klass)
+{
+       GObjectClass *object_class = (GObjectClass *)klass;
+       const gchar *signalNames[E_SIGNAL_MAX] = {
+               SIGNAL_NAME_NET_CLOSED,
+               SIGNAL_NAME_STA_CONNECT,
+               SIGNAL_NAME_STA_DISCONNECT,
+               SIGNAL_NAME_WIFI_TETHER_ON,
+               SIGNAL_NAME_WIFI_TETHER_OFF,
+               SIGNAL_NAME_USB_TETHER_ON,
+               SIGNAL_NAME_USB_TETHER_OFF,
+               SIGNAL_NAME_BT_TETHER_ON,
+               SIGNAL_NAME_BT_TETHER_OFF,
+               SIGNAL_NAME_NO_DATA_TIMEOUT,
+               SIGNAL_NAME_LOW_BATTERY_MODE,
+               SIGNAL_NAME_FLIGHT_MODE,
+               SIGNAL_NAME_SECURITY_TYPE_CHANGED,
+               SIGNAL_NAME_SSID_VISIBILITY_CHANGED,
+               SIGNAL_NAME_PASSPHRASE_CHANGED
+       };
+
+       int i = 0;
+
+       g_assert(klass != NULL);
+
+       object_class->finalize = tethering_object_finalize;
+
+       DBG("Creating signals\n");
+
+       for (i = 0; i < E_SIGNAL_MAX; i++) {
+               guint signalId;
+
+               signalId = g_signal_new(signalNames[i],
+                                       G_OBJECT_CLASS_TYPE(klass),
+                                       G_SIGNAL_RUN_LAST,
+                                       0, NULL, NULL,
+                                       g_cclosure_marshal_VOID__STRING,
+                                       G_TYPE_NONE, 1, G_TYPE_STRING);
+               klass->signals[i] = signalId;
+       }
+
+       DBG("Binding to GLib/D-Bus\n");
+
+       dbus_g_object_type_install_info(TETHERING_TYPE_OBJECT,
+                                       &dbus_glib_tethering_object_info);
+}
+
+static void __add_station_info_to_array(gpointer data, gpointer user_data)
+{
+       mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)data;
+       GPtrArray *array = (GPtrArray *)user_data;
+       GValue value = {0, {{0}}};
+
+       g_value_init(&value, DBUS_STRUCT_STATIONS);
+       g_value_take_boxed(&value,
+                       dbus_g_type_specialized_construct(DBUS_STRUCT_STATIONS));
+       dbus_g_type_struct_set(&value, 0, si->interface, 1, si->ip,
+                       2, si->mac, 3, si->hostname, G_MAXUINT);
+       g_ptr_array_add(array, g_value_get_boxed(&value));
+}
+
+gboolean _mobileap_set_state(int state)
+{
+       int vconf_ret = 0;
+
+       DBG("Before mobileap_state : %d\n", mobileap_state);
+       mobileap_state |= state;
+       DBG("After mobileap_state : %d\n", mobileap_state);
+
+       vconf_ret = vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_MODE, mobileap_state);
+       if (vconf_ret != 0) {
+               ERR("vconf_set_int is failed : %d\n", vconf_ret);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+gboolean _mobileap_is_disabled(void)
+{
+       return mobileap_state ? FALSE : TRUE;
+}
+
+gboolean _mobileap_is_enabled(int state)
+{
+       return (mobileap_state & state) ? TRUE : FALSE;
+}
+
+gboolean _mobileap_is_enabled_by_type(mobile_ap_type_e type)
+{
+       switch (type) {
+       case MOBILE_AP_TYPE_WIFI:
+               if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
+                       return TRUE;
+               break;
+
+       case MOBILE_AP_TYPE_BT:
+               if (_mobileap_is_enabled(MOBILE_AP_STATE_BT))
+                       return TRUE;
+               break;
+
+       case MOBILE_AP_TYPE_USB:
+               if (_mobileap_is_enabled(MOBILE_AP_STATE_USB))
+                       return TRUE;
+               break;
+
+       default:
+               ERR("Unknow type : %d\n", type);
+               break;
+       }
+
+       return FALSE;
+}
+
+gboolean _mobileap_clear_state(int state)
+{
+       int vconf_ret = 0;
+
+       DBG("Before mobileap_state : %d\n", mobileap_state);
+       mobileap_state &= (~state);
+       DBG("After mobileap_state : %d\n", mobileap_state);
+
+       vconf_ret = vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_MODE, mobileap_state);
+       if (vconf_ret != 0) {
+               ERR("vconf_set_int is failed : %d\n", vconf_ret);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static void __block_device_sleep(void)
+{
+       int ret = 0;
+
+       ret = pm_lock_state(LCD_OFF, STAY_CUR_STATE, 0);
+       if (ret < 0)
+               ERR("PM control [ERROR] result = %d\n", ret);
+       else
+               DBG("PM control [SUCCESS]\n");
+}
+
+static void __unblock_device_sleep(void)
+{
+       int ret = 0;
+
+       ret = pm_unlock_state(LCD_OFF, PM_SLEEP_MARGIN);
+       if (ret < 0)
+               ERR("PM control [ERROR] result = %d\n", ret);
+       else
+               DBG("PM control [SUCCESS]\n");
+}
+
+gboolean _init_tethering(TetheringObject *obj)
+{
+       DBG("obj->init_count: %d\n", obj->init_count);
+
+       if (obj->init_count > 0) {
+               DBG("Already env. is initialized for tethering: %d\n",
+                               obj->init_count);
+               obj->init_count++;
+               return TRUE;
+       }
+
+       obj->init_count++;
+
+       __block_device_sleep();
+
+       DBG("Open network\n");
+       _open_network();
+
+       DBG("Run DHCP server\n");
+       _mh_core_execute_dhcp_server();
+
+       return TRUE;
+}
+
+gboolean _deinit_tethering(TetheringObject *obj)
+{
+       DBG("obj->init_count: %d\n", obj->init_count);
+
+       if (obj->init_count > 1) {
+               DBG("Already deinitialized\n");
+               obj->init_count--;
+               return TRUE;
+       } else if (obj->init_count <= 0) {
+               ERR("Already deinitialized\n");
+               obj->init_count = 0;
+               return TRUE;
+       }
+
+       obj->init_count = 0;
+
+       DBG("Terminate DHCP / IPTABLES\n");
+       _mh_core_terminate_dhcp_server();
+       _close_network();
+       __unblock_device_sleep();
+
+       return TRUE;
+}
+
+
+gboolean tethering_deinit(TetheringObject *obj, GError **error)
+{
+       DBG("+\n");
+       g_assert(obj != NULL);
+
+       if (_mobileap_is_disabled()) {
+               DBG("Mobile AP is not activated, so we quit the mobileap-agent.\n");
+               g_main_loop_quit(mainloop);
+       }
+
+       return TRUE;
+}
+
+gboolean tethering_disable(TetheringObject *obj, DBusGMethodInvocation *context)
+{
+       int ret = MOBILE_AP_ERROR_NONE;
+
+       DBG("+\n");
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+       if (_mobileap_is_disabled()) {
+               ERR("Mobile hotspot has not been enabled\n");
+               ret = MOBILE_AP_ERROR_NOT_ENABLED;
+               dbus_g_method_return(context, MOBILE_AP_DISABLE_CFM, ret);
+               return FALSE;
+       }
+
+       _disable_wifi_tethering(obj);
+       _disable_bt_tethering(obj);
+       _disable_usb_tethering(obj);
+
+       dbus_g_method_return(context, MOBILE_AP_DISABLE_CFM, ret);
+
+       return TRUE;
+}
+
+gboolean tethering_get_station_info(TetheringObject *obj,
+                                               DBusGMethodInvocation *context)
+{
+       DBG("+\n");
+
+       GPtrArray *array = g_ptr_array_new();
+
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+       _station_info_foreach(__add_station_info_to_array, array);
+
+       dbus_g_method_return(context, MOBILE_AP_GET_STATION_INFO_CFM, array);
+       g_ptr_array_free(array, TRUE);
+
+       DBG("-\n");
+
+       return TRUE;
+}
+
+gboolean tethering_get_data_packet_usage(TetheringObject *obj,
+                                               DBusGMethodInvocation *context)
+{
+       char *if_name = NULL;
+       unsigned long long wifi_tx_bytes = 0;
+       unsigned long long wifi_rx_bytes = 0;
+       unsigned long long bt_tx_bytes = 0;
+       unsigned long long bt_rx_bytes = 0;
+       unsigned long long usb_tx_bytes = 0;
+       unsigned long long usb_rx_bytes = 0;
+       unsigned long long tx_bytes = 0;
+       unsigned long long rx_bytes = 0;
+
+       if (_get_network_interface_name(&if_name) == FALSE) {
+               ERR("No network interface\n");
+               dbus_g_method_return(context, MOBILE_AP_GET_DATA_PACKET_USAGE_CFM,
+                               0, 0);
+               return FALSE;
+       }
+
+       if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
+               _get_data_usage(WIFI_IF, if_name,
+                               &wifi_tx_bytes, &wifi_rx_bytes);
+
+       if (_mobileap_is_enabled(MOBILE_AP_STATE_BT))
+               _get_data_usage(BT_IF_ALL, if_name,
+                               &bt_tx_bytes, &bt_rx_bytes);
+
+       if (_mobileap_is_enabled(MOBILE_AP_STATE_USB))
+               _get_data_usage(USB_IF, if_name,
+                               &usb_tx_bytes, &usb_rx_bytes);
+       free(if_name);
+
+       tx_bytes = wifi_tx_bytes + bt_tx_bytes + usb_tx_bytes;
+       rx_bytes = wifi_rx_bytes + bt_rx_bytes + usb_rx_bytes;
+
+       dbus_g_method_return(context, MOBILE_AP_GET_DATA_PACKET_USAGE_CFM,
+                       tx_bytes, rx_bytes);
+
+       return TRUE;
+}
+
+
+static DBusHandlerResult __dnsmasq_signal_filter(DBusConnection *conn,
+               DBusMessage *msg, void *user_data)
+{
+       if (!user_data) {
+               ERR("Invalid param\n");
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+       }
+
+       char *ip_addr = NULL;
+       char *mac = NULL;
+       char *name = NULL;
+       char *bt_remote_device_name = NULL;
+       DBusError error;
+       mobile_ap_type_e type = MOBILE_AP_TYPE_MAX;
+       TetheringObject *obj = (TetheringObject *)user_data;
+       mobile_ap_station_info_t *info = NULL;
+       int n_station = 0;
+
+       dbus_error_init(&error);
+       if (dbus_message_is_signal(msg, DNSMASQ_DBUS_INTERFACE,
+                               "DhcpConnected")) {
+               if (!dbus_message_get_args(msg, &error,
+                                       DBUS_TYPE_STRING, &ip_addr,
+                                       DBUS_TYPE_STRING, &mac,
+                                       DBUS_TYPE_STRING, &name,
+                                       DBUS_TYPE_INVALID)) {
+                       ERR("Cannot read message, cause: %s\n", error.message);
+                       dbus_error_free(&error);
+                       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+               }
+               DBG("DhcpConnected signal : %s  %s %s\n", ip_addr, mac, name);
+
+               if (_get_tethering_type_from_ip(ip_addr, &type) != MOBILE_AP_ERROR_NONE)
+                       return DBUS_HANDLER_RESULT_HANDLED;
+
+               if (_mobileap_is_enabled_by_type(type) == FALSE) {
+                       DBG("Tethering[%d] is disabled. Ignore ACK\n", type);
+                       return DBUS_HANDLER_RESULT_HANDLED;
+               }
+
+               info = (mobile_ap_station_info_t *)malloc(sizeof(mobile_ap_station_info_t));
+               if (info == NULL) {
+                       ERR("malloc failed\n");
+                       return DBUS_HANDLER_RESULT_HANDLED;
+               }
+
+               info->interface = type;
+               g_strlcpy(info->ip, ip_addr, sizeof(info->ip));
+               g_strlcpy(info->mac, mac, sizeof(info->mac));
+               if (type == MOBILE_AP_TYPE_WIFI || type == MOBILE_AP_TYPE_USB) {
+                       if (name[0] == '\0')
+                               g_strlcpy(info->hostname,
+                                               MOBILE_AP_NAME_UNKNOWN,
+                                               sizeof(info->hostname));
+                       else
+                               g_strlcpy(info->hostname, name,
+                                               sizeof(info->hostname));
+               } else if (type == MOBILE_AP_TYPE_BT) {
+                       _bt_get_remote_device_name(obj, mac, &bt_remote_device_name);
+                       if (bt_remote_device_name == NULL)
+                               g_strlcpy(info->hostname,
+                                               MOBILE_AP_NAME_UNKNOWN,
+                                               sizeof(info->hostname));
+                       else {
+                               g_strlcpy(info->hostname, bt_remote_device_name,
+                                               sizeof(info->hostname));
+                               free(bt_remote_device_name);
+                       }
+               }
+
+               if (_add_station_info(info) != MOBILE_AP_ERROR_NONE) {
+                       free(info);
+                       return DBUS_HANDLER_RESULT_HANDLED;
+               }
+
+               _get_station_count((gconstpointer)type,
+                               _slist_find_station_by_interface, &n_station);
+               if (n_station == 1)
+                       _stop_timeout_cb(type);
+
+               _send_dbus_station_info("DhcpConnected", info);
+
+               return DBUS_HANDLER_RESULT_HANDLED;
+       } else if (dbus_message_is_signal(msg, DNSMASQ_DBUS_INTERFACE,
+                               "DhcpLeaseDeleted")) {
+               if (!dbus_message_get_args(msg, &error,
+                                       DBUS_TYPE_STRING, &ip_addr,
+                                       DBUS_TYPE_STRING, &mac,
+                                       DBUS_TYPE_STRING, &name,
+                                       DBUS_TYPE_INVALID)) {
+                       ERR("Cannot read message, cause: %s\n", error.message);
+                       dbus_error_free(&error);
+                       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+               }
+
+               DBG("DhcpLeaseDeleted signal : %s %s %s\n", ip_addr, mac, name);
+
+               _remove_station_info(ip_addr, _slist_find_station_by_ip_addr);
+
+               return DBUS_HANDLER_RESULT_HANDLED;
+       }
+
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+int main(int argc, char **argv)
+{
+       TetheringObject *tethering_obj = NULL;
+       DBusError dbus_error;
+       char *rule = "type='signal',interface='"DNSMASQ_DBUS_INTERFACE"'";
+       DBusGConnection *tethering_bus = NULL;
+       DBusGProxy *tethering_bus_proxy = NULL;
+       guint result = 0;
+       GError *error = NULL;
+       int mobileap_vconf_key = VCONFKEY_MOBILE_HOTSPOT_MODE_NONE;
+
+       g_type_init();
+
+       if (vconf_get_int(VCONFKEY_MOBILE_HOTSPOT_MODE, &mobileap_vconf_key)) {
+               ERR("vconf_get_int FAIL\n");
+               mobileap_state = MOBILE_AP_STATE_NONE;
+       } else {
+               ERR("vconf_get_int OK(mobileap_vconf_key value is %d)\n",
+                                mobileap_vconf_key);
+               mobileap_state = mobileap_vconf_key;
+       }
+
+       mainloop = g_main_loop_new(NULL, FALSE);
+       if (mainloop == NULL) {
+               ERR("Couldn't create GMainLoop\n");
+               goto failure;
+       }
+
+       tethering_bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
+       if (error != NULL) {
+               ERR("Couldn't connect to system bus[%s]\n", error->message);
+               goto failure;
+       }
+
+       tethering_conn = dbus_g_connection_get_connection(tethering_bus);
+
+       DBG("Registering the well-known name (%s)\n", TETHERING_SERVICE_NAME);
+
+       tethering_bus_proxy = dbus_g_proxy_new_for_name(tethering_bus,
+                                                      DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
+       if (tethering_bus_proxy == NULL) {
+               ERR("Failed to get a proxy for D-Bus\n");
+               goto failure;
+       }
+
+       if (!dbus_g_proxy_call(tethering_bus_proxy,
+                              "RequestName",
+                              &error,
+                              G_TYPE_STRING,
+                              TETHERING_SERVICE_NAME,
+                              G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &result, G_TYPE_INVALID)) {
+               ERR("D-Bus.RequestName RPC failed[%s]\n", error->message);
+               goto failure;
+       }
+
+       if (result != 1) {
+               ERR("Failed to get the primary well-known name.\n");
+               goto failure;
+       }
+
+       g_object_unref(tethering_bus_proxy);
+       tethering_bus_proxy = NULL;
+
+       tethering_obj = g_object_new(TETHERING_TYPE_OBJECT, NULL);
+       if (tethering_obj == NULL) {
+               ERR("Failed to create one MobileAP instance.\n");
+               goto failure;
+       }
+
+       /* Registering it on the D-Bus */
+       dbus_g_connection_register_g_object(tethering_bus,
+                       TETHERING_SERVICE_OBJECT_PATH, G_OBJECT(tethering_obj));
+
+       DBG("Ready to serve requests.\n");
+
+       _init_network(NULL);
+       _register_wifi_station_handler();
+       _register_vconf_cb((void *)tethering_obj);
+
+       dbus_error_init(&dbus_error);
+       dbus_bus_add_match(tethering_conn, rule, &dbus_error);
+       if (dbus_error_is_set(&dbus_error)) {
+               ERR("Cannot add D-BUS match rule, cause: %s", dbus_error.message);
+               dbus_error_free(&dbus_error);
+               goto failure;
+       }
+
+       DBG("Listening to D-BUS signals from dnsmasq");
+       dbus_connection_add_filter(tethering_conn, __dnsmasq_signal_filter, tethering_obj, NULL);
+
+       g_main_loop_run(mainloop);
+
+       _unregister_vconf_cb((void *)tethering_obj);
+       _deinit_network();
+
+ failure:
+       ERR("Terminate the mobileap-agent\n");
+
+       if (tethering_bus)
+               dbus_g_connection_unref(tethering_bus);
+       if (tethering_bus_proxy)
+               g_object_unref(tethering_bus_proxy);
+       if (tethering_obj)
+               g_object_unref(tethering_obj);
+
+       return 0;
+}
diff --git a/src/mobileap_network.c b/src/mobileap_network.c
new file mode 100644 (file)
index 0000000..796f097
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <net_connection.h>
+
+#include "mobileap_agent.h"
+#include "mobileap_common.h"
+#include "mobileap_network.h"
+
+static connection_h connection = NULL;
+static connection_profile_h cprof = NULL;
+static connection_profile_h old_prof = NULL;
+
+static void __print_profile(connection_profile_h profile)
+{
+#define __check_connection_return(conn_ret)    \
+       do {    \
+               if (conn_ret != CONNECTION_ERROR_NONE)  \
+                       ERR("connection API fail : 0x%X\n", conn_ret);  \
+       } while(0)
+
+       if (profile == NULL)
+               return;
+
+       int conn_ret;
+       bool roaming;
+       char *apn;
+       char *home_url;
+       connection_cellular_network_type_e network_type;
+       connection_cellular_service_type_e service_type;
+
+       conn_ret = connection_profile_get_cellular_network_type(profile, &network_type);
+       __check_connection_return(conn_ret);
+       DBG("Network type : %d\n", network_type);
+
+       conn_ret = connection_profile_get_cellular_service_type(profile, &service_type);
+       __check_connection_return(conn_ret);
+       DBG("Service type : %d\n", service_type);
+
+       conn_ret = connection_profile_get_cellular_apn(profile, &apn);
+       __check_connection_return(conn_ret);
+       DBG("APN : %s\n", apn);
+       free(apn);
+
+       conn_ret = connection_profile_get_cellular_home_url(profile, &home_url);
+       __check_connection_return(conn_ret);
+       DBG("Home url : %s\n", home_url);
+       free(home_url);
+
+       conn_ret = connection_profile_is_cellular_roaming(profile, &roaming);
+       __check_connection_return(conn_ret);
+       DBG("Roaming : %d\n", roaming);
+
+#undef __check_connection_return
+       return;
+}
+
+static gboolean __is_connected_prof(connection_profile_h profile)
+{
+       int conn_ret;
+       connection_profile_state_e pstat = CONNECTION_PROFILE_STATE_DISCONNECTED;
+
+       conn_ret = connection_profile_get_state(profile, &pstat);
+       if (conn_ret != CONNECTION_ERROR_NONE) {
+               ERR("connection_profile_get_state is failed: 0x%X\n", conn_ret);
+               return FALSE;
+       }
+
+       if (pstat != CONNECTION_PROFILE_STATE_CONNECTED) {
+               DBG("Profile is not connected\n");
+               return FALSE;
+       }
+
+       DBG("Profile is connected\n");
+       return TRUE;
+}
+
+static gboolean __get_current_prof(connection_profile_h *r_prof, connection_profile_type_e *r_net_type)
+{
+       int conn_ret;
+       connection_profile_h profile = NULL;
+       connection_profile_type_e net_type = CONNECTION_PROFILE_TYPE_CELLULAR;
+
+       conn_ret = connection_get_current_profile(connection, &profile);
+       if (conn_ret != CONNECTION_ERROR_NONE) {
+               ERR("connection_get_current_profile is failed : %d\n", conn_ret);
+               return FALSE;
+       }
+
+       conn_ret = connection_profile_get_type(profile, &net_type);
+       if (conn_ret != CONNECTION_ERROR_NONE) {
+               ERR("connection_profile_get_type is failed : 0x%X\n", conn_ret);
+               connection_profile_destroy(profile);
+               return FALSE;
+       }
+
+       *r_prof = profile;
+       *r_net_type = net_type;
+       return TRUE;
+}
+
+static gboolean __get_network_prof(connection_profile_h *r_prof)
+{
+       connection_profile_h profile;
+       connection_profile_type_e net_type = CONNECTION_PROFILE_TYPE_CELLULAR;
+
+       if (__get_current_prof(&profile, &net_type) != TRUE) {
+               ERR("There is no available network\n");
+               return FALSE;
+       }
+
+       DBG("Current connected net_type : %d\n", net_type);
+       if (net_type == CONNECTION_PROFILE_TYPE_CELLULAR) {
+               __print_profile(profile);
+       }
+
+       *r_prof = profile;
+       return TRUE;
+}
+
+static void __connection_type_changed_cb(connection_type_e type, void *user_data)
+{
+       if (_mobileap_is_disabled()) {
+               DBG("Tethering is not enabled\n");
+               return;
+       }
+
+       DBG("Changed connection type is %s\n",
+                       type == CONNECTION_TYPE_DISCONNECTED ? "DISCONNECTED" :
+                       type == CONNECTION_TYPE_WIFI ? "Wi-FI" :
+                       type == CONNECTION_TYPE_CELLULAR ? "Cellular" :
+                       type == CONNECTION_TYPE_ETHERNET ? "Ethernet" :
+                       "Unknown");
+
+       _close_network();
+       if (type == CONNECTION_TYPE_DISCONNECTED)
+               return;
+
+       _open_network();
+       return;
+}
+
+gboolean _get_network_interface_name(char **if_name)
+{
+       int conn_ret = 0;
+
+       if (cprof == NULL)
+               return FALSE;
+
+       conn_ret = connection_profile_get_network_interface_name(cprof, if_name);
+       if (conn_ret != CONNECTION_ERROR_NONE) {
+               ERR("connection_profile_get_network_interface_name is failed : 0x%X\n", conn_ret);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+gboolean _set_masquerade(void)
+{
+       char *if_name = NULL;
+
+       if (_get_network_interface_name(&if_name) == FALSE) {
+               ERR("_get_network_interface_name is failed\n");
+               return FALSE;
+       }
+       DBG("Network interface : %s\n", if_name);
+
+       _mh_core_enable_masquerade(if_name);
+       free(if_name);
+
+       return TRUE;
+}
+
+gboolean _unset_masquerade(void)
+{
+       char *if_name = NULL;
+
+       if (_get_network_interface_name(&if_name) == FALSE) {
+               ERR("_get_network_interface_name is failed\n");
+               return FALSE;
+       }
+       DBG("Network interface : %s\n", if_name);
+
+       _mh_core_disable_masquerade(if_name);
+       free(if_name);
+
+       return TRUE;
+}
+
+gboolean _open_network(void)
+{
+       connection_profile_h profile = NULL;
+
+       DBG("+\n");
+
+       if (__get_network_prof(&profile) == FALSE) {
+               ERR("__get_network_prof is failed\n");
+               return FALSE;
+       }
+       cprof = profile;
+
+       if (__is_connected_prof(cprof) == FALSE) {
+               DBG("Connection is not yet opened\n");
+               return TRUE;
+       }
+
+       DBG("Set masquerading\n");
+       if (_set_masquerade() == FALSE) {
+               ERR("_set_masquerade is failed\n");
+               _close_network();
+               return FALSE;
+       }
+
+       DBG("-\n");
+
+       return TRUE;
+}
+
+gboolean _close_network(void)
+{
+       gboolean ret;
+
+       DBG("+\n");
+
+       if (cprof == NULL && old_prof == NULL) {
+               ERR("There is nothing to handle\n");
+               return TRUE;
+       }
+
+       ret = _unset_masquerade();
+       if (ret == FALSE)
+               ERR("_unset_masquerade is failed\n");
+
+       connection_profile_destroy(cprof);
+       cprof = NULL;
+
+       DBG("-\n");
+       return TRUE;
+}
+
+gboolean _init_network(void *user_data)
+{
+       int conn_ret;
+
+       conn_ret = connection_create(&connection);
+       if (conn_ret != CONNECTION_ERROR_NONE) {
+               ERR("connection_create is failed : 0x%X\n", conn_ret);
+               return FALSE;
+       }
+
+       conn_ret = connection_set_type_changed_cb(connection,
+                       __connection_type_changed_cb, user_data);
+       if (conn_ret != CONNECTION_ERROR_NONE) {
+               ERR("connection_set_type_changed cb is failed : 0x%X\n", conn_ret);
+               connection_destroy(connection);
+               connection = NULL;
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+gboolean _deinit_network(void)
+{
+       int conn_ret;
+
+       if (connection == NULL) {
+               ERR("Connection handle is not initialized\n");
+               return TRUE;
+       }
+
+       conn_ret = connection_unset_type_changed_cb(connection);
+       if (conn_ret != CONNECTION_ERROR_NONE) {
+               ERR("connection_unset_type_changed_cb is failed : %d\n", conn_ret);
+       }
+
+       connection_destroy(connection);
+       connection = NULL;
+
+       return TRUE;
+}
diff --git a/src/mobileap_notification.c b/src/mobileap_notification.c
new file mode 100644 (file)
index 0000000..4004cee
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <stdio.h>
+#include <string.h>
+#include <notification.h>
+
+#include "mobileap_agent.h"
+
+#define MH_NOTI_APP_NAME       "org.tizen.tethering"
+
+static int connected_noti_id = 0;
+static int timeout_noti_id = 0;
+
+int _create_timeout_noti(const char *content, const char *title,
+               const char *icon_path)
+{
+       DBG("+\n");
+       notification_h noti = NULL;
+       notification_error_e ret = NOTIFICATION_ERROR_NONE;
+
+       if (timeout_noti_id) {
+               noti = notification_load(APPNAME, timeout_noti_id);
+               if (noti == NULL) {
+                       DBG("Notification can be deleted already\n");
+               } else {
+                       ret = notification_delete(noti);
+                       if (ret != NOTIFICATION_ERROR_NONE) {
+                               ERR("Fail to notification_delete [%d]\n", ret);
+
+                               ret = notification_free(noti);
+                               if (ret != NOTIFICATION_ERROR_NONE)
+                                       ERR("Fail to notification_free [%d]\n", ret);
+                               return MOBILE_AP_ERROR_INTERNAL;
+                       }
+
+                       ret = notification_free(noti);
+                       if (ret != NOTIFICATION_ERROR_NONE) {
+                               ERR("Fail to notification_free [%d]\n", ret);
+                               return MOBILE_AP_ERROR_INTERNAL;
+                       }
+               }
+               timeout_noti_id = 0;
+       }
+
+       noti = notification_new(NOTIFICATION_TYPE_NOTI,
+                       NOTIFICATION_GROUP_ID_NONE, NOTIFICATION_PRIV_ID_NONE);
+       if (!noti) {
+               ERR("Fail to notification_new [%d]\n", ret);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       ret = notification_set_property(noti,
+                       NOTIFICATION_PROP_VOLATILE_DISPLAY);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_property [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_set_layout(noti, NOTIFICATION_LY_NOTI_EVENT_SINGLE);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_image [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_set_image(noti,
+                       NOTIFICATION_IMAGE_TYPE_ICON, icon_path);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_image [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_set_text(noti,
+                       NOTIFICATION_TEXT_TYPE_TITLE,
+                       title,
+                       NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_text [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_set_text(noti,
+                       NOTIFICATION_TEXT_TYPE_CONTENT,
+                       content,
+                       NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_text [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_set_pkgname(noti, APPNAME);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_pkgname [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_set_application(noti, MH_NOTI_APP_NAME);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_application [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_insert(noti, &timeout_noti_id);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_insert [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_free(noti);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_free [%d]\n", ret);
+               goto FAIL;
+       }
+
+       DBG("-\n");
+       return MOBILE_AP_ERROR_NONE;
+
+FAIL:
+       ret = notification_free(noti);
+       if (ret != NOTIFICATION_ERROR_NONE)
+               ERR("Fail to notification_free [%d]\n", ret);
+
+       return MOBILE_AP_ERROR_INTERNAL;
+}
+
+int _create_connected_noti(const char *content, const char *title,
+               const char *icon_path)
+{
+       DBG("+\n");
+       notification_h noti = NULL;
+       notification_error_e ret = NOTIFICATION_ERROR_NONE;
+
+       noti = notification_new(NOTIFICATION_TYPE_ONGOING,
+                       NOTIFICATION_GROUP_ID_NONE, NOTIFICATION_PRIV_ID_NONE);
+       if (!noti) {
+               ERR("Fail to notification_new [%d]\n", ret);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       ret = notification_set_property(noti,
+                       NOTIFICATION_PROP_DISABLE_AUTO_DELETE |
+                       NOTIFICATION_PROP_VOLATILE_DISPLAY);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_property [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_set_layout(noti, NOTIFICATION_LY_ONGOING_EVENT);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_image [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_set_image(noti, NOTIFICATION_IMAGE_TYPE_ICON, icon_path);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_image [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_set_text(noti,
+                       NOTIFICATION_TEXT_TYPE_TITLE,
+                       title,
+                       NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_text [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_set_text(noti,
+                       NOTIFICATION_TEXT_TYPE_CONTENT,
+                       content,
+                       NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_text [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_set_pkgname(noti, APPNAME);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_pkgname [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_set_application(noti, MH_NOTI_APP_NAME);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_application [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_insert(noti, &connected_noti_id);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_insert [%d]\n", ret);
+               goto FAIL;
+       }
+
+       ret = notification_free(noti);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_free [%d]\n", ret);
+               goto FAIL;
+       }
+
+       DBG("-\n");
+       return MOBILE_AP_ERROR_NONE;
+
+FAIL:
+       ret = notification_free(noti);
+       if (ret != NOTIFICATION_ERROR_NONE)
+               ERR("Fail to notification_free [%d]\n", ret);
+       return MOBILE_AP_ERROR_INTERNAL;
+}
+
+int _update_connected_noti(const char *content)
+{
+       DBG("+\n");
+
+       if (content == NULL) {
+               ERR("Invalid param\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       notification_h noti = NULL;
+       notification_error_e ret = NOTIFICATION_ERROR_NONE;
+
+       noti = notification_load(APPNAME, connected_noti_id);
+       if (noti == NULL) {
+               ERR("notification_load is failed\n");
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       ret = notification_set_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT,
+                       content, NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_set_text [%d]\n", ret);
+
+               ret = notification_free(noti);
+               if (ret != NOTIFICATION_ERROR_NONE)
+                       ERR("Fail to notification_free [%d]\n", ret);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       ret = notification_update(noti);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_update [%d]\n", ret);
+
+               ret = notification_free(noti);
+               if (ret != NOTIFICATION_ERROR_NONE)
+                       ERR("Fail to notification_free [%d]\n", ret);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       ret = notification_free(noti);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_free [%d]\n", ret);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       DBG("-\n");
+       return MOBILE_AP_ERROR_NONE;
+}
+
+int _delete_connected_noti(void)
+{
+       DBG("+\n");
+       notification_h noti = NULL;
+       notification_error_e ret;
+
+       noti = notification_load(APPNAME, connected_noti_id);
+       if (noti == NULL) {
+               ERR("notification_load is failed\n");
+               connected_noti_id = 0;
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+       connected_noti_id = 0;
+
+       ret = notification_delete(noti);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_delete [%d]\n", ret);
+
+               ret = notification_free(noti);
+               if (ret != NOTIFICATION_ERROR_NONE)
+                       ERR("Fail to notification_free [%d]\n", ret);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       ret = notification_free(noti);
+       if (ret != NOTIFICATION_ERROR_NONE) {
+               ERR("Fail to notification_free [%d]\n", ret);
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       DBG("-\n");
+       return MOBILE_AP_ERROR_NONE;
+}
+
diff --git a/src/mobileap_usb.c b/src/mobileap_usb.c
new file mode 100644 (file)
index 0000000..8de107f
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "mobileap_agent.h"
+#include "mobileap_common.h"
+#include "mobileap_usb.h"
+
+
+static void __handle_usb_disconnect_cb(keynode_t *key, void *data)
+{
+       if (key == NULL || data == NULL) {
+               ERR("Parameter is NULL\n");
+               return;
+       }
+
+       char *vconf_name;
+       int vconf_key;
+       TetheringObject *obj = (TetheringObject *)data;
+
+       if (!_mobileap_is_enabled(MOBILE_AP_STATE_USB)) {
+               ERR("USB tethering is not enabled\n");
+               return;
+       }
+
+       if (vconf_keynode_get_type(key) != VCONF_TYPE_INT) {
+               ERR("Invalid vconf key type\n");
+               return;
+       }
+
+       vconf_name = vconf_keynode_get_name(key);
+       vconf_key = vconf_keynode_get_int(key);
+       DBG("key = %s, value = %d(int)\n", vconf_name, vconf_key);
+
+       if (!strcmp(vconf_name, VCONFKEY_SYSMAN_USB_STATUS) &&
+                       vconf_key == VCONFKEY_SYSMAN_USB_DISCONNECTED)
+               DBG("USB is disconnected\n");
+       else if (!strcmp(vconf_name, VCONFKEY_SETAPPL_USB_MODE_INT) &&
+                       vconf_key != SETTING_USB_TETHERING_MODE)
+               DBG("USB Mode is changed [%d]\n", vconf_key);
+       else
+               return;
+
+       _disable_usb_tethering(obj);
+       _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_OFF,
+                       SIGNAL_MSG_NOT_AVAIL_INTERFACE);
+}
+
+static void __handle_usb_mode_change(keynode_t *key, void *data)
+{
+       if (key == NULL || data == NULL) {
+               ERR("Parameter is NULL\n");
+               return;
+       }
+
+       TetheringObject *obj = (TetheringObject *)data;
+       int ret;
+       int vconf_key;
+
+       if (vconf_keynode_get_type(key) != VCONF_TYPE_INT) {
+               ERR("Invalid vconf key\n");
+               return;
+       }
+
+       vconf_key = vconf_keynode_get_int(key);
+       DBG("key = %s, value = %d(int)\n",
+                       vconf_keynode_get_name(key), vconf_key);
+
+       if (_mobileap_is_enabled(MOBILE_AP_STATE_USB)) {
+               if (vconf_key != SETTING_USB_TETHERING_MODE) {
+                       DBG("Is progressing for usb mode change\n");
+                       return;
+               }
+
+               DBG("USB tethering is enabled\n");
+               vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
+                               __handle_usb_mode_change);
+               _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_ON, NULL);
+               dbus_g_method_return(obj->usb_context,
+                               MOBILE_AP_ENABLE_USB_TETHERING_CFM,
+                               MOBILE_AP_ERROR_NONE);
+               obj->usb_context = NULL;
+
+               /* USB Mode change is handled while USB tethering is enabled */
+               vconf_notify_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
+                               __handle_usb_disconnect_cb, (void *)obj);
+               ret = vconf_get_int(VCONFKEY_SETAPPL_USB_MODE_INT, &vconf_key);
+               if (ret != 0) {
+                       ERR("vconf_get_int is failed. but ignored [%d]\n", ret);
+                       return;
+               }
+               if (vconf_key != SETTING_USB_TETHERING_MODE) {
+                       ERR("USB Mode is changed suddenly\n");
+                       _disable_usb_tethering(obj);
+                       _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_OFF,
+                                       SIGNAL_MSG_NOT_AVAIL_INTERFACE);
+               }
+       } else {
+               if (vconf_key == SETTING_USB_TETHERING_MODE) {
+                       DBG("Is progressing for usb mode change\n");
+                       return;
+               }
+
+               DBG("USB tethering is disabled\n");
+               vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
+                               __handle_usb_mode_change);
+               _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_OFF, NULL);
+               dbus_g_method_return(obj->usb_context,
+                               MOBILE_AP_DISABLE_USB_TETHERING_CFM,
+                               MOBILE_AP_ERROR_NONE);
+               obj->usb_context = NULL;
+       }
+}
+
+mobile_ap_error_code_e _disable_usb_tethering(TetheringObject *obj)
+{
+       mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
+
+       if (!_mobileap_is_enabled(MOBILE_AP_STATE_USB)) {
+               ERR("USB tethering has not been enabled\n");
+               ret = MOBILE_AP_ERROR_NOT_ENABLED;
+               return ret;
+       }
+
+       _deinit_tethering(obj);
+
+       if (_remove_station_info_all(MOBILE_AP_TYPE_USB) != MOBILE_AP_ERROR_NONE) {
+               ERR("_remove_station_info_all is failed. Ignore it\n");
+       }
+
+       vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
+                       __handle_usb_disconnect_cb);
+       vconf_ignore_key_changed(VCONFKEY_SYSMAN_USB_STATUS,
+                       __handle_usb_disconnect_cb);
+
+       _mobileap_clear_state(MOBILE_AP_STATE_USB);
+
+       DBG("_disable_usb_tethering is done\n");
+
+       return ret;
+}
+
+gboolean tethering_enable_usb_tethering(TetheringObject *obj,
+                                               DBusGMethodInvocation *context)
+{
+       int vconf_ret;
+       int usb_mode = SETTING_USB_NONE_MODE;
+       int ret = MOBILE_AP_ERROR_NONE;
+
+       DBG("+\n");
+
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+
+       if (_mobileap_is_enabled(MOBILE_AP_STATE_USB)) {
+               ERR("USB tethering is already enabled\n");
+               ret = MOBILE_AP_ERROR_ALREADY_ENABLED;
+               dbus_g_method_return(context,
+                               MOBILE_AP_ENABLE_USB_TETHERING_CFM, ret);
+               return FALSE;
+       }
+
+       if (obj->usb_context) {
+               ERR("USB request is progressing\n");
+               ret = MOBILE_AP_ERROR_IN_PROGRESS;
+               dbus_g_method_return(context,
+                               MOBILE_AP_ENABLE_USB_TETHERING_CFM, ret);
+               return FALSE;
+       }
+
+       vconf_notify_key_changed(VCONFKEY_SYSMAN_USB_STATUS,
+                       __handle_usb_disconnect_cb, obj);
+       vconf_ret = vconf_get_int(VCONFKEY_SYSMAN_USB_STATUS, &usb_mode);
+       if (vconf_ret != 0 || usb_mode == VCONFKEY_SYSMAN_USB_DISCONNECTED) {
+               ERR("Error getting vconf\n");
+               ret = MOBILE_AP_ERROR_RESOURCE;
+               goto FAIL;
+       }
+
+       if (!_mobileap_set_state(MOBILE_AP_STATE_USB)) {
+               ret = MOBILE_AP_ERROR_RESOURCE;
+               goto FAIL;
+       }
+
+       if (!_init_tethering(obj)) {
+               ret = MOBILE_AP_ERROR_RESOURCE;
+               goto FAIL;
+       }
+
+       obj->usb_context = context;
+       vconf_notify_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
+                       __handle_usb_mode_change, (void *)obj);
+
+       vconf_ret = vconf_get_int(VCONFKEY_SETAPPL_USB_MODE_INT, &usb_mode);
+       if (vconf_ret != 0) {
+               ERR("Error getting vconf\n");
+               obj->usb_context = NULL;
+               vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
+                               __handle_usb_mode_change);
+               _deinit_tethering(obj);
+               ret = MOBILE_AP_ERROR_RESOURCE;
+               goto FAIL;
+       }
+
+       if (usb_mode == SETTING_USB_TETHERING_MODE) {
+               DBG("Don't need to wait for usb-setting\n");
+               obj->usb_context = NULL;
+               vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
+                               __handle_usb_mode_change);
+               _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_ON, NULL);
+               dbus_g_method_return(context,
+                               MOBILE_AP_ENABLE_USB_TETHERING_CFM, ret);
+               return TRUE;
+       }
+
+       DBG("-\n");
+       return TRUE;
+
+FAIL:
+       vconf_ignore_key_changed(VCONFKEY_SYSMAN_USB_STATUS,
+                       __handle_usb_disconnect_cb);
+       _mobileap_clear_state(MOBILE_AP_STATE_USB);
+       dbus_g_method_return(context,
+                       MOBILE_AP_ENABLE_USB_TETHERING_CFM, ret);
+       return FALSE;
+}
+
+gboolean tethering_disable_usb_tethering(TetheringObject *obj,
+               DBusGMethodInvocation *context)
+{
+       mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
+       int usb_mode = SETTING_USB_NONE_MODE;
+       int vconf_ret = 0;
+
+       DBG("+\n");
+
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+       if (obj->usb_context) {
+               ERR("USB request is progressing\n");
+               ret = MOBILE_AP_ERROR_IN_PROGRESS;
+               dbus_g_method_return(context,
+                               MOBILE_AP_DISABLE_USB_TETHERING_CFM, ret);
+               return FALSE;
+       }
+
+       ret = _disable_usb_tethering(obj);
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               dbus_g_method_return(context,
+                               MOBILE_AP_DISABLE_USB_TETHERING_CFM, ret);
+               return FALSE;
+       }
+
+       obj->usb_context = context;
+       vconf_notify_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
+                       __handle_usb_mode_change, (void *)obj);
+       vconf_ret = vconf_get_int(VCONFKEY_SETAPPL_USB_MODE_INT, &usb_mode);
+       if (vconf_ret != 0) {
+               ERR("Error getting vconf : %d. This error is ignored\n", vconf_ret);
+               goto DONE;
+       }
+       if (usb_mode != SETTING_USB_TETHERING_MODE) {
+               DBG("Don't need to wait for usb-setting\n");
+               goto DONE;
+       }
+
+       DBG("-\n");
+       return TRUE;
+
+DONE:
+       vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
+                       __handle_usb_mode_change);
+       _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_OFF, NULL);
+       dbus_g_method_return(context,
+                       MOBILE_AP_DISABLE_USB_TETHERING_CFM, ret);
+       return TRUE;
+}
+
+static void __add_usb_station_info_to_array(GPtrArray *array, mobile_ap_station_info_t *node)
+{
+       GValue value = {0, {{0}}};
+
+       g_value_init(&value, DBUS_STRUCT_STATION);
+       g_value_take_boxed(&value,
+                       dbus_g_type_specialized_construct(DBUS_STRUCT_STATION));
+       dbus_g_type_struct_set(&value, 0, node->ip, 1, node->mac,
+                       2, node->hostname, G_MAXUINT);
+       g_ptr_array_add(array, g_value_get_boxed(&value));
+}
+
+gboolean tethering_get_usb_station_info(TetheringObject *obj,
+                                               DBusGMethodInvocation *context)
+{
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+       GPtrArray *array = g_ptr_array_new();
+       mobile_ap_station_info_t *node = NULL;
+
+       if (_get_station_info((gconstpointer)MOBILE_AP_TYPE_USB,
+                               _slist_find_station_by_interface,
+                               &node) != MOBILE_AP_ERROR_NONE) {
+               DBG("There is no USB station\n");
+               dbus_g_method_return(context, array);
+               g_ptr_array_free(array, TRUE);
+               return TRUE;
+       }
+
+       __add_usb_station_info_to_array(array, node);
+       dbus_g_method_return(context, array);
+       g_ptr_array_free(array, TRUE);
+
+       return TRUE;
+}
+
+gboolean tethering_get_usb_interface_info(TetheringObject *obj,
+               DBusGMethodInvocation *context)
+{
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+       GPtrArray *array = g_ptr_array_new();
+       GValue value = {0, {{0}}};
+       struct in_addr addr;
+
+       addr.s_addr = htonl(IP_ADDRESS_USB);
+
+       g_value_init(&value, DBUS_STRUCT_INTERFACE);
+       g_value_take_boxed(&value,
+                       dbus_g_type_specialized_construct(DBUS_STRUCT_INTERFACE));
+       dbus_g_type_struct_set(&value, 0, USB_IF, 1, inet_ntoa(addr),
+                       2, inet_ntoa(addr), 3, IP_SUBNET_MASK, G_MAXUINT);
+
+       g_ptr_array_add(array, g_value_get_boxed(&value));
+       dbus_g_method_return(context, array);
+       g_ptr_array_free(array, TRUE);
+
+       return TRUE;
+}
diff --git a/src/mobileap_wifi.c b/src/mobileap_wifi.c
new file mode 100644 (file)
index 0000000..10069b4
--- /dev/null
@@ -0,0 +1,660 @@
+/*
+ * mobileap-agent
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ss_manager.h>
+
+#include "mobileap_agent.h"
+#include "mobileap_common.h"
+#include "mobileap_wifi.h"
+#include "mobileap_handler.h"
+
+static int __generate_initial_passphrase(char *passphrase_buf);
+static mobile_ap_error_code_e __get_hide_mode(int *hide_mode);
+static mobile_ap_error_code_e __set_hide_mode(const int hide_mode);
+static mobile_ap_error_code_e __get_ssid(char *ssid, unsigned int size);
+static mobile_ap_error_code_e __get_security_type(char *security_type, unsigned int len);
+static mobile_ap_error_code_e __set_security_type(const char *security_type);
+static mobile_ap_error_code_e __get_passphrase(char *passphrase, unsigned int size, unsigned int *passphrase_len);
+static mobile_ap_error_code_e __set_passphrase(const char *passphrase, const unsigned int size);
+static gboolean __send_station_event_cb(gpointer data);
+static void __handle_station_signal(int sig);
+static mobile_ap_error_code_e __update_wifi_data(TetheringObject *obj);
+
+static int __generate_initial_passphrase(char *passphrase_buf)
+{
+       DBG("+\n");
+
+       guint32 rand_int;
+       int index;
+
+       for (index = 0; index < MOBILE_AP_WIFI_KEY_MIN_LEN; index++) {
+               rand_int = g_random_int_range('a', 'z');
+               passphrase_buf[index] = rand_int;
+       }
+       passphrase_buf[index] = '\0';
+
+       return index;
+}
+
+static mobile_ap_error_code_e __get_hide_mode(int *hide_mode)
+{
+       if (hide_mode == NULL) {
+               ERR("Invalid param\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       if (vconf_get_int(VCONFKEY_MOBILE_HOTSPOT_HIDE, hide_mode) < 0) {
+               ERR("vconf_get_int is failed\n");
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+static mobile_ap_error_code_e __set_hide_mode(const int hide_mode)
+{
+       if (vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_HIDE, hide_mode) < 0) {
+               ERR("vconf_set_int is failed\n");
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+static mobile_ap_error_code_e __get_ssid(char *ssid, unsigned int size)
+{
+       if (ssid == NULL)
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+
+       char *ptr = NULL;
+       char *ptr_tmp = NULL;
+
+       ptr = vconf_get_str(VCONFKEY_SETAPPL_DEVICE_NAME_STR);
+       if (ptr == NULL)
+               return MOBILE_AP_ERROR_RESOURCE;
+
+       if (!g_utf8_validate(ptr, -1, (const char **)&ptr_tmp))
+               *ptr_tmp = '\0';
+
+       g_strlcpy(ssid, ptr, size);
+       free(ptr);
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+static mobile_ap_error_code_e __get_security_type(char *security_type, unsigned int len)
+{
+       if (security_type == NULL)
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+
+       char *type_str = NULL;
+       softap_security_type_e type;
+
+       if (vconf_get_int(VCONFKEY_MOBILE_HOTSPOT_SECURITY, (int *)&type) < 0) {
+               ERR("vconf_get_int is failed\n");
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       switch (type) {
+       case SOFTAP_SECURITY_TYPE_OPEN:
+               type_str = SOFTAP_SECURITY_TYPE_OPEN_STR;
+               break;
+
+       case SOFTAP_SECURITY_TYPE_WPA2_PSK:
+               type_str = SOFTAP_SECURITY_TYPE_WPA2_PSK_STR;
+               break;
+
+       default:
+               ERR("Invalid data\n");
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       g_strlcpy(security_type, type_str, len);
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+static mobile_ap_error_code_e __set_security_type(const char *security_type)
+{
+       if (security_type == NULL) {
+               ERR("Invalid param\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       softap_security_type_e type;
+
+       if (!strcmp(security_type, SOFTAP_SECURITY_TYPE_OPEN_STR)) {
+               type = SOFTAP_SECURITY_TYPE_OPEN;
+       } else if (!strcmp(security_type, SOFTAP_SECURITY_TYPE_WPA2_PSK_STR)) {
+               type = SOFTAP_SECURITY_TYPE_WPA2_PSK;
+       } else {
+               ERR("Invalid param\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       if (vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_SECURITY, type) < 0) {
+               ERR("vconf_set_int is failed\n");
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+static mobile_ap_error_code_e __get_passphrase(char *passphrase,
+               unsigned int size, unsigned int *passphrase_len)
+{
+       if (passphrase == NULL || passphrase_len == NULL) {
+               ERR("Invalid parameter\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       int ret = 0;
+       ssm_file_info_t sfi;
+
+       ret = ssm_getinfo(SOFTAP_PASSPHRASE_PATH, &sfi,
+                       SSM_FLAG_SECRET_OPERATION, NULL);
+       if (ret == -SS_FILE_OPEN_ERROR) {
+               *passphrase_len = __generate_initial_passphrase(passphrase);
+
+               ret = __set_passphrase(passphrase, *passphrase_len);
+               if (ret != MOBILE_AP_ERROR_NONE) {
+                       memset(passphrase, 0x00, size);
+                       *passphrase_len = 0;
+                       return ret;
+               }
+
+               ret = ssm_getinfo(SOFTAP_PASSPHRASE_PATH, &sfi,
+                               SSM_FLAG_SECRET_OPERATION, NULL);
+               if (ret < 0) {
+                       ERR("ssm_getinfo is failed : %d\n", ret);
+                       memset(passphrase, 0x00, size);
+                       *passphrase_len = 0;
+                       return MOBILE_AP_ERROR_RESOURCE;
+               }
+       } else if (ret < 0) {
+               ERR("ssm_getinfo is failed : %d\n", ret);
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       memset(passphrase, 0x00, size);
+       ret = ssm_read(SOFTAP_PASSPHRASE_PATH, passphrase, sfi.originSize,
+                       passphrase_len, SSM_FLAG_SECRET_OPERATION, NULL);
+       if (ret < 0) {
+               ERR("ssm_read is failed : %d\n", ret);
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+static mobile_ap_error_code_e __set_passphrase(const char *passphrase, const unsigned int size)
+{
+       if (size < MOBILE_AP_WIFI_KEY_MIN_LEN || size > MOBILE_AP_WIFI_KEY_MAX_LEN ||
+                       passphrase == NULL) {
+               ERR("Invalid parameter\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       int ret = 0;
+
+       ret = ssm_write_buffer((char *)passphrase, size, SOFTAP_PASSPHRASE_PATH,
+                       SSM_FLAG_SECRET_OPERATION, NULL);
+       if (ret < 0) {
+               ERR("ssm_write_buffer is failed : %d\n", ret);
+               return MOBILE_AP_ERROR_RESOURCE;
+       }
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+static gboolean __send_station_event_cb(gpointer data)
+{
+       int sig = GPOINTER_TO_INT(data);
+       int n_station = 0;
+       mobile_ap_station_info_t *si = NULL;
+
+       if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) {
+               return FALSE;
+       }
+
+       if (sig == SIGUSR1) {
+               DBG("STA connected(%d)\n", sig);
+               /* STA connection is handled in the dnsmasq signal handler */
+       } else if (sig == SIGUSR2) {
+               DBG("STA disconnected(%d)\n", sig);
+
+               /* Temporarily care only one station.
+                * Driver team should be support detail information */
+               if (_get_station_info(MOBILE_AP_TYPE_WIFI,
+                               _slist_find_station_by_interface,
+                               &si) != MOBILE_AP_ERROR_NONE) {
+                       return FALSE;
+               }
+               _remove_station_info(si->mac, _slist_find_station_by_mac);
+
+               _get_station_count((gconstpointer)MOBILE_AP_TYPE_WIFI,
+                               _slist_find_station_by_interface, &n_station);
+               if (n_station == 0)
+                       _start_timeout_cb(MOBILE_AP_TYPE_WIFI);
+       }
+
+       return FALSE;
+}
+
+static void __handle_station_signal(int sig)
+{
+       g_idle_add(__send_station_event_cb, GINT_TO_POINTER(sig));
+       return;
+}
+
+void _register_wifi_station_handler(void)
+{
+       struct sigaction sa;
+
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = __handle_station_signal;
+       sigaction(SIGUSR1, &sa, NULL);
+       sigaction(SIGUSR2, &sa, NULL);
+}
+
+void _add_wifi_device_to_array(softap_device_info_t *di, GPtrArray *array)
+{
+       int i = 0;
+       GIOChannel *io = NULL;
+       gchar *line = NULL;
+       gchar *device_name = NULL;
+       gchar ip_addr[MOBILE_AP_STR_INFO_LEN] = {0, };
+       gchar mac_addr[MOBILE_AP_STR_INFO_LEN] = {0, };
+       gchar name[MOBILE_AP_STR_HOSTNAME_LEN] = {0, };
+       gchar expire[MOBILE_AP_STR_INFO_LEN] = {0, };
+       gchar extra[MOBILE_AP_STR_INFO_LEN] = {0, };
+
+       int found = 0;
+
+       for (i = 0; i < di->number; i++)
+               DBG("bssid[%d]:%s\n", i, di->bssid[i]);
+
+       DBG("Number of connected device:%d\n", di->number);
+
+       io = g_io_channel_new_file(DNSMASQ_LEASES_FILE, "r", NULL);
+
+       while (g_io_channel_read_line(io, &line, NULL, NULL, NULL) ==
+                                                       G_IO_STATUS_NORMAL) {
+               sscanf(line, "%19s %19s %19s %19s %19s", expire, mac_addr,
+                                                       ip_addr, name, extra);
+               DBG("mac_addr:%s ip_addr:%s name:%s expire:%s\n", mac_addr,
+                                                       ip_addr, name, expire);
+
+               for (i = 0; i < di->number; i++) {
+                       if (g_ascii_strcasecmp(di->bssid[i], mac_addr) == 0) {
+                               if (!strcmp(name, "*"))
+                                       device_name = MOBILE_AP_NAME_UNKNOWN;
+                               else
+                                       device_name = name;
+
+                               _mh_core_add_data_to_array(array, MOBILE_AP_TYPE_WIFI,
+                                                               device_name);
+
+                               found++;
+
+                               break;
+                       }
+               }
+
+               g_free(line);
+       }
+       g_io_channel_unref(io);
+
+       /* Set the name UNKNOWN unless we got the name. */
+       for (i = found; i < di->number; i++) {
+               _mh_core_add_data_to_array(array, MOBILE_AP_TYPE_WIFI,
+                                                       MOBILE_AP_NAME_UNKNOWN);
+       }
+}
+
+mobile_ap_error_code_e _disable_wifi_tethering(TetheringObject *obj)
+{
+       int ret = MOBILE_AP_ERROR_NONE;
+
+       if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) {
+               ERR("Wi-Fi tethering has not been activated\n");
+               ret = MOBILE_AP_ERROR_NOT_ENABLED;
+               return ret;
+       }
+
+       _deinit_timeout_cb(MOBILE_AP_TYPE_WIFI);
+
+       if (_remove_station_info_all(MOBILE_AP_TYPE_WIFI) !=
+                       MOBILE_AP_ERROR_NONE) {
+               ERR("_remove_station_info_all is failed. Ignore it.\n");
+       }
+
+       ret = _mh_core_disable_softap();
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               ERR("_mh_core_disable_softap is failed : %d\n", ret);
+               return ret;
+       }
+
+       _deinit_tethering(obj);
+       _mobileap_clear_state(MOBILE_AP_STATE_WIFI);
+
+       DBG("_disable_wifi_tethering is done\n");
+
+       return ret;
+}
+
+static mobile_ap_error_code_e __update_wifi_data(TetheringObject *obj)
+{
+       if (obj == NULL) {
+               ERR("Invalid param\n");
+               return MOBILE_AP_ERROR_INVALID_PARAM;
+       }
+
+       mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
+       unsigned int read_len = 0;
+
+       ret = __get_ssid(obj->ssid, sizeof(obj->ssid));
+       if (ret != MOBILE_AP_ERROR_NONE)
+               return ret;
+
+       ret = __get_security_type(obj->security_type, sizeof(obj->security_type));
+       if (ret != MOBILE_AP_ERROR_NONE)
+               return ret;
+
+       ret = __get_hide_mode(&obj->hide_mode);
+       if (ret != MOBILE_AP_ERROR_NONE)
+               return ret;
+
+       if (strcmp(obj->security_type, SOFTAP_SECURITY_TYPE_OPEN_STR) == 0) {
+               g_strlcpy(obj->key, "00000000", sizeof(obj->key));
+       } else if (strcmp(obj->security_type, SOFTAP_SECURITY_TYPE_WPA2_PSK_STR) == 0) {
+               ret = __get_passphrase(obj->key, sizeof(obj->key), &read_len);
+               if (ret != MOBILE_AP_ERROR_NONE)
+                       return ret;
+       } else {
+               ERR("Unknown security type\n");
+               return MOBILE_AP_ERROR_INTERNAL;
+       }
+
+       DBG("ssid : %s security type : %s hide mode : %d\n",
+                       obj->ssid, obj->security_type, obj->hide_mode);
+
+       return MOBILE_AP_ERROR_NONE;
+}
+
+gboolean tethering_enable_wifi_tethering(TetheringObject *obj, gchar *ssid,
+               gchar *key, gint hide_mode, DBusGMethodInvocation *context)
+{
+       int ret = MOBILE_AP_ERROR_NONE;
+
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+
+       if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) {
+               ERR("Wi-Fi tethering is already enabled\n");
+               ret = MOBILE_AP_ERROR_ALREADY_ENABLED;
+               dbus_g_method_return(context,
+                               MOBILE_AP_ENABLE_WIFI_TETHERING_CFM, ret);
+               return FALSE;
+       }
+
+       /* Update global state */
+       if (!_mobileap_set_state(MOBILE_AP_STATE_WIFI)) {
+               ret = MOBILE_AP_ERROR_RESOURCE;
+               goto FAIL;
+       }
+
+       /* Update Wi-Fi hotspot data to common object */
+       ret = __update_wifi_data(obj);
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               goto FAIL;
+       }
+
+       /* Initialize tethering */
+       if (!_init_tethering(obj)) {
+               ret = MOBILE_AP_ERROR_RESOURCE;
+               goto FAIL;
+       }
+
+       /* Upload driver */
+       ret = _mh_core_enable_softap(obj->ssid, obj->security_type,
+                       obj->key, obj->hide_mode);
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               _deinit_tethering(obj);
+               goto FAIL;
+       }
+
+       _init_timeout_cb(MOBILE_AP_TYPE_WIFI, (void *)obj);
+       _start_timeout_cb(MOBILE_AP_TYPE_WIFI);
+
+       _emit_mobileap_dbus_signal(obj, E_SIGNAL_WIFI_TETHER_ON, NULL);
+       dbus_g_method_return(context, MOBILE_AP_ENABLE_WIFI_TETHERING_CFM, ret);
+
+       return TRUE;
+
+FAIL:
+       _mobileap_clear_state(MOBILE_AP_STATE_WIFI);
+       dbus_g_method_return(context, MOBILE_AP_ENABLE_WIFI_TETHERING_CFM, ret);
+
+       return FALSE;
+}
+
+gboolean tethering_disable_wifi_tethering(TetheringObject *obj,
+               DBusGMethodInvocation *context)
+{
+       int ret = MOBILE_AP_ERROR_NONE;
+
+       DBG("+\n");
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+       ret = _disable_wifi_tethering(obj);
+
+       _emit_mobileap_dbus_signal(obj, E_SIGNAL_WIFI_TETHER_OFF, NULL);
+       dbus_g_method_return(context, MOBILE_AP_DISABLE_WIFI_TETHERING_CFM, ret);
+
+       if (ret != MOBILE_AP_ERROR_NONE)
+               return FALSE;
+       else
+               return TRUE;
+}
+
+gboolean tethering_get_wifi_tethering_hide_mode(TetheringObject *obj,
+               DBusGMethodInvocation *context)
+{
+       mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
+       int hide_mode = 0;
+
+       DBG("+\n");
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+       ret = __get_hide_mode(&hide_mode);
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               ERR("__get_hide_mode is failed : %d\n", ret);
+       }
+
+       dbus_g_method_return(context, hide_mode);
+
+       return TRUE;
+}
+
+gboolean tethering_set_wifi_tethering_hide_mode(TetheringObject *obj,
+               gint hide_mode, DBusGMethodInvocation *context)
+{
+       int ret = 0;
+
+       DBG("+\n");
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+       int old_hide_mode;
+
+       ret = __get_hide_mode(&old_hide_mode);
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               ERR("__get_hide_mode is failed : %d\n", ret);
+       } else if (old_hide_mode == hide_mode) {
+               DBG("old_hide_mode == hide_mode\n");
+               dbus_g_method_return(context);
+               return TRUE;
+       }
+
+       ret = __set_hide_mode(hide_mode);
+       if (ret < 0) {
+               ERR("__set_hide_mode is failed : %d\n", ret);
+       }
+
+       _emit_mobileap_dbus_signal(obj, E_SIGNAL_SSID_VISIBILITY_CHANGED,
+                       hide_mode == VCONFKEY_MOBILE_AP_HIDE_OFF ?
+                       SIGNAL_MSG_SSID_VISIBLE :
+                       SIGNAL_MSG_SSID_HIDE);
+       dbus_g_method_return(context);
+
+       return TRUE;
+}
+
+gboolean tethering_get_wifi_tethering_ssid(TetheringObject *obj,
+               DBusGMethodInvocation *context)
+{
+       mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
+       char ssid[MOBILE_AP_WIFI_SSID_MAX_LEN + 1] = {0, };
+
+       DBG("+\n");
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+       ret = __get_ssid(ssid, sizeof(ssid));
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               ERR("__get_ssid is failed : %d\n", ret);
+       }
+
+       dbus_g_method_return(context, ssid);
+
+       return TRUE;
+
+}
+
+gboolean tethering_get_wifi_tethering_security_type(TetheringObject *obj,
+               DBusGMethodInvocation *context)
+{
+       mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
+       char security_type[SECURITY_TYPE_LEN] = {0, };
+
+       DBG("+\n");
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+       ret = __get_security_type(security_type, sizeof(security_type));
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               ERR("__get_security_type is failed : %d\n", ret);
+       }
+
+       dbus_g_method_return(context, security_type);
+
+       return TRUE;
+}
+
+gboolean tethering_set_wifi_tethering_security_type(TetheringObject *obj,
+               gchar *security_type, DBusGMethodInvocation *context)
+{
+       mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
+       char old_security_type[SECURITY_TYPE_LEN] = {0, };
+
+       DBG("+\n");
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+       ret = __get_security_type(old_security_type, sizeof(old_security_type));
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               ERR("__get_security_type is failed : %d\n", ret);
+       } else if (g_strcmp0(old_security_type, security_type) == 0) {
+               DBG("old_security_type == security_type\n");
+               dbus_g_method_return(context);
+               return TRUE;
+       }
+
+       ret = __set_security_type(security_type);
+       if (ret < 0) {
+               ERR("__set_security_type is failed: %d\n", ret);
+       }
+
+       _emit_mobileap_dbus_signal(obj, E_SIGNAL_SECURITY_TYPE_CHANGED,
+                       security_type);
+       dbus_g_method_return(context);
+
+       return TRUE;
+}
+
+gboolean tethering_get_wifi_tethering_passphrase(TetheringObject *obj,
+               DBusGMethodInvocation *context)
+{
+       mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
+       char passphrase[MOBILE_AP_WIFI_KEY_MAX_LEN + 1] = {0, };
+       unsigned int len = 0;
+
+       DBG("+\n");
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+       ret = __get_passphrase(passphrase, sizeof(passphrase), &len);
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               len = 0;
+               ERR("__get_password is failed : %d\n", ret);
+       }
+
+       dbus_g_method_return(context, passphrase, len);
+
+       return TRUE;
+}
+
+gboolean tethering_set_wifi_tethering_passphrase(TetheringObject *obj,
+               gchar *passphrase, guint len, DBusGMethodInvocation *context)
+{
+       mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
+       char old_passphrase[MOBILE_AP_WIFI_KEY_MAX_LEN + 1] = {0, };
+       unsigned int old_len = 0;
+
+       DBG("+\n");
+       g_assert(obj != NULL);
+       g_assert(context != NULL);
+
+       ret = __get_passphrase(old_passphrase, sizeof(old_passphrase), &old_len);
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               ERR("__get_passphrase is failed : %d\n", ret);
+       } else if (old_len == len && !g_strcmp0(old_passphrase, passphrase)) {
+               dbus_g_method_return(context);
+               return TRUE;
+       }
+
+       ret = __set_passphrase(passphrase, len);
+       if (ret != MOBILE_AP_ERROR_NONE) {
+               ERR("__set_passphrase is failed : %d\n", ret);
+       }
+
+       _emit_mobileap_dbus_signal(obj, E_SIGNAL_PASSPHRASE_CHANGED, NULL);
+       dbus_g_method_return(context);
+
+       return TRUE;
+}