From: jk7744.park Date: Sun, 1 Feb 2015 04:38:36 +0000 (+0900) Subject: tizen 2.3 release X-Git-Tag: submit/tizen_2.3/20150202.061848^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f9b62dd7cbc2265f3f7b26ce30a62b67fefb549e;p=framework%2Fconnectivity%2Fmobileap-agent.git tizen 2.3 release --- diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100644 new mode 100755 index 4a28d24..8c4df51 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(mobileap-agent C) -SET(SRCS src/mobileap_agent.c +SET(SRCS src/mobileap_softap.c src/mobileap_main.c src/mobileap_wifi.c src/mobileap_usb.c @@ -10,11 +10,12 @@ SET(SRCS src/mobileap_agent.c src/mobileap_common.c src/mobileap_notification.c src/mobileap_network.c + src/mobileap_iptables.c ) SET(CMAKE_INSTALL_PREFIX /usr) -SET(APP_VENDOR "tizen") +SET(APP_VENDOR "samsung") SET(APP_NAME mobileap-agent) SET(APP_DIR ${CMAKE_INSTALL_PREFIX}/bin) SET(INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include) @@ -28,7 +29,7 @@ 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}) +pkg_check_modules(pkgs REQUIRED gio-2.0 dlog dbus-glib-1 deviced vconf notification capi-network-connection capi-network-bluetooth appcore-common capi-network-wifi capi-network-wifi-direct alarm-service appsvc libssl) FOREACH(flag ${pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") ENDFOREACH(flag) @@ -59,5 +60,5 @@ 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) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/tethering_dump.sh DESTINATION /opt/etc/dump.d/module.d/) diff --git a/include/mobileap.h b/include/mobileap.h index e751ec8..a5ad66f 100644 --- a/include/mobileap.h +++ b/include/mobileap.h @@ -52,9 +52,12 @@ extern "C" { #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_WIFI_AP_ON "wifi_ap_on" +#define SIGNAL_NAME_WIFI_AP_OFF "wifi_ap_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_POWER_SAVE_MODE "power_save_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" @@ -78,9 +81,12 @@ typedef enum { E_SIGNAL_USB_TETHER_OFF, E_SIGNAL_BT_TETHER_ON, E_SIGNAL_BT_TETHER_OFF, + E_SIGNAL_WIFI_AP_ON, + E_SIGNAL_WIFI_AP_OFF, E_SIGNAL_NO_DATA_TIMEOUT, E_SIGNAL_LOW_BATTERY_MODE, E_SIGNAL_FLIGHT_MODE, + E_SIGNAL_POWER_SAVE_MODE, E_SIGNAL_SECURITY_TYPE_CHANGED, E_SIGNAL_SSID_VISIBILITY_CHANGED, E_SIGNAL_PASSPHRASE_CHANGED, @@ -92,20 +98,21 @@ typedef enum { */ #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_SSID_MAX_LEN 32 /**< 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 */ +#define MOBILE_AP_WIFI_PLAIN_TEXT_KEY_MAX_LEN 63 /**< Maximum length of wifi plain text key */ +#define MOBILE_AP_WIFI_KEY_MAX_LEN 64 /**< Maximum length of wifi hash 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_MAX_WIFI_STA 10 /**< Firmware limitation (BCM4339) */ +#define MOBILE_AP_MAX_BT_STA 4 /**< Bluetooth specification (1 Master and 4 Slaves) */ +#define MOBILE_AP_MAX_USB_STA 1 /**< Only one usb connection is possible */ +#define MOBILE_AP_MAX_CONNECTED_STA 15 /**< Maximum connected station. 10(Wi-Fi) + 4(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_STR_HOSTNAME_LEN 33 /**< length of the hostname */ #define MOBILE_AP_NAME_UNKNOWN "UNKNOWN" /** @@ -123,6 +130,7 @@ typedef enum { 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_PERMISSION_DENIED, /**< Permission Denied */ MOBILE_AP_ERROR_MAX } mobile_ap_error_code_e; @@ -144,6 +152,9 @@ typedef enum { MOBILE_AP_ENABLE_BT_TETHERING_CFM, /* mobile_ap_enable_bt_tethering() */ MOBILE_AP_DISABLE_BT_TETHERING_CFM, /* mobile_ap_disable_bt_tethering() */ + MOBILE_AP_ENABLE_WIFI_AP_CFM, /* mobile_ap_enable_wifi_ap() */ + MOBILE_AP_DISABLE_WIFI_AP_CFM, /* mobile_ap_disable_wifi_ap() */ + MOBILE_AP_GET_STATION_INFO_CFM, /* mobile_ap_get_station_info() */ MOBILE_AP_GET_DATA_PACKET_USAGE_CFM, /* mobile_ap_get_data_packet_usage() */ @@ -158,6 +169,9 @@ typedef enum { MOBILE_AP_ENABLED_BT_TETHERING_IND, /* Turning on BT tethering indication */ MOBILE_AP_DISABLED_BT_TETHERING_IND, /* Turning off BT tethering indication */ + MOBILE_AP_ENABLED_WIFI_AP_IND, /* Turning on WiFi AP indication */ + MOBILE_AP_DISABLED_WIFI_AP_IND, /* Turning off WiFi AP indication */ + MOBILE_AP_STATION_CONNECT_IND, /* Station connection indication */ MOBILE_AP_STATION_DISCONNECT_IND, /* Station disconnection indication */ MOBILE_AP_USB_STATION_CONNECT_IND, @@ -169,6 +183,7 @@ typedef enum { MOBILE_AP_TYPE_WIFI, MOBILE_AP_TYPE_USB, MOBILE_AP_TYPE_BT, + MOBILE_AP_TYPE_WIFI_AP, MOBILE_AP_TYPE_MAX, } mobile_ap_type_e; @@ -181,7 +196,7 @@ 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 */ + char *hostname; time_t tm; /**< connection time*/ } mobile_ap_station_info_t; diff --git a/include/mobileap_bluetooth.h b/include/mobileap_bluetooth.h index 95e28a7..f37f8e2 100644 --- a/include/mobileap_bluetooth.h +++ b/include/mobileap_bluetooth.h @@ -18,10 +18,14 @@ #ifndef __MOBILEAP_BLUETOOTH_H__ #define __MOBILEAP_BLUETOOTH_H__ -#include "mobileap_agent.h" +#include "mobileap_softap.h" + +#define PS_RECHECK_INTERVAL 500 +#define PS_RECHECK_COUNT_MAX 5 void _bt_get_remote_device_name(TetheringObject *obj, const char *mac, char **name); mobile_ap_error_code_e _disable_bt_tethering(TetheringObject *obj); +gboolean _is_trying_bt_operation(void); gboolean tethering_enable_bt_tethering(TetheringObject *obj, DBusGMethodInvocation *context); diff --git a/include/mobileap_common.h b/include/mobileap_common.h old mode 100644 new mode 100755 index ab1e549..c5c1678 --- a/include/mobileap_common.h +++ b/include/mobileap_common.h @@ -20,7 +20,7 @@ #include -#include "mobileap_agent.h" +#include "mobileap_softap.h" gint _slist_find_station_by_interface(gconstpointer a, gconstpointer b); gint _slist_find_station_by_mac(gconstpointer a, gconstpointer b); @@ -38,9 +38,11 @@ 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 _add_interface_routing(const char *interface, const in_addr_t gateway); +int _del_interface_routing(const char *interface, const in_addr_t gateway); +int _add_routing_rule(const char *interface); +int _del_routing_rule(const char *interface); +int _flush_ip_address(const char *interface); int _execute_command(const char *cmd); int _get_tethering_type_from_ip(const char *ip, mobile_ap_type_e *type); diff --git a/include/mobileap_handler.h b/include/mobileap_handler.h index c1bc03b..8315858 100644 --- a/include/mobileap_handler.h +++ b/include/mobileap_handler.h @@ -18,13 +18,22 @@ #ifndef __MOBILEAP_HANDLER_H__ #define __MOBILEAP_HANDLER_H__ +#include +#include + +typedef struct { + void *obj; + unsigned int state; +} changed_state_t; + void _register_vconf_cb(void *user_data); void _unregister_vconf_cb(void *user_data); +gboolean _is_power_save_survival_mode(void); +int _sp_timeout_handler(alarm_id_t alarm_id, void *user_param); void _init_timeout_cb(mobile_ap_type_e type, void *user_data); -void _start_timeout_cb(mobile_ap_type_e type); +void _start_timeout_cb(mobile_ap_type_e type, time_t end_time); void _stop_timeout_cb(mobile_ap_type_e type); void _deinit_timeout_cb(mobile_ap_type_e type); - #endif diff --git a/include/mobileap_iptables.h b/include/mobileap_iptables.h new file mode 100644 index 0000000..520764b --- /dev/null +++ b/include/mobileap_iptables.h @@ -0,0 +1,55 @@ +/* + * 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_IPTABLES_H__ +#define __MOBILEAP_IPTABLES_H__ + +#define IPTABLES "/usr/sbin/iptables" +#define TABLE_FILTER "filter" +#define TABLE_NAT "nat" +#define TABLE_MANGLE "mangle" +#define CHAIN_FW "FORWARD" +#define CHAIN_POST "POSTROUTING" +#define CHAIN_PRE "PREROUTING" +#define TETH_FILTER_FW "teth_filter_fw" +#define TETH_NAT_POST "teth_nat_post" +#define TETH_NAT_PRE "teth_nat_pre" +#define STATE_RELATED_ESTAB "RELATED,ESTABLISHED" +#define STATE_INVALID "INVALID" +#define ACTION_DROP "DROP" +#define ACTION_RETURN "RETURN" + +typedef enum { + PKT_REDIRECTION_RULE, + FORWARD_RULE_WITH_ACTION, + FORWARD_RULE_WITH_ACTION_AND_STATE, + DEFAULT_RULE, + PORT_FW_RULE, + MASQ_RULE, + CLAMP_MSS_RULE, +} iptables_rule_e; + +int _iptables_create_chain(const char *table_name, const char *chain_name); +int _iptables_flush_rules(const char *table_name, const char *chain_name); +int _iptables_delete_chain(const char *table_name, const char *chain_name); +int _iptables_add_rule(iptables_rule_e rule_type, const char *table, + const char *chain, ...); +int _iptables_delete_rule(iptables_rule_e rule_type, const char *table, + const char *chain, ...); +int _get_data_usage(const char *src, const char *dest, unsigned long long *tx, + unsigned long long *rx); +#endif diff --git a/include/mobileap_network.h b/include/mobileap_network.h index 3959886..18f1dbf 100644 --- a/include/mobileap_network.h +++ b/include/mobileap_network.h @@ -20,12 +20,19 @@ #include +#define TETHERING_NET_OPEN_RETRY_INTERVAL 2000 /* 2 secs */ + gboolean _get_network_interface_name(char **if_name); +gboolean _get_network_gateway_address(char **ip); gboolean _is_trying_network_operation(void); gboolean _set_masquerade(void); gboolean _unset_masquerade(void); -gboolean _open_network(void); -gboolean _close_network(void); +gboolean _add_default_router(void); +gboolean _del_default_router(void); +void _add_port_forward_rule(void); +void _del_port_forward_rule(void); +int _open_network(void); +void _close_network(void); gboolean _init_network(void *user_data); gboolean _deinit_network(void); diff --git a/include/mobileap_notification.h b/include/mobileap_notification.h index b457aa8..6b38ef6 100644 --- a/include/mobileap_notification.h +++ b/include/mobileap_notification.h @@ -18,29 +18,39 @@ #ifndef __MOBILEAP_NOTIFICATION_H__ #define __MOBILEAP_NOTIFICATION_H__ +#include #include -#define MH_NOTI_STR_MAX 50 -#define MH_NOTI_ICON_PATH "/usr/ug/res/images/ug-setting-mobileap-efl/tethering.png" +#define MH_NOTI_STR_MAX 50 +#define MH_NOTI_PATH_MAX 256 -#define MOBILEAP_LOCALE_COMMON_PKG "ug-setting-mobileap-efl" -#define MOBILEAP_LOCALE_COMMON_RES "/usr/ug/res/locale" +#define MH_NOTI_ICON_PATH "/usr/ug/res/images/ug-setting-mobileap-efl" +#define MH_NOTI_ICON_BT MH_NOTI_ICON_PATH"/noti_tethering_bluetooth.png" +#define MH_NOTI_ICON_GENERAL MH_NOTI_ICON_PATH"/noti_tethering_general.png" +#define MH_NOTI_ICON_USB MH_NOTI_ICON_PATH"/noti_tethering_usb.png" +#define MH_NOTI_ICON_WIFI MH_NOTI_ICON_PATH"/noti_tethering_wifi_num.png" +#define MH_NOTI_ICON_WIFI_PD MH_NOTI_ICON_PATH"/noti_tethering_wifi_num_%02d.png" -#define _(str) dgettext(MOBILEAP_LOCALE_COMMON_PKG, str) +#define MOBILEAP_LOCALE_COMMON_PKG "ug-setting-mobileap-efl" +#define MOBILEAP_LOCALE_COMMON_RES "/usr/ug/res/locale" -#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") +#ifdef _ +#undef _ +#endif +#define _(str) dgettext(MOBILEAP_LOCALE_COMMON_PKG, str) +#define MH_STR_TETHERING "IDS_MOBILEAP_BODY_TETHERING" +#define MH_STR_CONNECTED_DEV "IDS_MOBILEAP_POP_CONNECTED_DEVICES_C_PD" +#define MH_STR_CONNECTION_TIMEOUT "IDS_ST_BODY_CONNECTION_TIMEOUT" +#define MH_STR_CONFIGURE_TETHERING "IDS_MOBILEAP_BODY_TAP_TO_CONFIGURE_TETHERING" +#define MH_STR_TETHERING_ACTIVE _("IDS_MOBILEAP_BODY_TETHERING_ACTIVE_ABB") +#define MH_STR_BT_VISIBILITY _("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 _create_timeout_noti(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 _create_connected_noti(int count, const char *icon_path); +int _update_connected_noti(int count, const char *icon_path); int _delete_connected_noti(void); -int _create_status_noti(const char *content); +void _create_tethering_active_noti(void); +void _create_bt_tethering_active_noti(void); #endif diff --git a/include/mobileap_agent.h b/include/mobileap_softap.h old mode 100644 new mode 100755 similarity index 70% rename from include/mobileap_agent.h rename to include/mobileap_softap.h index 8ae515e..14ce713 --- a/include/mobileap_agent.h +++ b/include/mobileap_softap.h @@ -15,9 +15,10 @@ * limitations under the License. */ -#ifndef __MOBILEAP_AGENT_H__ -#define __MOBILEAP_AGENT_H__ +#ifndef __MOBILEAP_SOFTAP_H__ +#define __MOBILEAP_SOFTAP_H__ +#include #include #include #include @@ -27,11 +28,15 @@ #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) +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "MOBILEAP_AGENT" + +#define DBG(fmt, args...) LOGD(fmt, ##args) +#define ERR(fmt, args...) LOGE(fmt, ##args) +#define SDBG(fmt, args...) SECURE_LOGD(fmt, ##args) +#define SERR(fmt, args...) SECURE_LOGE(fmt, ##args) #define DRIVER_DELAY 250000 /* micro seconds */ @@ -44,10 +49,10 @@ #define IP_SUBNET_MASK "255.255.255.0" #define WIFI_IF "wlan0" -#define IP_ADDRESS_WIFI 0xC0A83D02 /* 192.168.61.2 */ +#define IP_ADDRESS_WIFI 0xC0A82B02 /* 192.168.43.2 */ #define SOFTAP_IF "wl0.1" -#define IP_ADDRESS_SOFTAP 0xC0A83D01 /* 192.168.61.1 */ +#define IP_ADDRESS_SOFTAP 0xC0A82B01 /* 192.168.43.1 */ #define USB_IF "usb0" #define IP_ADDRESS_USB 0xC0A88103 /* 192.168.129.3 */ @@ -67,7 +72,8 @@ #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" \ +#define DNSMASQ_CONF \ + "dhcp-range=192.168.43.3,192.168.43.254,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" \ @@ -78,6 +84,8 @@ "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" \ + "group=app\n" \ + "user=app\n" \ "dhcp-option=tag:blue,option:router,192.168.129.3\n" #define DNSMASQ_CONF_FILE "/tmp/dnsmasq.conf" @@ -96,63 +104,73 @@ "ssid=%s\n" \ "channel=%d\n" \ "ignore_broadcast_ssid=%d\n" \ + "hw_mode=g\n" \ "max_num_sta=%d\n" \ - "ieee80211n=1\n" \ - "%s\n" -#define HOSTAPD_DEBUG_FILE "/tmp/hostapd.log" + "ieee80211n=1\n" +#define HOSTAPD_DEBUG_FILE "/var/log/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_STA_CONN "AP-STA-CONNECTED " +#define HOSTAPD_STA_DISCONN_LEN 20 +#define HOSTAPD_STA_CONN_LEN 17 #define HOSTAPD_MONITOR_ATTACH "ATTACH" #define HOSTAPD_MONITOR_DETACH "DETACH" -/* End of hostapd configuration */ +#define HOSTAPD_DHCP_MAX_INTERVAL 30000 /* 30 seconds */ -#define WLAN_SCRIPT "/usr/bin/wlan.sh" +/* Samsung VSIE value in beacon / probe response. + * Wi-Fi station can identify AP whether it is tethering or AP only using this value. + */ +#define HOSTAPD_VENDOR_ELEMENTS_TETH "DD050016328000" /* Samsung tethering device */ +#define HOSTAPD_VENDOR_ELEMENTS_WIFI_AP "DD050016321000" /* Specific application mode AP (e.g. GroupPlay) */ +/* End of hostapd configuration */ #define IP_FORWARD "/proc/sys/net/ipv4/ip_forward" -#define IPTABLES "/usr/sbin/iptables" +#define IP_CMD "/usr/sbin/ip" #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 TETHERING_ROUTING_TABLE 252 +#define SRC_ROUTING_RULE "iif %s lookup %d" +#define DEFAULT_ROUTER "default via %s dev %s scope global table %d" +#define INTERFACE_ROUTING "%s/24 table %d dev %s" #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 MOBILE_AP_STATE_WIFI_AP 8 +#define MOBILE_AP_STATE_ALL 15 #define DNSMASQ_DBUS_INTERFACE "uk.org.thekelleys.dnsmasq" #define PROC_NET_DEV "/proc/net/dev" -#define TETHERING_CONN_TIMEOUT (1200000) /* 20 Mins */ +#define TETHERING_CONN_TIMEOUT (1200) /* 20 Mins */ +#define WIFI_AP_CONN_TIMEOUT (300) /* 5 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]; + /* in AP case, hex key will be passed from library, so one extra byte is needed */ char key[MOBILE_AP_WIFI_KEY_MAX_LEN + 1]; char security_type[SECURITY_TYPE_LEN]; +} softap_settings_t; + +typedef struct { + /* The parent class object state. */ + GObject parent; + + int init_count; + + softap_settings_t softap_settings; } TetheringObject; typedef struct { @@ -175,16 +193,20 @@ typedef struct { int *value; } vconf_reg_t; - typedef enum { MOBILE_AP_DRV_INTERFACE_NONE, MOBILE_AP_WEXT, MOBILE_AP_NL80211, } mobile_ap_drv_interface_e; +typedef struct { + guint tid; + char *mac_addr; +} sta_timer_t; + /* ssid : 32 key : 64 */ -int _mh_core_enable_softap(const char *ssid, const char *security, - const char *key, int hide_mode); +int _mh_core_enable_softap(const mobile_ap_type_e type, 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); @@ -193,16 +215,23 @@ 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); +void _register_wifi_station_handler(void); +void _unregister_wifi_station_handler(void); -gboolean _init_tethering(TetheringObject *obj); +void _block_device_sleep(void); +void _unblock_device_sleep(void); +int _init_tethering(TetheringObject *obj); gboolean _deinit_tethering(TetheringObject *obj); gboolean _mobileap_clear_state(int state); +gboolean _terminate_mobileap_agent(gpointer user_data); 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); +void _flush_dhcp_ack_timer(void); +void _destroy_dhcp_ack_timer(char *mac_addr); #endif diff --git a/include/mobileap_usb.h b/include/mobileap_usb.h index 4ad58b8..74f9a30 100644 --- a/include/mobileap_usb.h +++ b/include/mobileap_usb.h @@ -18,17 +18,13 @@ #ifndef __MOBILEAP_USB_H__ #define __MOBILEAP_USB_H__ -#include "mobileap_agent.h" - +#include "mobileap_softap.h" mobile_ap_error_code_e _disable_usb_tethering(TetheringObject *obj); +gboolean _is_trying_usb_operation(void); 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 index d64a595..61e3f71 100644 --- a/include/mobileap_wifi.h +++ b/include/mobileap_wifi.h @@ -18,47 +18,61 @@ #ifndef __MOBILEAP_WIFI_H__ #define __MOBILEAP_WIFI_H__ -#include "mobileap_agent.h" +#include "mobileap_softap.h" +#define VCONFKEY_MOBILE_HOTSPOT_SSID "memory/private/mobileap-agent/ssid" #define SOFTAP_SECURITY_TYPE_OPEN_STR "open" #define SOFTAP_SECURITY_TYPE_WPA2_PSK_STR "wpa2-psk" #define SOFTAP_PASSPHRASE_PATH "wifi_tethering.txt" +#define SOFTAP_PASSPHRASE_GROUP_ID "secure-storage::tethering" typedef enum { SOFTAP_SECURITY_TYPE_OPEN, SOFTAP_SECURITY_TYPE_WPA2_PSK, } softap_security_type_e; -void _register_wifi_station_handler(void); +typedef struct { + int hide_mode; + char *ssid; + char *key; + softap_security_type_e security_type; +} wifi_saved_settings; + +int _get_wifi_name_from_lease_info(const char *mac, char **name_buf); void _add_wifi_device_to_array(softap_device_info_t *di, GPtrArray *array); +mobile_ap_error_code_e _enable_wifi_tethering(TetheringObject *obj, gchar *ssid, + gchar *passphrase, int hide_mode, softap_security_type_e security_type); mobile_ap_error_code_e _disable_wifi_tethering(TetheringObject *obj); +gboolean _is_trying_wifi_operation(void); +mobile_ap_error_code_e _reload_softap_settings(TetheringObject *obj, + gchar *ssid, gchar *key, gint hide_mode, gint security_type); +mobile_ap_error_code_e _reload_softap_settings_for_ap(TetheringObject *obj, + gchar *ssid, gchar *key, gint hide_mode, gint security_type); /* Dbus method */ +mobile_ap_error_code_e _enable_wifi_ap(TetheringObject *obj, gchar *ssid, + gchar *passphrase, int hide_mode, + softap_security_type_e security_type); +mobile_ap_error_code_e _disable_wifi_ap(TetheringObject *obj); gboolean tethering_enable_wifi_tethering(TetheringObject *obj, gchar *ssid, - gchar *key, gint hide_mode, + gchar *key, gint hide_mode, gint security_type, DBusGMethodInvocation *context); gboolean tethering_disable_wifi_tethering(TetheringObject *obj, DBusGMethodInvocation *context); -gboolean tethering_get_wifi_tethering_hide_mode(TetheringObject *obj, +gboolean tethering_reload_wifi_settings(TetheringObject *obj, gchar *ssid, + gchar *key, gint visibility, gint security_type, DBusGMethodInvocation *context); -gboolean tethering_set_wifi_tethering_hide_mode(TetheringObject *obj, - gint hide_mode, DBusGMethodInvocation *context); +gboolean tethering_reload_wifi_ap_settings(TetheringObject *obj, gchar *ssid, + gchar *key, gint hide_mode, + gint security, DBusGMethodInvocation *context); -gboolean tethering_get_wifi_tethering_ssid(TetheringObject *obj, +gboolean tethering_enable_wifi_ap(TetheringObject *obj, gchar *ssid, + gchar *key, gint hide_mode, gint security_type, DBusGMethodInvocation *context); -gboolean tethering_get_wifi_tethering_security_type(TetheringObject *obj, +gboolean tethering_disable_wifi_ap(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 index 3dbcac1..ad6127b 100644 --- a/include/tethering-dbus-interface.xml +++ b/include/tethering-dbus-interface.xml @@ -9,12 +9,6 @@ - - - - - - @@ -26,6 +20,7 @@ + @@ -60,74 +55,51 @@ - + + + + + - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + + + - + - + + + + + - + - - + + - + - - + + + @@ -167,38 +139,27 @@ - + - + - + - - - - - - - - - + - + - - + - - - + \ No newline at end of file diff --git a/mobileap-agent.manifest b/mobileap-agent.manifest index 75b0fa5..9e1197e 100644 --- a/mobileap-agent.manifest +++ b/mobileap-agent.manifest @@ -1,5 +1,38 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobileap-agent.rule b/mobileap-agent.rule deleted file mode 100644 index ae46bac..0000000 --- a/mobileap-agent.rule +++ /dev/null @@ -1,4 +0,0 @@ -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 index 183236a..bc0623a 100644 --- a/packaging/mobileap-agent.spec +++ b/packaging/mobileap-agent.spec @@ -1,182 +1,69 @@ -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 +Name: mobileap-agent +Summary: Mobile AP daemon for setting tethering environments +Version: 1.0.12 +Release: 1 +Group: System/Network +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(deviced) +BuildRequires: pkgconfig(vconf) +BuildRequires: pkgconfig(notification) +BuildRequires: pkgconfig(capi-network-connection) +BuildRequires: pkgconfig(capi-network-bluetooth) +BuildRequires: pkgconfig(syspopup-caller) +BuildRequires: pkgconfig(bundle) +BuildRequires: pkgconfig(appcore-common) +BuildRequires: pkgconfig(capi-network-wifi-direct) +BuildRequires: pkgconfig(capi-network-wifi) +BuildRequires: pkgconfig(alarm-service) +BuildRequires: pkgconfig(appsvc) +BuildRequires: pkgconfig(libssl) +BuildRequires: cmake +Requires(post): /usr/bin/vconftool +Requires(post): bluetooth-agent +Requires(post): ss-server +Requires: iproute2 +Requires: iptables +Requires: dnsmasq + %description Mobile AP daemon for setting tethering environments %prep %setup -q + %build -%cmake . +export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE" +export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE" +export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE" + +%cmake -DCMAKE_BUILD_TYPE="" \ + . + 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 +/usr/bin/vconftool set -t string memory/private/mobileap-agent/ssid "" -u 0 -i -f -s system::vconf_network +/usr/bin/vconftool set -t int memory/mobile_hotspot/connected_device "0" -u 0 -i -f -s system::vconf_network +/usr/bin/vconftool set -t int memory/mobile_hotspot/mode "0" -u 0 -i -f -s system::vconf_network +/usr/bin/vconftool set -t int db/mobile_hotspot/security "1" -u 5000 -f -s system::vconf_network +/usr/bin/vconftool set -t int db/mobile_hotspot/hide "0" -u 5000 -f -s system::vconf_network + +/bin/chmod +x /opt/etc/dump.d/module.d/tethering_dump.sh %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 +/opt/etc/dump.d/module.d/tethering_dump.sh -* 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/src/mobileap_bluetooth.c b/src/mobileap_bluetooth.c old mode 100644 new mode 100755 index 077f18a..43cd1c2 --- a/src/mobileap_bluetooth.c +++ b/src/mobileap_bluetooth.c @@ -22,7 +22,7 @@ #include #include -#include "mobileap_agent.h" +#include "mobileap_softap.h" #include "mobileap_common.h" #include "mobileap_bluetooth.h" #include "mobileap_handler.h" @@ -38,10 +38,16 @@ 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}}; + {NULL, NULL, IP_ADDRESS_BT_4}}; + +static DBusGMethodInvocation *g_context = NULL; + +static void __bt_nap_connection_changed(bool connected, const char *remote_address, + const char *interface_name, void *user_data); +static void __bt_adapter_state_changed(int result, bt_adapter_state_e adapter_state, void *user_data); +static void __handle_bt_adapter_visibility(); + +int __recheck_bt_adapter_timer = 0; static __bt_remote_device_s *__find_bt_remote(const char *mac) { @@ -56,7 +62,7 @@ static __bt_remote_device_s *__find_bt_remote(const char *mac) } if (i == MOBILE_AP_MAX_BT_STA) { - ERR("Not found : %s\n", mac); + SERR("Not found : %s\n", mac); return NULL; } @@ -83,6 +89,9 @@ static __bt_remote_device_s *__add_bt_remote(bt_device_info_s *info, const char return NULL; } + _add_interface_routing(__bt_remote_devices[i].intf_name, + __bt_remote_devices[i].intf_ip); + _add_routing_rule(__bt_remote_devices[i].intf_name); __bt_remote_devices[i].info = info; return &__bt_remote_devices[i]; @@ -101,10 +110,13 @@ static gboolean __del_bt_remote(const char *mac) } if (i == MOBILE_AP_MAX_BT_STA) { - ERR("Not found : %s\n", mac); + SERR("Not found : %s\n", mac); return FALSE; } + _del_routing_rule(__bt_remote_devices[i].intf_name); + _del_interface_routing(__bt_remote_devices[i].intf_name, + __bt_remote_devices[i].intf_ip); bt_adapter_free_device_info(__bt_remote_devices[i].info); g_free(__bt_remote_devices[i].intf_name); @@ -125,6 +137,9 @@ static void __del_bt_remote_all(void) } if (__bt_remote_devices[i].intf_name) { + _del_routing_rule(__bt_remote_devices[i].intf_name); + _del_interface_routing(__bt_remote_devices[i].intf_name, + __bt_remote_devices[i].intf_ip); g_free(__bt_remote_devices[i].intf_name); __bt_remote_devices[i].intf_name = NULL; } @@ -133,6 +148,213 @@ static void __del_bt_remote_all(void) return; } +static mobile_ap_error_code_e __init_bt(TetheringObject *obj) +{ + int ret; + + ret = bt_initialize(); + if (ret != BT_ERROR_NONE) { + ERR("bt_initialize is failed : %d\n", ret); + return MOBILE_AP_ERROR_RESOURCE; + } + + ret = bt_adapter_set_state_changed_cb(__bt_adapter_state_changed, (void *)obj); + if (ret != BT_ERROR_NONE) { + ERR("bt_adapter_set_state_changed_cb is failed : %d\n", ret); + bt_deinitialize(); + return MOBILE_AP_ERROR_RESOURCE; + } + + return MOBILE_AP_ERROR_NONE; +} + +static void __deinit_bt(void) +{ + int ret; + + ret = bt_adapter_unset_state_changed_cb(); + if (ret != BT_ERROR_NONE) + ERR("bt_adapter_unset_state_changed_cb is failed : %d\n", ret); + + ret = bt_deinitialize(); + if (ret != BT_ERROR_NONE) + ERR("bt_deinitialize is failed : %d\n", ret); + + return; +} + +static gboolean __is_bt_adapter_on(void) +{ + int ret; + bt_adapter_state_e adapter_state = BT_ADAPTER_DISABLED; + + ret = bt_adapter_get_state(&adapter_state); + if (ret != BT_ERROR_NONE) { + ERR("bt_adapter_get_state is failed : %d\n", ret); + return FALSE; + } + + if (adapter_state == BT_ADAPTER_ENABLED) + return TRUE; + else + return FALSE; +} + +gboolean __bt_adapter_timeout_cb(gpointer data) +{ + DBG("+\n"); + + static int retry_count = 0; + if (__is_bt_adapter_on() == TRUE) { + DBG("BT Adapter is enabled by other process \n"); + retry_count = 0; + DBG("-\n"); + return FALSE; + } else { + if (++retry_count >= PS_RECHECK_COUNT_MAX) { + retry_count = 0; + ERR("_enable_bt_tethering() is failed because of bt_adapter_eanbled() failed:n"); + _mobileap_clear_state(MOBILE_AP_STATE_BT); + __deinit_bt(); + dbus_g_method_return(g_context, + MOBILE_AP_ENABLE_BT_TETHERING_CFM, MOBILE_AP_ERROR_INTERNAL); + g_context = NULL; + _unblock_device_sleep(); + DBG("-\n"); + return FALSE; + } else { + DBG("-\n"); + return TRUE; + } + } +} + +static mobile_ap_error_code_e __turn_on_bt_adapter(TetheringObject *obj) +{ + int ret; + + ret = bt_adapter_enable(); + if (ret == BT_ERROR_NOW_IN_PROGRESS) { + if (__recheck_bt_adapter_timer) { + g_source_remove(__recheck_bt_adapter_timer); + } + __recheck_bt_adapter_timer = g_timeout_add(PS_RECHECK_INTERVAL, + __bt_adapter_timeout_cb, NULL); + return MOBILE_AP_ERROR_NONE; + } + + if (ret != BT_ERROR_NONE && ret != BT_ERROR_ALREADY_DONE) { + ERR("bt_adapter_enable is failed : %d\n", ret); + if (ret == BT_ERROR_PERMISSION_DENIED) + return MOBILE_AP_ERROR_PERMISSION_DENIED; + else + return MOBILE_AP_ERROR_RESOURCE; + } + + return MOBILE_AP_ERROR_NONE; +} + +static mobile_ap_error_code_e __turn_on_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); + if (bt_ret == BT_ERROR_PERMISSION_DENIED) + return MOBILE_AP_ERROR_PERMISSION_DENIED; + else + return MOBILE_AP_ERROR_RESOURCE; + } + + return MOBILE_AP_ERROR_NONE; +} + +static void __turn_off_bt_nap(void) +{ + int bt_ret; + + bt_ret = bt_nap_disconnect_all(); + if (bt_ret != BT_ERROR_NONE) + ERR("bt_nap_disconnect_all is failed : %d\n", bt_ret); + else + DBG("bt_nap_disconnect_all is called\n"); + + 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; +} + +mobile_ap_error_code_e _enable_bt_tethering(TetheringObject *obj) +{ + mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE; + + DBG("+\n"); + if (__recheck_bt_adapter_timer) { + g_source_remove(__recheck_bt_adapter_timer); + __recheck_bt_adapter_timer = 0; + } + + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) { + ERR("Wi-Fi AP is enabled\n"); + return MOBILE_AP_ERROR_RESOURCE; + } + + ret = _init_tethering(obj); + if (ret != MOBILE_AP_ERROR_NONE) { + return ret; + } + + ret = __turn_on_bt_nap(obj); + if (ret != MOBILE_AP_ERROR_NONE) { + _deinit_tethering(obj); + return ret; + } + _delete_timeout_noti(); + _init_timeout_cb(MOBILE_AP_TYPE_BT, (void *)obj); + _start_timeout_cb(MOBILE_AP_TYPE_BT, time(NULL) + TETHERING_CONN_TIMEOUT); + + return ret; +} + +mobile_ap_error_code_e _disable_bt_tethering(TetheringObject *obj) +{ + int ret = BT_ERROR_NONE; + if (!_mobileap_is_enabled(MOBILE_AP_STATE_BT)) { + ERR("BT tethering has not been enabled\n"); + return MOBILE_AP_ERROR_NOT_ENABLED; + } + ret = bt_adapter_unset_visibility_mode_changed_cb(); + if (ret != BT_ERROR_NONE) + ERR("bt_adapter_unset_visibility_mode_changed_cb is failed : %d\n", ret); + + _block_device_sleep(); + if (__is_bt_adapter_on()) { + __turn_off_bt_nap(); + __deinit_bt(); + } + + _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); + _unblock_device_sleep(); + + return MOBILE_AP_ERROR_NONE; +} + + 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) { @@ -145,11 +367,10 @@ static void __bt_nap_connection_changed(bool connected, const char *remote_addre int ret; int n_station = 0; - DBG("Remote address : %s, Interface : %s, %s\n", + SDBG("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) { @@ -177,47 +398,12 @@ static void __bt_nap_connection_changed(bool connected, const char *remote_addre _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); + _start_timeout_cb(MOBILE_AP_TYPE_BT, time(NULL) + TETHERING_CONN_TIMEOUT); } 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) { @@ -225,28 +411,20 @@ static void __bt_adapter_state_changed(int result, bt_adapter_state_e adapter_st return; } + DBG("+\n"); + if (!_mobileap_is_enabled(MOBILE_AP_STATE_BT)) return; - int ret; - int duration; - bt_adapter_visibility_mode_e mode; + int ret = MOBILE_AP_ERROR_RESOURCE; 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; + goto FAIL; } - DBG("BT Adapter is %s\n", adapter_state == BT_ADAPTER_ENABLED ? + SDBG("BT Adapter is %s\n", adapter_state == BT_ADAPTER_ENABLED ? "enabled" : "disabled"); if (adapter_state == BT_ADAPTER_DISABLED) { _disable_bt_tethering(obj); @@ -254,26 +432,30 @@ static void __bt_adapter_state_changed(int result, bt_adapter_state_e adapter_st 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 = _enable_bt_tethering(obj); + if (ret != MOBILE_AP_ERROR_NONE) { + ERR("_enable_bt_tethering() is failed : %d\n", ret); + __deinit_bt(); + goto FAIL; + } - 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, + _emit_mobileap_dbus_signal(obj, E_SIGNAL_BT_TETHER_ON, NULL); + dbus_g_method_return(g_context, MOBILE_AP_ENABLE_BT_TETHERING_CFM, ret); - _mobileap_clear_state(MOBILE_AP_STATE_BT); + __handle_bt_adapter_visibility(); + g_context = NULL; + _unblock_device_sleep(); + 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); +FAIL: + dbus_g_method_return(g_context, + MOBILE_AP_ENABLE_BT_TETHERING_CFM, ret); + g_context = NULL; + _mobileap_clear_state(MOBILE_AP_STATE_BT); + _unblock_device_sleep(); + return; } @@ -299,159 +481,115 @@ void _bt_get_remote_device_name(TetheringObject *obj, const char *mac, char **na return; } -mobile_ap_error_code_e _enable_bt_tethering(TetheringObject *obj, - DBusGMethodInvocation *context) +static void __bt_adapter_visibility_changed_cb(int result, + bt_adapter_visibility_mode_e visibility_mode, void *user_data) { - 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; + DBG("+\n"); - if (_mobileap_is_enabled(MOBILE_AP_STATE_BT)) { - ERR("Bluetooth tethering is already enabled\n"); - ret = MOBILE_AP_ERROR_ALREADY_ENABLED; - return ret; - } + int ret; + int duration; + bt_adapter_visibility_mode_e mode = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE; - if (obj->bt_context != NULL) { - ERR("Bluetooth tethering request is progressing\n"); - ret = MOBILE_AP_ERROR_IN_PROGRESS; - return ret; + ret = bt_adapter_get_visibility(&mode, &duration); + if (ret != BT_ERROR_NONE) { + ERR("bt_adapter_get_visibility is failed 0x[%X]\n", ret); } - if (!_mobileap_set_state(MOBILE_AP_STATE_BT)) { - ret = MOBILE_AP_ERROR_RESOURCE; - goto FAIL; + if (mode == BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE) { + ERR("_launch_toast_popup() is failed\n"); } - if (!_init_tethering(obj)) { - ret = MOBILE_AP_ERROR_RESOURCE; - goto FAIL; - } + DBG("-\n"); +} - 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; - } +static void __handle_bt_adapter_visibility() +{ + DBG("+\n"); - 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; - } + int ret; + int duration; + bt_adapter_visibility_mode_e mode = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE; - 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; + ret = bt_adapter_get_visibility(&mode, &duration); + if (ret != BT_ERROR_NONE) { + ERR("bt_adapter_get_visibility is failed 0x[%X]\n", ret); } - 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; + if (mode == BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE) { + ret = bt_adapter_set_visibility(BT_ADAPTER_VISIBILITY_MODE_LIMITED_DISCOVERABLE, 120); + if (ret != BT_ERROR_NONE) { + ERR("bt_adapter_set_visibility is failed 0x[%X]\n", ret); } - 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; + bt_adapter_set_visibility_mode_changed_cb(__bt_adapter_visibility_changed_cb, NULL); + DBG("-\n"); } - gboolean tethering_enable_bt_tethering(TetheringObject *obj, DBusGMethodInvocation *context) { mobile_ap_error_code_e ret; + gboolean ret_val = FALSE; DBG("+\n"); g_assert(obj != NULL); g_assert(context != NULL); + if (g_context) { + DBG("It is turnning on\n"); + dbus_g_method_return(context, + MOBILE_AP_ENABLE_BT_TETHERING_CFM, + MOBILE_AP_ERROR_IN_PROGRESS); + return FALSE; + } + + g_context = context; + + _block_device_sleep(); - ret = _enable_bt_tethering(obj, context); + ret = __init_bt(obj); + if (ret != MOBILE_AP_ERROR_NONE) + goto DONE; + + if (!_mobileap_set_state(MOBILE_AP_STATE_BT)) { + ret = MOBILE_AP_ERROR_RESOURCE; + __deinit_bt(); + goto DONE; + } + + if (__is_bt_adapter_on() == FALSE) { + DBG("Bluetooth is deactivated\n"); + if (__turn_on_bt_adapter(obj) != MOBILE_AP_ERROR_NONE) { + ERR("__turn_on_bt_adapter is failed\n"); + ret = MOBILE_AP_ERROR_INTERNAL; + _mobileap_clear_state(MOBILE_AP_STATE_BT); + __deinit_bt(); + goto DONE; + } + + return TRUE; + } + + ret = _enable_bt_tethering(obj); 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) { + _mobileap_clear_state(MOBILE_AP_STATE_BT); + __deinit_bt(); + } else { _emit_mobileap_dbus_signal(obj, E_SIGNAL_BT_TETHER_ON, NULL); - dbus_g_method_return(context, - MOBILE_AP_ENABLE_BT_TETHERING_CFM, ret); + __handle_bt_adapter_visibility(); + ret_val = TRUE; } - return TRUE; -} +DONE: + dbus_g_method_return(g_context, + MOBILE_AP_ENABLE_BT_TETHERING_CFM, ret); + g_context = NULL; + _unblock_device_sleep(); + + return ret_val; +} gboolean tethering_disable_bt_tethering(TetheringObject *obj, DBusGMethodInvocation *context) @@ -473,3 +611,8 @@ gboolean tethering_disable_bt_tethering(TetheringObject *obj, dbus_g_method_return(context, MOBILE_AP_DISABLE_BT_TETHERING_CFM, ret); return TRUE; } + +gboolean _is_trying_bt_operation(void) +{ + return (g_context ? TRUE : FALSE); +} diff --git a/src/mobileap_common.c b/src/mobileap_common.c old mode 100644 new mode 100755 index 8271601..39a1989 --- a/src/mobileap_common.c +++ b/src/mobileap_common.c @@ -70,7 +70,13 @@ void _emit_mobileap_dbus_signal(TetheringObject *obj, { TetheringObjectClass *klass = TETHERING_OBJECT_GET_CLASS(obj); - DBG("Emitting signal id [%d], with message [%s]\n", num, message); + SDBG("Emitting signal id [%d], with message [%s]\n", num, message); + + if (num == E_SIGNAL_WIFI_TETHER_ON || + num == E_SIGNAL_USB_TETHER_ON || num == E_SIGNAL_BT_TETHER_ON) { + _create_tethering_active_noti(); + } + g_signal_emit(obj, klass->signals[num], 0, message); } @@ -116,18 +122,22 @@ void _send_dbus_station_info(const char *member, mobile_ap_station_info_t *info) return; } - void _update_station_count(int count) { static int prev_cnt = 0; - char str[MH_NOTI_STR_MAX] = {0, }; + char icon_path[MH_NOTI_PATH_MAX] = {0, }; + int wifi_count = 0; + int bt_count = 0; + int usb_count = 0; + + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) { + return; + } 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"); @@ -140,13 +150,26 @@ void _update_station_count(int count) return; } - snprintf(str, MH_NOTI_STR_MAX, MH_NOTI_STR, count); + _get_station_count((gconstpointer)MOBILE_AP_TYPE_WIFI, _slist_find_station_by_interface, &wifi_count); + _get_station_count((gconstpointer)MOBILE_AP_TYPE_BT, _slist_find_station_by_interface, &bt_count); + _get_station_count((gconstpointer)MOBILE_AP_TYPE_USB, _slist_find_station_by_interface, &usb_count); + + if (wifi_count > 0 && bt_count == 0 && usb_count == 0) { + g_strlcpy(icon_path, MH_NOTI_ICON_WIFI, sizeof(icon_path)); + } else if (wifi_count == 0 && bt_count > 0 && usb_count == 0) { + g_strlcpy(icon_path, MH_NOTI_ICON_BT, sizeof(icon_path)); + } else if (wifi_count == 0 && bt_count == 0 && usb_count > 0) { + g_strlcpy(icon_path, MH_NOTI_ICON_USB, sizeof(icon_path)); + } else if (wifi_count == 0 && bt_count == 0 && usb_count == 0) { + return; + } else { + g_strlcpy(icon_path, MH_NOTI_ICON_GENERAL, sizeof(icon_path)); + } + if (prev_cnt == 0) { - DBG("Create notification\n"); - _create_connected_noti(str, MH_NOTI_TITLE, MH_NOTI_ICON_PATH); + _create_connected_noti(count, icon_path); } else { - DBG("Update notification\n"); - _update_connected_noti(str); + _update_connected_noti(count, icon_path); } prev_cnt = count; @@ -167,18 +190,26 @@ int _add_station_info(mobile_ap_station_info_t *info) 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; + if (!si) { + return MOBILE_AP_ERROR_INTERNAL; + } + + if (g_strcmp0(si->hostname, info->hostname) == 0 && + g_strcmp0(si->ip, info->ip) == 0) { + return MOBILE_AP_ERROR_INTERNAL; + } + + _remove_station_info(si->mac, _slist_find_station_by_mac); } 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); + SDBG("[%d] interface : %d\n", i, si->interface); + SDBG("[%d] station MAC : %s\n", i, si->mac); + SDBG("[%d] station Hostname : %s\n", i, si->hostname); + SDBG("[%d] station IP : %s\n", i, si->ip); + SDBG("[%d] station connected time : %d\n", i, si->tm); i++; } @@ -211,9 +242,10 @@ int _remove_station_info(gconstpointer data, GCompareFunc func) } si = (mobile_ap_station_info_t *)l->data; - DBG("Remove station MAC : %s\n", si->mac); + SDBG("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->hostname); g_free(si); count = g_slist_length(station_list); @@ -233,16 +265,18 @@ int _remove_station_info_all(mobile_ap_type_e type) mobile_ap_station_info_t *si = NULL; int count; + _flush_dhcp_ack_timer(); + 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); + SDBG("Remove station MAC : %s\n", si->mac); _send_dbus_station_info("DhcpLeaseDeleted", si); + g_free(si->hostname); g_free(si); temp_l = l; @@ -279,7 +313,7 @@ int _get_station_info(gconstpointer data, GCompareFunc func, } node = l->data; - DBG("Found station : %s\n", node->mac); + SDBG("Found station : %s\n", node->mac); *si = node; return MOBILE_AP_ERROR_NONE; @@ -302,7 +336,6 @@ int _get_station_count(gconstpointer data, GCompareFunc func, int *count) } *count = _count; - DBG("Station count : %d\n", *count); return MOBILE_AP_ERROR_NONE; } @@ -319,115 +352,115 @@ int _station_info_foreach(GFunc func, void *user_data) return MOBILE_AP_ERROR_NONE; } -int _add_data_usage_rule(const char *src, const char *dest) +int _add_interface_routing(const char *interface, const in_addr_t gateway) { - if (src == NULL || src[0] == '\0' || - dest == NULL || dest[0] == '\0' || - g_strcmp0(src, dest) == 0) { + if (interface == NULL || interface[0] == '\0') { ERR("Invalid parameter\n"); return MOBILE_AP_ERROR_INVALID_PARAM; } char cmd[MAX_BUF_SIZE] = {0, }; + struct in_addr addr; + char *interface_gw; + in_addr_t subnet; - 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; - } + addr.s_addr = htonl(gateway); + + subnet = inet_netof(addr); + addr = inet_makeaddr(subnet, 0); + interface_gw = inet_ntoa(addr); - snprintf(cmd, sizeof(cmd), "%s -A FORWARD "FORWARD_RULE, - IPTABLES, dest, src); - DBG("ADD IPTABLES RULE : %s\n", cmd); + snprintf(cmd, sizeof(cmd), "%s route add "INTERFACE_ROUTING, + IP_CMD, interface_gw, TETHERING_ROUTING_TABLE, interface); if (_execute_command(cmd)) { - ERR("iptables failed : %s\n", cmd); + ERR("cmd 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) +int _del_interface_routing(const char *interface, const in_addr_t gateway) { - if (src == NULL || src[0] == '\0' || - dest == NULL || dest[0] == '\0' || - g_strcmp0(src, dest) == 0) { + if (interface == NULL || interface[0] == '\0') { ERR("Invalid parameter\n"); return MOBILE_AP_ERROR_INVALID_PARAM; } char cmd[MAX_BUF_SIZE] = {0, }; + struct in_addr addr; + char *interface_gw; + in_addr_t subnet; - 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; - } + addr.s_addr = htonl(gateway); + + subnet = inet_netof(addr); + addr = inet_makeaddr(subnet, 0); + interface_gw = inet_ntoa(addr); - snprintf(cmd, sizeof(cmd), "%s -D FORWARD "FORWARD_RULE, - IPTABLES, dest, src); - DBG("REMOVE IPTABLES RULE : %s\n", cmd); + snprintf(cmd, sizeof(cmd), "%s route del "INTERFACE_ROUTING, + IP_CMD, interface_gw, TETHERING_ROUTING_TABLE, interface); if (_execute_command(cmd)) { - ERR("iptables failed : %s\n", cmd); + ERR("cmd 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) +int _add_routing_rule(const char *interface) { - if (src == NULL || src[0] == '\0' || - dest == NULL || dest[0] == '\0' || - tx == NULL || rx == NULL) { + if (interface == NULL || interface[0] == '\0') { 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"); + snprintf(cmd, sizeof(cmd), "%s rule add "SRC_ROUTING_RULE, + IP_CMD, interface, TETHERING_ROUTING_TABLE); + if (_execute_command(cmd)) { + ERR("cmd failed : %s\n", cmd); + return MOBILE_AP_ERROR_INTERNAL; } - /* 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"); + return MOBILE_AP_ERROR_NONE; +} + +int _del_routing_rule(const char *interface) +{ + if (interface == NULL || interface[0] == '\0') { + ERR("Invalid parameter\n"); + return MOBILE_AP_ERROR_INVALID_PARAM; } - fp = fopen(DATA_USAGE_FILE, "r"); - if (fp == NULL) { - ERR("%s open failed\n", DATA_USAGE_FILE); - ERR("%s\n", strerror(errno)); + char cmd[MAX_BUF_SIZE] = {0, }; + + snprintf(cmd, sizeof(cmd), "%s rule del "SRC_ROUTING_RULE, + IP_CMD, interface, TETHERING_ROUTING_TABLE); + if (_execute_command(cmd)) { + ERR("cmd failed : %s\n", cmd); return MOBILE_AP_ERROR_INTERNAL; } - if (fgets(buf, sizeof(buf), fp) == NULL) - *tx = 0LL; - else - *tx = atoll(buf); + return MOBILE_AP_ERROR_NONE; +} + +int _flush_ip_address(const char *interface) +{ + if (interface == NULL || interface[0] == '\0') { + ERR("Invalid parameter\n"); + return MOBILE_AP_ERROR_INVALID_PARAM; + } - if (fgets(buf, sizeof(buf), fp) == NULL) - *rx = 0LL; - else - *rx = atoll(buf); + char cmd[MAX_BUF_SIZE] = {0, }; - fclose(fp); - unlink(DATA_USAGE_FILE); + snprintf(cmd, sizeof(cmd), "%s addr flush dev %s", + IP_CMD, interface); + if (_execute_command(cmd)) { + ERR("cmd failed : %s\n", cmd); + return MOBILE_AP_ERROR_INTERNAL; + } return MOBILE_AP_ERROR_NONE; } @@ -444,7 +477,7 @@ int _execute_command(const char *cmd) pid_t pid = 0; gchar **args = NULL; - DBG("cmd : %s\n", cmd); + SDBG("CMD : %s\n", cmd); args = g_strsplit_set(cmd, " ", -1); if (!args) { @@ -465,8 +498,6 @@ int _execute_command(const char *cmd) 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); @@ -477,7 +508,6 @@ int _execute_command(const char *cmd) 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"); @@ -503,7 +533,7 @@ int _get_tethering_type_from_ip(const char *ip, mobile_ap_type_e *type) in_addr_t subnet; if (inet_aton(ip, &addr) == 0) { - ERR("Address : %s is invalid\n", ip); + SERR("Address : %s is invalid\n", ip); return MOBILE_AP_ERROR_INVALID_PARAM; } subnet = inet_netof(addr); @@ -524,7 +554,10 @@ int _get_tethering_type_from_ip(const char *ip, mobile_ap_type_e *type) } if (subnet == subnet_wifi) { - *type = MOBILE_AP_TYPE_WIFI; + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) + *type = MOBILE_AP_TYPE_WIFI; + else + *type = MOBILE_AP_TYPE_WIFI_AP; return MOBILE_AP_ERROR_NONE; } else if (subnet >= subnet_bt_min && subnet <= subnet_bt_max) { *type = MOBILE_AP_TYPE_BT; @@ -534,6 +567,7 @@ int _get_tethering_type_from_ip(const char *ip, mobile_ap_type_e *type) return MOBILE_AP_ERROR_NONE; } - ERR("Tethering type cannot be decided from %s\n", ip); + SERR("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 index c48e676..89915c1 100644 --- a/src/mobileap_handler.c +++ b/src/mobileap_handler.c @@ -19,17 +19,21 @@ #include #include #include +#include -#include "mobileap_agent.h" +#include "mobileap_softap.h" #include "mobileap_common.h" #include "mobileap_bluetooth.h" #include "mobileap_wifi.h" #include "mobileap_usb.h" #include "mobileap_notification.h" +#include "mobileap_handler.h" +#define VCONF_IS_DEVICE_RENAMED_IN_UG "file/private/libug-setting-mobileap-efl/is_device_rename_local" typedef struct { - guint src_id; + alarm_id_t alarm_id; + time_t end_time; GSourceFunc func; void *user_data; } sp_timeout_handler_t; @@ -38,13 +42,12 @@ 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}}; + {0, 0, __wifi_timeout_cb, NULL}, + {0, 0, NULL, NULL}, + {0, 0, __bt_timeout_cb, NULL}, + {0, 0, NULL, NULL}}; - - -static void __handle_flight_mode_changed_cb(keynode_t *key, void *data) +static void __handle_network_cellular_state_changed_cb(keynode_t *key, void *data) { if (key == NULL) { ERR("Parameter is NULL\n"); @@ -54,25 +57,29 @@ static void __handle_flight_mode_changed_cb(keynode_t *key, void *data) TetheringObject *obj = (TetheringObject *)data; int vconf_key = 0; - if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) { - DBG("Wi-Fi tethering is not enabled\n"); + if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI | MOBILE_AP_STATE_WIFI_AP)) { return; } - if (vconf_keynode_get_type(key) != VCONF_TYPE_BOOL) { + if (vconf_keynode_get_type(key) != VCONF_TYPE_INT) { ERR("Invalid vconf key type\n"); return; } - vconf_key = vconf_keynode_get_bool(key); - DBG("key = %s, value = %d(bool)\n", + vconf_key = vconf_keynode_get_int(key); + SDBG("key = %s, value = %d(int)\n", vconf_keynode_get_name(key), vconf_key); - if (vconf_key == FALSE) + if (vconf_key != VCONFKEY_NETWORK_CELLULAR_FLIGHT_MODE) return; - DBG("Flight mode\n"); - _disable_wifi_tethering(obj); + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) + _disable_wifi_tethering(obj); + else if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) + _disable_wifi_ap(obj); + if (_mobileap_is_enabled(MOBILE_AP_STATE_USB)) + _disable_usb_tethering(obj); + _emit_mobileap_dbus_signal(obj, E_SIGNAL_FLIGHT_MODE, NULL); return; @@ -87,9 +94,10 @@ static void __handle_device_name_changed_cb(keynode_t *key, void *data) TetheringObject *obj = (TetheringObject *)data; char *vconf_key = NULL; + softap_settings_t new_settings; + softap_security_type_e sec_type; - if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) { - DBG("Wi-Fi hotspot is not enabled\n"); + if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI | MOBILE_AP_STATE_WIFI_AP)) { return; } @@ -97,21 +105,71 @@ static void __handle_device_name_changed_cb(keynode_t *key, void *data) 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); + if (g_strcmp0(vconf_key, obj->softap_settings.ssid) != 0) { + DBG("Device name is changed\n"); + new_settings = obj->softap_settings; + if (!g_strcmp0(new_settings.security_type, SOFTAP_SECURITY_TYPE_WPA2_PSK_STR)) { + sec_type = SOFTAP_SECURITY_TYPE_WPA2_PSK; + } else { + sec_type = SOFTAP_SECURITY_TYPE_OPEN; + } + g_strlcpy(new_settings.ssid, vconf_key, sizeof(new_settings.ssid)); + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) { + _reload_softap_settings(obj, new_settings.ssid, new_settings.key, + new_settings.hide_mode, sec_type); + } else if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) { + _reload_softap_settings_for_ap(obj, new_settings.ssid, new_settings.key, + new_settings.hide_mode, sec_type); + } + } + return; +} + +static void __handle_language_changed_cb(keynode_t *key, void *data) +{ + if (key == NULL || data == NULL) { + ERR("Parameter is NULL\n"); + return; + } + + char *language = NULL; + + if (vconf_keynode_get_type(key) != VCONF_TYPE_STRING) { + ERR("Invalid vconf key type\n"); + return; + } + + language = vconf_get_str(VCONFKEY_LANGSET); + if (language) { + setenv("LANG", language, 1); + setenv("LC_MESSAGES", language, 1); + setlocale(LC_ALL, language); + free(language); } return; } +gboolean _is_power_save_survival_mode(void) +{ + int ret; + int status; + + ret = vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &status); + if (ret != 0) { + ERR("vconf_get_int is failed : %d\n", ret); + return FALSE; + } + + DBG(" PS mode status : %d", status); + if (status == SETTING_PSMODE_SURVIVAL) + return TRUE; + else + return FALSE; +} + void _register_vconf_cb(void *user_data) { if (user_data == NULL) { @@ -120,10 +178,12 @@ void _register_vconf_cb(void *user_data) } vconf_reg_t vconf_reg[] = { - {VCONFKEY_TELEPHONY_FLIGHT_MODE, - __handle_flight_mode_changed_cb, NULL}, + {VCONFKEY_NETWORK_CELLULAR_STATE, + __handle_network_cellular_state_changed_cb, NULL}, {VCONFKEY_SETAPPL_DEVICE_NAME_STR, __handle_device_name_changed_cb, NULL}, + {VCONFKEY_LANGSET, + __handle_language_changed_cb, NULL}, {NULL, NULL, NULL} }; @@ -131,7 +191,6 @@ void _register_vconf_cb(void *user_data) 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) { @@ -160,10 +219,12 @@ void _unregister_vconf_cb(void *user_data) } vconf_reg_t vconf_reg[] = { - {VCONFKEY_TELEPHONY_FLIGHT_MODE, - __handle_flight_mode_changed_cb, NULL}, + {VCONFKEY_NETWORK_CELLULAR_STATE, + __handle_network_cellular_state_changed_cb, NULL}, {VCONFKEY_SETAPPL_DEVICE_NAME_STR, __handle_device_name_changed_cb, NULL}, + {VCONFKEY_LANGSET, + __handle_language_changed_cb, NULL}, {NULL, NULL, NULL} }; @@ -171,7 +232,6 @@ void _unregister_vconf_cb(void *user_data) 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) { @@ -203,9 +263,6 @@ static gboolean __wifi_timeout_cb(gpointer data) _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; } @@ -229,17 +286,100 @@ static gboolean __bt_timeout_cb(gpointer data) _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; } +static sp_timeout_handler_t *__find_next_timeout(void) +{ + sp_timeout_handler_t *next_timeout = &sp_timeout_handler[MOBILE_AP_TYPE_WIFI]; + mobile_ap_type_e i; + + for (i = MOBILE_AP_TYPE_USB; i < MOBILE_AP_TYPE_MAX; i++) { + if (sp_timeout_handler[i].end_time == 0) + continue; + + if (sp_timeout_handler[i].end_time < next_timeout->end_time || + next_timeout->end_time == 0) + next_timeout = &sp_timeout_handler[i]; + } + + return next_timeout; +} + +static void __expire_timeout(sp_timeout_handler_t *sp) +{ + if (sp->alarm_id > 0) { + alarmmgr_remove_alarm(sp->alarm_id); + sp->alarm_id = 0; + } + + sp->end_time = 0; + + if (sp->func) + sp->func(sp->user_data); +} + +static void __reset_timeout(sp_timeout_handler_t *sp) +{ + if (sp->alarm_id > 0) { + alarmmgr_remove_alarm(sp->alarm_id); + sp->alarm_id = 0; + } + + sp->end_time = 0; +} + +int _sp_timeout_handler(alarm_id_t alarm_id, void *user_param) +{ + DBG("+\n"); + + int ret; + time_t now; + time_t interval; + mobile_ap_type_e i; + sp_timeout_handler_t *next_timeout; + + now = time(NULL); + for (i = MOBILE_AP_TYPE_WIFI; i < MOBILE_AP_TYPE_MAX; i++) { + if (sp_timeout_handler[i].end_time == 0) + continue; + + if (sp_timeout_handler[i].alarm_id == alarm_id) { + sp_timeout_handler[i].alarm_id = 0; + __expire_timeout(&sp_timeout_handler[i]); + continue; + } + + interval = (time_t)difftime(sp_timeout_handler[i].end_time, now); + if (interval > 0) + continue; + + __expire_timeout(&sp_timeout_handler[i]); + } + + next_timeout = __find_next_timeout(); + if (next_timeout->end_time == 0) + return 0; + + interval = (time_t)difftime(next_timeout->end_time, now); + ret = alarmmgr_add_alarm(ALARM_TYPE_VOLATILE, interval, 0, NULL, + &next_timeout->alarm_id); + if (ret != ALARMMGR_RESULT_SUCCESS) { + ERR("alarmmgr_add_alarm is failed. end_time : %d\n", + next_timeout->end_time); + return 0; + } + + DBG("-\n"); + return 0; +} + 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; } @@ -248,54 +388,103 @@ void _init_timeout_cb(mobile_ap_type_e type, void *user_data) 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].alarm_id = 0; + sp_timeout_handler[type].end_time = 0; sp_timeout_handler[type].user_data = user_data; DBG("-\n"); return; } -void _start_timeout_cb(mobile_ap_type_e type) +void _start_timeout_cb(mobile_ap_type_e type, time_t end_time) { - DBG("+\n"); + int ret; + time_t interval; + mobile_ap_type_e i; + sp_timeout_handler_t *next_timeout; + 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"); + __reset_timeout(&sp_timeout_handler[type]); + sp_timeout_handler[type].end_time = end_time; + + next_timeout = __find_next_timeout(); + if (next_timeout->alarm_id > 0) { return; } - sp_timeout_handler[type].src_id = g_timeout_add(TETHERING_CONN_TIMEOUT, - sp_timeout_handler[type].func, - sp_timeout_handler[type].user_data); + for (i = MOBILE_AP_TYPE_WIFI; i < MOBILE_AP_TYPE_MAX; i++) { + if (sp_timeout_handler[i].alarm_id == 0) + continue; + + __reset_timeout(&sp_timeout_handler[i]); + } + + interval = (time_t)difftime(next_timeout->end_time, time(NULL)); + if (interval <= 0) { + __expire_timeout(next_timeout); + return; + } + + ret = alarmmgr_add_alarm(ALARM_TYPE_VOLATILE, interval, 0, NULL, + &next_timeout->alarm_id); + if (ret != ALARMMGR_RESULT_SUCCESS) { + ERR("alarmmgr_add_alarm is failed. type : %d, end_time : %d\n", + type, end_time); + return; + } - DBG("-\n"); return; } void _stop_timeout_cb(mobile_ap_type_e type) { DBG("+\n"); + + int ret; + time_t interval; + mobile_ap_type_e i; + sp_timeout_handler_t *next_timeout; + 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"); + if (sp_timeout_handler[type].alarm_id == 0) { + sp_timeout_handler[type].end_time = 0; return; } - g_source_remove(sp_timeout_handler[type].src_id); - sp_timeout_handler[type].src_id = 0; + for (i = MOBILE_AP_TYPE_WIFI; i < MOBILE_AP_TYPE_MAX; i++) { + if (sp_timeout_handler[i].end_time != sp_timeout_handler[type].end_time || + type == i) + continue; + + sp_timeout_handler[i].alarm_id = sp_timeout_handler[type].alarm_id; + sp_timeout_handler[type].alarm_id = 0; + sp_timeout_handler[type].end_time = 0; + return; + } + __reset_timeout(&sp_timeout_handler[type]); + + next_timeout = __find_next_timeout(); + if (next_timeout->end_time == 0) + return; + + interval = (time_t)difftime(next_timeout->end_time, time(NULL)); + if (interval <= 0) { + __expire_timeout(next_timeout); + return; + } + + ret = alarmmgr_add_alarm(ALARM_TYPE_VOLATILE, interval, 0, NULL, + &next_timeout->alarm_id); + if (ret != ALARMMGR_RESULT_SUCCESS) { + ERR("alarmmgr_add_alarm is failed. type : %d, end_time : %d\n", + type, next_timeout->end_time); + } DBG("-\n"); return; @@ -303,19 +492,18 @@ void _stop_timeout_cb(mobile_ap_type_e type) 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; + if (sp_timeout_handler[type].alarm_id > 0) { + _stop_timeout_cb(type); } sp_timeout_handler[type].user_data = NULL; + sp_timeout_handler[type].end_time = 0; DBG("-\n"); return; } - diff --git a/src/mobileap_iptables.c b/src/mobileap_iptables.c new file mode 100755 index 0000000..429cbf2 --- /dev/null +++ b/src/mobileap_iptables.c @@ -0,0 +1,329 @@ +/* + * 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 "mobileap_iptables.h" +#include "mobileap_softap.h" +#include "mobileap.h" +#include "mobileap_common.h" + +#define CREATE_CHAIN_STR "-t %s -N %s" /* table_name, chain_name */ +#define REDIRECTION_ADD_RULE_STR "-t %s -A %s -j %s" +#define REDIRECTION_DEL_RULE_STR "-t %s -D %s -j %s" +#define FLUSH_CMD_STR "-t %s -F %s" +#define DELETE_CHAIN_STR "-t %s -X %s" +#define FORWARD_RULE_WITH_ACTION_STR "-t %s -A %s -i %s -o %s -j %s" +#define FORWARD_RULE_WITH_ACTION_AND_STATE_STR "-t %s -A %s -i %s -o %s -m state --state %s -j %s" +#define MASQUERADE_RULE_STR "-t %s -A %s -o %s -j MASQUERADE" +#define PORT_FORWARD_RULE_STR "-t %s -A %s -i %s -p %s -d %s --dport %d -j DNAT --to %s:%d" +#define CLAMP_MSS_RULE_STR "-t %s -A %s -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu" +#define DEFAULT_RULE_STR "-t %s -A %s -j %s" + + +int _iptables_create_chain(const char *table_name, const char *chain_name) +{ + char cmd[MAX_BUF_SIZE] = { 0, }; + + snprintf(cmd, sizeof(cmd), "%s "CREATE_CHAIN_STR, IPTABLES, table_name, + chain_name); + SDBG("command [%s]\n", cmd); + if (_execute_command(cmd)) { + SERR("command [%s] failed\n", cmd); + return MOBILE_AP_ERROR_INTERNAL; + } + + return MOBILE_AP_ERROR_NONE; +} + +int _iptables_flush_rules(const char *table_name, const char *chain_name) +{ + char cmd[MAX_BUF_SIZE] = { 0, }; + + snprintf(cmd, sizeof(cmd), "%s "FLUSH_CMD_STR, IPTABLES, table_name, + chain_name); + SDBG("command [%s]\n", cmd); + if (_execute_command(cmd)) { + SERR("command [%s] failed\n", cmd); + return MOBILE_AP_ERROR_INTERNAL; + } + + return MOBILE_AP_ERROR_NONE; +} + +int _iptables_delete_chain(const char *table_name, const char *chain_name) +{ + char cmd[MAX_BUF_SIZE] = { 0, }; + + snprintf(cmd, sizeof(cmd), "%s "DELETE_CHAIN_STR, IPTABLES, table_name, + chain_name); + SDBG("command [%s]\n", cmd); + if (_execute_command(cmd)) { + SERR("command [%s] failed\n", cmd); + return MOBILE_AP_ERROR_INTERNAL; + } + + return MOBILE_AP_ERROR_NONE; +} + +int _iptables_add_rule(iptables_rule_e rule_type, const char *table, const char *chain, ...) +{ + if (table == NULL || chain == NULL) { + ERR("invalid parameters\n"); + return MOBILE_AP_ERROR_INVALID_PARAM; + } + + va_list ap; + char cmd[MAX_BUF_SIZE] = { 0, }; + + va_start(ap, chain); + switch (rule_type) { + case PKT_REDIRECTION_RULE: { + char *dst_chain; + + dst_chain = va_arg(ap, char *); + if (dst_chain == NULL) { + ERR("invalid parameters\n"); + goto ERROR_EXIT; + } + + snprintf(cmd, sizeof(cmd), "%s "REDIRECTION_ADD_RULE_STR, IPTABLES, + table, chain, dst_chain); + break; + } + + case FORWARD_RULE_WITH_ACTION: { + char *in_iface = NULL; + char *out_iface = NULL; + char *action = NULL; + + in_iface = va_arg(ap, char *); + out_iface = va_arg(ap, char *); + action = va_arg(ap, char *); + + if (in_iface == NULL || out_iface == NULL || action == NULL) { + ERR("invalid parameters\n"); + goto ERROR_EXIT; + } + + snprintf(cmd, sizeof(cmd), "%s "FORWARD_RULE_WITH_ACTION_STR, IPTABLES, + table, chain, in_iface, out_iface, action); + break; + } + + case FORWARD_RULE_WITH_ACTION_AND_STATE: { + char *in_iface = NULL; + char *out_iface = NULL; + char *action = NULL; + char *state = NULL; + + in_iface = va_arg(ap, char *); + out_iface = va_arg(ap, char *); + action = va_arg(ap, char *); + state = va_arg(ap, char *); + + if (in_iface == NULL || out_iface == NULL || action == NULL || + state == NULL) { + ERR("invalid parameters\n"); + goto ERROR_EXIT; + } + + snprintf(cmd, sizeof(cmd), "%s "FORWARD_RULE_WITH_ACTION_AND_STATE_STR, + IPTABLES, table, chain, in_iface, out_iface, state, action); + + break; + } + + case PORT_FW_RULE: { + char *ip_iface = NULL; + char *proto = NULL; + char *org_ip = NULL; + char *final_ip = NULL; + unsigned short org_port = 0; + unsigned short final_port = 0; + + ip_iface = va_arg(ap, char *); + proto = va_arg(ap, char *); + org_ip = va_arg(ap, char *); + final_ip = va_arg(ap, char *); + org_port = va_arg(ap, int); + final_port = va_arg(ap, int); + + if (ip_iface == NULL || proto == NULL || org_ip == NULL || + final_ip == NULL) { + ERR("invalid parameters\n"); + goto ERROR_EXIT; + } + + snprintf(cmd, sizeof(cmd), "%s "PORT_FORWARD_RULE_STR, + IPTABLES, table, chain, ip_iface, proto, + org_ip, org_port, final_ip, final_port); + break; + } + + case MASQ_RULE: { + char *ext_iface = NULL; + + ext_iface = va_arg(ap, char *); + + if (ext_iface == NULL) { + ERR("invalid parameters\n"); + goto ERROR_EXIT; + } + + snprintf(cmd, sizeof(cmd), "%s "MASQUERADE_RULE_STR, IPTABLES, + table, chain, ext_iface); + break; + } + + case CLAMP_MSS_RULE: { + snprintf(cmd, sizeof(cmd), "%s "CLAMP_MSS_RULE_STR, IPTABLES, + table, chain); + break; + } + + case DEFAULT_RULE: { + char *action; + + action = va_arg(ap, char *); + + if (action == NULL) { + ERR("invalid parameters\n"); + goto ERROR_EXIT; + } + + snprintf(cmd, sizeof(cmd), "%s "DEFAULT_RULE_STR, IPTABLES, + table, chain, action); + break; + } + + default: + ERR("case not supported\n"); + goto ERROR_EXIT; + } + + if (_execute_command(cmd)) { + SERR("command [%s] failed\n", cmd); + goto ERROR_EXIT; + } + + va_end(ap); + return MOBILE_AP_ERROR_NONE; + +ERROR_EXIT: + va_end(ap); + return MOBILE_AP_ERROR_INVALID_PARAM; +} + +int _iptables_delete_rule(iptables_rule_e rule_type, const char *table, const char *chain, ...) +{ + va_list ap; + char cmd[MAX_BUF_SIZE] = { 0, }; + + va_start(ap, chain); + switch (rule_type) { + case PKT_REDIRECTION_RULE: { + char *dst_chain = NULL; + + dst_chain = va_arg(ap, char *); + snprintf(cmd, sizeof(cmd), "%s "REDIRECTION_DEL_RULE_STR, IPTABLES, + table, chain, dst_chain); + break; + } + default: + ERR("case not supported\n"); + goto ERROR_EXIT; + } + + if (_execute_command(cmd)) { + SERR("command [%s] failed\n", cmd); + return MOBILE_AP_ERROR_INTERNAL; + } + va_end(ap); + return MOBILE_AP_ERROR_NONE; + +ERROR_EXIT: + va_end(ap); + return MOBILE_AP_ERROR_INTERNAL; +} + +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 -t %s -L %s -vx | %s -v DROP | %s \"%s[ ]*%s\" | %s '{ print $2 }' > %s", + IPTABLES, TABLE_FILTER, TETH_FILTER_FW, GREP, GREP, src, dest, AWK, DATA_USAGE_FILE); + if (system(cmd) < 0) { + ERR("cmd %s is failed\n", cmd); + } + + *tx = 0; + + 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; + } + + while (fgets(buf, sizeof(buf), fp) != NULL) { + *tx += atoll(buf); + } + + fclose(fp); + unlink(DATA_USAGE_FILE); + + /* Rx : Dest. -> Src. */ + snprintf(cmd, sizeof(cmd), + "%s -t %s -L %s -vx | %s -v DROP | %s \"%s[ ]*%s\" | %s '{ print $2 }' > %s", + IPTABLES, TABLE_FILTER, TETH_FILTER_FW, GREP, GREP, dest, src, AWK, DATA_USAGE_FILE); + if (system(cmd) < 0) { + ERR("cmd %s is failed\n", cmd); + } + + *rx = 0; + + 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; + } + + while (fgets(buf, sizeof(buf), fp) != NULL) { + *rx += atoll(buf); + } + + fclose(fp); + unlink(DATA_USAGE_FILE); + + return MOBILE_AP_ERROR_NONE; +} diff --git a/src/mobileap_main.c b/src/mobileap_main.c index 421e8f7..c906bb4 100644 --- a/src/mobileap_main.c +++ b/src/mobileap_main.c @@ -24,12 +24,15 @@ #include #include #include -#include +#include +#include #include #include #include +#include +#include -#include "mobileap_agent.h" +#include "mobileap_softap.h" #include "mobileap_handler.h" #include "mobileap_common.h" #include "mobileap_bluetooth.h" @@ -37,6 +40,7 @@ #include "mobileap_usb.h" #include "mobileap_network.h" #include "mobileap_notification.h" +#include "mobileap_iptables.h" GType tethering_object_get_type(void); #define TETHERING_TYPE_OBJECT (tethering_object_get_type()) @@ -46,32 +50,21 @@ 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; + obj->init_count = 0; + memset(&obj->softap_settings, 0x00, sizeof(obj->softap_settings)); } static void tethering_object_finalize(GObject *obj) @@ -94,9 +87,12 @@ static void tethering_object_class_init(TetheringObjectClass *klass) SIGNAL_NAME_USB_TETHER_OFF, SIGNAL_NAME_BT_TETHER_ON, SIGNAL_NAME_BT_TETHER_OFF, + SIGNAL_NAME_WIFI_AP_ON, + SIGNAL_NAME_WIFI_AP_OFF, SIGNAL_NAME_NO_DATA_TIMEOUT, SIGNAL_NAME_LOW_BATTERY_MODE, SIGNAL_NAME_FLIGHT_MODE, + SIGNAL_NAME_POWER_SAVE_MODE, SIGNAL_NAME_SECURITY_TYPE_CHANGED, SIGNAL_NAME_SSID_VISIBILITY_CHANGED, SIGNAL_NAME_PASSPHRASE_CHANGED @@ -146,9 +142,7 @@ 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) { @@ -187,6 +181,11 @@ gboolean _mobileap_is_enabled_by_type(mobile_ap_type_e type) return TRUE; break; + case MOBILE_AP_TYPE_WIFI_AP: + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) + return TRUE; + break; + default: ERR("Unknow type : %d\n", type); break; @@ -199,9 +198,7 @@ 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) { @@ -212,58 +209,94 @@ gboolean _mobileap_clear_state(int state) return TRUE; } -static void __block_device_sleep(void) +gboolean _terminate_mobileap_agent(gpointer user_data) +{ + if (mainloop == NULL) { + return FALSE; + } + + if (!_mobileap_is_disabled()) { + DBG("Tethering is enabled\n"); + return FALSE; + } + + if (_is_trying_network_operation()) { + DBG("Network operation is going on\n"); + return FALSE; + } + + if (_is_trying_wifi_operation()) { + DBG("Wi-Fi operation is going on\n"); + return FALSE; + } + + if (_is_trying_bt_operation()) { + DBG("BT operation is going on\n"); + return FALSE; + } + + if (_is_trying_usb_operation()) { + DBG("USB operation is going on\n"); + return FALSE; + } + + DBG("All tethering / AP's are turned off\n"); + g_main_loop_quit(mainloop); + mainloop = NULL; + + return FALSE; +} + +void _block_device_sleep(void) { int ret = 0; - ret = pm_lock_state(LCD_OFF, STAY_CUR_STATE, 0); + ret = display_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) +void _unblock_device_sleep(void) { int ret = 0; - ret = pm_unlock_state(LCD_OFF, PM_SLEEP_MARGIN); + ret = display_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) +int _init_tethering(TetheringObject *obj) { + int ret = MOBILE_AP_ERROR_NONE; + 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; + return MOBILE_AP_ERROR_NONE; } - obj->init_count++; - - __block_device_sleep(); - - DBG("Open network\n"); - _open_network(); - - DBG("Run DHCP server\n"); + if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) { + ret = _open_network(); + } _mh_core_execute_dhcp_server(); - return TRUE; + obj->init_count++; + + return ret; } gboolean _deinit_tethering(TetheringObject *obj) { DBG("obj->init_count: %d\n", obj->init_count); + guint idle_id; + if (obj->init_count > 1) { - DBG("Already deinitialized\n"); obj->init_count--; return TRUE; } else if (obj->init_count <= 0) { @@ -274,30 +307,16 @@ gboolean _deinit_tethering(TetheringObject *obj) 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); + if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) { + _close_network(); } - DBG("There are [%d] references\n", ref_agent); + idle_id = g_idle_add(_terminate_mobileap_agent, NULL); + if (idle_id == 0) { + ERR("g_idle_add is failed\n"); + } return TRUE; } @@ -360,7 +379,6 @@ gboolean tethering_get_data_packet_usage(TetheringObject *obj, 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; @@ -388,52 +406,6 @@ gboolean tethering_get_data_packet_usage(TetheringObject *obj, 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) { @@ -465,13 +437,16 @@ static DBusHandlerResult __dnsmasq_signal_filter(DBusConnection *conn, dbus_error_free(&error); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - DBG("DhcpConnected signal : %s %s %s\n", ip_addr, mac, name); + SDBG("DhcpConnected signal : %s %s %s\n", ip_addr, mac, name); + /* + * DHCP ACK received, destroy timeout if exists + */ + _destroy_dhcp_ack_timer(mac); 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; } @@ -484,30 +459,24 @@ static DBusHandlerResult __dnsmasq_signal_filter(DBusConnection *conn, 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 (type == MOBILE_AP_TYPE_WIFI || type == MOBILE_AP_TYPE_USB || + type == MOBILE_AP_TYPE_WIFI_AP) { if (name[0] == '\0') - g_strlcpy(info->hostname, - MOBILE_AP_NAME_UNKNOWN, - sizeof(info->hostname)); + info->hostname = g_strdup(MOBILE_AP_NAME_UNKNOWN); else - g_strlcpy(info->hostname, name, - sizeof(info->hostname)); + info->hostname = g_strdup(name); } 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); - } + info->hostname = g_strdup(MOBILE_AP_NAME_UNKNOWN); + else + info->hostname = bt_remote_device_name; } time(&tm); info->tm = tm; if (_add_station_info(info) != MOBILE_AP_ERROR_NONE) { + g_free(info->hostname); free(info); return DBUS_HANDLER_RESULT_HANDLED; } @@ -531,8 +500,7 @@ static DBusHandlerResult __dnsmasq_signal_filter(DBusConnection *conn, dbus_error_free(&error); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - - DBG("DhcpLeaseDeleted signal : %s %s %s\n", ip_addr, mac, name); + SDBG("DhcpLeaseDeleted signal : %s %s %s\n", ip_addr, mac, name); _remove_station_info(ip_addr, _slist_find_station_by_ip_addr); @@ -544,88 +512,70 @@ static DBusHandlerResult __dnsmasq_signal_filter(DBusConnection *conn, int main(int argc, char **argv) { + const char *rule = "type='signal',interface='"DNSMASQ_DBUS_INTERFACE"'"; + 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; + DBusError dbus_error; GError *error = NULL; - int mobileap_vconf_key = VCONFKEY_MOBILE_HOTSPOT_MODE_NONE; + guint result = 0; + int ret; + + DBG("+\n"); -#if !GLIB_CHECK_VERSION(2,35,0) +#if !GLIB_CHECK_VERSION(2,36,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; + return 0; } + /* D-Bus init */ tethering_bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error); if (error != NULL) { ERR("Couldn't connect to system bus[%s]\n", error->message); + g_error_free(error); 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); + 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); + 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("dbus_g_proxy_call is failed\n"); + if (error) { + ERR("D-Bus.RequestName RPC failed[%s]\n", + error->message); + g_error_free(error); + } 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"); + ERR("Failed to create one Tethering 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); - + tethering_conn = dbus_g_connection_get_connection(tethering_bus); dbus_error_init(&dbus_error); dbus_bus_add_match(tethering_conn, rule, &dbus_error); if (dbus_error_is_set(&dbus_error)) { @@ -633,24 +583,67 @@ int main(int argc, char **argv) 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); + /* Platform modules */ + if (appcore_set_i18n(MOBILEAP_LOCALE_COMMON_PKG, MOBILEAP_LOCALE_COMMON_RES) < 0) { + ERR("appcore_set_i18n is failed\n"); + } + + if (vconf_get_int(VCONFKEY_MOBILE_HOTSPOT_MODE, &mobileap_state) < 0) { + ERR("vconf_get_int is failed\n"); + mobileap_state = MOBILE_AP_STATE_NONE; + } + + _init_network((void *)tethering_obj); + _register_wifi_station_handler(); + _register_vconf_cb((void *)tethering_obj); + + ret = wifi_initialize(); + if (ret != WIFI_ERROR_NONE) { + ERR("wifi_initialize() is failed : %d\n", ret); + } + + ret = alarmmgr_init(APPNAME); + if (ret != ALARMMGR_RESULT_SUCCESS) { + ERR("alarmmgr_init(%s) is failed : %d\n", APPNAME, ret); + } else { + ret = alarmmgr_set_cb(_sp_timeout_handler, NULL); + if (ret != ALARMMGR_RESULT_SUCCESS) { + ERR("alarmmgr_set_cb is failed : %d\n", ret); + } + } + g_main_loop_run(mainloop); + alarmmgr_fini(); + + ret = wifi_deinitialize(); + if (ret != WIFI_ERROR_NONE) { + ERR("wifi_deinitialize() is failed : %d\n", ret); + } + _unregister_vconf_cb((void *)tethering_obj); + _unregister_wifi_station_handler(); _deinit_network(); - failure: - ERR("Terminate the mobileap-agent\n"); + dbus_connection_remove_filter(tethering_conn, __dnsmasq_signal_filter, tethering_obj); + dbus_bus_remove_match(tethering_conn, rule, NULL); - if (tethering_bus) - dbus_g_connection_unref(tethering_bus); - if (tethering_bus_proxy) - g_object_unref(tethering_bus_proxy); + g_object_unref(tethering_obj); + dbus_g_connection_unref(tethering_bus); + + DBG("-\n"); + return 0; + + failure: if (tethering_obj) g_object_unref(tethering_obj); + if (tethering_bus_proxy) + g_object_unref(tethering_bus_proxy); + if (tethering_bus) + dbus_g_connection_unref(tethering_bus); + DBG("-\n"); return 0; } diff --git a/src/mobileap_network.c b/src/mobileap_network.c index 8a65ecb..337faab 100644 --- a/src/mobileap_network.c +++ b/src/mobileap_network.c @@ -16,67 +16,373 @@ */ #include +#include #include +#include +#include #include -#include "mobileap_agent.h" +#include "mobileap_softap.h" #include "mobileap_common.h" #include "mobileap_network.h" +#include "mobileap_wifi.h" +#include "mobileap_bluetooth.h" +#include "mobileap_usb.h" +#include "mobileap_iptables.h" + +typedef enum { + __NO_SERVICE, + __INTERNET, + __TETHERING_ONLY +} tethering_cellular_service_type_e; + +typedef struct { + connection_profile_h handle; + tethering_cellular_service_type_e svc_type; +} tethering_cellular_profile_s; + +#define MH_PORT_FORWARD_CONF_FILEPATH "/tmp/mobileap_agent_port_forward_info" +#define MH_MAX_PORT_FORWARD_RULE_LEN 64 /* interface(10) protocol(10) ip(15):port(5) ip(15):port(5) */ +#define MH_MAX_NO_OF_PORT_FORWARD_RULE 64 + +typedef struct { + char *input_interface; + char *proto; + char *org_dest_ip; + unsigned short org_dest_port; + char *new_dest_ip; + unsigned short new_dest_port; +} port_forward_info_s; + +static TetheringObject *obj = NULL; +static connection_h connection = NULL; +static tethering_cellular_profile_s c_prof = {NULL, __NO_SERVICE}; +static guint net_timeout_id; +static connection_profile_h tethered_prof = NULL; +static GSList *port_forward_info = NULL; -extern int ref_agent; -static connection_h connection = NULL; -static connection_profile_h cprof = NULL; +static gboolean __try_to_open_tethering_profile(gpointer user_data); -static void __print_profile(connection_profile_h profile) +static mobile_ap_error_code_e __get_conn_error(int conn_error) { - if (profile == NULL) - return; + mobile_ap_error_code_e err = MOBILE_AP_ERROR_NONE; + + switch (conn_error) { + case CONNECTION_ERROR_NONE: + err = MOBILE_AP_ERROR_NONE; + break; + + case CONNECTION_ERROR_OUT_OF_MEMORY: + err = MOBILE_AP_ERROR_RESOURCE; + break; + + case CONNECTION_ERROR_INVALID_OPERATION: + err = MOBILE_AP_ERROR_INTERNAL; + break; + + case CONNECTION_ERROR_INVALID_PARAMETER: + err = MOBILE_AP_ERROR_INVALID_PARAM; + break; + + case CONNECTION_ERROR_ALREADY_EXISTS: + err = MOBILE_AP_ERROR_ALREADY_ENABLED; + break; + + case CONNECTION_ERROR_PERMISSION_DENIED: + err = MOBILE_AP_ERROR_PERMISSION_DENIED; + break; + + case CONNECTION_ERROR_DHCP_FAILED: + err = MOBILE_AP_ERROR_DHCP; + break; + + case CONNECTION_ERROR_NOW_IN_PROGRESS: + err = MOBILE_AP_ERROR_IN_PROGRESS; + break; + + default: + ERR("Not defined error : %d\n", conn_error); + err = MOBILE_AP_ERROR_INTERNAL; + break; + } + + return err; +} + +static gboolean __is_valid_ipv4_addr(const char *ip) +{ + int i; + int len; + int dot_count = 0; + int addr; + char tmp_ip[16] = {0, }; + char *p = tmp_ip; + + if (ip == NULL) + return FALSE; + + len = strlen(ip); + if (len > 15 /* 255.255.255.255 */ || len < 7 /* 0.0.0.0 */) + return FALSE; + g_strlcpy(tmp_ip, ip, sizeof(tmp_ip)); + + for (i = 0; i <= len; i++) { + if (tmp_ip[i] == '.') { + if (++dot_count > 3) + return FALSE; + if (&tmp_ip[i] == p) + return FALSE; + tmp_ip[i] = '\0'; + addr = atoi(p); + if (addr < 0 || addr > 255) + return FALSE; + p = &tmp_ip[i + 1]; + } else if (tmp_ip[i] == '\0') { + if (&tmp_ip[i] == p) + return FALSE; + addr = atoi(p); + if (addr < 0 || addr > 255) + return FALSE; + break; + } else if (tmp_ip[i] < '0' || tmp_ip[i] > '9') + return FALSE; + } + + if (dot_count != 3) + return FALSE; + + return TRUE; +} + +static void __clear_port_forward_info(void) +{ + GSList *l; + GSList *temp_l; + port_forward_info_s *pf; + + for (l = port_forward_info; l; ) { + pf = (port_forward_info_s *)l->data; + if (pf) { + g_free(pf->new_dest_ip); + g_free(pf->org_dest_ip); + g_free(pf->proto); + g_free(pf->input_interface); + g_free(pf); + } + + temp_l = l; + l = g_slist_next(l); + port_forward_info = g_slist_delete_link(port_forward_info, temp_l); + } + + return; +} + +static gboolean __read_port_forward_info(const char *conf_file) +{ + if (conf_file == NULL) { + ERR("Invalid parameter\n"); + return FALSE; + } + + DBG("+\n"); + + FILE *fp; + char buf[MH_MAX_PORT_FORWARD_RULE_LEN]; + port_forward_info_s *pf; + int no_of_rule = 0; - int conn_ret; - bool roaming; + __clear_port_forward_info(); + + fp = fopen(conf_file, "r"); + if (fp == NULL) { + ERR("fopen is failed : %s\n", strerror(errno)); + return FALSE; + } + + while (fgets(buf, sizeof(buf), fp)) { + int i; + char *token; + char *saveptr1 = NULL; + char *saveptr2 = NULL; + + char *input_interface; + char *proto; + char *dest_ip[2]; + char *dest_port[2]; + + if (no_of_rule++ >= MH_MAX_NO_OF_PORT_FORWARD_RULE) { + DBG("There are too many rules\n"); + break; + } + + /* "Input interface" "Protocol" "Original destination IP:Port" "New destination IP:Port" */ + /* pdp0 udp 10.90.50.38:23 192.168.43.10:23 */ + + input_interface = strtok_r(buf, " ", &saveptr1); + if (input_interface == NULL) { + SERR("Invalid rule : %s\n", buf); + continue; + } + + proto = strtok_r(NULL, " ", &saveptr1); + if (proto == NULL) { + SERR("Invalid rule : %s\n", buf); + continue; + } + + for (i = 0; i < sizeof(dest_ip) / sizeof(char *); i++) { + token = strtok_r(NULL, " ", &saveptr1); + if (token == NULL) { + SERR("Invalid rule : %s\n", buf); + break; + } + + dest_ip[i] = strtok_r(token, ":", &saveptr2); + if (dest_ip[i] == NULL || + !__is_valid_ipv4_addr(dest_ip[i])) { + SERR("Invalid rule : %s\n", buf); + break; + } + + dest_port[i] = strtok_r(NULL, ":", &saveptr2); + if (dest_port[i] == NULL) { + SERR("Invalid rule : %s\n", buf); + break; + } + } + + if (i < sizeof(dest_ip) / sizeof(char *)) + continue; + + pf = (port_forward_info_s *)malloc(sizeof(port_forward_info_s)); + if (pf == NULL) + break; + + pf->input_interface = g_strdup(input_interface); + pf->proto = g_strdup(proto); + pf->org_dest_ip = g_strdup(dest_ip[0]); + pf->org_dest_port = (unsigned short)atoi(dest_port[0]); + pf->new_dest_ip = g_strdup(dest_ip[1]); + pf->new_dest_port = (unsigned short)atoi(dest_port[1]); + port_forward_info = g_slist_append(port_forward_info, pf); + + SDBG("Port forward rule #%d : %s %s %s:%d %s:%d\n", no_of_rule, + pf->input_interface, pf->proto, + pf->org_dest_ip, pf->org_dest_port, + pf->new_dest_ip, pf->new_dest_port); + } + + fclose(fp); + + return TRUE; +} + +static gboolean __is_valid_port_forward_info(port_forward_info_s *pf) +{ + if (pf == NULL) + return FALSE; + + if (!pf->input_interface || !pf->proto || + !pf->org_dest_ip || !pf->new_dest_ip) + return FALSE; + + if (!strlen(pf->input_interface) || !strlen(pf->proto) || + !strlen(pf->org_dest_ip) || !strlen(pf->new_dest_ip)) + return FALSE; + + return TRUE; +} + +static void __print_cellular_profile(void) +{ + int ret = 0; char *apn = NULL; char *home_url = NULL; - connection_cellular_network_type_e network_type; + bool roaming = false; 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); + if (c_prof.handle == NULL) + return; - 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); + ret = connection_profile_get_cellular_service_type(c_prof.handle, &service_type); + if (ret != CONNECTION_ERROR_NONE) + ERR("connection API fail: 0x%X\n", ret); else - DBG("Service type : %d\n", service_type); + SDBG("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); + ret = connection_profile_get_cellular_apn(c_prof.handle, &apn); + if (ret != CONNECTION_ERROR_NONE) + ERR("connection API fail: 0x%X\n", ret); else { - DBG("APN : %s\n", apn); - free(apn); + SDBG("APN: %s\n", apn); + g_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); + ret = connection_profile_get_cellular_home_url(c_prof.handle, &home_url); + if (ret != CONNECTION_ERROR_NONE) + ERR("connection API fail: 0x%X\n", ret); else { - DBG("Home url : %s\n", home_url); - free(home_url); + SDBG("Home url: %s\n", home_url); + g_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); + ret = connection_profile_is_cellular_roaming(c_prof.handle, &roaming); + if (ret != CONNECTION_ERROR_NONE) + ERR("connection API fail: 0x%X\n", ret); else - DBG("Roaming : %d\n", roaming); + SDBG("Roaming: %d\n", roaming); +} + +static void __handle_open_network_error(void) +{ + int ret = MOBILE_AP_ERROR_NONE; + + if (_mobileap_is_disabled()) { + return; + } + + ret = _disable_wifi_tethering(obj); + DBG("_disable_wifi_tethering returns %d\n", ret); + + ret = _disable_bt_tethering(obj); + DBG("_disable_bt_tethering returns %d\n", ret); + + ret = _disable_usb_tethering(obj); + DBG("_disable_usb_tethering returns %d\n", ret); + + _emit_mobileap_dbus_signal(obj, E_SIGNAL_NET_CLOSED, NULL); return; } +static gboolean __is_equal_profile(connection_profile_h a, connection_profile_h b) +{ + char *a_id = NULL; + char *b_id = NULL; + int ret; + + ret = connection_profile_get_id(a, &a_id); + if (ret != CONNECTION_ERROR_NONE || a_id == NULL) { + ERR("connection_profile_get_id is failed [0x%X]\n", ret); + return FALSE; + } + + ret = connection_profile_get_id(b, &b_id); + if (ret != CONNECTION_ERROR_NONE || b_id == NULL) { + ERR("connection_profile_get_id is failed [0x%X]\n", ret); + g_free(a_id); + return FALSE; + } + + ret = g_strcmp0(a_id, b_id); + g_free(a_id); + g_free(b_id); + + return (ret == 0) ? TRUE : FALSE; +} + static gboolean __is_connected_profile(connection_profile_h profile) { if (profile == NULL) { @@ -84,17 +390,16 @@ static gboolean __is_connected_profile(connection_profile_h profile) return FALSE; } - int conn_ret; + int 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); + ret = connection_profile_get_state(profile, &pstat); + if (ret != CONNECTION_ERROR_NONE) { + ERR("connection_profile_get_state is failed: 0x%X\n", ret); return FALSE; } if (pstat != CONNECTION_PROFILE_STATE_CONNECTED) { - DBG("Profile is not connected\n"); return FALSE; } @@ -102,102 +407,368 @@ static gboolean __is_connected_profile(connection_profile_h 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 disabled\n"); + return; + } + + if (_open_network() != MOBILE_AP_ERROR_NONE) { + ERR("_open_network() is failed\n"); + __handle_open_network_error(); + } + + return; +} + +void __cellular_state_changed_cb(keynode_t *node, void *user_data) +{ + if (node == NULL) { + ERR("Invalid parameter\n"); + return; + } + + if (vconf_keynode_get_type(node) != VCONF_TYPE_INT) { + ERR("Invalid vconf key type\n"); + return; + } + + int ret; + int cellular_state; + connection_type_e net_type; + + cellular_state = vconf_keynode_get_int(node); + SDBG("key = %s, value = %d(int)\n", + vconf_keynode_get_name(node), cellular_state); -static gboolean __get_connected_profile(connection_profile_h *r_prof, connection_profile_type_e *r_net_type) + if (_mobileap_is_disabled()) + return; + + if (cellular_state != VCONFKEY_NETWORK_CELLULAR_ON) + return; + + ret = connection_get_type(connection, &net_type); + if (ret != CONNECTION_ERROR_NONE) { + ERR("connection_get_type is failed [0x%X]\n", ret); + return; + } + + if (net_type != CONNECTION_TYPE_DISCONNECTED && + net_type != CONNECTION_TYPE_CELLULAR) + return; + + if (tethered_prof) + return; + + DBG("VCONFKEY_NETWORK_CELLULAR_ON\n"); + if (_open_network() != MOBILE_AP_ERROR_NONE) { + ERR("_open_network() is failed\n"); + __handle_open_network_error(); + } + + return; +} + +static void __profile_state_changed_cb(connection_profile_state_e state, void *user_data) { - if (r_prof == NULL || r_net_type == NULL) { - ERR("Invalid param [%p] [%p]\n", r_prof, r_net_type); - return FALSE; + if (c_prof.handle == NULL || c_prof.svc_type == __NO_SERVICE) { + ERR("There is no proper profile\n"); + return; } - int conn_ret; - connection_profile_h profile = NULL; - connection_profile_type_e net_type = CONNECTION_PROFILE_TYPE_CELLULAR; + DBG("Tethering cellular profile is %s\n", + state == CONNECTION_PROFILE_STATE_DISCONNECTED ? "Disconnected" : + state == CONNECTION_PROFILE_STATE_ASSOCIATION ? "Associated" : + state == CONNECTION_PROFILE_STATE_CONFIGURATION ? "Configured" : + state == CONNECTION_PROFILE_STATE_CONNECTED ? "Connected" : + "Unknown"); - 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; + int ret; + int cellular_state; + + connection_profile_refresh(c_prof.handle); + + if (_mobileap_is_disabled()) + return; + + if (c_prof.svc_type != __TETHERING_ONLY) + return; + + if (tethered_prof) { + if (!__is_equal_profile(tethered_prof, c_prof.handle)) + return; + connection_profile_refresh(tethered_prof); + } + + if (state != CONNECTION_PROFILE_STATE_DISCONNECTED) + return; + + DBG("Cellular profile is disconnected\n"); + _close_network(); + + ret = vconf_get_int(VCONFKEY_NETWORK_CELLULAR_STATE, &cellular_state); + if (ret < 0) { + ERR("vconf_get_int is failed : %d\n", ret); + if (vconf_ignore_key_changed(VCONFKEY_NETWORK_CELLULAR_STATE, + __cellular_state_changed_cb) < 0) { + ERR("vconf_ignore_key_changed is failed\n"); + } + return; + } + + if (cellular_state != VCONFKEY_NETWORK_CELLULAR_ON) + return; + + if (_open_network() != MOBILE_AP_ERROR_NONE) { + ERR("_open_network() is failed\n"); + __handle_open_network_error(); } - 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); + DBG("-\n"); + return; +} + +static void __update_tethering_cellular_profile(void) +{ + int ret; + connection_profile_h profile; + tethering_cellular_service_type_e svc_type; + + ret = connection_get_default_cellular_service_profile(connection, + CONNECTION_CELLULAR_SERVICE_TYPE_TETHERING, &profile); + if (ret == CONNECTION_ERROR_NONE) { + svc_type = __TETHERING_ONLY; + goto DONE; + } + DBG("There is no tethering profile\n"); + + ret = connection_get_default_cellular_service_profile(connection, + CONNECTION_CELLULAR_SERVICE_TYPE_INTERNET, &profile); + if (ret == CONNECTION_ERROR_NONE) { + svc_type = __INTERNET; + goto DONE; + } + ERR("Getting default connection for internet is failed\n"); + /* To-Do : Need to consider prepaid internet profile */ + + if (c_prof.handle) { + connection_profile_unset_state_changed_cb(c_prof.handle); + connection_profile_destroy(c_prof.handle); + c_prof.handle = NULL; + c_prof.svc_type = __NO_SERVICE; + } + return; + +DONE: + if (c_prof.handle == NULL || + !__is_equal_profile(c_prof.handle, profile)) { + if (c_prof.handle) { + DBG("Tethering cellular profile is updated\n"); + connection_profile_unset_state_changed_cb(c_prof.handle); + connection_profile_destroy(c_prof.handle); + } + + c_prof.handle = profile; + c_prof.svc_type = svc_type; + connection_profile_set_state_changed_cb(c_prof.handle, + __profile_state_changed_cb, NULL); + } else { connection_profile_destroy(profile); - return FALSE; + connection_profile_refresh(c_prof.handle); } - *r_prof = profile; - *r_net_type = net_type; - return TRUE; + return; } -static gboolean __get_network_profile(connection_profile_h *r_prof) +static void __profile_closed_cb(connection_error_e result, void *user_data) { - if (r_prof == NULL) { - ERR("r_prof is NULL\n"); + connection_profile_refresh(c_prof.handle); + + if (result != CONNECTION_ERROR_NONE) { + ERR("Unable to close profile [0x%X]", result); + } else { + DBG("Tethering profile is closed"); + } + + return; +} + +static gboolean __close_tethering_profile(void) +{ + if (c_prof.handle == NULL || c_prof.svc_type == __NO_SERVICE) { + ERR("There is no proper cellular profile\n"); return FALSE; } - connection_profile_h profile; - connection_profile_type_e net_type = CONNECTION_PROFILE_TYPE_CELLULAR; + int ret; + connection_profile_state_e state; + + DBG("+\n"); + + if (net_timeout_id) { + g_source_remove(net_timeout_id); + net_timeout_id = 0; + } + + if (c_prof.svc_type == __INTERNET) { + __profile_closed_cb(CONNECTION_ERROR_NONE, NULL); + return TRUE; + } - if (__get_connected_profile(&profile, &net_type) == FALSE) { - ERR("There is no available network\n"); + ret = connection_profile_get_state(c_prof.handle, &state); + if (ret != CONNECTION_ERROR_NONE) { + ERR("connection_profile_get_state is failed [0x%X]\n", ret); return FALSE; } - DBG("Current connected net_type : %d\n", net_type); - if (net_type == CONNECTION_PROFILE_TYPE_WIFI) { - *r_prof = profile; + if (state == CONNECTION_PROFILE_STATE_DISCONNECTED) { + DBG("Already disconnected profile\n"); return TRUE; } - if (net_type != CONNECTION_PROFILE_TYPE_CELLULAR) { - ERR("Network type [%d] is not supported\n", net_type); + ret = connection_close_profile(connection, c_prof.handle, + __profile_closed_cb, NULL); + if (ret != CONNECTION_ERROR_NONE) { + ERR("Connection close Failed!!\n"); return FALSE; } - __print_profile(profile); - *r_prof = profile; + DBG("-\n"); return TRUE; } -static void __connection_type_changed_cb(connection_type_e type, void *user_data) +static void __profile_opened_cb(connection_error_e result, 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 (c_prof.handle == NULL || c_prof.svc_type == __NO_SERVICE) { + ERR("There is no proper profile\n"); + return; + } + int ret; + connection_type_e net_type; + + DBG("+\n"); + + connection_profile_refresh(c_prof.handle); if (_mobileap_is_disabled()) { - DBG("Tethering is not enabled\n"); + __close_tethering_profile(); return; } - if (_unset_masquerade() == FALSE) { - ERR("_unset_masquerade is failed\n"); + if (result == CONNECTION_ERROR_OPERATION_ABORTED) { + DBG("connection_open_profile is cancelled\n"); + return; } - if (cprof) { - connection_profile_destroy(cprof); - cprof = NULL; + /* Check opened and retry context */ + ret = connection_get_type(connection, &net_type); + if (ret != CONNECTION_ERROR_NONE) { + ERR("connection_get_type is failed\n"); + __close_tethering_profile(); + return; } - if (type == CONNECTION_TYPE_DISCONNECTED) { + if (net_type != CONNECTION_TYPE_DISCONNECTED && + net_type != CONNECTION_TYPE_CELLULAR) { + DBG("Connection type is changed\n"); + __close_tethering_profile(); return; } - _open_network(); + if (tethered_prof) { + connection_profile_refresh(tethered_prof); + return; + } + /* End of check */ + + if (result != CONNECTION_ERROR_ALREADY_EXISTS && + result != CONNECTION_ERROR_NONE) { + DBG("Retry to open profile [0x%X]\n", result); + if (net_timeout_id) { + g_source_remove(net_timeout_id); + net_timeout_id = 0; + } + net_timeout_id = g_timeout_add(TETHERING_NET_OPEN_RETRY_INTERVAL, + __try_to_open_tethering_profile, + NULL); + return; + } + + DBG("Tethering profile is opened"); + + __print_cellular_profile(); + + connection_profile_clone(&tethered_prof, c_prof.handle); + _set_masquerade(); + _add_default_router(); + _add_port_forward_rule(); + + DBG("-\n"); return; } +static gboolean __open_tethering_profile(void) +{ + if (c_prof.handle == NULL || c_prof.svc_type == __NO_SERVICE) { + ERR("There is no proper cellular profile\n"); + return FALSE; + } + + int ret; + + DBG("+\n"); + + if (c_prof.svc_type == __INTERNET) { + return TRUE; + } + + if (__is_connected_profile(c_prof.handle)) { + DBG("Already connected profile\n"); + return TRUE; + } + + ret = connection_open_profile(connection, c_prof.handle, + __profile_opened_cb, NULL); + if (ret != CONNECTION_ERROR_NONE) { + ERR("Unable to open profile [0x%X]", ret); + return FALSE; + } + + DBG("-\n"); + return TRUE; +} + +static gboolean __try_to_open_tethering_profile(gpointer user_data) +{ + DBG("+\n"); + + if (_mobileap_is_disabled()) { + DBG("Tethering is disabled\n"); + net_timeout_id = 0; + return FALSE; + } + + if (__open_tethering_profile() == FALSE) + return TRUE; + + net_timeout_id = 0; + return FALSE; +} + gboolean _is_trying_network_operation(void) { + if (net_timeout_id) + return TRUE; return FALSE; } @@ -209,16 +780,48 @@ gboolean _get_network_interface_name(char **if_name) return FALSE; } - if (cprof == NULL) { - ERR("There is no connected profile\n"); + if (tethered_prof == NULL) { return FALSE; } - int conn_ret = 0; + int 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); + connection_profile_refresh(tethered_prof); + + ret = connection_profile_get_network_interface_name(tethered_prof, if_name); + if (ret != CONNECTION_ERROR_NONE) { + ERR("connection_profile_get_network_interface_name is failed : 0x%X\n", ret); + return FALSE; + } + + if (strlen(*if_name) == 0) { + ERR("if_name is zero length\n"); + free(*if_name); + return FALSE; + } + + return TRUE; +} + +gboolean _get_network_gateway_address(char **ip) +{ + if (ip == NULL) { + ERR("ip is NULL\n"); + return FALSE; + } + + if (tethered_prof == NULL) { + return FALSE; + } + + int ret = 0; + + connection_profile_refresh(tethered_prof); + + ret = connection_profile_get_gateway_address(tethered_prof, + CONNECTION_ADDRESS_FAMILY_IPV4, ip); + if (ret != CONNECTION_ERROR_NONE) { + ERR("connection_profile_get_ip_address is failed : 0x%X\n", ret); return FALSE; } @@ -233,7 +836,7 @@ gboolean _set_masquerade(void) ERR("_get_network_interface_name is failed\n"); return FALSE; } - DBG("Network interface : %s\n", if_name); + SDBG("Network interface : %s\n", if_name); _mh_core_enable_masquerade(if_name); free(if_name); @@ -243,7 +846,7 @@ gboolean _set_masquerade(void) gboolean _unset_masquerade(void) { - if (cprof == NULL) { + if (tethered_prof == NULL) { DBG("There is nothing to unset masquerading\n"); return TRUE; } @@ -254,7 +857,7 @@ gboolean _unset_masquerade(void) ERR("_get_network_interface_name is failed\n"); return FALSE; } - DBG("Network interface : %s\n", if_name); + SDBG("Network interface : %s\n", if_name); _mh_core_disable_masquerade(if_name); free(if_name); @@ -262,90 +865,331 @@ gboolean _unset_masquerade(void) return TRUE; } -gboolean _open_network(void) +gboolean _add_default_router(void) { - connection_profile_h profile = NULL; + if (tethered_prof == NULL) { + DBG("There is no network\n"); + return TRUE; + } - DBG("+\n"); + char cmd[MAX_BUF_SIZE] = {0, }; + char *ip = NULL; + char *interface = NULL; - if (__get_network_profile(&profile) == FALSE) { - ERR("__get_network_profile is failed\n"); + if (_get_network_gateway_address(&ip) == FALSE) { return FALSE; } - if (!__is_connected_profile(profile)) { - connection_profile_destroy(profile); + if (_get_network_interface_name(&interface) == FALSE) { + free(ip); + return FALSE; + } + + snprintf(cmd, sizeof(cmd), "%s route replace "DEFAULT_ROUTER, + IP_CMD, ip, interface, TETHERING_ROUTING_TABLE); + free(interface); + free(ip); + + if (_execute_command(cmd)) { + ERR("%s is failed\n", cmd); + return FALSE; + } + + return TRUE; +} + +gboolean _del_default_router(void) +{ + if (tethered_prof == NULL) { + DBG("There is no network\n"); return TRUE; } - cprof = profile; - if (_set_masquerade() == FALSE) { - ERR("_set_masquerade is failed\n"); - _close_network(); + char cmd[MAX_BUF_SIZE] = {0, }; + char *ip = NULL; + char *interface = NULL; + + if (_get_network_gateway_address(&ip) == FALSE) { return FALSE; } - DBG("-\n"); + if (_get_network_interface_name(&interface) == FALSE) { + free(ip); + return FALSE; + } + + snprintf(cmd, sizeof(cmd), "%s route del "DEFAULT_ROUTER, + IP_CMD, ip, interface, TETHERING_ROUTING_TABLE); + free(interface); + free(ip); + + if (_execute_command(cmd)) { + ERR("%s is failed\n", cmd); + return FALSE; + } return TRUE; } -gboolean _close_network(void) +void _add_port_forward_rule(void) +{ + DBG("+\n"); + + GSList *l; + port_forward_info_s *pf; + + if (access(MH_PORT_FORWARD_CONF_FILEPATH, F_OK) < 0) { + return; + } + + if (__read_port_forward_info(MH_PORT_FORWARD_CONF_FILEPATH) == FALSE) { + ERR("__read_port_forward_info() is failed\n"); + return; + } + + _iptables_create_chain(TABLE_NAT, TETH_NAT_PRE); + _iptables_add_rule(PKT_REDIRECTION_RULE, TABLE_NAT, CHAIN_PRE, + TETH_NAT_PRE); + + for (l = port_forward_info; l; l = g_slist_next(l)) { + pf = (port_forward_info_s *)l->data; + + if (__is_valid_port_forward_info(pf) == FALSE) + continue; + + _iptables_add_rule(PORT_FW_RULE, TABLE_NAT, TETH_NAT_PRE, + pf->input_interface, pf->proto, pf->org_dest_ip, + pf->new_dest_ip, (int)pf->org_dest_port, (int)pf->new_dest_port); + } + + return; +} + +void _del_port_forward_rule(void) { - gboolean ret; + GSList *l; + GSList *temp_l; + port_forward_info_s *pf; DBG("+\n"); - ret = _unset_masquerade(); - if (ret == FALSE) - ERR("_unset_masquerade is failed\n"); + if (port_forward_info == NULL) { + DBG("port forwarding rules were not applied, no need to deleted\n"); + return; + } + + for(l = port_forward_info; l;) { + pf = (port_forward_info_s *)l->data; + if (pf) { + g_free(pf->new_dest_ip); + g_free(pf->org_dest_ip); + g_free(pf->proto); + g_free(pf->input_interface); + g_free(pf); + } + + temp_l = l; + l = g_slist_next(l); + port_forward_info = g_slist_delete_link(port_forward_info, + temp_l); + } + + _iptables_delete_rule(PKT_REDIRECTION_RULE, TABLE_NAT, CHAIN_PRE, + TETH_NAT_PRE); + _iptables_flush_rules(TABLE_NAT, TETH_NAT_PRE); + _iptables_delete_chain(TABLE_NAT, TETH_NAT_PRE); - connection_profile_destroy(cprof); - cprof = NULL; + return; +} + +int _open_network(void) +{ + DBG("+\n"); + + int ret; + int con_ret; + int cellular_state; + connection_type_e net_type; + + ret = connection_get_type(connection, &net_type); + if (ret != CONNECTION_ERROR_NONE) { + ERR("connection_get_type is failed\n"); + con_ret = __get_conn_error(ret); + return con_ret; + } + + if (vconf_get_int(VCONFKEY_NETWORK_CELLULAR_STATE, &cellular_state) < 0) { + ERR("vconf_get_int is failed\n"); + return MOBILE_AP_ERROR_INTERNAL; + } + + DBG("Connection type : %d, Cellular State : %d\n", + net_type, cellular_state); + + if (tethered_prof) { + if (net_type == CONNECTION_TYPE_CELLULAR) { + __update_tethering_cellular_profile(); + if (__is_equal_profile(tethered_prof, c_prof.handle)) { + DBG("Cellular profile is already configured\n"); + return MOBILE_AP_ERROR_NONE; + } + } + + DBG("There is already tethered profile\n"); + _close_network(); + } + + if (net_type == CONNECTION_TYPE_DISCONNECTED && + cellular_state != VCONFKEY_NETWORK_CELLULAR_ON) { + DBG("There is no network\n"); + /* Callback will handle this once Network type is changed */ + return MOBILE_AP_ERROR_NONE; + } + + switch (net_type) { + case CONNECTION_TYPE_DISCONNECTED: + case CONNECTION_TYPE_CELLULAR: + __update_tethering_cellular_profile(); + if (c_prof.handle == NULL || c_prof.svc_type == __NO_SERVICE) { + DBG("There is no proper cellular profile for tethering\n"); + return MOBILE_AP_ERROR_NONE; + } + __print_cellular_profile(); + + if (!__is_connected_profile(c_prof.handle)) { + if (c_prof.svc_type != __TETHERING_ONLY) { + return MOBILE_AP_ERROR_NONE; + } + + if (net_timeout_id) { + g_source_remove(net_timeout_id); + net_timeout_id = 0; + } + net_timeout_id = g_timeout_add(TETHERING_NET_OPEN_RETRY_INTERVAL, + __try_to_open_tethering_profile, NULL); + + return MOBILE_AP_ERROR_NONE; + } + connection_profile_clone(&tethered_prof, c_prof.handle); + break; + + case CONNECTION_TYPE_WIFI: + case CONNECTION_TYPE_ETHERNET: + case CONNECTION_TYPE_BT: + ret = connection_get_current_profile(connection, &tethered_prof); + if (ret != CONNECTION_ERROR_NONE) { + ERR("connection_get_current_profile is failed [0x%X]\n", ret); + con_ret = __get_conn_error(ret); + return con_ret; + } + break; + + default: + ERR("Unknown connection type : %d\n", net_type); + return MOBILE_AP_ERROR_INTERNAL; + } + + _set_masquerade(); + _add_default_router(); + _add_port_forward_rule(); DBG("-\n"); - return TRUE; + return MOBILE_AP_ERROR_NONE; } -gboolean _init_network(void *user_data) +void _close_network(void) { - int conn_ret; + if (tethered_prof == NULL) { + DBG("There is no tethered profile\n"); + return; + } - conn_ret = connection_create(&connection); - if (conn_ret != CONNECTION_ERROR_NONE) { - ERR("connection_create is failed : 0x%X\n", conn_ret); + DBG("+\n"); + + _del_port_forward_rule(); + _del_default_router(); + _unset_masquerade(); + + connection_profile_destroy(tethered_prof); + tethered_prof = NULL; + __close_tethering_profile(); + + DBG("-\n"); + return; +} + +gboolean _init_network(void *user_data) +{ + if (user_data == NULL) { + ERR("Invalid parameter\n"); return FALSE; } - conn_ret = connection_set_type_changed_cb(connection, + int ret; + + obj = (TetheringObject *)user_data; + + ret = connection_create(&connection); + if (ret != CONNECTION_ERROR_NONE) { + ERR("connection_create is failed : 0x%X\n", ret); + goto FAIL; + } + + 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); + if (ret != CONNECTION_ERROR_NONE) { + ERR("connection_set_type_changed cb is failed : 0x%X\n", ret); + goto FAIL; + } + + ret = vconf_notify_key_changed(VCONFKEY_NETWORK_CELLULAR_STATE, + __cellular_state_changed_cb, NULL); + if (ret < 0) { + ERR("vconf_notify_key_changed is failed : %d\n", ret); + connection_unset_type_changed_cb(connection); + goto FAIL; + } + + __update_tethering_cellular_profile(); + + return TRUE; + +FAIL: + if (connection) { connection_destroy(connection); connection = NULL; - return FALSE; } - return TRUE; + return FALSE; } gboolean _deinit_network(void) { - int conn_ret; + int 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); + if (c_prof.handle) { + vconf_ignore_key_changed(VCONFKEY_NETWORK_CELLULAR_STATE, + __cellular_state_changed_cb); + connection_profile_unset_state_changed_cb(c_prof.handle); + connection_profile_destroy(c_prof.handle); + c_prof.handle = NULL; + c_prof.svc_type = __NO_SERVICE; + } + + ret = connection_unset_type_changed_cb(connection); + if (ret != CONNECTION_ERROR_NONE) { + ERR("connection_unset_type_changed_cb is failed : %d\n", ret); } connection_destroy(connection); connection = NULL; + obj = NULL; return TRUE; } diff --git a/src/mobileap_notification.c b/src/mobileap_notification.c old mode 100644 new mode 100755 index 16dbec4..b812b2d --- a/src/mobileap_notification.c +++ b/src/mobileap_notification.c @@ -22,28 +22,57 @@ #include #include #include +#include -#include "mobileap_agent.h" +#include "mobileap_softap.h" +#include "mobileap_notification.h" + +#define MH_NOTI_LAUNCH_PKGNAME "setting-mobileap-efl" +#define MH_NOTI_CALLER_PKGNAME "mobileap-agent" +#define MH_LOCALE_DOMAIN "ug-setting-mobileap-efl" +#define MH_LOCALE_DIR "/usr/ug/res/locale" -//#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) +static 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; +} + +int _create_timeout_noti(const char *icon_path) { DBG("+\n"); + notification_h noti = NULL; notification_error_e ret = NOTIFICATION_ERROR_NONE; + char *old_icon_path = NULL; + char *general_icon_path = NULL; if (timeout_noti_id) { - noti = notification_load(APPNAME, timeout_noti_id); + noti = notification_load(MH_NOTI_CALLER_PKGNAME, timeout_noti_id); if (noti == NULL) { DBG("Notification can be deleted already\n"); } else { + ret = notification_get_image(noti, + NOTIFICATION_IMAGE_TYPE_ICON, &old_icon_path); + if (ret == NOTIFICATION_ERROR_NONE) { + if (g_strcmp0(icon_path, old_icon_path)) + general_icon_path = MH_NOTI_ICON_GENERAL; + } + ret = notification_delete(noti); if (ret != NOTIFICATION_ERROR_NONE) { ERR("Fail to notification_delete [%d]\n", ret); @@ -57,9 +86,9 @@ int _create_timeout_noti(const char *content, const char *title, 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; } @@ -69,13 +98,14 @@ int _create_timeout_noti(const char *content, const char *title, return MOBILE_AP_ERROR_INTERNAL; } + ret = notification_set_pkgname(noti, MH_NOTI_CALLER_PKGNAME); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("Fail to notification_set_pkgname [%d]\n", ret); + goto FAIL; + } + 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; @@ -83,47 +113,48 @@ int _create_timeout_noti(const char *content, const char *title, ret = notification_set_layout(noti, NOTIFICATION_LY_NOTI_EVENT_SINGLE); if (ret != NOTIFICATION_ERROR_NONE) { - ERR("Fail to notification_set_image [%d]\n", ret); + ERR("Fail to notification_set_layout [%d]\n", ret); goto FAIL; } ret = notification_set_image(noti, - NOTIFICATION_IMAGE_TYPE_ICON, icon_path); + NOTIFICATION_IMAGE_TYPE_ICON, general_icon_path ? + general_icon_path : 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); + NOTIFICATION_TEXT_TYPE_TITLE, NULL, + MH_STR_CONNECTION_TIMEOUT, + 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); + NOTIFICATION_TEXT_TYPE_CONTENT, NULL, + MH_STR_CONFIGURE_TETHERING, + 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); + ret = notification_set_text_domain(noti, MH_LOCALE_DOMAIN, MH_LOCALE_DIR); if (ret != NOTIFICATION_ERROR_NONE) { - ERR("Fail to notification_set_pkgname [%d]\n", ret); + ERR("Fail to notification_set_text_domain [%d]\n", ret); goto FAIL; } -#ifdef __ENABLE_UG_LAUNCH - ret = notification_set_application(noti, MH_NOTI_APP_NAME); + + ret = notification_set_application(noti, MH_NOTI_LAUNCH_PKGNAME); 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); @@ -151,31 +182,47 @@ int _delete_timeout_noti(void) { notification_error_e ret = NOTIFICATION_ERROR_NONE; notification_list_h noti_list = NULL; + notification_list_h l = NULL; notification_h noti = NULL; + notification_ly_type_e layout; + + DBG("+\n"); - ret = notification_get_detail_list(MH_AGENT_PKG_NAME, - NOTIFICATION_GROUP_ID_NONE, - NOTIFICATION_PRIV_ID_NONE, - -1, - ¬i_list); + ret = notification_get_detail_list(MH_NOTI_CALLER_PKGNAME, + 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); + if (noti_list == NULL) { + return MOBILE_AP_ERROR_NONE; + } + + for (l = noti_list; l; l = notification_list_get_next(l)) { + noti = notification_list_get_data(l); + if (noti == NULL) + break; - notification_free_list(noti_list); + ret = notification_get_layout(noti, &layout); + if (ret == NOTIFICATION_ERROR_NONE && + layout == NOTIFICATION_LY_NOTI_EVENT_SINGLE) { + DBG("Found timeout noti\n"); + notification_delete(noti); + } } + notification_free_list(noti_list); + + DBG("-\n"); + return MOBILE_AP_ERROR_NONE; } -int _create_connected_noti(const char *content, const char *title, - const char *icon_path) +int _create_connected_noti(int count, const char *icon_path) { DBG("+\n"); notification_h noti = NULL; @@ -187,14 +234,15 @@ int _create_connected_noti(const char *content, const char *title, return MOBILE_AP_ERROR_INTERNAL; } + ret = notification_set_pkgname(noti, MH_NOTI_CALLER_PKGNAME); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("Fail to notification_set_pkgname [%d]\n", ret); + goto FAIL; + } + 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; @@ -213,35 +261,43 @@ int _create_connected_noti(const char *content, const char *title, } ret = notification_set_text(noti, - NOTIFICATION_TEXT_TYPE_TITLE, - title, - NULL, NOTIFICATION_VARIABLE_TYPE_NONE); + NOTIFICATION_TEXT_TYPE_TITLE, NULL, + MH_STR_TETHERING, + 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); + NOTIFICATION_TEXT_TYPE_CONTENT, NULL, + MH_STR_CONNECTED_DEV, + NOTIFICATION_VARIABLE_TYPE_INT, count, + 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); + ret = notification_set_text_domain(noti, MH_LOCALE_DOMAIN, MH_LOCALE_DIR); if (ret != NOTIFICATION_ERROR_NONE) { - ERR("Fail to notification_set_pkgname [%d]\n", ret); + ERR("Fail to notification_set_text_domain [%d]\n", ret); goto FAIL; } -#ifdef __ENABLE_UG_LAUNCH - ret = notification_set_application(noti, MH_NOTI_APP_NAME); + + ret = notification_set_application(noti, MH_NOTI_LAUNCH_PKGNAME); if (ret != NOTIFICATION_ERROR_NONE) { ERR("Fail to notification_set_application [%d]\n", ret); goto FAIL; } -#endif + + ret = notification_set_display_applist(noti, + NOTIFICATION_DISPLAY_APP_ALL ^ NOTIFICATION_DISPLAY_APP_INDICATOR); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("Fail to notification_set_display_applist [%d]\n", ret); + goto FAIL; + } + ret = notification_insert(noti, &connected_noti_id); if (ret != NOTIFICATION_ERROR_NONE) { ERR("Fail to notification_insert [%d]\n", ret); @@ -264,43 +320,40 @@ FAIL: return MOBILE_AP_ERROR_INTERNAL; } -int _update_connected_noti(const char *content) +int _update_connected_noti(int count, const char *icon_path) { 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); + noti = notification_load(MH_NOTI_CALLER_PKGNAME, 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); + ret = notification_set_image(noti, + NOTIFICATION_IMAGE_TYPE_ICON, icon_path); if (ret != NOTIFICATION_ERROR_NONE) { - ERR("Fail to notification_set_text [%d]\n", ret); + ERR("Fail to notification_set_image [%d]\n", ret); + goto FAIL; + } - ret = notification_free(noti); - if (ret != NOTIFICATION_ERROR_NONE) - ERR("Fail to notification_free [%d]\n", ret); - return MOBILE_AP_ERROR_INTERNAL; + ret = notification_set_text(noti, + NOTIFICATION_TEXT_TYPE_CONTENT, NULL, + MH_STR_CONNECTED_DEV, + NOTIFICATION_VARIABLE_TYPE_INT, count, + NOTIFICATION_VARIABLE_TYPE_NONE); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("Fail to notification_set_text [%d]\n", ret); + goto FAIL; } 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; + goto FAIL; } ret = notification_free(noti); @@ -311,6 +364,14 @@ int _update_connected_noti(const char *content) 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_connected_noti(void) @@ -319,7 +380,7 @@ int _delete_connected_noti(void) notification_h noti = NULL; notification_error_e ret; - noti = notification_load(APPNAME, connected_noti_id); + noti = notification_load(MH_NOTI_CALLER_PKGNAME, connected_noti_id); if (noti == NULL) { ERR("notification_load is failed\n"); connected_noti_id = 0; @@ -347,18 +408,50 @@ int _delete_connected_noti(void) return MOBILE_AP_ERROR_NONE; } -int _create_status_noti(const char *content) +void _create_tethering_active_noti(void) { - if (content == NULL) - return MOBILE_AP_ERROR_INVALID_PARAM; + int active_count = 0; - notification_error_e ret; + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) + active_count++; - 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; + if (_mobileap_is_enabled(MOBILE_AP_STATE_BT)) + active_count++; + + if (_mobileap_is_enabled(MOBILE_AP_STATE_USB)) + active_count++; + + if (active_count == 1) + __create_status_noti(_("IDS_MOBILEAP_BODY_TETHERING_ACTIVE_ABB")); + + return; +} + +void _create_bt_tethering_active_noti(void) +{ + int ret; + bt_adapter_visibility_mode_e mode = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE; + int duration; + int str_len; + char *str1 = NULL; + char *str2 = NULL; + char *str = NULL; + + if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI) && + !_mobileap_is_enabled(MOBILE_AP_STATE_USB)) { + str1 = MH_STR_TETHERING_ACTIVE; + __create_status_noti(str1); } - return MOBILE_AP_ERROR_NONE; + ret = bt_adapter_get_visibility(&mode, &duration); + if (ret != BT_ERROR_NONE) { + ERR("bt_adapter_get_visibility is failed 0x[%X]\n", ret); + } + + if (mode == BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE) { + str2 = MH_STR_BT_VISIBILITY; + __create_status_noti(str2); + } + + return; } diff --git a/src/mobileap_agent.c b/src/mobileap_softap.c old mode 100644 new mode 100755 similarity index 55% rename from src/mobileap_agent.c rename to src/mobileap_softap.c index 609cfb0..1137a1b --- a/src/mobileap_agent.c +++ b/src/mobileap_softap.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -33,13 +34,20 @@ #include #include #include - #include #include #include "mobileap_common.h" -#include "mobileap_agent.h" +#include "mobileap_softap.h" #include "mobileap_handler.h" +#include "mobileap_wifi.h" +#include "mobileap_iptables.h" + +#define NETCONFIG_SERVICE "net.netconfig" +#define NETCONFIG_WIFI_INTERFACE "net.netconfig.wifi" +#define NETCONFIG_WIFI_PATH "/net/netconfig/wifi" + +#define NETCONFIG_DBUS_REPLY_TIMEOUT (10 * 1000) static pid_t dnsmasq_pid = 0; static pid_t hostapd_pid = 0; @@ -47,6 +55,25 @@ static int hostapd_ctrl_fd = 0; static int hostapd_monitor_fd = 0; static GIOChannel *hostapd_io_channel = NULL; static guint hostapd_io_source = 0; +GSList *sta_timer_list = NULL; + +static gboolean __hostapd_connect_timer_cb(gpointer user_data); + +static char *__find_first_caps_char(char *str) +{ + if (str == NULL) { + ERR("NULL string passes\n"); + return NULL; + } + + while(*str) { + if (isupper(*str)) { + return str; + } + str++; + } + return NULL; +} static int __issue_ioctl(int sock_fd, char *if_name, char *cmd, char *buf) { @@ -73,28 +100,25 @@ static int __issue_ioctl(int sock_fd, char *if_name, char *cmd, char *buf) return ret_val; } -static int __get_psk_hexascii(const char *pass, const unsigned char *salt, char *psk, unsigned int psk_len) +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) { + if (pass == NULL || salt == NULL || psk == NULL || psk_len < + (SHA256_DIGEST_LENGTH * 2 + 1)) { 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; + int i = 0; + int d_16 = 0; + int r_16 = 0; 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; + return MOBILE_AP_ERROR_RESOURCE; } for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { @@ -109,44 +133,68 @@ static int __get_psk_hexascii(const char *pass, const unsigned char *salt, char return MOBILE_AP_ERROR_NONE; } -static int __execute_hostapd(const char *ssid, const char *security, - const char *key, int hide_mode) +static int __execute_hostapd(const mobile_ap_type_e type, const char *ssid, + const char *security, const char *passphrase, int hide_mode) { DBG("+\n"); - char psk[2 * SHA256_DIGEST_LENGTH + 1] = {0, }; + char *conf = NULL; + char *old_conf; 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, + int ret; + char key[MOBILE_AP_WIFI_KEY_MAX_LEN + 1]; + /* Default conf. */ + snprintf(buf, sizeof(buf), HOSTAPD_CONF, WIFI_IF, HOSTAPD_CTRL_INTF_DIR, ssid, MOBILE_AP_WIFI_CHANNEL, hide_mode ? 2 : 0, - MOBILE_AP_MAX_WIFI_STA, - sec_buf); + MOBILE_AP_MAX_WIFI_STA); + conf = g_strdup(buf); + + /* Vendor elements conf. */ + if (type == MOBILE_AP_TYPE_WIFI) { + snprintf(buf, sizeof(buf), + "vendor_elements=%s\n", HOSTAPD_VENDOR_ELEMENTS_TETH); + } else if (type == MOBILE_AP_TYPE_WIFI_AP) { + snprintf(buf, sizeof(buf), + "vendor_elements=%s\n", HOSTAPD_VENDOR_ELEMENTS_WIFI_AP); + } else { + ERR("Unknown type: %d\n", type); + g_free(conf); + return MOBILE_AP_ERROR_INVALID_PARAM; + } + old_conf = conf; + conf = g_strconcat(old_conf, buf, NULL); + g_free(old_conf); + + /* Security conf. */ + if (security != NULL && !strcmp(security, "wpa2-psk")) { + ret = __get_psk_hexascii(passphrase, (const unsigned char *)ssid, key, sizeof(key)); + if (ret != MOBILE_AP_ERROR_NONE) { + g_free(conf); + ERR("hex conversion failed\n"); + return MOBILE_AP_ERROR_RESOURCE; + } + snprintf(buf, sizeof(buf), + "wpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", key); + + old_conf = conf; + conf = g_strconcat(old_conf, buf, NULL); + g_free(old_conf); + } fp = fopen(HOSTAPD_CONF_FILE, "w"); if (NULL == fp) { ERR("Could not create the file.\n"); + g_free(conf); return MOBILE_AP_ERROR_RESOURCE; } - fputs(buf, fp); + fputs(conf, fp); + g_free(conf); fclose(fp); pid = fork(); @@ -155,10 +203,10 @@ static int __execute_hostapd(const char *ssid, const char *security, return MOBILE_AP_ERROR_RESOURCE; } - if (pid == 0) { + if (pid == 0) { if (execl(HOSTAPD_BIN, HOSTAPD_BIN, "-e", HOSTAPD_ENTROPY_FILE, HOSTAPD_CONF_FILE, - "-f", HOSTAPD_DEBUG_FILE, "-dd", + "-f", HOSTAPD_DEBUG_FILE, "-ddd", (char *)NULL)) { ERR("execl failed\n"); } @@ -176,8 +224,10 @@ static int __terminate_hostapd() { DBG("+\n"); + int ret; + if (hostapd_pid == 0) { - DBG("There is no hostapd\n"); + ERR("There is no hostapd\n"); return MOBILE_AP_ERROR_NONE; } @@ -185,6 +235,11 @@ static int __terminate_hostapd() waitpid(hostapd_pid, NULL, 0); hostapd_pid = 0; + ret = unlink(HOSTAPD_CONF_FILE); + if (ret < 0) { + ERR("unlink is failed : %s\n", strerror(errno)); + } + return MOBILE_AP_ERROR_NONE; } @@ -236,7 +291,7 @@ static int __send_hostapd_req(int fd, const char *req, const int req_len, } if (buf[0] == '<') { - DBG("Unsolicited message\n"); + ERR("Unsolicited message\n"); continue; } @@ -277,7 +332,6 @@ static int __open_hostapd_intf(int *fd, const char *intf) 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); } @@ -295,7 +349,6 @@ static int __open_hostapd_intf(int *fd, const char *intf) 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); @@ -332,10 +385,17 @@ static gboolean __hostapd_monitor_cb(GIOChannel *source) { DBG("+\n"); - char buf[HOSTAPD_REQ_MAX_LEN] = {0, }; + GSList *l; + char buf[HOSTAPD_REQ_MAX_LEN + 1] = {0, }; char *pbuf = NULL; gsize read = 0; int n_station = 0; + int type; + sta_timer_t *ptr = NULL; + char *mac = NULL; + char *end = NULL; + gboolean discon_event = FALSE; + #if !GLIB_CHECK_VERSION(2, 31, 0) int ret = 0; @@ -367,35 +427,121 @@ static gboolean __hostapd_monitor_cb(GIOChannel *source) if (pbuf != NULL) *pbuf = '\0'; - if (buf[0] == '<' && (pbuf = strchr(buf, '>')) != NULL) { - pbuf++; - } else { - pbuf = buf; - } - - DBG("Event : %s\n", pbuf); + SDBG("Read string from hostapd = [%s]\n", buf); + pbuf = buf; + /* concatenated string, containing multiple events can arrive */ + while (pbuf && *pbuf) { + pbuf = __find_first_caps_char(pbuf); + if (!pbuf || !*pbuf) { + break; + } - 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; + if (!strncmp(pbuf, HOSTAPD_STA_CONN, HOSTAPD_STA_CONN_LEN)) { + pbuf = pbuf + HOSTAPD_STA_CONN_LEN; + if (!pbuf || !*pbuf) { + ERR("No mac address\n"); + return TRUE; + } + + end = strchr(pbuf, '<'); + if (end && *end) { + mac = g_strndup(pbuf, (long)(end - pbuf)); + pbuf = end + 1; + } else { + mac = g_strdup(pbuf); + pbuf += strlen(mac); + } + + if (mac == NULL) { + ERR("strdup failed\n"); + return TRUE; + } + + for (l = sta_timer_list; l != NULL; l = g_slist_next(l)) { + ptr = (sta_timer_t *)l->data; + if (ptr == NULL) { + continue; + } + + if (g_strcmp0(ptr->mac_addr, mac) == 0) { + g_free(mac); + mac = NULL; + break; + } + } + + /* Matched station found, so skip */ + if (l != NULL) { + continue; + } + + SDBG("%s%s\n", HOSTAPD_STA_CONN, mac); + ptr = (sta_timer_t *)g_malloc(sizeof(sta_timer_t)); + ptr->mac_addr = mac; + ptr->tid = g_timeout_add(HOSTAPD_DHCP_MAX_INTERVAL, + __hostapd_connect_timer_cb, mac); + sta_timer_list = g_slist_append(sta_timer_list, ptr); + + } else if (!strncmp(pbuf, HOSTAPD_STA_DISCONN, HOSTAPD_STA_DISCONN_LEN)) { + pbuf = pbuf + HOSTAPD_STA_DISCONN_LEN; + if (!pbuf || !*pbuf) { + break; + } + + end = strchr(pbuf, '<'); + if (end && *end) { + mac = g_strndup(pbuf, (long)(end - pbuf)); + pbuf = end + 1; + } else { + mac = g_strdup(pbuf); + pbuf += strlen(mac); + } + + if (mac == NULL) { + ERR("strdup failed\n"); + return TRUE; + } + + SDBG("%s%s\n", HOSTAPD_STA_DISCONN, mac); + _remove_station_info(mac, _slist_find_station_by_mac); + + /* + * Destroy the timer if its not expired before disconnection + */ + _destroy_dhcp_ack_timer(mac); + g_free(mac); + mac = NULL; + discon_event = TRUE; + + } else { + pbuf = strchr(pbuf, '>'); + if (pbuf == NULL) + break; + pbuf++; } - pbuf++; + } - DBG("Disconnected station MAC : %s\n", pbuf); - _remove_station_info(pbuf, _slist_find_station_by_mac); + if (discon_event == FALSE) + goto DONE; - _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; + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) { + type = MOBILE_AP_TYPE_WIFI; + } else if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) { + type = MOBILE_AP_TYPE_WIFI_AP; } else { - DBG("Event is not handled\n"); + goto DONE; } + _get_station_count((gconstpointer)type, + _slist_find_station_by_interface, &n_station); + + if (n_station == 0) { + if (type == MOBILE_AP_TYPE_WIFI) + _start_timeout_cb(type, time(NULL) + TETHERING_CONN_TIMEOUT); + else if (type == MOBILE_AP_TYPE_WIFI_AP) + _start_timeout_cb(type, time(NULL) + WIFI_AP_CONN_TIMEOUT); + } +DONE: return TRUE; } @@ -432,7 +578,6 @@ static int __open_hostapd_monitor(int *fd) 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; } @@ -446,7 +591,6 @@ static int __close_hostapd_monitor(int *fd) 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); @@ -504,8 +648,118 @@ static mobile_ap_drv_interface_e __get_drv_interface(void) return drv_interface; } -int _mh_core_enable_softap(const char *ssid, const char *security, - const char *key, int hide_mode) +static int __mh_core_softap_firmware_start(void) +{ + int err = 0; + DBusError error; + DBusMessageIter iter; + DBusMessage *reply = NULL; + DBusMessage *message = NULL; + DBusConnection *connection = NULL; + const char *device = "softap"; + + connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); + if (connection == NULL) { + ERR("Failed to get system bus"); + return -EIO; + } + + message = dbus_message_new_method_call(NETCONFIG_SERVICE, + NETCONFIG_WIFI_PATH, NETCONFIG_WIFI_INTERFACE ".Firmware", "Start"); + if (message == NULL) { + ERR("Failed DBus method call"); + dbus_connection_unref(connection); + return -EIO; + } + + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &device); + + dbus_error_init(&error); + + reply = dbus_connection_send_with_reply_and_block(connection, message, + NETCONFIG_DBUS_REPLY_TIMEOUT, &error); + if (dbus_error_is_set(&error) == TRUE) { + if (NULL != strstr(error.message, ".AlreadyExists")) { + // softap already enabled + } else { + ERR("dbus_connection_send_with_reply_and_block() failed. " + "DBus error [%s: %s]", error.name, error.message); + + err = -EIO; + + dbus_error_free(&error); + } + + dbus_error_free(&error); + } + + if (reply != NULL) + dbus_message_unref(reply); + + dbus_message_unref(message); + dbus_connection_unref(connection); + + return err; +} + +static int __mh_core_softap_firmware_stop(void) +{ + int err = 0; + DBusError error; + DBusMessageIter iter; + DBusMessage *reply = NULL; + DBusMessage *message = NULL; + DBusConnection *connection = NULL; + const char *device = "softap"; + + connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); + if (connection == NULL) { + ERR("Failed to get system bus"); + return -EIO; + } + + message = dbus_message_new_method_call(NETCONFIG_SERVICE, + NETCONFIG_WIFI_PATH, NETCONFIG_WIFI_INTERFACE ".Firmware", "Stop"); + if (message == NULL) { + ERR("Failed DBus method call"); + dbus_connection_unref(connection); + return -EIO; + } + + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &device); + + dbus_error_init(&error); + + reply = dbus_connection_send_with_reply_and_block(connection, message, + NETCONFIG_DBUS_REPLY_TIMEOUT, &error); + if (dbus_error_is_set(&error) == TRUE) { + if (NULL != strstr(error.message, ".AlreadyExists")) { + // softap already disabled + } else { + ERR("dbus_connection_send_with_reply_and_block() failed. " + "DBus error [%s: %s]", error.name, error.message); + + err = -EIO; + + dbus_error_free(&error); + } + + dbus_error_free(&error); + } + + if (reply != NULL) + dbus_message_unref(reply); + + dbus_message_unref(message); + dbus_connection_unref(connection); + + return err; +} + +int _mh_core_enable_softap(const mobile_ap_type_e type, const char *ssid, + const char *security, const char *key, int hide_mode) { if (ssid == NULL || security == NULL || key == NULL) { ERR("Invalid param\n"); @@ -520,11 +774,11 @@ int _mh_core_enable_softap(const char *ssid, const char *security, 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); + char wext_ssid[MOBILE_AP_WIFI_SSID_MAX_LEN] = { 0 }; + char *ptr = NULL; + + if (__mh_core_softap_firmware_start() < 0) return MOBILE_AP_ERROR_INTERNAL; - } drv_interface = __get_drv_interface(); @@ -536,11 +790,19 @@ int _mh_core_enable_softap(const char *ssid, const char *security, break; } + /* + * In case of Wireless extension interface, + * 32 byte SSID including null character can be accepted. + */ + g_strlcpy(wext_ssid, ssid, sizeof(wext_ssid)); + if (!g_utf8_validate(wext_ssid, -1, (const char **)&ptr)) + *ptr = '\0'; + 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, + strlen(wext_ssid), wext_ssid, security, strlen(key), key, MOBILE_AP_WIFI_CHANNEL, MOBILE_AP_MAX_WIFI_STA, hide_mode); @@ -569,7 +831,6 @@ int _mh_core_enable_softap(const char *ssid, const char *security, 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) { @@ -579,6 +840,7 @@ int _mh_core_enable_softap(const char *ssid, const char *security, break; case MOBILE_AP_NL80211: + ret_status = _mh_core_set_ip_address(WIFI_IF, IP_ADDRESS_SOFTAP); if (ret_status != MOBILE_AP_ERROR_NONE) { @@ -586,7 +848,7 @@ int _mh_core_enable_softap(const char *ssid, const char *security, break; } - ret_status = __execute_hostapd(ssid, security, key, hide_mode); + ret_status = __execute_hostapd(type, ssid, security, key, hide_mode); if (ret_status != MOBILE_AP_ERROR_NONE) { ERR("__execute_hostapd is failed\n"); break; @@ -610,16 +872,12 @@ int _mh_core_enable_softap(const char *ssid, const char *security, break; default: - DBG("Unknown driver interface : %d\n", drv_interface); + ERR("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); - } - } + if (ret_status != MOBILE_AP_ERROR_NONE) + __mh_core_softap_firmware_stop(); return ret_status; } @@ -672,15 +930,12 @@ int _mh_core_disable_softap(void) break; default: - DBG("Unknown driver interface : %d\n", drv_interface); + ERR("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); + if (__mh_core_softap_firmware_stop() < 0) ret_status = MOBILE_AP_ERROR_INTERNAL; - } return ret_status; } @@ -714,7 +969,6 @@ static int __get_device_info_by_wext(softap_device_info_t *di) 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++) { @@ -727,7 +981,7 @@ static int __get_device_info_by_wext(softap_device_info_t *di) 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]); + SDBG("STA[%d] address[%s]\n", i, di->bssid[i]); buf_ptr += 12; } @@ -780,7 +1034,7 @@ static int __get_device_info_by_nl80211(softap_device_info_t *di) break; } - DBG("Station : %s\n", buf); + SDBG("Station : %s\n", buf); g_strlcpy(di->bssid[no_of_sta++], buf, MOBILE_AP_STR_INFO_LEN); buf_len = sizeof(buf); @@ -863,8 +1117,10 @@ int _mh_core_execute_dhcp_server(void) int _mh_core_terminate_dhcp_server(void) { + int ret; + if (dnsmasq_pid == 0) { - DBG("There is no dnsmasq\n"); + ERR("There is no dnsmasq\n"); return MOBILE_AP_ERROR_NONE; } @@ -872,6 +1128,11 @@ int _mh_core_terminate_dhcp_server(void) waitpid(dnsmasq_pid, NULL, 0); dnsmasq_pid = 0; + ret = unlink(DNSMASQ_CONF_FILE); + if (ret < 0) { + ERR("unlink is failed : %s\n", strerror(errno)); + } + return MOBILE_AP_ERROR_NONE; } @@ -883,7 +1144,6 @@ int _mh_core_enable_masquerade(const char *ext_if) } int fd = -1; - char cmd[MAX_BUF_SIZE] = {0, }; fd = open(IP_FORWARD, O_WRONLY); if (fd < 0) { @@ -898,16 +1158,48 @@ int _mh_core_enable_masquerade(const char *ext_if) } 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); + _iptables_create_chain(TABLE_NAT, TETH_NAT_POST); + _iptables_add_rule(PKT_REDIRECTION_RULE, TABLE_NAT, CHAIN_POST, + TETH_NAT_POST); + _iptables_add_rule(MASQ_RULE, TABLE_NAT, TETH_NAT_POST, ext_if); + + _iptables_create_chain(TABLE_FILTER, TETH_FILTER_FW); + + _iptables_add_rule(PKT_REDIRECTION_RULE, TABLE_FILTER, CHAIN_FW, + TETH_FILTER_FW); + + _iptables_add_rule(CLAMP_MSS_RULE, TABLE_FILTER, TETH_FILTER_FW); + + _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW, + BT_IF_ALL, ext_if, ACTION_RETURN, STATE_RELATED_ESTAB); + _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW, + WIFI_IF, ext_if, ACTION_RETURN, STATE_RELATED_ESTAB); + _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW, + USB_IF, ext_if, ACTION_RETURN, STATE_RELATED_ESTAB); + + _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW, + ext_if, BT_IF_ALL, ACTION_DROP, STATE_INVALID); + _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW, + ext_if, WIFI_IF, ACTION_DROP, STATE_INVALID); + _iptables_add_rule(FORWARD_RULE_WITH_ACTION_AND_STATE, TABLE_FILTER, TETH_FILTER_FW, + ext_if, USB_IF, ACTION_DROP, STATE_INVALID); + + _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW, + ext_if, BT_IF_ALL, ACTION_RETURN); + _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW, + ext_if, WIFI_IF, ACTION_RETURN); + _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW, + ext_if, USB_IF, ACTION_RETURN); + + _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW, + BT_IF_ALL, ext_if, ACTION_RETURN); + _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW, + WIFI_IF, ext_if, ACTION_RETURN); + _iptables_add_rule(FORWARD_RULE_WITH_ACTION, TABLE_FILTER, TETH_FILTER_FW, + USB_IF, ext_if, ACTION_RETURN); + + _iptables_add_rule(DEFAULT_RULE, TABLE_FILTER, TETH_FILTER_FW, + ACTION_DROP); return MOBILE_AP_ERROR_NONE; } @@ -920,7 +1212,6 @@ int _mh_core_disable_masquerade(const char *ext_if) } int fd = -1; - char cmd[MAX_BUF_SIZE] = {0, }; fd = open(IP_FORWARD, O_WRONLY); if (fd < 0) { @@ -935,16 +1226,15 @@ int _mh_core_disable_masquerade(const char *ext_if) } 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; - } + _iptables_delete_rule(PKT_REDIRECTION_RULE, TABLE_NAT, CHAIN_POST, + TETH_NAT_POST); + _iptables_flush_rules(TABLE_NAT, TETH_NAT_POST); + _iptables_delete_chain(TABLE_NAT, TETH_NAT_POST); - _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); + _iptables_delete_rule(PKT_REDIRECTION_RULE, TABLE_FILTER, CHAIN_FW, + TETH_FILTER_FW); + _iptables_flush_rules(TABLE_FILTER, TETH_FILTER_FW); + _iptables_delete_chain(TABLE_FILTER, TETH_FILTER_FW); return MOBILE_AP_ERROR_NONE; } @@ -966,11 +1256,10 @@ int _mh_core_set_ip_address(const char *if_name, const in_addr_t ip) struct sockaddr_in addr; int sock_fd; - DBG("if_name : %s ip address : 0x%X\n", if_name, ip); + SDBG("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; } @@ -984,14 +1273,12 @@ int _mh_core_set_ip_address(const char *if_name, const in_addr_t 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; } @@ -999,7 +1286,6 @@ int _mh_core_set_ip_address(const char *if_name, const in_addr_t ip) 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; } @@ -1008,3 +1294,224 @@ int _mh_core_set_ip_address(const char *if_name, const in_addr_t ip) return MOBILE_AP_ERROR_NONE; } + +static gboolean __send_station_event_cb(gpointer data) +{ + int sig = GPOINTER_TO_INT(data); + int n_station = 0; + int type; + mobile_ap_station_info_t *si = NULL; + + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) + type = MOBILE_AP_TYPE_WIFI; + else if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) + type = MOBILE_AP_TYPE_WIFI_AP; + else + 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((gconstpointer)type, + _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)type, + _slist_find_station_by_interface, &n_station); + if (n_station == 0) { + if (type == MOBILE_AP_TYPE_WIFI) + _start_timeout_cb(type, time(NULL) + TETHERING_CONN_TIMEOUT); + else if (type == MOBILE_AP_TYPE_WIFI_AP) + _start_timeout_cb(type, time(NULL) + WIFI_AP_CONN_TIMEOUT); + } + } + + 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; + + if (__get_drv_interface() != MOBILE_AP_WEXT) + return; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = __handle_station_signal; + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); + + return; +} + +void _unregister_wifi_station_handler(void) +{ + struct sigaction sa; + + if (__get_drv_interface() != MOBILE_AP_WEXT) + return; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); + + return; +} + +static gboolean __hostapd_connect_timer_cb(gpointer user_data) +{ + char *mac = (char *)user_data; + GSList *l = NULL; + GSList *temp = NULL; + sta_timer_t *ptr = NULL; + mobile_ap_station_info_t *info = NULL; + time_t tm; + int n_station = 0; + int type; + int ret; + + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) + type = MOBILE_AP_TYPE_WIFI; + else if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) + type = MOBILE_AP_TYPE_WIFI_AP; + else + return FALSE; + + for (l = sta_timer_list; l != NULL; l = g_slist_next(l)) { + ptr = (sta_timer_t *)l->data; + if (ptr == NULL) + continue; + + if (!g_strcmp0(ptr->mac_addr, mac)) { + DBG("client with Static IP, Add station\n"); + + info = (mobile_ap_station_info_t *)g_malloc(sizeof(mobile_ap_station_info_t)); + if (info == NULL) { + ERR("g_malloc failed\n"); + g_free(ptr->mac_addr); + g_free(ptr); + temp = l; + l = g_slist_next(l); + sta_timer_list = g_slist_delete_link(sta_timer_list, temp); + break; + } + + time(&tm); + info->tm = tm; + info->interface = type; + g_strlcpy(info->ip, "", sizeof(info->ip)); + g_strlcpy(info->mac, mac, sizeof(info->mac)); + + ret = _get_wifi_name_from_lease_info(mac, &info->hostname); + if (ret != MOBILE_AP_ERROR_NONE) + info->hostname = g_strdup(MOBILE_AP_NAME_UNKNOWN); + + g_free(ptr->mac_addr); + g_free(ptr); + temp = l; + l = g_slist_next(l); + sta_timer_list = g_slist_delete_link(sta_timer_list, temp); + + goto SUCCESS; + } + } + + return FALSE; + +SUCCESS : + if (_add_station_info(info) != MOBILE_AP_ERROR_NONE) { + g_free(info->hostname); + g_free(info); + return FALSE; + } + + _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 FALSE; +} + +void _flush_dhcp_ack_timer(void) +{ + DBG("+\n"); + + GSList *l = NULL; + GSList *temp = NULL; + sta_timer_t *ptr = NULL; + + for (l = sta_timer_list; l != NULL; l = g_slist_next(l)) { + ptr = (sta_timer_t *)l->data; + if (ptr) { + if (ptr->tid != 0) { + g_source_remove(ptr->tid); + ptr->tid = 0; + } + g_free(ptr->mac_addr); + g_free(ptr); + } + + temp = l; + l = g_slist_next(l); + sta_timer_list = g_slist_delete_link(sta_timer_list, temp); + } + + DBG("-\n"); + return; +} + +void _destroy_dhcp_ack_timer(char *mac_addr) +{ + DBG("+\n"); + if (mac_addr == NULL) { + ERR("mac address passed NULL\n"); + return; + } + + GSList *l = NULL; + GSList *temp = NULL; + sta_timer_t *ptr = NULL; + + for (l = sta_timer_list; l != NULL; l = g_slist_next(l)) { + + ptr = (sta_timer_t *)l->data; + if (ptr == NULL) + continue; + + if (!g_strcmp0(ptr->mac_addr, mac_addr)) { + + if (ptr->tid != 0) { + g_source_remove(ptr->tid); + ptr->tid = 0; + } + g_free(ptr->mac_addr); + g_free(ptr); + temp = l; + l = g_slist_next(l); + sta_timer_list = g_slist_delete_link(sta_timer_list, + temp); + break; + } + } + + DBG("-\n"); + return; +} diff --git a/src/mobileap_usb.c b/src/mobileap_usb.c old mode 100644 new mode 100755 index edf870e..de1037c --- a/src/mobileap_usb.c +++ b/src/mobileap_usb.c @@ -24,11 +24,113 @@ #include #include #include +#include -#include "mobileap_agent.h" +#include "mobileap_softap.h" #include "mobileap_common.h" #include "mobileap_usb.h" +static DBusGMethodInvocation *g_context = NULL; +static gboolean in_progress = FALSE; +static GDBusConnection *conn = NULL; +static guint subscription_id = 0; +static int usb_client_state = 0; + +#define USB_SYSTEM_DEVICE_PATH "/Org/Tizen/System/DeviceD/Usb" +#define USB_SYSTEM_DEVICE_IFACE "org.tizen.system.deviced.Usb" +#define USB_STATE_CHANGE_SIGNAL "StateChanged" + +enum usbclient_state { + USBCLIENT_STATE_DISCONNECTED = 0x00, /* usb cable is detached */ + USBCLIENT_STATE_CONNECTED = 0x01, /* usb cable is attached */ + /* usb cable is attached and available (ready to use) */ + USBCLIENT_STATE_AVAILABLE = 0x02, +}; + +/* GDbus Signal Handler for USB Device State Changes */ +static void __usb_device_state_change_cb(GDBusConnection *connection, + const gchar *sender_name, const gchar *object_path, + const gchar *interface_name, const gchar *signal_name, + GVariant *parameters, gpointer user_data) +{ + unsigned int value = 0; + TetheringObject *obj = (TetheringObject *)user_data; + + if (NULL == parameters || NULL == obj) { + ERR("Paramters Invalid \n"); + return; + } + + if (strcmp(object_path, USB_SYSTEM_DEVICE_PATH) || + strcmp(interface_name, USB_SYSTEM_DEVICE_IFACE) || + strcmp(signal_name, USB_STATE_CHANGE_SIGNAL)) { + ERR("Unknown DBUS Signal\n"); + return; + } + g_variant_get(parameters, "(u)", &value); + DBG("Received signal(%s), value: (%u)", signal_name, value); + DBG("USB connected ? (%s)", value & USBCLIENT_STATE_CONNECTED? "Yes":"No"); + DBG("USB available ? (%s)", value & USBCLIENT_STATE_AVAILABLE? "Yes":"No"); + + if (USBCLIENT_STATE_DISCONNECTED == value) { + _disable_usb_tethering(obj); + + if (g_context) { + dbus_g_method_return(g_context, MOBILE_AP_ENABLE_USB_TETHERING_CFM, + MOBILE_AP_ERROR_RESOURCE); + g_context = NULL; + } else { + _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_OFF, + SIGNAL_MSG_NOT_AVAIL_INTERFACE); + } + } + + usb_client_state = value; +} + +int _dbus_register_usb_state_change_signal(void *data) +{ + mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE; + GError *error = NULL; + +#if !GLIB_CHECK_VERSION(2,36,0) + g_type_init(); +#endif + + conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + if (error) { + ERR("Error occurred (%s)", error->message); + g_error_free(error); + ret = MOBILE_AP_ERROR_RESOURCE; + goto FAIL; + } + if (!conn) { + ERR("Failed to get gdbus connection"); + ret = MOBILE_AP_ERROR_RESOURCE; + goto FAIL; + } + + subscription_id = g_dbus_connection_signal_subscribe( + conn, NULL, USB_SYSTEM_DEVICE_IFACE, + USB_STATE_CHANGE_SIGNAL, USB_SYSTEM_DEVICE_PATH, NULL, + G_DBUS_SIGNAL_FLAGS_NONE, __usb_device_state_change_cb, + data, NULL); + + if (subscription_id == 0) { + ERR("Failed to subscribe signal (%d)", USB_STATE_CHANGE_SIGNAL); + ret = MOBILE_AP_ERROR_RESOURCE; + goto FAIL; + } + + usb_client_state = -1; + DBG("Successfully Subscribed USB State Signal Handler"); + return ret; + +FAIL: + if (conn) + g_object_unref(conn); + return ret; +} static void __handle_usb_disconnect_cb(keynode_t *key, void *data) { @@ -53,20 +155,33 @@ static void __handle_usb_disconnect_cb(keynode_t *key, void *data) 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); + SDBG("key = %s, value = %d(int)\n", vconf_name, vconf_key); - if (!strcmp(vconf_name, VCONFKEY_SYSMAN_USB_STATUS) && - vconf_key == VCONFKEY_SYSMAN_USB_DISCONNECTED) + /* + * P140305-02551: Disconnected State is implemented from DBUS instead of + * VCONF key. + */ + if (usb_client_state == USBCLIENT_STATE_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); + SDBG("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); + + if (g_context) { + dbus_g_method_return(g_context, + MOBILE_AP_ENABLE_USB_TETHERING_CFM, + MOBILE_AP_ERROR_RESOURCE); + g_context = NULL; + } else { + _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_OFF, + SIGNAL_MSG_NOT_AVAIL_INTERFACE); + } + + return; } static void __handle_usb_mode_change(keynode_t *key, void *data) @@ -79,6 +194,7 @@ static void __handle_usb_mode_change(keynode_t *key, void *data) TetheringObject *obj = (TetheringObject *)data; int ret; int vconf_key; + guint idle_id; if (vconf_keynode_get_type(key) != VCONF_TYPE_INT) { ERR("Invalid vconf key\n"); @@ -86,7 +202,7 @@ static void __handle_usb_mode_change(keynode_t *key, void *data) } vconf_key = vconf_keynode_get_int(key); - DBG("key = %s, value = %d(int)\n", + SDBG("key = %s, value = %d(int)\n", vconf_keynode_get_name(key), vconf_key); if (_mobileap_is_enabled(MOBILE_AP_STATE_USB)) { @@ -98,11 +214,6 @@ static void __handle_usb_mode_change(keynode_t *key, void *data) 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, @@ -110,13 +221,28 @@ static void __handle_usb_mode_change(keynode_t *key, void *data) 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); + if (g_context) { + dbus_g_method_return(g_context, + MOBILE_AP_ENABLE_USB_TETHERING_CFM, + MOBILE_AP_ERROR_RESOURCE); + g_context = NULL; + } + return; + } + _add_interface_routing(USB_IF, IP_ADDRESS_USB); + _add_routing_rule(USB_IF); + + _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_ON, NULL); + if (g_context) { + dbus_g_method_return(g_context, + MOBILE_AP_ENABLE_USB_TETHERING_CFM, + MOBILE_AP_ERROR_NONE); + g_context = NULL; } } else { if (vconf_key == SETTING_USB_TETHERING_MODE) { @@ -128,15 +254,21 @@ static void __handle_usb_mode_change(keynode_t *key, void *data) 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; + if (g_context) { + dbus_g_method_return(g_context, + MOBILE_AP_DISABLE_USB_TETHERING_CFM, + MOBILE_AP_ERROR_NONE); + g_context = NULL; + } + + in_progress = FALSE; + idle_id = g_idle_add(_terminate_mobileap_agent, NULL); + if (idle_id == 0) + ERR("g_idle_add is failed\n"); } } -mobile_ap_error_code_e _enable_usb_tethering(TetheringObject *obj, - DBusGMethodInvocation *context) +mobile_ap_error_code_e _enable_usb_tethering(TetheringObject *obj) { mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE; int vconf_ret; @@ -148,17 +280,15 @@ mobile_ap_error_code_e _enable_usb_tethering(TetheringObject *obj, return ret; } - if (obj->usb_context) { - ERR("USB request is progressing\n"); - ret = MOBILE_AP_ERROR_IN_PROGRESS; + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) { + ERR("Wi-Fi AP is enabled\n"); + ret = MOBILE_AP_ERROR_RESOURCE; 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"); + /* Register DBus Signal Handler for USB Client State */ + if (_dbus_register_usb_state_change_signal(obj) != MOBILE_AP_ERROR_NONE) { + ERR("Failed to register dbus signal(%d)", ret); ret = MOBILE_AP_ERROR_RESOURCE; goto FAIL; } @@ -168,19 +298,17 @@ mobile_ap_error_code_e _enable_usb_tethering(TetheringObject *obj, goto FAIL; } - if (!_init_tethering(obj)) { - ret = MOBILE_AP_ERROR_RESOURCE; + ret = _init_tethering(obj); + if (ret != MOBILE_AP_ERROR_NONE) { 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); @@ -189,17 +317,25 @@ mobile_ap_error_code_e _enable_usb_tethering(TetheringObject *obj, } if (usb_mode == SETTING_USB_TETHERING_MODE) { - obj->usb_context = NULL; vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT, __handle_usb_mode_change); + _add_interface_routing(USB_IF, IP_ADDRESS_USB); + _add_routing_rule(USB_IF); } DBG("-\n"); return MOBILE_AP_ERROR_NONE; FAIL: - vconf_ignore_key_changed(VCONFKEY_SYSMAN_USB_STATUS, - __handle_usb_disconnect_cb); + /* Clear DBus Signal Handler for USB Client State */ + if (conn) { + if (subscription_id > 0) { + g_dbus_connection_signal_unsubscribe(conn, subscription_id); + subscription_id = 0; + } + g_object_unref(conn); + conn = NULL; + } _mobileap_clear_state(MOBILE_AP_STATE_USB); return ret; @@ -221,12 +357,22 @@ mobile_ap_error_code_e _disable_usb_tethering(TetheringObject *obj) ERR("_remove_station_info_all is failed. Ignore it\n"); } + /* Clear DBus Signal Handler for USB Client State */ + if (conn) { + if (subscription_id > 0) { + g_dbus_connection_signal_unsubscribe(conn, subscription_id); + subscription_id = 0; + } + g_object_unref(conn); + conn = NULL; + } + 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); + _del_routing_rule(USB_IF); + _del_interface_routing(USB_IF, IP_ADDRESS_USB); DBG("_disable_usb_tethering is done\n"); @@ -237,31 +383,40 @@ gboolean tethering_enable_usb_tethering(TetheringObject *obj, DBusGMethodInvocation *context) { mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE; + gboolean ret_val = FALSE; DBG("+\n"); g_assert(obj != NULL); g_assert(context != NULL); + if (g_context) { + DBG("It is turnning on\n"); + dbus_g_method_return(context, + MOBILE_AP_ENABLE_USB_TETHERING_CFM, + MOBILE_AP_ERROR_IN_PROGRESS); + return FALSE; + } + + g_context = context; - ret = _enable_usb_tethering(obj, context); + ret = _enable_usb_tethering(obj); 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) { + goto DONE; + } else { 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"); + ret_val = TRUE; } - return TRUE; -} +DONE: + dbus_g_method_return(g_context, + MOBILE_AP_ENABLE_USB_TETHERING_CFM, ret); + g_context = NULL; + return ret_val; +} gboolean tethering_disable_usb_tethering(TetheringObject *obj, DBusGMethodInvocation *context) @@ -275,22 +430,24 @@ gboolean tethering_disable_usb_tethering(TetheringObject *obj, g_assert(obj != NULL); g_assert(context != NULL); - if (obj->usb_context) { - ERR("USB request is progressing\n"); - ret = MOBILE_AP_ERROR_IN_PROGRESS; + if (g_context) { + DBG("It is turnning on\n"); dbus_g_method_return(context, - MOBILE_AP_DISABLE_USB_TETHERING_CFM, ret); + MOBILE_AP_DISABLE_USB_TETHERING_CFM, + MOBILE_AP_ERROR_IN_PROGRESS); return FALSE; } + g_context = context; + ret = _disable_usb_tethering(obj); if (ret != MOBILE_AP_ERROR_NONE) { - dbus_g_method_return(context, + dbus_g_method_return(g_context, MOBILE_AP_DISABLE_USB_TETHERING_CFM, ret); + g_context = NULL; 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); @@ -298,11 +455,14 @@ gboolean tethering_disable_usb_tethering(TetheringObject *obj, 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; } + in_progress = TRUE; + DBG("-\n"); return TRUE; @@ -310,69 +470,14 @@ 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, + dbus_g_method_return(g_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); + g_context = NULL; return TRUE; } -gboolean tethering_get_usb_interface_info(TetheringObject *obj, - DBusGMethodInvocation *context) +gboolean _is_trying_usb_operation(void) { - 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; + return (g_context ? TRUE : FALSE || in_progress); } diff --git a/src/mobileap_wifi.c b/src/mobileap_wifi.c old mode 100644 new mode 100755 index fea6629..8f6d505 --- a/src/mobileap_wifi.c +++ b/src/mobileap_wifi.c @@ -22,261 +22,408 @@ #include #include #include -#include +#include +#include -#include "mobileap_agent.h" +#include "mobileap_softap.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) +#define WIFI_RECOVERY_GUARD_TIME 1000 /* ms */ + +static mobile_ap_error_code_e __update_softap_settings(softap_settings_t *st, + gchar *ssid, gchar *passphrase, int hide_mode, softap_security_type_e security_type); +static int __turn_off_wifi(TetheringObject *obj); + +static DBusGMethodInvocation *g_context = NULL; +static guint wifi_recovery_timeout_id = 0; +static gboolean prev_wifi_on = FALSE; +static wifi_saved_settings wifi_settings = {0, NULL, NULL, 0}; + +static void _wifi_direct_state_cb(int error_code, wifi_direct_device_state_e state, void *user_data) { + bool wifi_state = false; + DBG("+\n"); - guint32 rand_int; - int index; + if (user_data == NULL) { + ERR("The param is NULL\n"); + return; + } - for (index = 0; index < MOBILE_AP_WIFI_KEY_MIN_LEN; index++) { - rand_int = g_random_int_range('a', 'z'); - passphrase_buf[index] = rand_int; + TetheringObject *obj = (TetheringObject *)user_data; + int ret = 0; + + if (state != WIFI_DIRECT_DEVICE_STATE_DEACTIVATED) { + ERR("Unknown state : %d\n", state); + return; } - passphrase_buf[index] = '\0'; - return index; + wifi_direct_unset_device_state_changed_cb(); + wifi_direct_deinitialize(); + + if (error_code != 0) { + ERR("wifi_direct_deactivate fail in cb : %d\n", error_code); + ret = MOBILE_AP_ERROR_INTERNAL; + goto DONE; + } + DBG("Wi-Fi direct is turned off\n"); + + wifi_is_activated(&wifi_state); + if (wifi_state) { + DBG("Wi-Fi is turned on. Turn off Wi-Fi"); + if (__turn_off_wifi(obj) != MOBILE_AP_ERROR_NONE) { + ERR("_turn_off_wifi is failed\n"); + ret = MOBILE_AP_ERROR_INTERNAL; + goto DONE; + } + return; + } + + ret = _enable_wifi_tethering(obj, wifi_settings.ssid, wifi_settings.key, + wifi_settings.hide_mode, wifi_settings.security_type); + 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); + } + +DONE: + dbus_g_method_return(g_context, + MOBILE_AP_ENABLE_WIFI_TETHERING_CFM, ret); + g_context = NULL; + + g_free(wifi_settings.ssid); + g_free(wifi_settings.key); + memset(&wifi_settings, 0, sizeof(wifi_settings)); + + DBG("-\n"); + return; } -static mobile_ap_error_code_e __get_hide_mode(int *hide_mode) +static void __wifi_activated_cb(wifi_error_e result, void *user_data) { - if (hide_mode == NULL) { - ERR("Invalid param\n"); - return MOBILE_AP_ERROR_INVALID_PARAM; + DBG("Wi-Fi on is done\n"); + + return; +} + +static void __wifi_deactivated_cb(wifi_error_e result, void *user_data) +{ + DBG("+\n"); + + if (user_data == NULL) { + ERR("The param is NULL\n"); + return; } - if (vconf_get_int(VCONFKEY_MOBILE_HOTSPOT_HIDE, hide_mode) < 0) { - ERR("vconf_get_int is failed\n"); - return MOBILE_AP_ERROR_RESOURCE; + TetheringObject *obj = (TetheringObject *)user_data; + int ret; + + if (result != WIFI_ERROR_NONE) { + ERR("__wifi_deactivated_cb error : %d\n", result); + ret = MOBILE_AP_ERROR_INTERNAL; + goto DONE; } - return MOBILE_AP_ERROR_NONE; + DBG("Wi-Fi is turned off\n"); + + ret = _enable_wifi_tethering(obj, wifi_settings.ssid, wifi_settings.key, + wifi_settings.hide_mode, wifi_settings.security_type); + if (ret != MOBILE_AP_ERROR_NONE) { + ERR("_enable_wifi_tethering is failed\n"); + } else { + prev_wifi_on = TRUE; + _emit_mobileap_dbus_signal(obj, E_SIGNAL_WIFI_TETHER_ON, NULL); + } + +DONE: + dbus_g_method_return(g_context, + MOBILE_AP_ENABLE_WIFI_TETHERING_CFM, ret); + g_context = NULL; + + g_free(wifi_settings.ssid); + g_free(wifi_settings.key); + memset(&wifi_settings, 0, sizeof(wifi_settings)); + + DBG("-\n"); + return; } -static mobile_ap_error_code_e __set_hide_mode(const int hide_mode) +static int __turn_off_wifi(TetheringObject *obj) { - if (vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_HIDE, hide_mode) < 0) { - ERR("vconf_set_int is failed\n"); - return MOBILE_AP_ERROR_RESOURCE; + int ret; + + ret = wifi_deactivate(__wifi_deactivated_cb, (void *)obj); + if (ret != WIFI_ERROR_NONE) { + ERR("wifi_deactivate() is failed : %d\n", ret); + return MOBILE_AP_ERROR_INTERNAL; } return MOBILE_AP_ERROR_NONE; } -static mobile_ap_error_code_e __get_common_ssid(char *ssid, unsigned int size) +static gboolean __turn_on_wifi_timeout_cb(gpointer user_data) { - if (ssid == NULL) - return MOBILE_AP_ERROR_INVALID_PARAM; + int ret; + guint idle_id; - char *ptr = NULL; - char *ptr_tmp = NULL; + wifi_recovery_timeout_id = 0; - ptr = vconf_get_str(VCONFKEY_SETAPPL_DEVICE_NAME_STR); - if (ptr == NULL) - return MOBILE_AP_ERROR_RESOURCE; + ret = wifi_activate(__wifi_activated_cb, NULL); + if (ret != WIFI_ERROR_NONE) { + ERR("wifi_activate() is failed : %d\n", ret); + } - if (!g_utf8_validate(ptr, -1, (const char **)&ptr_tmp)) - *ptr_tmp = '\0'; + idle_id = g_idle_add(_terminate_mobileap_agent, NULL); + if (idle_id == 0) { + ERR("g_idle_add is failed\n"); + } - g_strlcpy(ssid, ptr, size); - free(ptr); + return FALSE; +} + +static int __turn_on_wifi(void) +{ + if (wifi_recovery_timeout_id > 0) { + g_source_remove(wifi_recovery_timeout_id); + wifi_recovery_timeout_id = 0; + } + + wifi_recovery_timeout_id = g_timeout_add(WIFI_RECOVERY_GUARD_TIME, + __turn_on_wifi_timeout_cb, NULL); + if (wifi_recovery_timeout_id == 0) { + ERR("g_timeout_add is failed\n"); + return MOBILE_AP_ERROR_INTERNAL; + } return MOBILE_AP_ERROR_NONE; } -static mobile_ap_error_code_e __get_security_type(char *security_type, unsigned int len) +static gboolean __is_wifi_direct_on(void) { - if (security_type == NULL) - return MOBILE_AP_ERROR_INVALID_PARAM; + int wifi_direct_state = 0; + int ret; - 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; + ret = vconf_get_int(VCONFKEY_WIFI_DIRECT_STATE, &wifi_direct_state); + if (ret < 0) { + ERR("vconf_get_int() is failed : %d\n", ret); + return FALSE; } - switch (type) { - case SOFTAP_SECURITY_TYPE_OPEN: - type_str = SOFTAP_SECURITY_TYPE_OPEN_STR; - break; + return wifi_direct_state != 0 ? TRUE : FALSE; +} - case SOFTAP_SECURITY_TYPE_WPA2_PSK: - type_str = SOFTAP_SECURITY_TYPE_WPA2_PSK_STR; - break; +static int __turn_off_wifi_direct(TetheringObject *obj) +{ + int ret; - default: - ERR("Invalid data\n"); - return MOBILE_AP_ERROR_RESOURCE; + ret = wifi_direct_initialize(); + if (ret < 0) { + ERR("wifi_direct_initialize() is failed : %d\n", ret); + return MOBILE_AP_ERROR_INTERNAL; + } + + ret = wifi_direct_set_device_state_changed_cb(_wifi_direct_state_cb, (void *)obj); + if (ret < 0) { + ERR("wifi_direct_set_device_state_changed_cb() is failed : %d\n", ret); + ret = wifi_direct_deinitialize(); + DBG("wifi_direct_deinitialize() ret : %d\n", ret); + return MOBILE_AP_ERROR_INTERNAL; } - g_strlcpy(security_type, type_str, len); + ret = wifi_direct_deactivate(); + if (ret < 0) { + ERR("wifi_direct_deactivate() is failed : %d\n", ret); + ret = wifi_direct_unset_device_state_changed_cb(); + DBG("wifi_direct_unset_device_state_changed_cb() ret : %d\n", ret); + ret = wifi_direct_deinitialize(); + DBG("wifi_direct_deinitialize() ret : %d\n", ret); + return MOBILE_AP_ERROR_INTERNAL; + } return MOBILE_AP_ERROR_NONE; } -static mobile_ap_error_code_e __set_security_type(const char *security_type) +static mobile_ap_error_code_e __update_softap_settings(softap_settings_t *st, + gchar *ssid, gchar *passphrase, int hide_mode, softap_security_type_e security_type) { - if (security_type == NULL) { + if (st == NULL) { ERR("Invalid param\n"); return MOBILE_AP_ERROR_INVALID_PARAM; } - softap_security_type_e type; + g_strlcpy(st->ssid, ssid, sizeof(st->ssid)); - 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; + if (security_type == SOFTAP_SECURITY_TYPE_WPA2_PSK) { + g_strlcpy(st->security_type, SOFTAP_SECURITY_TYPE_WPA2_PSK_STR, + sizeof(st->security_type)); + g_strlcpy(st->key, passphrase, sizeof(st->key)); + } else if (security_type == SOFTAP_SECURITY_TYPE_OPEN) { + g_strlcpy(st->security_type, SOFTAP_SECURITY_TYPE_OPEN_STR, + sizeof(st->security_type)); + g_strlcpy(st->key, "00000000", sizeof(st->key)); } else { - ERR("Invalid param\n"); - return MOBILE_AP_ERROR_INVALID_PARAM; + ERR("Unknown security type\n"); + return MOBILE_AP_ERROR_INTERNAL; } - if (vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_SECURITY, type) < 0) { - ERR("vconf_set_int is failed\n"); - return MOBILE_AP_ERROR_RESOURCE; - } + st->hide_mode = hide_mode; + + SDBG("ssid : %s security type : %s hide mode : %d\n", + st->ssid, st->security_type, st->hide_mode); return MOBILE_AP_ERROR_NONE; } -static mobile_ap_error_code_e __get_passphrase(char *passphrase, - unsigned int size, unsigned int *passphrase_len) +static gboolean __is_equal_softap_settings(softap_settings_t *a, softap_settings_t *b) { - if (passphrase == NULL || passphrase_len == NULL) { - ERR("Invalid parameter\n"); + if (a->hide_mode != b->hide_mode) + return FALSE; + + if (strcmp(a->ssid, b->ssid) != 0) + return FALSE; + + if (strcmp(a->key, b->key) != 0) + return FALSE; + + if (strcmp(a->security_type, b->security_type) != 0) + return FALSE; + + return TRUE; +} + +mobile_ap_error_code_e _reload_softap_settings(TetheringObject *obj, + gchar *ssid, gchar *key, gint hide_mode, gint security_type) +{ + gboolean backup_prev_wifi_on = prev_wifi_on; + mobile_ap_error_code_e ret; + softap_settings_t *old_settings = &obj->softap_settings; + softap_settings_t new_settings; + + if (obj == NULL || ssid == NULL || !strlen(ssid)) { + ERR("invalid parameters\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; - } + if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) + return MOBILE_AP_ERROR_NONE; - 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; + ret = __update_softap_settings(&new_settings, ssid, key, hide_mode, + (softap_security_type_e)security_type); + if (ret != MOBILE_AP_ERROR_NONE) { + ERR("__update_softap_settings is failed\n"); + return ret; } - 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; + if (__is_equal_softap_settings(&new_settings, old_settings) == TRUE) { + DBG("No need to reload settings\n"); + return MOBILE_AP_ERROR_NONE; + } + + prev_wifi_on = FALSE; + ret = _disable_wifi_tethering(obj); + + prev_wifi_on = backup_prev_wifi_on; + if (ret != MOBILE_AP_ERROR_NONE) { + ERR("_disable_wifi_tethering is failed : %d\n", ret); + return ret; + } + + ret = _enable_wifi_tethering(obj, ssid, key, hide_mode, + (softap_security_type_e)security_type); + if (ret != MOBILE_AP_ERROR_NONE) { + ERR("_enable_wifi_tethering is failed : %d\n", ret); + return ret; } + _emit_mobileap_dbus_signal(obj, E_SIGNAL_WIFI_TETHER_ON, NULL); return MOBILE_AP_ERROR_NONE; } -static mobile_ap_error_code_e __set_passphrase(const char *passphrase, const unsigned int size) +mobile_ap_error_code_e _reload_softap_settings_for_ap(TetheringObject *obj, + gchar *ssid, gchar *key, gint hide_mode, gint security_type) { - if (size < MOBILE_AP_WIFI_KEY_MIN_LEN || size > MOBILE_AP_WIFI_KEY_MAX_LEN || - passphrase == NULL) { - ERR("Invalid parameter\n"); + gboolean backup_prev_wifi_on = prev_wifi_on; + mobile_ap_error_code_e ret; + softap_settings_t *old_settings = &obj->softap_settings; + softap_settings_t new_settings; + + if (obj == NULL || ssid == NULL || !strlen(ssid)) { + ERR("invalid parameters\n"); return MOBILE_AP_ERROR_INVALID_PARAM; } - int ret = 0; + ret = __update_softap_settings(&new_settings, ssid, key, hide_mode, + (softap_security_type_e)security_type); + if (ret != MOBILE_AP_ERROR_NONE) { + ERR("__update_softap_settings is failed\n"); + return ret; + } - 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; + if (__is_equal_softap_settings(&new_settings, old_settings) == TRUE) { + DBG("No need to reload settings\n"); + return MOBILE_AP_ERROR_NONE; + } + + prev_wifi_on = FALSE; + + ret = _disable_wifi_ap(obj); + prev_wifi_on = backup_prev_wifi_on; + if (ret != MOBILE_AP_ERROR_NONE) { + ERR("_disable_wifi_ap is failed : %d\n", ret); + return ret; + } + + ret = _enable_wifi_ap(obj, ssid, key, hide_mode, + (softap_security_type_e)security_type); + if (ret != MOBILE_AP_ERROR_NONE) { + ERR("_enable_wifi_ap is failed : %d\n", ret); + return ret; } return MOBILE_AP_ERROR_NONE; } -static gboolean __send_station_event_cb(gpointer data) +int _get_wifi_name_from_lease_info(const char *mac, char **name_buf) { - 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 (mac == NULL || name_buf == NULL) { + return MOBILE_AP_ERROR_INVALID_PARAM; } - 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); + GIOChannel *io = NULL; + char *line = NULL; + char *device_name = MOBILE_AP_NAME_UNKNOWN; + char ip_addr[MOBILE_AP_STR_INFO_LEN] = {0, }; + char mac_addr[MOBILE_AP_STR_INFO_LEN] = {0, }; + char name[MOBILE_AP_STR_HOSTNAME_LEN] = {0, }; + char expire[MOBILE_AP_STR_INFO_LEN] = {0, }; + char extra[MOBILE_AP_STR_INFO_LEN] = {0, }; - _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); + io = g_io_channel_new_file(DNSMASQ_LEASES_FILE, "r", NULL); + if (io == NULL) { + return MOBILE_AP_ERROR_RESOURCE; } - return FALSE; -} + 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); + g_free(line); -static void __handle_station_signal(int sig) -{ - g_idle_add(__send_station_event_cb, GINT_TO_POINTER(sig)); - return; -} + if (g_ascii_strcasecmp(mac_addr, mac) == 0) { + if (g_strcmp0(name, "*") != 0) + device_name = name; + break; + } + } + g_io_channel_unref(io); -void _register_wifi_station_handler(void) -{ - struct sigaction sa; + *name_buf = g_strdup(device_name); - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = __handle_station_signal; - sigaction(SIGUSR1, &sa, NULL); - sigaction(SIGUSR2, &sa, NULL); + return MOBILE_AP_ERROR_NONE; } void _add_wifi_device_to_array(softap_device_info_t *di, GPtrArray *array) @@ -294,7 +441,7 @@ void _add_wifi_device_to_array(softap_device_info_t *di, GPtrArray *array) int found = 0; for (i = 0; i < di->number; i++) - DBG("bssid[%d]:%s\n", i, di->bssid[i]); + SDBG("bssid[%d]:%s\n", i, di->bssid[i]); DBG("Number of connected device:%d\n", di->number); @@ -304,7 +451,7 @@ void _add_wifi_device_to_array(softap_device_info_t *di, GPtrArray *array) 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, + SDBG("mac_addr:%s ip_addr:%s name:%s expire:%s\n", mac_addr, ip_addr, name, expire); for (i = 0; i < di->number; i++) { @@ -334,10 +481,27 @@ void _add_wifi_device_to_array(softap_device_info_t *di, GPtrArray *array) } } -mobile_ap_error_code_e _enable_wifi_tethering(TetheringObject *obj, gchar *ssid) +mobile_ap_error_code_e _enable_wifi_tethering(TetheringObject *obj, gchar *ssid, + gchar *passphrase, int hide_mode, softap_security_type_e security_type) { mobile_ap_error_code_e ret; + if (obj == NULL || ssid == NULL || !strlen(ssid)) { + ERR("invalid parameters\n"); + return MOBILE_AP_ERROR_INVALID_PARAM; + } + + if (security_type == SOFTAP_SECURITY_TYPE_WPA2_PSK && passphrase == NULL) { + ERR("passphrase is null\n"); + return MOBILE_AP_ERROR_INVALID_PARAM; + } + + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) { + ERR("Wi-Fi AP is already enabled\n"); + ret = MOBILE_AP_ERROR_RESOURCE; + return ret; + } + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) { ERR("Wi-Fi tethering is already enabled\n"); ret = MOBILE_AP_ERROR_ALREADY_ENABLED; @@ -351,121 +515,272 @@ mobile_ap_error_code_e _enable_wifi_tethering(TetheringObject *obj, gchar *ssid) } /* Update Wi-Fi hotspot data to common object */ - ret = __update_wifi_data(obj); + ret = __update_softap_settings(&obj->softap_settings, ssid, passphrase, + hide_mode, security_type); 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)); + if (vconf_set_str(VCONFKEY_MOBILE_HOTSPOT_SSID, + obj->softap_settings.ssid) < 0) { + ERR("vconf_set_str is failed\n"); } /* Initialize tethering */ - if (!_init_tethering(obj)) { + _block_device_sleep(); + ret = _init_tethering(obj); + if (ret != MOBILE_AP_ERROR_NONE) { _mobileap_clear_state(MOBILE_AP_STATE_WIFI); - ret = MOBILE_AP_ERROR_RESOURCE; - return ret; + goto DONE; } /* Upload driver */ - ret = _mh_core_enable_softap(obj->ssid, obj->security_type, - obj->key, obj->hide_mode); + ret = _mh_core_enable_softap(MOBILE_AP_TYPE_WIFI, + obj->softap_settings.ssid, + obj->softap_settings.security_type, + obj->softap_settings.key, + obj->softap_settings.hide_mode); if (ret != MOBILE_AP_ERROR_NONE) { _deinit_tethering(obj); _mobileap_clear_state(MOBILE_AP_STATE_WIFI); + goto DONE; + } + _delete_timeout_noti(); + + _init_timeout_cb(MOBILE_AP_TYPE_WIFI, (void *)obj); + _start_timeout_cb(MOBILE_AP_TYPE_WIFI, time(NULL) + TETHERING_CONN_TIMEOUT); + + _add_interface_routing(WIFI_IF, IP_ADDRESS_SOFTAP); + _add_routing_rule(WIFI_IF); + +DONE: + _unblock_device_sleep(); + return ret; +} + +mobile_ap_error_code_e _enable_wifi_ap(TetheringObject *obj, + gchar *ssid, gchar *passphrase, int hide_mode, + softap_security_type_e security_type) +{ + mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE; + + if (obj == NULL || ssid == NULL || !strlen(ssid)) { + ERR("invalid parameters\n"); + return MOBILE_AP_ERROR_INVALID_PARAM; + } + + if (security_type == SOFTAP_SECURITY_TYPE_WPA2_PSK && + (passphrase == NULL || strlen(passphrase) >= MOBILE_AP_WIFI_KEY_MAX_LEN)) { + ERR("hex key length is not correct\n"); + return MOBILE_AP_ERROR_INVALID_PARAM; + } + + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI | MOBILE_AP_STATE_BT + | MOBILE_AP_STATE_USB)) { + ERR("Tethering is already enabled\n"); + return MOBILE_AP_ERROR_RESOURCE; + } + + if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) { + ERR("Wi-Fi AP is already enabled\n"); + return MOBILE_AP_ERROR_ALREADY_ENABLED; + } + + if (!_mobileap_set_state(MOBILE_AP_STATE_WIFI_AP)) { + return MOBILE_AP_ERROR_RESOURCE; + } + + ret = __update_softap_settings(&obj->softap_settings, ssid, passphrase, + hide_mode, security_type); + if (ret != MOBILE_AP_ERROR_NONE) { + _mobileap_clear_state(MOBILE_AP_STATE_WIFI_AP); return ret; } + _block_device_sleep(); + + if (_init_tethering(obj) != MOBILE_AP_ERROR_NONE) { + _mobileap_clear_state(MOBILE_AP_STATE_WIFI_AP); + ret = MOBILE_AP_ERROR_RESOURCE; + goto DONE; + } + + /* Upload driver */ + ret = _mh_core_enable_softap(MOBILE_AP_TYPE_WIFI_AP, + obj->softap_settings.ssid, + obj->softap_settings.security_type, + obj->softap_settings.key, + obj->softap_settings.hide_mode); + if (ret != MOBILE_AP_ERROR_NONE) { + _deinit_tethering(obj); + _mobileap_clear_state(MOBILE_AP_STATE_WIFI_AP); + goto DONE; + } + _delete_timeout_noti(); - _init_timeout_cb(MOBILE_AP_TYPE_WIFI, (void *)obj); - _start_timeout_cb(MOBILE_AP_TYPE_WIFI); + _init_timeout_cb(MOBILE_AP_TYPE_WIFI_AP, (void *)obj); + _start_timeout_cb(MOBILE_AP_TYPE_WIFI_AP, time(NULL) + WIFI_AP_CONN_TIMEOUT); + _add_interface_routing(WIFI_IF, IP_ADDRESS_SOFTAP); + _add_routing_rule(WIFI_IF); - return MOBILE_AP_ERROR_NONE; +DONE: + _unblock_device_sleep(); + return ret; } mobile_ap_error_code_e _disable_wifi_tethering(TetheringObject *obj) { - int ret = MOBILE_AP_ERROR_NONE; + int ret; + int state; + mobile_ap_type_e type; + + type = MOBILE_AP_TYPE_WIFI; + state = MOBILE_AP_STATE_WIFI; - if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI)) { - ERR("Wi-Fi tethering has not been activated\n"); + if (!_mobileap_is_enabled(state)) { + ERR("Wi-Fi tethering ap has not been activated\n"); ret = MOBILE_AP_ERROR_NOT_ENABLED; return ret; } - _deinit_timeout_cb(MOBILE_AP_TYPE_WIFI); + _block_device_sleep(); + _del_routing_rule(WIFI_IF); + _del_interface_routing(WIFI_IF, IP_ADDRESS_SOFTAP); + _flush_ip_address(WIFI_IF); + _deinit_timeout_cb(type); - if (_remove_station_info_all(MOBILE_AP_TYPE_WIFI) != - MOBILE_AP_ERROR_NONE) { + if (_remove_station_info_all(type) != 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; + goto DONE; } _deinit_tethering(obj); - _mobileap_clear_state(MOBILE_AP_STATE_WIFI); + _mobileap_clear_state(state); + if (prev_wifi_on == TRUE) { + DBG("Previous Wi-Fi was turned on. Recover it\n"); + if (__turn_on_wifi() != MOBILE_AP_ERROR_NONE) { + ERR("__turn_on_wifi() is failed\n"); + } + prev_wifi_on = FALSE; + } DBG("_disable_wifi_tethering is done\n"); +DONE: + _unblock_device_sleep(); return ret; } -static mobile_ap_error_code_e __update_wifi_data(TetheringObject *obj) +mobile_ap_error_code_e _disable_wifi_ap(TetheringObject *obj) { - if (obj == NULL) { - ERR("Invalid param\n"); - return MOBILE_AP_ERROR_INVALID_PARAM; - } + int ret; + int state; + mobile_ap_type_e type; - mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE; - unsigned int read_len = 0; + type = MOBILE_AP_TYPE_WIFI_AP; + state = MOBILE_AP_STATE_WIFI_AP; - ret = __get_common_ssid(obj->ssid, sizeof(obj->ssid)); - if (ret != MOBILE_AP_ERROR_NONE) + if (!_mobileap_is_enabled(state)) { + ERR("Wi-Fi ap tethering has not been activated\n"); + ret = MOBILE_AP_ERROR_NOT_ENABLED; return ret; + } - ret = __get_security_type(obj->security_type, sizeof(obj->security_type)); - if (ret != MOBILE_AP_ERROR_NONE) - return ret; + _block_device_sleep(); + _del_routing_rule(WIFI_IF); + _del_interface_routing(WIFI_IF, IP_ADDRESS_SOFTAP); + _flush_ip_address(WIFI_IF); + _deinit_timeout_cb(type); - ret = __get_hide_mode(&obj->hide_mode); - if (ret != MOBILE_AP_ERROR_NONE) - return ret; + if (_remove_station_info_all(type) != MOBILE_AP_ERROR_NONE) { + ERR("_remove_station_info_all is failed. Ignore it.\n"); + } - 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; + ret = _mh_core_disable_softap(); + if (ret != MOBILE_AP_ERROR_NONE) { + ERR("_mh_core_disable_softap is failed : %d\n", ret); + goto DONE; } - DBG("ssid : %s security type : %s hide mode : %d\n", - obj->ssid, obj->security_type, obj->hide_mode); + _deinit_tethering(obj); + _mobileap_clear_state(state); + + DBG("_disable_wifi_ap is done\n"); - return MOBILE_AP_ERROR_NONE; +DONE: + _unblock_device_sleep(); + return ret; } gboolean tethering_enable_wifi_tethering(TetheringObject *obj, gchar *ssid, - gchar *key, gint hide_mode, DBusGMethodInvocation *context) + gchar *key, gint visibility, gint security_type, + DBusGMethodInvocation *context) { mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE; gboolean ret_val = FALSE; + bool wifi_state = false; + DBG("+\n"); g_assert(obj != NULL); g_assert(context != NULL); + if (g_context) { + DBG("It is turnning on\n"); + dbus_g_method_return(context, + MOBILE_AP_ENABLE_WIFI_TETHERING_CFM, + MOBILE_AP_ERROR_IN_PROGRESS); + return FALSE; + } + + g_context = context; + + wifi_settings.ssid = g_strdup(ssid); + if (security_type == SOFTAP_SECURITY_TYPE_WPA2_PSK) { + wifi_settings.key = g_strdup(key); + wifi_settings.security_type = SOFTAP_SECURITY_TYPE_WPA2_PSK; + } else { + wifi_settings.security_type = SOFTAP_SECURITY_TYPE_OPEN; + } + wifi_settings.hide_mode = (!visibility); + + if (wifi_recovery_timeout_id) { + DBG("Wi-Fi recovery is cancelled\n"); + g_source_remove(wifi_recovery_timeout_id); + wifi_recovery_timeout_id = 0; + prev_wifi_on = TRUE; + } + + if (__is_wifi_direct_on() == TRUE) { + DBG("Wi-Fi and Wi-Fi direct are turned on\n"); + if (__turn_off_wifi_direct(obj) != MOBILE_AP_ERROR_NONE) { + ERR("_turn_off_wifi_direct is failed\n"); + ret = MOBILE_AP_ERROR_INTERNAL; + goto DONE; + } + + return TRUE; + } + + wifi_is_activated(&wifi_state); + if (wifi_state == true) { + DBG("Wi-Fi is turned on\n"); + if (__turn_off_wifi(obj) != MOBILE_AP_ERROR_NONE) { + ERR("_turn_off_wifi is failed\n"); + ret = MOBILE_AP_ERROR_INTERNAL; + goto DONE; + } - ret = _enable_wifi_tethering(obj, ssid); + return TRUE; + } + + ret = _enable_wifi_tethering(obj, ssid, key, !visibility, + (softap_security_type_e)security_type); if (ret != MOBILE_AP_ERROR_NONE) { ERR("_enable_wifi_tethering is failed\n"); } else { @@ -473,12 +788,18 @@ gboolean tethering_enable_wifi_tethering(TetheringObject *obj, gchar *ssid, ret_val = TRUE; } - dbus_g_method_return(context, MOBILE_AP_ENABLE_WIFI_TETHERING_CFM, ret); +DONE: + dbus_g_method_return(g_context, + MOBILE_AP_ENABLE_WIFI_TETHERING_CFM, ret); + g_context = NULL; + + g_free(wifi_settings.ssid); + g_free(wifi_settings.key); + memset(&wifi_settings, 0, sizeof(wifi_settings)); return ret_val; } - gboolean tethering_disable_wifi_tethering(TetheringObject *obj, DBusGMethodInvocation *context) { @@ -499,183 +820,100 @@ gboolean tethering_disable_wifi_tethering(TetheringObject *obj, return TRUE; } -gboolean tethering_get_wifi_tethering_hide_mode(TetheringObject *obj, - DBusGMethodInvocation *context) +gboolean tethering_enable_wifi_ap(TetheringObject *obj, gchar *ssid, gchar *key, + gint visibility, gint security_type, DBusGMethodInvocation *context) { mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE; - int hide_mode = 0; + gboolean ret_val = FALSE; 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); + if (wifi_recovery_timeout_id) { + DBG("Wi-Fi recovery is cancelled\n"); + g_source_remove(wifi_recovery_timeout_id); + wifi_recovery_timeout_id = 0; } - 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); + ret = _enable_wifi_ap(obj, ssid, key, !visibility, + (softap_security_type_e)security_type); 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); + ERR("_enable_wifi_tethering is failed\n"); + } else { + _emit_mobileap_dbus_signal(obj, E_SIGNAL_WIFI_AP_ON, NULL); + ret_val = TRUE; } - _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); + dbus_g_method_return(context, MOBILE_AP_ENABLE_WIFI_AP_CFM, ret); - return TRUE; + return ret_val; } -gboolean tethering_get_wifi_tethering_ssid(TetheringObject *obj, +gboolean tethering_disable_wifi_ap(TetheringObject *obj, DBusGMethodInvocation *context) { - mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE; - char ssid[MOBILE_AP_WIFI_SSID_MAX_LEN + 1] = {0, }; + int ret = MOBILE_AP_ERROR_NONE; 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); - } - } + ret = _disable_wifi_ap(obj); - dbus_g_method_return(context, ssid); + _emit_mobileap_dbus_signal(obj, E_SIGNAL_WIFI_AP_OFF, NULL); + dbus_g_method_return(context, MOBILE_AP_DISABLE_WIFI_AP_CFM, ret); + + if (ret != MOBILE_AP_ERROR_NONE) + return FALSE; return TRUE; } -gboolean tethering_get_wifi_tethering_security_type(TetheringObject *obj, +gboolean tethering_reload_wifi_settings(TetheringObject *obj, gchar *ssid, + gchar *key, gint visibility, gint security_type, DBusGMethodInvocation *context) { mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE; - char security_type[SECURITY_TYPE_LEN] = {0, }; + gboolean ret_val = TRUE; DBG("+\n"); g_assert(obj != NULL); g_assert(context != NULL); - ret = __get_security_type(security_type, sizeof(security_type)); + ret = _reload_softap_settings(obj, ssid, key, !visibility, security_type); if (ret != MOBILE_AP_ERROR_NONE) { - ERR("__get_security_type is failed : %d\n", ret); + ERR("_reload_softap_settings is failed\n"); + ret_val = FALSE; } - dbus_g_method_return(context, security_type); + dbus_g_method_return(context, ret); - return TRUE; + return ret_val; } -gboolean tethering_set_wifi_tethering_security_type(TetheringObject *obj, - gchar *security_type, DBusGMethodInvocation *context) +gboolean tethering_reload_wifi_ap_settings(TetheringObject *obj, gchar *ssid, + gchar *key, gint visibility, gint security, 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; + gboolean ret_val = TRUE; DBG("+\n"); g_assert(obj != NULL); g_assert(context != NULL); - ret = __get_passphrase(passphrase, sizeof(passphrase), &len); + ret = _reload_softap_settings_for_ap(obj, ssid, key, !visibility, security); if (ret != MOBILE_AP_ERROR_NONE) { - len = 0; - ERR("__get_password is failed : %d\n", ret); + ERR("_reload_softap_settings_for_ap is failed\n"); + ret_val = FALSE; } - dbus_g_method_return(context, passphrase, len); - - return TRUE; + dbus_g_method_return(context, ret); + return ret_val; } -gboolean tethering_set_wifi_tethering_passphrase(TetheringObject *obj, - gchar *passphrase, guint len, DBusGMethodInvocation *context) +gboolean _is_trying_wifi_operation(void) { - 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; + return (g_context || wifi_recovery_timeout_id ? TRUE : FALSE); } diff --git a/tethering_dump.sh b/tethering_dump.sh new file mode 100644 index 0000000..887c55f --- /dev/null +++ b/tethering_dump.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# +# Tethering module log dump (tethering_dump.sh) +# + +# Variables +TETH_DEBUG=$1/tethering +mkdir -p ${TETH_DEBUG} + +# copy files +#/bin/cp -a /tmp/hostapd.log ${TETH_DEBUG} +/bin/cp -rf /tmp/dnsmasq.conf /opt/var/lib/misc/* ${TETH_DEBUG} + +#vconftool get db/mobile_hotspot > ${TETH_DEBUG}/vconf_db.log +#vconftool get memory/mobile_hotspot > ${TETH_DEBUG}/vconf_memory.log +/usr/sbin/iptables -t nat -L -vv > ${TETH_DEBUG}/iptables_nat.log +/usr/sbin/iptables -L -vv > ${TETH_DEBUG}/iptables_filter.log