From a4d30a2175884f305608ea0531a8b30d7ef00df2 Mon Sep 17 00:00:00 2001 From: Sehong Na Date: Sat, 31 May 2014 12:53:46 +0900 Subject: [PATCH 1/1] Initialize Tizen 2.3 --- AUTHORS | 3 + CMakeLists.txt | 63 ++ LICENSE.APLv2.0 | 202 +++++++ NOTICE | 3 + include/mobileap.h | 205 +++++++ include/mobileap_agent.h | 208 +++++++ include/mobileap_bluetooth.h | 31 + include/mobileap_common.h | 47 ++ include/mobileap_handler.h | 30 + include/mobileap_network.h | 32 ++ include/mobileap_notification.h | 46 ++ include/mobileap_usb.h | 34 ++ include/mobileap_wifi.h | 64 +++ include/tethering-dbus-interface.xml | 204 +++++++ mobileap-agent.manifest | 5 + mobileap-agent.rule | 4 + packaging/mobileap-agent.spec | 182 ++++++ packaging/org.tizen.tethering.service | 4 + src/mobileap_agent.c | 1010 +++++++++++++++++++++++++++++++++ src/mobileap_bluetooth.c | 475 ++++++++++++++++ src/mobileap_common.c | 539 ++++++++++++++++++ src/mobileap_handler.c | 321 +++++++++++ src/mobileap_main.c | 656 +++++++++++++++++++++ src/mobileap_network.c | 351 ++++++++++++ src/mobileap_notification.c | 364 ++++++++++++ src/mobileap_usb.c | 378 ++++++++++++ src/mobileap_wifi.c | 681 ++++++++++++++++++++++ 27 files changed, 6142 insertions(+) create mode 100644 AUTHORS create mode 100644 CMakeLists.txt create mode 100644 LICENSE.APLv2.0 create mode 100644 NOTICE create mode 100644 include/mobileap.h create mode 100644 include/mobileap_agent.h create mode 100644 include/mobileap_bluetooth.h create mode 100644 include/mobileap_common.h create mode 100644 include/mobileap_handler.h create mode 100644 include/mobileap_network.h create mode 100644 include/mobileap_notification.h create mode 100644 include/mobileap_usb.h create mode 100644 include/mobileap_wifi.h create mode 100644 include/tethering-dbus-interface.xml create mode 100644 mobileap-agent.manifest create mode 100644 mobileap-agent.rule create mode 100644 packaging/mobileap-agent.spec create mode 100644 packaging/org.tizen.tethering.service create mode 100644 src/mobileap_agent.c create mode 100644 src/mobileap_bluetooth.c create mode 100644 src/mobileap_common.c create mode 100644 src/mobileap_handler.c create mode 100644 src/mobileap_main.c create mode 100644 src/mobileap_network.c create mode 100644 src/mobileap_notification.c create mode 100644 src/mobileap_usb.c create mode 100644 src/mobileap_wifi.c diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..4d93362 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,3 @@ +Hocheol Seo +Injun Yang +Seungyoun Ju diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4a28d24 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,63 @@ +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(CMAKE_INSTALL_PREFIX /usr) + +SET(APP_VENDOR "tizen") +SET(APP_NAME mobileap-agent) +SET(APP_DIR ${CMAKE_INSTALL_PREFIX}/bin) +SET(INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include) + +IF("${CMAKE_BUILD_TYPE}" STREQUAL "") + SET(CMAKE_BUILD_TYPE "Release") +ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "") + +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 appcore-common ${PRIVATE_REQUIRED_PKGS}) +FOREACH(flag ${pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fpie -Wall") +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 -pie") + +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) +INSTALL(FILES ${CMAKE_BINARY_DIR}/mobileap-agent.rule DESTINATION /opt/etc/smack/accesses.d) + diff --git a/LICENSE.APLv2.0 b/LICENSE.APLv2.0 new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE.APLv2.0 @@ -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 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 index 0000000..e751ec8 --- /dev/null +++ b/include/mobileap.h @@ -0,0 +1,205 @@ +/* + * 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_UINT, 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 6 /**< 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 */ + time_t tm; /**< connection time*/ +} 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 index 0000000..8ae515e --- /dev/null +++ b/include/mobileap_agent.h @@ -0,0 +1,208 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#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" \ + "ieee80211n=1\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 index 0000000..95e28a7 --- /dev/null +++ b/include/mobileap_bluetooth.h @@ -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 /* __MOBILEAP_BLUETOOTH_H__ */ diff --git a/include/mobileap_common.h b/include/mobileap_common.h new file mode 100644 index 0000000..ab1e549 --- /dev/null +++ b/include/mobileap_common.h @@ -0,0 +1,47 @@ +/* + * 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 + +#include "mobileap_agent.h" + +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 /* __MOBILEAP_COMMON_H__ */ diff --git a/include/mobileap_handler.h b/include/mobileap_handler.h new file mode 100644 index 0000000..c1bc03b --- /dev/null +++ b/include/mobileap_handler.h @@ -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 index 0000000..3959886 --- /dev/null +++ b/include/mobileap_network.h @@ -0,0 +1,32 @@ +/* + * 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 + +gboolean _get_network_interface_name(char **if_name); +gboolean _is_trying_network_operation(void); +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 /* __MOBILEAP_NETWORK_H__ */ diff --git a/include/mobileap_notification.h b/include/mobileap_notification.h new file mode 100644 index 0000000..b457aa8 --- /dev/null +++ b/include/mobileap_notification.h @@ -0,0 +1,46 @@ +/* + * 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 + +#define MH_NOTI_STR_MAX 50 +#define MH_NOTI_ICON_PATH "/usr/ug/res/images/ug-setting-mobileap-efl/tethering.png" + +#define MOBILEAP_LOCALE_COMMON_PKG "ug-setting-mobileap-efl" +#define MOBILEAP_LOCALE_COMMON_RES "/usr/ug/res/locale" + +#define _(str) dgettext(MOBILEAP_LOCALE_COMMON_PKG, str) + +#define MH_NOTI_STR _("IDS_MOBILEAP_POP_CONNECTED_DEVICES_C_PD") +#define MH_NOTI_TITLE _("IDS_MOBILEAP_BODY_TETHERING") +#define MH_NOTI_TIMEOUT_STR _("IDS_MOBILEAP_BODY_TAP_TO_CONFIGURE_TETHERING") +#define MH_NOTI_TIMEOUT_TITLE "Disable tethering by timeout" +#define MH_NOTI_BT_VISIBILITY_STR _("IDS_ST_BODY_BLUETOOTH_VISIBILITY_HAS_TIMED_OUT_YOUR_DEVICE_MIGHT_NOT_BE_FOUND") + + +int _create_timeout_noti(const char *content, const char *title, + const char *icon_path); +int _delete_timeout_noti(void); +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); +int _create_status_noti(const char *content); +#endif diff --git a/include/mobileap_usb.h b/include/mobileap_usb.h new file mode 100644 index 0000000..4ad58b8 --- /dev/null +++ b/include/mobileap_usb.h @@ -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_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 /* __MOBILEAP_USB_H__ */ diff --git a/include/mobileap_wifi.h b/include/mobileap_wifi.h new file mode 100644 index 0000000..d64a595 --- /dev/null +++ b/include/mobileap_wifi.h @@ -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 index 0000000..3dbcac1 --- /dev/null +++ b/include/tethering-dbus-interface.xml @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobileap-agent.manifest b/mobileap-agent.manifest new file mode 100644 index 0000000..75b0fa5 --- /dev/null +++ b/mobileap-agent.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/mobileap-agent.rule b/mobileap-agent.rule new file mode 100644 index 0000000..ae46bac --- /dev/null +++ b/mobileap-agent.rule @@ -0,0 +1,4 @@ +root mobileap-agent rw--- +_default_ mobileap-agent rw--- +mobileap-agent secure-storage::tethering rw--- +mobileap-agent bt-service::admin -w--- diff --git a/packaging/mobileap-agent.spec b/packaging/mobileap-agent.spec new file mode 100644 index 0000000..183236a --- /dev/null +++ b/packaging/mobileap-agent.spec @@ -0,0 +1,182 @@ +Name: mobileap-agent +Summary: Mobile AP daemon for setting tethering environments +Version: 0.1.94 +Release: 1 +Group: TO_BE/FILLED_IN +License: Apache-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: pkgconfig(appcore-common) +BuildRequires: cmake +Requires(post): /usr/bin/vconftool +Requires: iptables +Requires: dnsmasq +%description +Mobile AP daemon for setting tethering environments + +%prep +%setup -q + +%build +%cmake . +make %{?jobs:-j%jobs} + +%install +%make_install +mkdir -p %{buildroot}/usr/share/license +cp LICENSE.APLv2.0 %{buildroot}/usr/share/license/%{name} + + +%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 +/opt/etc/smack/accesses.d/mobileap-agent.rule +%defattr(-,root,root,-) +/usr/share/dbus-1/services/org.tizen.tethering.service +%{_bindir}/mobileap-agent +/usr/share/license/%{name} + +%changelog +* Tue Apr 09 2013 Seungyoun Ju 0.1.86-1 +- Fix the multiple notification issue +- Support i80211n +- Channel is changed to 6 +- Implement status notification for bluetooth visibility +- Change the power manager api +- Implement connection timer +- Reference count is used +- Support Mobile AP + +* Sat Feb 16 2013 Seungyoun Ju 0.1.85-2 +- Function return value is checked +- Private SSID is considered +- Build option clean-up and g_type_init is deprecated from glib 2.35 + +* Thu Feb 14 2013 Seungyoun Ju 0.1.84-1 +- User is specified in service file for Dbus auto activation + +* Mon Jan 28 2013 Seungyoun Ju 0.1.83-1 +- Remove unrequired log + +* Thu Jan 24 2013 Seungyoun Ju 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 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 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 0.1.79-1 +- Notification's API usage is changed + +* Tue Nov 06 2012 Seungyoun Ju 0.1.78-1 +- Unnecessary BT API is removed + +* Sat Nov 03 2012 Seungyoun Ju 0.1.77-1 +- Prevent issues are fixed + +* Tue Oct 30 2012 Seungyoun Ju 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 0.1.75-1 +- Code clean-up and path for notification icon is changed + +* Thu Oct 22 2012 Seungyoun Ju 0.1.74-1 +- License is added + +* Thu Oct 11 2012 Seungyoun Ju 0.1.73-1 +- Source package name is changed (libmobileap -> mobileap-agent) + +* Thu Oct 11 2012 Injun Yang 0.1.72-1 +- Launch kcp-agent + +* Fri Sep 28 2012 Seungyoun Ju 0.1.71-1 +- Fix memory corruption + +* Fri Sep 21 2012 Seungyoun Ju 0.1.70-1 +- Manifest file is added for SMACK + +* Wed Sep 19 2012 Seungyoun Ju 0.1.69-1 +- The code for Legacy APIs is removed + +* Wed Sep 14 2012 Seungyoun Ju 0.1.68-1 +- Bluetooth PAN Managed APIs are applied +- MDM Phase 2 implementation + +* Wed Sep 06 2012 Seungyoun Ju 0.1.67-1 +- Connection Managed APIs are applied +- Network status is not checked in agent + +* Wed Aug 01 2012 Seungyoun Ju 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 0.1.65-1 +- Wi-Fi tethering disable / enable issues are fixed + +* Fri Jul 06 2012 Seungyoun Ju 0.1.64-1 +- Unnecessary dependency is removed + +* Mon Jun 25 2012 Seungyoun Ju 0.1.63-1 +- Data usage is fixed + +* Thu May 31 2012 Seungyoun Ju 0.1.62-1 +- Wi-Fi tethering security is implemented +- API for getting USB interface information is implemented + +* Wed May 23 2012 Seungyoun Ju 0.1.61-1 +- Tethering app. dependency is added + +* Tue May 22 2012 Seungyoun Ju 0.1.60-1 +- Wi-Fi interface name is changed from eth0 to wlan0 + +* Tue May 22 2012 Seungyoun Ju 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 0.1.58-1 +- Hostapd control interface is implemented + +* Mon Apr 09 2012 Seungyoun Ju 0.1.57-1 +- Unused vconfkey is removed + +* Wed Mar 14 2012 Seungyoun Ju 0.1.56-1 +- Export API's are changed + +* Mon Feb 06 2012 Seungyoun Ju 0.1.55-2 +- Fix build error + +* Mon Feb 06 2012 Seungyoun Ju 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 index 0000000..577633b --- /dev/null +++ b/packaging/org.tizen.tethering.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.tizen.tethering +Exec=/usr/bin/mobileap-agent +User=root diff --git a/src/mobileap_agent.c b/src/mobileap_agent.c new file mode 100644 index 0000000..609cfb0 --- /dev/null +++ b/src/mobileap_agent.c @@ -0,0 +1,1010 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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, + "wpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\nwps_state=2\neap_server=1", + 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, "-dd", + (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; + GIOStatus ios; + + ios = 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; + } else if (ios != G_IO_STATUS_NORMAL) { + ERR("g_io_channel_read_chars is failed : %d\n", ios); + 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 index 0000000..077f18a --- /dev/null +++ b/src/mobileap_bluetooth.c @@ -0,0 +1,475 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include "mobileap_agent.h" +#include "mobileap_common.h" +#include "mobileap_bluetooth.h" +#include "mobileap_handler.h" +#include "mobileap_notification.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; + int duration; + bt_adapter_visibility_mode_e mode; + 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; + } else { + ret = bt_adapter_get_visibility(&mode, &duration); + if (ret == BT_ERROR_NONE && mode == BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE) + _create_status_noti(MH_NOTI_BT_VISIBILITY_STR); + } + + 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 _enable_bt_tethering(TetheringObject *obj, + DBusGMethodInvocation *context) +{ + mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE; + int bt_ret; + int duration; + bt_adapter_visibility_mode_e mode; + bt_adapter_state_e adapter_state = BT_ADAPTER_DISABLED; + + if (_mobileap_is_enabled(MOBILE_AP_STATE_BT)) { + ERR("Bluetooth tethering is already enabled\n"); + ret = MOBILE_AP_ERROR_ALREADY_ENABLED; + return ret; + } + + if (obj->bt_context != NULL) { + ERR("Bluetooth tethering request is progressing\n"); + ret = MOBILE_AP_ERROR_IN_PROGRESS; + return ret; + } + + 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 ret; + } else { + bt_ret = bt_adapter_get_visibility(&mode, &duration); + if (bt_ret == BT_ERROR_NONE && mode == BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE) + _create_status_noti(MH_NOTI_BT_VISIBILITY_STR); + + } + + 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; + } + + _delete_timeout_noti(); + _init_timeout_cb(MOBILE_AP_TYPE_BT, (void *)obj); + _start_timeout_cb(MOBILE_AP_TYPE_BT); + + return ret; + +FAIL: + _mobileap_clear_state(MOBILE_AP_STATE_BT); + + return ret; +} + +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) +{ + mobile_ap_error_code_e ret; + + DBG("+\n"); + + g_assert(obj != NULL); + g_assert(context != NULL); + + + ret = _enable_bt_tethering(obj, context); + if (ret != MOBILE_AP_ERROR_NONE) { + ERR("_enable_bt_tethering() is failed : %d\n", ret); + dbus_g_method_return(context, + MOBILE_AP_ENABLE_BT_TETHERING_CFM, ret); + return FALSE; + } else if (obj->bt_context == NULL) { + _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; +} + + +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 index 0000000..8271601 --- /dev/null +++ b/src/mobileap_common.c @@ -0,0 +1,539 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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_UINT32, &info->tm, + 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); + DBG("[%d] station connected time : %d\n", i, si->tm); + 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); + 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); + 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); + + if (fgets(buf, sizeof(buf), fp) == NULL) + *rx = 0LL; + else + *rx = atoll(buf); + + 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 index 0000000..c48e676 --- /dev/null +++ b/src/mobileap_handler.c @@ -0,0 +1,321 @@ +/* + * 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 +#include +#include +#include + +#include "mobileap_agent.h" +#include "mobileap_common.h" +#include "mobileap_bluetooth.h" +#include "mobileap_wifi.h" +#include "mobileap_usb.h" +#include "mobileap_notification.h" + + +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 index 0000000..421e8f7 --- /dev/null +++ b/src/mobileap_main.c @@ -0,0 +1,656 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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" +#include "mobileap_notification.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_init(TetheringObject *obj, GError **error); +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); +gboolean tethering_set_ip_forward_status(TetheringObject *obj, + gint forward_mode, DBusGMethodInvocation *context); +gboolean tethering_get_ip_forward_status(TetheringObject *obj, gint *forward_mode); + +#include "tethering-server-stub.h" + +int ref_agent = 0; + +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, 4, (guint)(si->tm), 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_init(TetheringObject *obj, GError **error) +{ + DBG("There are [%d] references\n", ++ref_agent); + + return TRUE; +} + +gboolean tethering_deinit(TetheringObject *obj, GError **error) +{ + if (--ref_agent <= 0 && _mobileap_is_disabled() && + !_is_trying_network_operation()) { + DBG("Terminate mobileap-agent\n"); + g_main_loop_quit(mainloop); + } + + DBG("There are [%d] references\n", ref_agent); + + 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, + 0ULL, 0ULL); + 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; +} + +gboolean tethering_set_ip_forward_status(TetheringObject *obj, + gint forward_mode, DBusGMethodInvocation *context) +{ + g_assert(obj != NULL); + + gboolean ret; + + if (forward_mode == 0) { + ret = _unset_masquerade(); + } else { + ret = _set_masquerade(); + } + + dbus_g_method_return(context, ret); + + return TRUE; +} + +gboolean tethering_get_ip_forward_status(TetheringObject *obj, gint *forward_mode) +{ + g_assert(obj != NULL); + + int fd; + int ret; + char value[2] = {0, }; + + fd = open(IP_FORWARD, O_RDONLY); + if (fd < 0) { + ERR("open failed\n"); + return FALSE; + } + + ret = read(fd, value, sizeof(value)); + if (ret < 0) { + ERR("read is failed\n"); + close(fd); + return FALSE; + } + close(fd); + + *forward_mode = atoi(value); + + 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; + time_t tm; + + 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); + } + } + time(&tm); + info->tm = tm; + + 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; + +#if !GLIB_CHECK_VERSION(2,35,0) + g_type_init(); +#endif + + if (appcore_set_i18n(MOBILEAP_LOCALE_COMMON_PKG, MOBILEAP_LOCALE_COMMON_RES) < 0) + goto failure; + + 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 index 0000000..8a65ecb --- /dev/null +++ b/src/mobileap_network.c @@ -0,0 +1,351 @@ +/* + * 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 +#include +#include + +#include "mobileap_agent.h" +#include "mobileap_common.h" +#include "mobileap_network.h" + + +extern int ref_agent; +static connection_h connection = NULL; +static connection_profile_h cprof = NULL; + +static void __print_profile(connection_profile_h profile) +{ + if (profile == NULL) + return; + + int conn_ret; + bool roaming; + char *apn = NULL; + char *home_url = NULL; + 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); + if (conn_ret != CONNECTION_ERROR_NONE) + ERR("connection API fail : 0x%X\n", conn_ret); + else + DBG("Network type : %d\n", network_type); + + conn_ret = connection_profile_get_cellular_service_type(profile, &service_type); + if (conn_ret != CONNECTION_ERROR_NONE) + ERR("connection API fail : 0x%X\n", conn_ret); + else + DBG("Service type : %d\n", service_type); + + conn_ret = connection_profile_get_cellular_apn(profile, &apn); + if (conn_ret != CONNECTION_ERROR_NONE) + ERR("connection API fail : 0x%X\n", conn_ret); + else { + DBG("APN : %s\n", apn); + free(apn); + } + + conn_ret = connection_profile_get_cellular_home_url(profile, &home_url); + if (conn_ret != CONNECTION_ERROR_NONE) + ERR("connection API fail : 0x%X\n", conn_ret); + else { + DBG("Home url : %s\n", home_url); + free(home_url); + } + + conn_ret = connection_profile_is_cellular_roaming(profile, &roaming); + if (conn_ret != CONNECTION_ERROR_NONE) + ERR("connection API fail : 0x%X\n", conn_ret); + else + DBG("Roaming : %d\n", roaming); + + return; +} + +static gboolean __is_connected_profile(connection_profile_h profile) +{ + if (profile == NULL) { + ERR("profile is NULL\n"); + return FALSE; + } + + 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_connected_profile(connection_profile_h *r_prof, connection_profile_type_e *r_net_type) +{ + if (r_prof == NULL || r_net_type == NULL) { + ERR("Invalid param [%p] [%p]\n", r_prof, r_net_type); + return FALSE; + } + + 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_profile(connection_profile_h *r_prof) +{ + if (r_prof == NULL) { + ERR("r_prof is NULL\n"); + return FALSE; + } + + connection_profile_h profile; + connection_profile_type_e net_type = CONNECTION_PROFILE_TYPE_CELLULAR; + + if (__get_connected_profile(&profile, &net_type) == FALSE) { + ERR("There is no available network\n"); + return FALSE; + } + + DBG("Current connected net_type : %d\n", net_type); + if (net_type == CONNECTION_PROFILE_TYPE_WIFI) { + *r_prof = profile; + return TRUE; + } + + if (net_type != CONNECTION_PROFILE_TYPE_CELLULAR) { + ERR("Network type [%d] is not supported\n", net_type); + return FALSE; + } + __print_profile(profile); + + *r_prof = profile; + return TRUE; +} + +static void __connection_type_changed_cb(connection_type_e type, void *user_data) +{ + 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"); + + + if (_mobileap_is_disabled()) { + DBG("Tethering is not enabled\n"); + return; + } + + if (_unset_masquerade() == FALSE) { + ERR("_unset_masquerade is failed\n"); + } + + if (cprof) { + connection_profile_destroy(cprof); + cprof = NULL; + } + + if (type == CONNECTION_TYPE_DISCONNECTED) { + return; + } + + _open_network(); + + return; +} + +gboolean _is_trying_network_operation(void) +{ + + return FALSE; +} + +gboolean _get_network_interface_name(char **if_name) +{ + if (if_name == NULL) { + ERR("if_name is NULL\n"); + return FALSE; + } + + if (cprof == NULL) { + ERR("There is no connected profile\n"); + return FALSE; + } + + int conn_ret = 0; + + 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) +{ + if (cprof == NULL) { + DBG("There is nothing to unset masquerading\n"); + return TRUE; + } + + 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_profile(&profile) == FALSE) { + ERR("__get_network_profile is failed\n"); + return FALSE; + } + + if (!__is_connected_profile(profile)) { + connection_profile_destroy(profile); + return TRUE; + } + cprof = profile; + + 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"); + + 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 index 0000000..16dbec4 --- /dev/null +++ b/src/mobileap_notification.c @@ -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 +#include +#include +#include +#include +#include +#include + +#include "mobileap_agent.h" + +//#define __ENABLE_UG_LAUNCH +#define MH_NOTI_APP_NAME "setting-mobileap-efl" +#define MH_AGENT_PKG_NAME "mobileap-agent" + +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_create(NOTIFICATION_TYPE_NOTI); + if (!noti) { + ERR("Fail to notification_create\n"); + return MOBILE_AP_ERROR_INTERNAL; + } + + ret = notification_set_property(noti, +#ifdef __ENABLE_UG_LAUNCH + NOTIFICATION_PROP_VOLATILE_DISPLAY); +#else + NOTIFICATION_PROP_VOLATILE_DISPLAY | + NOTIFICATION_PROP_DISABLE_APP_LAUNCH); +#endif + 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; + } +#ifdef __ENABLE_UG_LAUNCH + 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; + } +#endif + 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 _delete_timeout_noti(void) +{ + notification_error_e ret = NOTIFICATION_ERROR_NONE; + notification_list_h noti_list = NULL; + notification_h noti = NULL; + + ret = notification_get_detail_list(MH_AGENT_PKG_NAME, + NOTIFICATION_GROUP_ID_NONE, + NOTIFICATION_PRIV_ID_NONE, + -1, + ¬i_list); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("Fail to notification_get_detail_list\n"); + return MOBILE_AP_ERROR_INTERNAL; + } + + if (noti_list) { + noti = notification_list_get_data(noti_list); + if (noti) + notification_delete(noti); + + notification_free_list(noti_list); + } + + return MOBILE_AP_ERROR_NONE; +} + +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_create(NOTIFICATION_TYPE_ONGOING); + if (!noti) { + ERR("Fail to notification_create\n"); + return MOBILE_AP_ERROR_INTERNAL; + } + + ret = notification_set_property(noti, + NOTIFICATION_PROP_DISABLE_AUTO_DELETE | +#ifdef __ENABLE_UG_LAUNCH + NOTIFICATION_PROP_VOLATILE_DISPLAY); +#else + NOTIFICATION_PROP_VOLATILE_DISPLAY | + NOTIFICATION_PROP_DISABLE_APP_LAUNCH); +#endif + 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; + } +#ifdef __ENABLE_UG_LAUNCH + 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; + } +#endif + 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; +} + +int _create_status_noti(const char *content) +{ + if (content == NULL) + return MOBILE_AP_ERROR_INVALID_PARAM; + + notification_error_e ret; + + ret = notification_status_message_post(content); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("notification_status_message_post() is failed : %d\n", ret); + return MOBILE_AP_ERROR_INTERNAL; + } + + return MOBILE_AP_ERROR_NONE; +} diff --git a/src/mobileap_usb.c b/src/mobileap_usb.c new file mode 100644 index 0000000..edf870e --- /dev/null +++ b/src/mobileap_usb.c @@ -0,0 +1,378 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 _enable_usb_tethering(TetheringObject *obj, + DBusGMethodInvocation *context) +{ + mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE; + int vconf_ret; + int usb_mode = SETTING_USB_NONE_MODE; + + if (_mobileap_is_enabled(MOBILE_AP_STATE_USB)) { + ERR("USB tethering is already enabled\n"); + ret = MOBILE_AP_ERROR_ALREADY_ENABLED; + return ret; + } + + if (obj->usb_context) { + ERR("USB request is progressing\n"); + ret = MOBILE_AP_ERROR_IN_PROGRESS; + return ret; + } + + 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) { + obj->usb_context = NULL; + vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT, + __handle_usb_mode_change); + } + + DBG("-\n"); + return MOBILE_AP_ERROR_NONE; + +FAIL: + vconf_ignore_key_changed(VCONFKEY_SYSMAN_USB_STATUS, + __handle_usb_disconnect_cb); + _mobileap_clear_state(MOBILE_AP_STATE_USB); + + return ret; +} + +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) +{ + mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE; + + DBG("+\n"); + + g_assert(obj != NULL); + g_assert(context != NULL); + + + ret = _enable_usb_tethering(obj, context); + if (ret != MOBILE_AP_ERROR_NONE) { + ERR("_enable_usb_tethering() is failed : %d\n", ret); + dbus_g_method_return(context, + MOBILE_AP_ENABLE_USB_TETHERING_CFM, ret); + return FALSE; + } else if (obj->usb_context == NULL) { + DBG("Don't need to wait for usb-setting\n"); + _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_ON, NULL); + dbus_g_method_return(context, + MOBILE_AP_ENABLE_USB_TETHERING_CFM, ret); + } else { + DBG("dbus will be returned by vconf callback\n"); + } + + return TRUE; +} + + +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 index 0000000..fea6629 --- /dev/null +++ b/src/mobileap_wifi.c @@ -0,0 +1,681 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "mobileap_agent.h" +#include "mobileap_common.h" +#include "mobileap_wifi.h" +#include "mobileap_handler.h" +#include "mobileap_notification.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_common_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_common_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 _enable_wifi_tethering(TetheringObject *obj, gchar *ssid) +{ + mobile_ap_error_code_e ret; + + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) { + ERR("Wi-Fi tethering is already enabled\n"); + ret = MOBILE_AP_ERROR_ALREADY_ENABLED; + return ret; + } + + /* Update global state */ + if (!_mobileap_set_state(MOBILE_AP_STATE_WIFI)) { + ret = MOBILE_AP_ERROR_RESOURCE; + return ret; + } + + /* Update Wi-Fi hotspot data to common object */ + ret = __update_wifi_data(obj); + if (ret != MOBILE_AP_ERROR_NONE) { + _mobileap_clear_state(MOBILE_AP_STATE_WIFI); + return ret; + } + + if (ssid != NULL && strlen(ssid) > 0) { + DBG("Private(Passed) SSID is used : %s\n", ssid); + g_strlcpy(obj->ssid, ssid, sizeof(obj->ssid)); + } + + /* Initialize tethering */ + if (!_init_tethering(obj)) { + _mobileap_clear_state(MOBILE_AP_STATE_WIFI); + ret = MOBILE_AP_ERROR_RESOURCE; + return ret; + } + + /* 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); + _mobileap_clear_state(MOBILE_AP_STATE_WIFI); + return ret; + } + + _delete_timeout_noti(); + _init_timeout_cb(MOBILE_AP_TYPE_WIFI, (void *)obj); + _start_timeout_cb(MOBILE_AP_TYPE_WIFI); + + return MOBILE_AP_ERROR_NONE; +} + +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_common_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) +{ + mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE; + gboolean ret_val = FALSE; + + g_assert(obj != NULL); + g_assert(context != NULL); + + + ret = _enable_wifi_tethering(obj, ssid); + if (ret != MOBILE_AP_ERROR_NONE) { + ERR("_enable_wifi_tethering is failed\n"); + } else { + _emit_mobileap_dbus_signal(obj, E_SIGNAL_WIFI_TETHER_ON, NULL); + ret_val = TRUE; + } + + dbus_g_method_return(context, MOBILE_AP_ENABLE_WIFI_TETHERING_CFM, ret); + + return ret_val; +} + + +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; + + 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); + + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) { + g_strlcpy(ssid, obj->ssid, sizeof(ssid)); + } else { + ret = __get_common_ssid(ssid, sizeof(ssid)); + if (ret != MOBILE_AP_ERROR_NONE) { + ERR("__get_common_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; +} -- 2.7.4