From: venkat-iyer Date: Wed, 26 Feb 2025 05:53:04 +0000 (+0900) Subject: Add tethering extension for p2p repeater X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9dd19cf87c789ee717fc64d6ccaec62415db1187;p=platform%2Fcore%2Fapi%2Ftethering.git Add tethering extension for p2p repeater Change-Id: I4ab5e0a137e634ce9b4af4e3dae038b6cf2a3e3b Signed-off-by: venkat-iyer --- diff --git a/include/tethering_ext.h b/include/tethering_ext.h new file mode 100644 index 0000000..af6e08b --- /dev/null +++ b/include/tethering_ext.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025 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 __TIZEN_NETWORK_TETHERING_EXT_H +#define __TIZEN_NETWORK_TETHERING_EXT_H + +#include +#include + +#define RET_ERR_IF_HANDLE_IS_NOT_VALID_OR_NOT_INITIALIZED(arg) \ + do { \ + if (!arg) { \ + LOGE("Tethering context is null"); \ + return TETHERING_ERROR_INVALID_PARAMETER; \ + } \ + if (!_tethering_ext_check_context(arg)) { \ + LOGE("Tethering context is not initialized"); \ + return TETHERING_ERROR_INVALID_PARAMETER; \ + } \ + } while (0) + + +int tethering_ext_initialize(tethering_ext_h *th_context); +int tethering_ext_deinitialize(tethering_ext_h th_context); +int tethering_ext_activate(tethering_ext_h th_context); +int tethering_ext_deactivate(tethering_ext_h th_context); +int tethering_ext_is_enabled(tethering_ext_h th_context, bool *is_enabled); +int tethering_ext_set_configuration(tethering_ext_h th_context, tethering_ext_config_h *src_config, int config_flags); +int tethering_ext_set_ssid(tethering_ext_h th_context, const char *ssid); +int tethering_ext_set_passphrase(tethering_ext_h th_context, const char *passphrase); +int tethering_ext_set_channel(tethering_ext_h th_context, int channel); +int tethering_ext_get_tethering_info(tethering_ext_h th_context, void **tethering_info); +int tethering_ext_get_channel(tethering_ext_h th_context, int *channel); +int tethering_ext_get_security(tethering_ext_h th_context, int *security); +int tethering_ext_get_visibility(tethering_ext_h th_context, int *visibility); +int tethering_ext_get_sharing(tethering_ext_h th_context, bool *sharing); + +#endif /* __TIZEN_NETWORK_TETHERING_EXT_H */ diff --git a/include/tethering_ext_common.h b/include/tethering_ext_common.h new file mode 100644 index 0000000..43e880a --- /dev/null +++ b/include/tethering_ext_common.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025 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 __TIZEN_NETWORK_TETHERING_EXT_COMMON_H +#define __TIZEN_NETWORK_TETHERING_EXT_COMMON_H +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define TETHERING_EXT_WIFI_SSID_MAX_LEN 32 +#define TETHERING_EXT_WIFI_KEY_MAX_LEN 64 +#define TETHERING_EXT_IPV4_ADDRESS_MAX_LEN 15 + +typedef void *tethering_ext_h; + +typedef enum { + TETHERING_EXT_SSID = 1, + TETHERING_EXT_PASSPHRASE = 2, + TETHERING_EXT_SECURITY_TYPE = 4, + TETHERING_EXT_CHANNEL = 8, + TETHERING_EXT_VISIBLE = 16, + TETHERING_EXT_SHARED = 32, + TETHERING_EXT_ALL = 63 +} tethering_ext_config_e; + +typedef struct { + char ssid[TETHERING_EXT_WIFI_SSID_MAX_LEN + 1]; + char passphrase[TETHERING_EXT_WIFI_KEY_MAX_LEN + 1]; + int security_type; + int mode_type; + bool visibility; + bool wifi_sharing; + int channel; + int wifi_max_connected; + char ipaddr[TETHERING_EXT_IPV4_ADDRESS_MAX_LEN + 1]; +} tethering_ext_config_h; + +#ifdef __cplusplus +} +#endif + + +#endif /* __TIZEN_NETWORK_TETHERING_EXT_COMMON_H */ diff --git a/include/tethering_ext_dbus.h b/include/tethering_ext_dbus.h new file mode 100644 index 0000000..ebd5d5f --- /dev/null +++ b/include/tethering_ext_dbus.h @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 __TIZEN_TETHERING_EXT_DBUS_H_ +#define __TIZEN_TETHERING_EXT_DBUS_H_ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* tethering-service */ +#define TETHERING_EXT_BUS_NAME "net.wifitethering" +#define TETHERING_EXT_OBJECT_PATH "/net/wifitethering" +#define TETHERING_EXT_INTERFACE_NAME TETHERING_EXT_BUS_NAME ".interface" + +#define TETHERING_EXT_METHOD_SET_MODE "SetWiFiTetheringMode" +#define TETHERING_EXT_METHOD_SET_MODE_WITH_PARAMS "SetWiFiTetheringModeWithParams" +#define TETHERING_EXT_METHOD_GET_MODE "GetWiFiTetheringMode" +#define TETHERING_EXT_METHOD_GET_INFO "GetWiFiTetheringInfo" + +#define SIGNAL_TETHERING_EXT_MODE_CHANGED "WiFiTetheringModeChanged" +#define SIGNAL_TETHERING_EXT_ENABLED "WiFiTetheringEnabled" +#define SIGNAL_TETHERING_EXT_DISABLED "WiFiTetheringDisabled" +#define SIGNAL_TETHERING_CONNECTION_CHANGED "WiFiTetheringConnectionChanged" + +/* ntc-service */ +#define NTC_BUS_NAME "net.ntc.service" +#define NTC_DBUS_OBJECT_PATH "/net/ntc/service" +#define NTC_DBUS_ITNERFACE_NAME "net.ntc.service.interface" + +/* Common */ +#define TETHERING_EXT_SIGNAL_NAME_LEN 64 + +GVariant *_invoke_dbus_method(_tethering_ext_h *tethering_ctx, const char *dest, const char *path, const char *interface_name, + const char *method, GVariant *params, int *dbus_error); + +int _tethering_ext_dbus_set_wifi_tethering_mode(_tethering_ext_h *tethering_ctx, bool enable); +int _tethering_ext_dbus_set_wifi_tethering_mode_with_params(_tethering_ext_h *tethering_ctx, bool enable); +int _tethering_ext_dbus_get_wifi_tethering_state(_tethering_ext_h *tethering_ctx, _tethering_ext_state_e *tethering_state); +int _tethering_ext_dbus_get_wifi_tethering_info(_tethering_ext_h *tethering_ctx, _tethering_ext_tethering_info *tethering_info); + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_TETHERING_EXT_DBUS_H_ */ + diff --git a/include/tethering_ext_internal.h b/include/tethering_ext_internal.h new file mode 100644 index 0000000..a25b793 --- /dev/null +++ b/include/tethering_ext_internal.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2025 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 __TIZEN_NETWORK_TETHERING_EXT_INTERNAL_H +#define __TIZEN_NETWORK_TETHERING_EXT_INTERNAL_H +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef API +#define API __attribute__ ((visibility("default"))) +#endif + +#define TETHERING_EXT_STR_INFO_LEN 40 + +typedef enum { + TETHERING_EXT_STATE_DISABLED = 0, + TETHERING_EXT_STATE_ENABLED = 1 +} _tethering_ext_state_e; + +typedef enum { + TETHERING_EXT_POWER_IND = 0 +} _tethering_ext_event_e; + +// Maps in value to tethering_disabled_cause_e +typedef enum { + TETHERING_EXT_DISABLED_BY_FLIGHT_MODE = 1, /**< Disabled due to flight mode */ + TETHERING_EXT_DISABLED_BY_LOW_BATTERY, /**< Disabled due to low battery */ + TETHERING_EXT_DISABLED_BY_NETWORK_CLOSE, /**< Disabled due to pdp network close */ + TETHERING_EXT_DISABLED_BY_TIMEOUT, /**< Disabled due to timeout */ + TETHERING_EXT_DISABLED_BY_OTHERS, /**< Disabled by other apps */ + TETHERING_EXT_DISABLED_BY_REQUEST, /**< Disabled by your request */ + TETHERING_EXT_DISABLED_BY_WIFI_ON, /**< Disabled due to Wi-Fi on */ +} _tethering_ext_disabled_cause_e; + +typedef enum { + TETHERING_EXT_ERR_NONE = 0x00, /** No error */ + + /* Common Error value */ + TETHERING_EXT_ERR_UNKNOWN = -999, /** Error unknown */ + + /* Client Register related Errors used in API return */ + TETHERING_EXT_ERR_APP_ALREADY_REGISTERED = -990, /** Application is already registered */ + TETHERING_EXT_ERR_APP_NOT_REGISTERED = -989, /** Application is not registered */ + + /* Other Error */ + TETHERING_EXT_ERR_ACCESS_DENIED = -799, /** Access(permission) denied */ + TETHERING_EXT_ERR_IN_PROGRESS = -798, /** Operation is in progress */ + TETHERING_EXT_ERR_OPERATION_ABORTED = -797, /** Operation was aborted by client or network*/ + TETHERING_EXT_ERR_INVALID_PARAM = -796, /** Invalid value of API parameter */ + TETHERING_EXT_ERR_INVALID_OPERATION = -795, /** Invalid operation depending on current state */ + TETHERING_EXT_ERR_NOT_SUPPORTED = -794, /** Feature not supported */ + TETHERING_EXT_ERR_TIME_OUT = -793, /** TimeOut Error */ + TETHERING_EXT_ERR_UNKNOWN_METHOD = -792, /** DBus can't find appropriate method */ + TETHERING_EXT_ERR_ALREADY_EXISTS = -791, /** Already exists */ + TETHERING_EXT_ERR_OUT_OF_MEMORY = -790, /** Failed to allocate memory */ + TETHERING_EXT_ERR_SERVICE_UNKNOWN = -789, /** DBus service is unknown */ + TETHERING_EXT_ERR_OPERATION_FAILED = -788, /** Operation failed */ + TETHERING_EXT_ERR_NOT_SET = -787, /** Not Set */ +} _tethering_ext_err_e; + + + +typedef struct { + _tethering_ext_event_e Event; + _tethering_ext_err_e Error; + int Datalength; + void *Data; +} _tethering_ext_event_info_h; + +typedef struct { + char *tethering_ssid; + char *tethering_password; +} _tethering_ext_tethering_info; + +typedef struct { + char ip[TETHERING_EXT_STR_INFO_LEN]; /**< assigned IP address */ + char mac[TETHERING_EXT_STR_INFO_LEN]; /**< MAC Address */ + char *hostname; + time_t tm; +} _tethering_ext_client_info_h; + + +typedef void *_tethering_ext_client_h; +typedef void (*_tethering_ext_enabled_cb) (tethering_error_e result, bool is_requested, void *user_data); +typedef void (*_tethering_ext_disabled_cb) (tethering_error_e result, _tethering_ext_disabled_cause_e cause, void *user_data); +typedef void (*_tethering_ext_connection_state_changed_cb) (_tethering_ext_client_h client, bool opened, void *user_data); + +// Tethering state callbacks +typedef void(*_tethering_ext_state_changed_cb)(_tethering_ext_state_e state, void *user_data); +typedef void (*_tethering_ext_event_cb) (const _tethering_ext_event_info_h *tethering_ext_event, void *user_data); + +typedef struct { + _tethering_ext_enabled_cb enabled_cb; + void *enabled_user_data; + _tethering_ext_disabled_cb disabled_cb; + void *disabled_user_data; + _tethering_ext_connection_state_changed_cb changed_cb; + void *changed_user_data; +} _tethering_ext_callback_h; + +typedef struct { + GDBusConnection *tethering_ext_client; + GCancellable *tethering_ext_cancellable; + guint subscribe_id_wifi_tethering_state; + _tethering_ext_state_e tethering_ext_state; + _tethering_ext_state_changed_cb tethering_ext_state_changed_cb; + void *tethering_ext_state_changed_user_data; + _tethering_ext_event_cb tethering_ext_event_cb; + void *tethering_ext_user_data; + tethering_ext_config_h tethering_ext_config; + _tethering_ext_callback_h *tethering_ext_callbacks; +} _tethering_ext_h; + +int _tethering_ext_create_context(tethering_ext_h *tethering_context); +void _tethering_ext_destroy_context(tethering_ext_h tethering_context); +bool _tethering_ext_check_context(tethering_ext_h tethering_context); +void _tethering_ext_add_context(tethering_ext_h *tethering_context); +void _tethering_ext_remove_context(tethering_ext_h tethering_context); +int _tethering_ext_register_dbus(tethering_ext_h tethering_context); +void _tethering_ext_unregister_dbus(tethering_ext_h tethering_context); +int _tethering_ext_set_wifi_tethering_mode(tethering_ext_h tethering_context, bool enable); +int _tethering_ext_set_wifi_tethering_mode_with_params(tethering_ext_h tethering_context, bool enable); +int _tethering_ext_get_wifi_tethering_mode(tethering_ext_h tethering_context, bool *is_enabled); +int _tethering_ext_set_config(tethering_ext_h tethering_context, void *src_config, int type); +int _tethering_ext_get_config(tethering_ext_h tethering_context, void *target_config, int type); +int _tethering_ext_client_clone(_tethering_ext_client_h *dest, _tethering_ext_client_h origin); +int _tethering_ext_client_get_name(_tethering_ext_client_h client, char **name); +int _tethering_ext_client_get_ip_address(_tethering_ext_client_h client, char **ip_address); +int _tethering_ext_client_get_mac_address(_tethering_ext_client_h client, char **mac_address); +int _tethering_ext_client_destroy(_tethering_ext_client_h client); +void _tethering_ext_register_callbacks(tethering_ext_h tethering_context, _tethering_ext_callback_h callbacks); +#ifdef __cplusplus +} +#endif + + +#endif /* __TIZEN_NETWORK_TETHERING_EXT_INTERNAL_H */ diff --git a/src/tethering_ext.c b/src/tethering_ext.c new file mode 100644 index 0000000..6556745 --- /dev/null +++ b/src/tethering_ext.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2025 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 + +#define DISABLE_REASON_TEXT_LEN 64 +#define TETHERING_GET_CONFIG(context, value, config, retval)\ +do {\ + if (!context || !value) {\ + LOGE("Invalid paramater, exiting");\ + retval = TETHERING_ERROR_INVALID_PARAMETER;\ + } else {\ + int rv = _tethering_ext_get_config(th_context, (void *) (value), config);\ + if (rv != TETHERING_EXT_ERR_NONE) {\ + LOGE("%s failed with error code %d", __FUNCTION__, rv);\ + retval = TETHERING_ERROR_OPERATION_FAILED;\ + } else {\ + retval = TETHERING_ERROR_NONE;\ + }\ + }\ +} while (0); + +/* Tethering callbacks */ +static void __enabled_cb(tethering_error_e result, bool is_requested, void *user_data) +{ + if (result != TETHERING_ERROR_NONE) { + if (!is_requested) + return; + + g_print("P2P Tethering is not enabled. error code[0x%X]\n", result); + return; + } + + if (is_requested) + g_print("P2P Tethering is enabled successfully\n"); + else + g_print("P2P Tethering is enabled by other app\n"); + + return; +} + +static const char *__convert_disabled_code_to_str(const _tethering_ext_disabled_cause_e code) +{ + static char str_buf[DISABLE_REASON_TEXT_LEN] = {0, }; + + switch (code) { + case TETHERING_EXT_DISABLED_BY_FLIGHT_MODE: + strncpy(str_buf, "disabled due to flight mode on", sizeof(str_buf)); + break; + + case TETHERING_EXT_DISABLED_BY_LOW_BATTERY: + strncpy(str_buf, "disabled due to low battery", sizeof(str_buf)); + break; + + case TETHERING_EXT_DISABLED_BY_NETWORK_CLOSE: + strncpy(str_buf, "disabled due to pdp network close", sizeof(str_buf)); + break; + + case TETHERING_EXT_DISABLED_BY_TIMEOUT: + strncpy(str_buf, "disabled due to timeout", sizeof(str_buf)); + break; + + case TETHERING_EXT_DISABLED_BY_OTHERS: + strncpy(str_buf, "disabled by other apps", sizeof(str_buf)); + break; + + case TETHERING_EXT_DISABLED_BY_REQUEST: + strncpy(str_buf, "disabled by my request", sizeof(str_buf)); + break; + + case TETHERING_EXT_DISABLED_BY_WIFI_ON: + strncpy(str_buf, "disabled by Wi-Fi station on", sizeof(str_buf)); + break; + + default: + strncpy(str_buf, "disabled by unknown reason", sizeof(str_buf)); + break; + } + + return str_buf; +} + +static void __disabled_cb(tethering_error_e result, _tethering_ext_disabled_cause_e cause, void *user_data) +{ + if (result != TETHERING_ERROR_NONE) { + if (cause != TETHERING_EXT_DISABLED_BY_REQUEST) + return; + + g_print("P2P Tethering is not disabled. error code[0x%X]\n", result); + return; + } + + g_print("P2P Tethering is %s\n", __convert_disabled_code_to_str(cause)); + + return; +} + +static void __connection_state_changed_cb(_tethering_ext_client_h client, bool open, void *user_data) +{ + _tethering_ext_client_h clone = NULL; + // tethering_type_e type; + char *ip_address = NULL; + char *mac_address = NULL; + char *hostname = NULL; + + _tethering_ext_client_clone(&clone, client); + if (clone == NULL) { + g_print("tetheirng_client_clone is failed\n"); + return; + } + + _tethering_ext_client_get_ip_address(clone, &ip_address); + _tethering_ext_client_get_mac_address(clone, &mac_address); + _tethering_ext_client_get_name(clone, &hostname); + + if (open) { + g_print("## New station Type [P2P Tethering], IP [%s], MAC [%s], hostname [%s]\n", + ip_address, mac_address, hostname); + } else { + g_print("## Disconnected station Type [P2P Tethering], IP [%s], MAC [%s], hostname [%s]\n", + ip_address, mac_address, hostname); + } + + if (ip_address) + free(ip_address); + if (mac_address) + free(mac_address); + if (hostname) + free(hostname); + + _tethering_ext_client_destroy(clone); + + return; +} + + +API int tethering_ext_initialize(tethering_ext_h *tethering_context) { + // __TETHERING_EXT_CAPI_FUNC_ENTER__; + + int rv; + + if (tethering_context == NULL) { + LOGE("Invalid Parameter"); + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + return TETHERING_ERROR_INVALID_PARAMETER; + } + + // TETHERING_EXT_LOCK; + + if (_tethering_ext_check_context(*tethering_context)) { + LOGE("Already initialized"); + // TETHERING_EXT_UNLOCK; + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + return TETHERING_ERROR_NONE; + } + + rv = _tethering_ext_create_context(tethering_context); + if (rv != TETHERING_EXT_ERR_NONE) { + LOGE("Init failed[%d]", rv); + // TETHERING_EXT_UNLOCK; + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + return TETHERING_ERROR_OUT_OF_MEMORY; + } + + rv = _tethering_ext_register_dbus(*tethering_context); + if (rv != TETHERING_EXT_ERR_NONE && rv != TETHERING_EXT_ERR_APP_ALREADY_REGISTERED) { + LOGE("dbus register failed[%d]", rv); + _tethering_ext_destroy_context(*tethering_context); + // TETHERING_EXT_UNLOCK; + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + return TETHERING_ERROR_OPERATION_FAILED; + } + + _tethering_ext_callback_h callbacks = {__enabled_cb, NULL, __disabled_cb, NULL, __connection_state_changed_cb, NULL}; + _tethering_ext_register_callbacks(tethering_context, callbacks); + + _tethering_ext_add_context(tethering_context); + + LOGD("Tethering context successfully initialized"); + + // TETHERING_EXT_UNLOCK; + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + return TETHERING_ERROR_NONE; +} + +API int tethering_ext_deinitialize(tethering_ext_h tethering_context) { + // __TETHERING_EXT_CAPI_FUNC_ENTER__; + + // TETHERING_EXT_LOCK; + + RET_ERR_IF_HANDLE_IS_NOT_VALID_OR_NOT_INITIALIZED(tethering_context); + + LOGD("Destroy Tethering context : %p", tethering_context); + + _tethering_ext_remove_context(tethering_context); + _tethering_ext_unregister_dbus(tethering_context); + _tethering_ext_destroy_context(tethering_context); + + return TETHERING_ERROR_NONE; +} + +API int tethering_ext_activate(tethering_ext_h tethering_context) { + // __TETHERING_EXT_CAPI_FUNC_ENTER__; + + int rv = 0; + + RET_ERR_IF_HANDLE_IS_NOT_VALID_OR_NOT_INITIALIZED(tethering_context); + + rv = _tethering_ext_set_wifi_tethering_mode_with_params(tethering_context, true); + if (rv == TETHERING_EXT_ERR_ACCESS_DENIED) { + LOGE("Access denied"); + return TETHERING_ERROR_PERMISSION_DENIED; + } else if (rv == TETHERING_EXT_ERR_INVALID_OPERATION) { + return TETHERING_ERROR_INVALID_OPERATION; + } else if (rv != TETHERING_EXT_ERR_NONE) { + LOGE("Failed to set tethering mode"); + return TETHERING_ERROR_OPERATION_FAILED; + } + + return TETHERING_ERROR_NONE; +} + +API int tethering_ext_deactivate(tethering_ext_h tethering_context) { + // __TETHERING_EXT_CAPI_FUNC_ENTER__; + + int rv = 0; + + RET_ERR_IF_HANDLE_IS_NOT_VALID_OR_NOT_INITIALIZED(tethering_context); + + rv = _tethering_ext_set_wifi_tethering_mode_with_params(tethering_context, false); + if (rv == TETHERING_EXT_ERR_ACCESS_DENIED) { + LOGE("Access denied"); + return TETHERING_ERROR_PERMISSION_DENIED; + } else if (rv == TETHERING_EXT_ERR_INVALID_OPERATION) { + return TETHERING_ERROR_INVALID_OPERATION; + } else if (rv != TETHERING_EXT_ERR_NONE) { + LOGE("Failed to set tethering mode"); + return TETHERING_ERROR_OPERATION_FAILED; + } + + return TETHERING_ERROR_NONE; +} + +API int tethering_ext_is_enabled(tethering_ext_h tethering_context, bool *is_enabled) { + // __TETHERING_EXT_CAPI_FUNC_ENTER__; + + int rv = TETHERING_ERROR_NONE; + + RET_ERR_IF_HANDLE_IS_NOT_VALID_OR_NOT_INITIALIZED(tethering_context); + + if (!is_enabled) { + LOGE("Invalid parameter"); + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + return TETHERING_ERROR_INVALID_PARAMETER; + } + + rv = _tethering_ext_get_wifi_tethering_mode(tethering_context, is_enabled); + + // __TETHERING_EXT_CAPI_FUNC_EXIT__TETHERING_ERROR_OPERATION_FAILED + + return rv; +} + +API int tethering_ext_set_ssid(tethering_ext_h th_context, const char *ssid) { + size_t length = strlen(ssid); + if (length > TETHERING_EXT_WIFI_SSID_MAX_LEN) { + return TETHERING_ERROR_INVALID_PARAMETER; + } + return _tethering_ext_set_config(th_context, (void *) ssid, TETHERING_EXT_SSID); + return TETHERING_ERROR_NONE; +} + +API int tethering_ext_set_passphrase(tethering_ext_h th_context, const char *passphrase) { + size_t length = strlen(passphrase); + if (length > TETHERING_EXT_WIFI_KEY_MAX_LEN) { + return TETHERING_ERROR_INVALID_PARAMETER; + } + return _tethering_ext_set_config(th_context, (void *) passphrase, TETHERING_EXT_PASSPHRASE); +} + +API int tethering_ext_set_channel(tethering_ext_h th_context, int channel) { + return _tethering_ext_set_config(th_context, (void *) &channel, TETHERING_EXT_CHANNEL); +} + +API int tethering_ext_get_tethering_info(tethering_ext_h th_context, void **tethering_info) { + int ret; + TETHERING_GET_CONFIG(th_context, *tethering_info, TETHERING_EXT_SSID | TETHERING_EXT_PASSPHRASE, ret); + return ret; +} + +API int tethering_ext_get_channel(tethering_ext_h th_context, int *channel) { + int ret; + TETHERING_GET_CONFIG(th_context, channel, TETHERING_EXT_CHANNEL, ret); + return ret; +} + +API int tethering_ext_get_security(tethering_ext_h th_context, int *security) { + int ret; + TETHERING_GET_CONFIG(th_context, security, TETHERING_EXT_SECURITY_TYPE, ret); + return ret; +} + +API int tethering_ext_get_visibility(tethering_ext_h th_context, int *visibility) { + int ret; + TETHERING_GET_CONFIG(th_context, visibility, TETHERING_EXT_VISIBLE, ret); + return ret; +} + +API int tethering_ext_get_sharing(tethering_ext_h th_context, bool *sharing) { + int ret; + TETHERING_GET_CONFIG(th_context, sharing, TETHERING_EXT_SHARED, ret); + return ret; +} diff --git a/src/tethering_ext_dbus.c b/src/tethering_ext_dbus.c new file mode 100644 index 0000000..f2e1765 --- /dev/null +++ b/src/tethering_ext_dbus.c @@ -0,0 +1,236 @@ +#include +#include +#include +#include +#include + +#define DBUS_REPLY_TIMEOUT_SYNC (10 * 1000) + +static int __tethering_ext_error_string_to_enum(const char *error) +{ + LOGD("Passed error string [%s]", error); + + if (strstr(error, "NoReply")) + return TETHERING_EXT_ERR_TIME_OUT; + else if (strstr(error, "UnknownMethod")) + return TETHERING_EXT_ERR_UNKNOWN_METHOD; + else if (strstr(error, "InvalidArgs")) + return TETHERING_EXT_ERR_INVALID_PARAM; + else if (strstr(error, "AccessDenied")) + return TETHERING_EXT_ERR_ACCESS_DENIED; + else if (strstr(error, "PermissionDenied")) + return TETHERING_EXT_ERR_ACCESS_DENIED; + else if (strstr(error, "NotRegistered")) + return TETHERING_EXT_ERR_INVALID_OPERATION; + else if (strstr(error, "NotSupported")) + return TETHERING_EXT_ERR_NOT_SUPPORTED; + else if (strstr(error, "InProgress")) + return TETHERING_EXT_ERR_IN_PROGRESS; + else if (strstr(error, "AlreadyExists")) + return TETHERING_EXT_ERR_ALREADY_EXISTS; + else if (strstr(error, "AlreadyEnabled")) + return TETHERING_EXT_ERR_INVALID_OPERATION; + else if (strstr(error, "AlreadyDisabled")) + return TETHERING_EXT_ERR_INVALID_OPERATION; + else if (strstr(error, "OperationFailed")) + return TETHERING_EXT_ERR_OPERATION_FAILED; + else if (strstr(error, "OperationAborted")) + return TETHERING_EXT_ERR_OPERATION_ABORTED; + else if (strstr(error, "OperationTimeout")) + return TETHERING_EXT_ERR_TIME_OUT; + else if (strstr(error, "OutOfMemory")) + return TETHERING_EXT_ERR_OUT_OF_MEMORY; + else if (strstr(error, "NotSet")) + return TETHERING_EXT_ERR_NOT_SET; + else if (strstr(error, "ServiceUnknown")) + return TETHERING_EXT_ERR_SERVICE_UNKNOWN; + + return TETHERING_EXT_ERR_NONE; +} + +GVariant *_invoke_dbus_method(_tethering_ext_h *tethering_ctx, const char *dest, const char *path, const char *interface_name, + const char *method, GVariant *params, int *dbus_error) +{ + //__TETHERING_EXT_CAPI_FUNC_ENTER__; + + GError *error = NULL; + GVariant *message = NULL; + GDBusConnection *connection = NULL; + *dbus_error = TETHERING_EXT_ERR_NONE; + gboolean created = FALSE; + + if (!tethering_ctx || tethering_ctx->tethering_ext_client == NULL) { + connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + created = TRUE; + } else { + connection = tethering_ctx->tethering_ext_client; + created = FALSE; + } + + if (!connection) { + if (error) { + LOGE("Failed to connect to the D-BUS daemon [%s]", error->message); + g_error_free(error); + } + return NULL; + } + + message = g_dbus_connection_call_sync(connection, + dest, + path, + interface_name, + method, + params, + NULL, + G_DBUS_CALL_FLAGS_NONE, + DBUS_REPLY_TIMEOUT_SYNC, + NULL, + &error); + + if (!message) { + if (error) { + LOGE("g_dbus_connection_call_sync() failed error [%d]: %s", error->code, error->message); + *dbus_error = __tethering_ext_error_string_to_enum(error->message); + g_error_free(error); + } else { + LOGE("g_dbus_connection_call_sync() failed"); + *dbus_error = TETHERING_EXT_ERR_UNKNOWN; + } + + if (created) + g_object_unref(connection); + + //__TETHERING_WIFI_EXT_CAPI_FUNC_EXIT__; + return NULL; + } + + if (created) + g_object_unref(connection); + + //__TETHERING_WIFI_EXT_CAPI_FUNC_EXIT__; + return message; +} + +int _tethering_ext_dbus_set_wifi_tethering_mode(_tethering_ext_h *tethering_ctx, bool enable) +{ + //__TETHERING_EXT_CAPI_FUNC_ENTER__; + + GVariant *message = NULL; + GVariant *params = NULL; + _tethering_ext_err_e Error = TETHERING_EXT_ERR_NONE; + + LOGD("_tethering_ext_dbus_set_wifi_tethering_mode() called : %s", enable ? "Enable" : "Disable"); + + params = g_variant_new("(b)", enable); + + message = _invoke_dbus_method(tethering_ctx, TETHERING_EXT_BUS_NAME, TETHERING_EXT_OBJECT_PATH, + TETHERING_EXT_INTERFACE_NAME, TETHERING_EXT_METHOD_SET_MODE, params, &Error); + + if (message == NULL) { + LOGE("Failed to set tethering %s", enable ? "Enable" : "Disable"); + //__TETHERING_WIFI_EXT_CAPI_FUNC_EXIT__; + return Error; + } + + g_variant_unref(message); + //__TETHERING_WIFI_EXT_CAPI_FUNC_EXIT__; + + return Error; +} + +int _tethering_ext_dbus_set_wifi_tethering_mode_with_params(_tethering_ext_h *tethering_ctx, bool enable) +{ + //__TETHERING_EXT_CAPI_FUNC_ENTER__; + + GVariant *message = NULL; + GVariant *params = NULL; + _tethering_ext_err_e Error = TETHERING_EXT_ERR_NONE; + + LOGD("_tethering_ext_dbus_set_wifi_tethering_mode() called : %s", enable ? "Enable" : "Disable"); + char *ssid = tethering_ctx->tethering_ext_config.ssid; + char *password = tethering_ctx->tethering_ext_config.passphrase; + int channel = tethering_ctx->tethering_ext_config.channel; + if (enable == TRUE) { + params = g_variant_new("(bssi)", enable, ssid, password, channel); + message = _invoke_dbus_method(tethering_ctx, TETHERING_EXT_BUS_NAME, TETHERING_EXT_OBJECT_PATH, + TETHERING_EXT_INTERFACE_NAME, TETHERING_EXT_METHOD_SET_MODE_WITH_PARAMS, params, &Error); + } else { + params = g_variant_new("(b)", enable); + message = _invoke_dbus_method(tethering_ctx, TETHERING_EXT_BUS_NAME, TETHERING_EXT_OBJECT_PATH, + TETHERING_EXT_INTERFACE_NAME, TETHERING_EXT_METHOD_SET_MODE, params, &Error); + } + + if (message == NULL) { + LOGE("Failed to set tethering %s", enable ? "Enable" : "Disable"); + //__TETHERING_WIFI_EXT_CAPI_FUNC_EXIT__; + return Error; + } + + g_variant_unref(message); + //__TETHERING_WIFI_EXT_CAPI_FUNC_EXIT__; + + return Error; +} + +int _tethering_ext_dbus_get_wifi_tethering_state(_tethering_ext_h *tethering_ctx, _tethering_ext_state_e *tethering_state) +{ + //__TETHERING_EXT_CAPI_FUNC_ENTER__; + + GVariant *message = NULL; + _tethering_ext_err_e Error = TETHERING_EXT_ERR_NONE; + gboolean state = 0; + + LOGD("_tethering_ext_dbus_get_wifi_tethering_state() called"); + + message = _invoke_dbus_method(tethering_ctx, TETHERING_EXT_BUS_NAME, TETHERING_EXT_OBJECT_PATH, + TETHERING_EXT_INTERFACE_NAME, TETHERING_EXT_METHOD_GET_MODE, NULL, &Error); + + if (message == NULL) { + LOGE("Failed to get tethering state"); + //__TETHERING_WIFI_EXT_CAPI_FUNC_EXIT__; + return Error; + } + + g_variant_get(message, "(b)", &state); + + if (state) + *tethering_state = TETHERING_EXT_STATE_ENABLED; + else + *tethering_state = TETHERING_EXT_STATE_DISABLED; + + LOGD("Tethering mode state : %d", *tethering_state); + + g_variant_unref(message); + + //__TETHERING_WIFI_EXT_CAPI_FUNC_EXIT__; + return Error; +} + +int _tethering_ext_dbus_get_wifi_tethering_info(_tethering_ext_h *tethering_ctx, _tethering_ext_tethering_info *tethering_info) +{ + //__TETHERING_EXT_CAPI_FUNC_ENTER__; + + GVariant *message = NULL; + _tethering_ext_err_e Error = TETHERING_EXT_ERR_NONE; + + LOGD("_tethering_ext_dbus_get_wifi_tethering_info() called"); + + message = _invoke_dbus_method(tethering_ctx, TETHERING_EXT_BUS_NAME, TETHERING_EXT_OBJECT_PATH, + TETHERING_EXT_INTERFACE_NAME, TETHERING_EXT_METHOD_GET_INFO, NULL, &Error); + + if (message == NULL) { + LOGE("Failed to get tethering info"); + //__TETHERING_WIFI_EXT_CAPI_FUNC_EXIT__; + return Error; + } + + g_variant_get(message, "(ss)", &tethering_info->tethering_ssid, &tethering_info->tethering_password); + + LOGD("Tethering info : ssid[%s] password[%s]", tethering_info->tethering_ssid, tethering_info->tethering_password); + + g_variant_unref(message); + + //__TETHERING_WIFI_EXT_CAPI_FUNC_EXIT__; + + return Error; +} diff --git a/src/tethering_ext_internal.c b/src/tethering_ext_internal.c new file mode 100644 index 0000000..fa9eecd --- /dev/null +++ b/src/tethering_ext_internal.c @@ -0,0 +1,656 @@ +/* + * Copyright (c) 2025 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. + */ +#define _GNU_SOURCE +#include +#include +#include + +#define tethering_ext_err_to_str(x) #x + +static GSList *tethering_ctx_list = NULL; + +int _tethering_ext_create_context(tethering_ext_h *tethering_context) +{ + _tethering_ext_h *tethering_ctx = g_try_malloc0(sizeof(_tethering_ext_h)); + if (!tethering_ctx) { + LOGE("Failed to create tethering_ctx : %d", TETHERING_ERROR_OUT_OF_MEMORY); + return TETHERING_ERROR_OUT_OF_MEMORY; + } + tethering_ctx->tethering_ext_callbacks = g_try_malloc0(sizeof(_tethering_ext_callback_h)); + *tethering_context = tethering_ctx; + + LOGD("New tethering_ctx create[%p]", *tethering_context); + + return TETHERING_EXT_ERR_NONE; +} + +void _tethering_ext_destroy_context(tethering_ext_h tethering_context) +{ + if (!tethering_context) { + return; + } + _tethering_ext_h *tethering_ctx = (_tethering_ext_h *) tethering_context; + if (tethering_ctx->tethering_ext_callbacks) { + g_free(tethering_ctx->tethering_ext_callbacks); + } + g_free(tethering_context); +} + +bool _tethering_ext_check_context(tethering_ext_h tethering_context) +{ + if (g_slist_find(tethering_ctx_list, tethering_context) != NULL) { + return TRUE; + } + + return FALSE; +} + +void _tethering_ext_add_context(tethering_ext_h *tethering_context) +{ + // TETHERING_EXT_LOCK; + tethering_ctx_list = g_slist_append(tethering_ctx_list, *tethering_context); + // TETHERING_EXT_UNLOCK; +} + +void _tethering_ext_remove_context(tethering_ext_h tethering_context) +{ + // TETHERING_EXT_LOCK; + tethering_ctx_list = g_slist_remove(tethering_ctx_list, tethering_context); + // TETHERING_EXT_UNLOCK; +} + + +static void __wifi_tethering_mode_on_off_cb(_tethering_ext_h *tethering_ctx, + _tethering_ext_event_info_h *event_cb) +{ + tethering_error_e error_code = TETHERING_ERROR_NONE; + _tethering_ext_state_e state = TETHERING_EXT_STATE_DISABLED; // out + _tethering_ext_state_e *tethering_state = (_tethering_ext_state_e *)event_cb->Data; + + if (tethering_ctx->tethering_ext_state_changed_cb == NULL) + return; + + if (event_cb->Error == TETHERING_EXT_ERR_NONE && + event_cb->Datalength == sizeof(_tethering_ext_state_e)) { + if (*tethering_state == TETHERING_EXT_STATE_ENABLED) { + LOGD("Tethering mode is enabled"); + state = TETHERING_EXT_STATE_ENABLED; + } else if (*tethering_state == TETHERING_EXT_STATE_DISABLED) { + LOGD("Tethering mode is disabled"); + state = TETHERING_EXT_STATE_DISABLED; + } else { + LOGE("Error Tethering state %d", *tethering_state); + error_code = TETHERING_ERROR_OPERATION_FAILED; + } + } else { + LOGE("Tethering power request failed(%d)", event_cb->Error); + error_code = TETHERING_ERROR_OPERATION_FAILED; + state = TETHERING_EXT_STATE_DISABLED; + } + + if (error_code == TETHERING_ERROR_NONE) { + if (tethering_ctx->tethering_ext_state_changed_cb) + tethering_ctx->tethering_ext_state_changed_cb(state, tethering_ctx->tethering_ext_state_changed_user_data); + } +} + +static void __tethering_ext_evt_cb(_tethering_ext_event_info_h *event_cb, void *user_data) +{ + // TETHERING_EXT_LOCK; + _tethering_ext_h *tethering_ctx = (_tethering_ext_h *)user_data; + + if (!_tethering_ext_check_context(tethering_ctx)) { + LOGE("WiFi Extension context is not initialized"); + // TETHERING_EXT_UNLOCK; + return; + } + + switch (event_cb->Event) { + case TETHERING_EXT_POWER_IND: + __wifi_tethering_mode_on_off_cb(tethering_ctx, event_cb); + break; + default: + break; + } + + // TETHERING_EXT_UNLOCK; +} + +static int __tethering_ext_mode_changed(_tethering_ext_h *tethering_ctx, GVariant *param) +{ + // __TETHERING_EXT_CAPI_FUNC_ENTER__; + + gboolean value = FALSE; + _tethering_ext_event_info_h *event_data = NULL; + + g_variant_get(param, "(b)", &value); + + event_data = g_try_malloc0(sizeof(_tethering_ext_event_info_h)); + if (!event_data) { + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + return TETHERING_EXT_ERR_OUT_OF_MEMORY; + } + + LOGD("Tethering mode changed to %s", value ? "enabled" : "disabled"); + + event_data->Event = TETHERING_EXT_POWER_IND; + event_data->Error = TETHERING_EXT_ERR_NONE; + event_data->Datalength = sizeof(gboolean); + event_data->Data = &value; + + if (tethering_ctx->tethering_ext_event_cb) + tethering_ctx->tethering_ext_event_cb(event_data, tethering_ctx->tethering_ext_user_data); + + g_free(event_data); + + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + + return TETHERING_EXT_ERR_NONE; +} + +static int __tethering_ext_enabled_callback(_tethering_ext_h *tethering_ctx, GVariant *param) { + gboolean is_enabled = FALSE; + g_variant_get(param, "(bi)", &is_enabled); + + if (! is_enabled) { + return TETHERING_EXT_ERR_INVALID_PARAM; + } + _tethering_ext_callback_h *callbacks = tethering_ctx->tethering_ext_callbacks; + if (callbacks->enabled_cb) { + callbacks->enabled_cb(TETHERING_ERROR_NONE, true, callbacks->enabled_user_data); + } + return TETHERING_EXT_ERR_NONE; +} + +static int __tethering_ext_disabled_callback(_tethering_ext_h *tethering_ctx, GVariant *param) { + gboolean is_disabled = FALSE; + gint disabled_cause; + g_variant_get(param, "(bi)", &is_disabled, &disabled_cause); + + if (! is_disabled) { + return TETHERING_EXT_ERR_INVALID_PARAM; + } + _tethering_ext_callback_h *callbacks = tethering_ctx->tethering_ext_callbacks; + if (callbacks->disabled_cb) { + callbacks->disabled_cb(TETHERING_ERROR_NONE, disabled_cause, callbacks->disabled_user_data); + } + return TETHERING_EXT_ERR_NONE; +} + +static int __tethering_ext_connection_state_callback(_tethering_ext_h *tethering_ctx, GVariant *param) { + _tethering_ext_err_e ret = TETHERING_EXT_ERR_NONE; + char *buf = NULL; + char *name = NULL; + char *mac = NULL; + char *ip = NULL; + guint timestamp; + bool opened = false; + _tethering_ext_client_info_h client; + _tethering_ext_callback_h *callbacks = tethering_ctx->tethering_ext_callbacks; + memset(&client, 0, sizeof(_tethering_ext_client_info_h)); + g_variant_get(param, "(ssssu)", &buf, &ip, &mac, &name, ×tamp); + + if (!g_strcmp0(buf, "DhcpConnected")) { + opened = true; + } else if (!g_strcmp0(buf, "DhcpLeaseDeleted")) { + opened = false; + } else { + LOGE("Unknown event [%s]\n", buf); + ret = TETHERING_ERROR_INVALID_PARAMETER; + goto DONE; + } + + LOGI("P2P tethering type %s, ip %s, mac %s, name %s, timestamp %d", + buf, ip, mac, name, timestamp); + g_strlcpy(client.ip, ip, sizeof(client.ip)); + g_strlcpy(client.mac, mac, sizeof(client.mac)); + if (name != NULL) + client.hostname = g_strdup(name); + client.tm = (time_t)timestamp; + if (callbacks->changed_cb) { + callbacks->changed_cb((_tethering_ext_client_h)&client, opened, callbacks->changed_user_data); + } + +DONE: + g_free(buf); + g_free(ip); + g_free(mac); + g_free(name); + return ret; +} + +static _tethering_ext_err_e __tethering_ext_dbus_create(_tethering_ext_h *tethering_ctx) { + GError *error = NULL; + #if !GLIB_CHECK_VERSION(2, 36, 0) + g_type_init(); + #endif + + if (!tethering_ctx) { + return TETHERING_EXT_ERR_APP_NOT_REGISTERED; + } + + tethering_ctx->tethering_ext_client = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + + if (!tethering_ctx->tethering_ext_client) { + if (error) { + LOGE("Failed to get dbus connection [%s]", error->message); + g_error_free(error); + } + return TETHERING_EXT_ERR_UNKNOWN; + } + + tethering_ctx->tethering_ext_cancellable = g_cancellable_new(); + return TETHERING_EXT_ERR_NONE; +} + +static void __tethering_ext_close_gdbus_call(_tethering_ext_h *tethering_ctx) +{ + if (tethering_ctx->tethering_ext_cancellable) { + g_cancellable_cancel(tethering_ctx->tethering_ext_cancellable); + g_object_unref(tethering_ctx->tethering_ext_cancellable); + tethering_ctx->tethering_ext_cancellable = NULL; + } + + if (tethering_ctx->tethering_ext_client) { + g_object_unref(tethering_ctx->tethering_ext_client); + tethering_ctx->tethering_ext_client = NULL; + } +} + +static void __tethering_ext_signal_filter(GDBusConnection *conn, + const gchar *name, const gchar *path, const gchar *interface, + const gchar *sig, GVariant *param, gpointer user_data) +{ + // __TETHERING_EXT_CAPI_FUNC_ENTER__; + _tethering_ext_h *tethering_ctx = (_tethering_ext_h *)user_data; + + if (!g_strcmp0(sig, SIGNAL_TETHERING_EXT_MODE_CHANGED)) { + __tethering_ext_mode_changed(tethering_ctx, param); + } else if (!g_strcmp0(sig, SIGNAL_TETHERING_EXT_ENABLED)) { + __tethering_ext_enabled_callback(tethering_ctx, param); + } else if (!g_strcmp0(sig, SIGNAL_TETHERING_EXT_DISABLED)) { + __tethering_ext_disabled_callback(tethering_ctx, param); + } else if (!g_strcmp0(sig, SIGNAL_TETHERING_CONNECTION_CHANGED)) { + __tethering_ext_connection_state_callback(tethering_ctx, param); + } + + // __TETHERING_EXT_CAPI_FUNC_EXIT__; +} + +static void __tethering_ext_unregister_signal(_tethering_ext_h *tethering_ctx) +{ + // __TETHERING_EXT_CAPI_FUNC_ENTER__; + + if (tethering_ctx) { + g_dbus_connection_signal_unsubscribe(tethering_ctx->tethering_ext_client, tethering_ctx->subscribe_id_wifi_tethering_state); + } + + // __TETHERING_EXT_CAPI_FUNC_EXIT__; +} + +static int __tethering_ext_dbus_register_signal(_tethering_ext_h *tethering_ctx) +{ + // __TETHERING_EXT_CAPI_FUNC_ENTER__; + + _tethering_ext_err_e Error = TETHERING_EXT_ERR_NONE; + + if (!tethering_ctx) { + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + return TETHERING_EXT_ERR_APP_NOT_REGISTERED; + } + + /* Create wifi-tethering-service connection */ + tethering_ctx->subscribe_id_wifi_tethering_state = g_dbus_connection_signal_subscribe( + tethering_ctx->tethering_ext_client, + TETHERING_EXT_BUS_NAME, + TETHERING_EXT_INTERFACE_NAME, + NULL, + TETHERING_EXT_OBJECT_PATH, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + __tethering_ext_signal_filter, + tethering_ctx, + NULL); + + + if (tethering_ctx->subscribe_id_wifi_tethering_state == 0) { + LOGE("Failed to register signal, subscribe_id_wifi_tethering_state(%d)", + tethering_ctx->subscribe_id_wifi_tethering_state); + __tethering_ext_unregister_signal(tethering_ctx); + Error = TETHERING_EXT_ERR_INVALID_OPERATION; + } + + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + return Error; +} + + +int _tethering_ext_register_dbus(tethering_ext_h tethering_context) { + // __TETHERING_EXT_CAPI_FUNC_ENTER__ + _tethering_ext_err_e Error = TETHERING_EXT_ERR_NONE; + _tethering_ext_h *tethering_ctx = (_tethering_ext_h *) tethering_context; + Error = __tethering_ext_dbus_create(tethering_ctx); + if (Error != TETHERING_EXT_ERR_NONE) { + return Error; + } + + Error = __tethering_ext_dbus_register_signal(tethering_ctx); + if (Error != TETHERING_EXT_ERR_NONE) { + LOGE("Failed to register DBus signal, Error(%d)", Error); + __tethering_ext_close_gdbus_call(tethering_ctx); + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + return Error; + } + + tethering_ctx->tethering_ext_event_cb = (_tethering_ext_event_cb) __tethering_ext_evt_cb; + tethering_ctx->tethering_ext_user_data = tethering_ctx; + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + return TETHERING_EXT_ERR_NONE; +} + +void _tethering_ext_unregister_dbus(tethering_ext_h tethering_context) { + // __TETHERING_EXT_CAPI_FUNC_ENTER__; + + _tethering_ext_h *tethering_ctx = (_tethering_ext_h *) tethering_context; + + if (tethering_ctx) { + tethering_ctx->tethering_ext_event_cb = NULL; + tethering_ctx->tethering_ext_user_data = NULL; + + __tethering_ext_unregister_signal(tethering_ctx); + __tethering_ext_close_gdbus_call(tethering_ctx); + } + + // __TETHERING_EXT_CAPI_FUNC_EXIT__; +} + +int _tethering_ext_set_wifi_tethering_mode(tethering_ext_h tethering_context, bool enable) +{ + // __TETHERING_EXT_CAPI_FUNC_ENTER__; + + _tethering_ext_h *tethering_ctx = (_tethering_ext_h *)tethering_context; + _tethering_ext_err_e Error = TETHERING_EXT_ERR_NONE; + + Error = _tethering_ext_dbus_set_wifi_tethering_mode(tethering_ctx, enable); + if (Error != TETHERING_EXT_ERR_NONE) + LOGE("Failed to set tethering mode(%d), Error[%s])", + enable, tethering_ext_err_to_str(Error)); + + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + return Error; +} + +int _tethering_ext_set_wifi_tethering_mode_with_params(tethering_ext_h tethering_context, bool enable) +{ + // __TETHERING_EXT_CAPI_FUNC_ENTER__; + + _tethering_ext_h *tethering_ctx = (_tethering_ext_h *)tethering_context; + _tethering_ext_err_e Error = TETHERING_EXT_ERR_NONE; + + Error = _tethering_ext_dbus_set_wifi_tethering_mode_with_params(tethering_ctx, enable); + if (Error != TETHERING_EXT_ERR_NONE) + LOGE("Failed to set tethering mode(%d), Error[%s])", + enable, tethering_ext_err_to_str(Error)); + + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + return Error; +} + + +int _tethering_ext_get_wifi_tethering_mode(tethering_ext_h tethering_context, bool *is_enabled) { + // __TETHERING_EXT_CAPI_FUNC_ENTER__; + _tethering_ext_h *tethering_ctx = (_tethering_ext_h *) tethering_context; + _tethering_ext_err_e Error = TETHERING_EXT_ERR_NONE; + _tethering_ext_state_e tethering_state = TETHERING_EXT_STATE_DISABLED; + + Error = _tethering_ext_dbus_get_wifi_tethering_state(tethering_ctx, &tethering_state); + if (Error != TETHERING_EXT_ERR_NONE) + LOGE("Failed to get tethering state [%s]", tethering_ext_err_to_str(Error)); + else { + if (tethering_state == TETHERING_EXT_STATE_ENABLED) { + *is_enabled = true; + } else { + *is_enabled = false; + } + tethering_ctx->tethering_ext_state = tethering_state; + } + // __TETHERING_EXT_CAPI_FUNC_EXIT__; + return Error; +} + +int _tethering_ext_set_config(tethering_ext_h tethering_context, void *src_config, int type) { + int Error = TETHERING_EXT_ERR_NONE; + _tethering_ext_h *tethering_ctx = (_tethering_ext_h *) tethering_context; + tethering_ext_config_h *target_config = &(tethering_ctx->tethering_ext_config); + + switch (type) { + case TETHERING_EXT_SSID | TETHERING_EXT_PASSPHRASE: + { + const char *ssid = (const char *) src_config; + size_t length = sizeof(ssid); + strncpy(target_config->ssid, ssid, length); + target_config->ssid[length + 1] = 0; + break; + } + case TETHERING_EXT_PASSPHRASE: + { + const char *passphrase = (const char *) src_config; + size_t length = sizeof(passphrase); + strncpy(target_config->passphrase, passphrase, length); + target_config->passphrase[length + 1] = 0; + break; + } + case TETHERING_EXT_CHANNEL: + target_config->channel = *((int *) src_config); + break; + default: + LOGE("Unknown type %d", type); + Error = TETHERING_ERROR_INVALID_PARAMETER; + break; + } + return Error; +} + +int _tethering_ext_get_config(tethering_ext_h tethering_context, void *target_config, int type) { + int Error = TETHERING_EXT_ERR_NONE; + _tethering_ext_h *tethering_ctx = (_tethering_ext_h *) tethering_context; + tethering_ext_config_h *src_config = &(tethering_ctx->tethering_ext_config); + switch (type) { + case TETHERING_EXT_SSID | TETHERING_EXT_PASSPHRASE: + { + _tethering_ext_tethering_info *t_info = (_tethering_ext_tethering_info *) target_config; + size_t ssid_length = strlen(src_config->ssid); + memcpy(t_info->tethering_ssid, src_config->ssid, ssid_length); + t_info->tethering_ssid[ssid_length + 1] = 0; + break; + size_t passphrase_length = strlen(src_config->passphrase); + memcpy(t_info->tethering_password, src_config->passphrase, passphrase_length); + t_info->tethering_password[passphrase_length + 1] = 0; + break; + } + case TETHERING_EXT_SECURITY_TYPE: + { + int *security_type = (int *) target_config; + if (vconf_get_int(VCONFKEY_MOBILE_HOTSPOT_SECURITY, security_type) < 0) { + LOGE("vconf_get_int is failed\n"); + return TETHERING_EXT_ERR_OPERATION_FAILED; + } + break; + } + case TETHERING_EXT_CHANNEL: + *((int *) target_config) = src_config->channel; + break; + case TETHERING_EXT_VISIBLE: + { + int hide = 0; + bool *visible = (bool *) target_config; + if (vconf_get_int(VCONFKEY_MOBILE_HOTSPOT_HIDE, &hide) < 0) { + LOGE("vconf_get_int is failed\n"); + return TETHERING_EXT_ERR_OPERATION_FAILED; + } + + if (hide) + *visible = false; + else + *visible = true; + break; + } + } + return Error; +} + +int _tethering_ext_client_clone(_tethering_ext_client_h *dest, _tethering_ext_client_h origin) { + // CHECK_FEATURE_SUPPORTED(TETHERING_FEATURE); + + if (dest == NULL) { + LOGE("Parameter(dest) is NULL\n"); + return TETHERING_EXT_ERR_INVALID_PARAM; + } + + if (origin == NULL) { + LOGE("Parameter(origin) is NULL\n"); + return TETHERING_EXT_ERR_INVALID_PARAM; + } + + + _tethering_ext_client_info_h *si = NULL; + _tethering_ext_client_info_h *source = NULL; + + source = (_tethering_ext_client_info_h *)origin; + + si = malloc(sizeof(_tethering_ext_client_info_h)); + if (si == NULL) { + LOGE("malloc is failed\n"); + return TETHERING_EXT_ERR_OUT_OF_MEMORY; + } + + memcpy(si, source, sizeof(_tethering_ext_client_info_h)); + si->hostname = g_strdup(source->hostname); + if (si->hostname == NULL) { + LOGE("malloc is failed\n"); + free(si); + return TETHERING_EXT_ERR_OUT_OF_MEMORY; + } + + *dest = (_tethering_ext_client_h)si; + + return TETHERING_EXT_ERR_NONE; +} + +int _tethering_ext_client_get_name(_tethering_ext_client_h client, char **name) +{ + if(client == NULL) { + LOGE("Parameter(client) is NULL\n"); + return TETHERING_EXT_ERR_INVALID_PARAM; + } + if(name == NULL) { + LOGE("Parameter(name) is NULL\n"); + return TETHERING_EXT_ERR_INVALID_PARAM; + } + + _tethering_ext_client_info_h *si = (_tethering_ext_client_info_h *)client; + + *name = strdup(si->hostname); + if (*name == NULL) { + LOGE("strdup is failed\n"); + return TETHERING_EXT_ERR_OUT_OF_MEMORY; + } + + return TETHERING_EXT_ERR_NONE; +} + +int _tethering_ext_client_get_ip_address(_tethering_ext_client_h client, char **ip_address) +{ + // CHECK_FEATURE_SUPPORTED(TETHERING_FEATURE); + + if(client == NULL) { + LOGE("Parameter(client) is NULL\n"); + return TETHERING_EXT_ERR_INVALID_PARAM; + } + if(ip_address == NULL) { + LOGE("Parameter(ip_address) is NULL\n"); + return TETHERING_EXT_ERR_INVALID_PARAM; + } + + _tethering_ext_client_info_h *si = (_tethering_ext_client_info_h *)client; + + *ip_address = strdup(si->ip); + if (*ip_address == NULL) { + LOGE("strdup is failed\n"); + return TETHERING_EXT_ERR_OUT_OF_MEMORY; + } + + return TETHERING_EXT_ERR_NONE; +} + +int _tethering_ext_client_get_mac_address(_tethering_ext_client_h client, char **mac_address) +{ + // CHECK_FEATURE_SUPPORTED(TETHERING_FEATURE); + + if(client == NULL) { + LOGE("Parameter(client) is NULL\n"); + return TETHERING_EXT_ERR_INVALID_PARAM; + } + if(mac_address == NULL) { + LOGE("Parameter(mac_address) is NULL\n"); + return TETHERING_EXT_ERR_INVALID_PARAM; + } + + _tethering_ext_client_info_h *si = (_tethering_ext_client_info_h *)client; + + *mac_address = strdup(si->mac); + if (*mac_address == NULL) { + LOGE("strdup is failed\n"); + return TETHERING_EXT_ERR_OUT_OF_MEMORY; + } + + return TETHERING_EXT_ERR_NONE; +} + +int _tethering_ext_client_destroy(_tethering_ext_client_h client) +{ + // CHECK_FEATURE_SUPPORTED(TETHERING_FEATURE); + + if(client == NULL){ + LOGE("Parameter(client) is NULL\n"); + return TETHERING_EXT_ERR_INVALID_PARAM; + } + + _tethering_ext_client_info_h *si = NULL; + + si = (_tethering_ext_client_info_h *)client; + + g_free(si->hostname); + + free(client); + + return TETHERING_EXT_ERR_NONE; +} + + +void _tethering_ext_register_callbacks(tethering_ext_h tethering_context, _tethering_ext_callback_h callbacks) { + _tethering_ext_h *tethering_ctx = (_tethering_ext_h *)tethering_context; + if (! tethering_ctx->tethering_ext_callbacks) + { + return; + } + tethering_ctx->tethering_ext_callbacks->enabled_cb = callbacks.enabled_cb; + tethering_ctx->tethering_ext_callbacks->enabled_user_data = callbacks.enabled_user_data; + tethering_ctx->tethering_ext_callbacks->disabled_cb = callbacks.disabled_cb; + tethering_ctx->tethering_ext_callbacks->disabled_user_data = callbacks.disabled_user_data; + tethering_ctx->tethering_ext_callbacks->changed_cb = callbacks.changed_cb; + tethering_ctx->tethering_ext_callbacks->changed_user_data = callbacks.changed_user_data; +} \ No newline at end of file