Add plugin for online monitoring 22/263622/11
authorJaehyun Kim <jeik01.kim@samsung.com>
Tue, 7 Sep 2021 05:59:37 +0000 (14:59 +0900)
committerJaehyun Kim <jeik01.kim@samsung.com>
Wed, 15 Sep 2021 07:25:56 +0000 (16:25 +0900)
Change-Id: Ic96e513404635c869e18aba870e040418705d457
Signed-off-by: Jaehyun Kim <jeik01.kim@samsung.com>
14 files changed:
CMakeLists.txt
include/network-state.h
include/plugin.h
include/util.h
packaging/net-config.spec
plugin/online-monitor/CMakeLists.txt [new file with mode: 0755]
plugin/online-monitor/online-monitor.c [new file with mode: 0755]
plugin/online-monitor/online-monitor.h [new file with mode: 0644]
plugin/online-monitor/online_monitor.conf [new file with mode: 0644]
plugin/online-monitor/report-manager.c [new file with mode: 0755]
plugin/online-monitor/url-checker.c [new file with mode: 0755]
src/network-state.c
src/signal-handler.c
src/utils/util.c

index 50a546f..b5646be 100755 (executable)
@@ -2,6 +2,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
 PROJECT(net-config C CXX)
 SET(PACKAGE ${PROJECT_NAME})
 SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(INCDIR "${PREFIX}/include")
 SET(BINDIR "${PREFIX}/bin")
 SET(DATADIR "${PREFIX}/share")
 SET(LIBDIR "${PREFIX}/${LIB_PATH}")
@@ -69,6 +70,10 @@ IF(TIZEN_CAPTIVE_PORTAL)
        SET(SRCS ${SRCS} src/utils/network-accessibility.c)
 ENDIF(TIZEN_CAPTIVE_PORTAL)
 
+IF(TIZEN_ARCH_64)
+       ADD_DEFINITIONS(-DTIZEN_ARCH_64)
+ENDIF(TIZEN_ARCH_64)
+
 IF(TIZEN_WEARABLE)
        ADD_DEFINITIONS(-DTIZEN_WEARABLE)
 ENDIF(TIZEN_WEARABLE)
@@ -139,6 +144,7 @@ ADD_SUBDIRECTORY(plugin/headed)
 ADD_SUBDIRECTORY(plugin/telephony)
 ADD_SUBDIRECTORY(plugin/stc)
 ADD_SUBDIRECTORY(plugin/battery)
+ADD_SUBDIRECTORY(plugin/online-monitor)
 ADD_SUBDIRECTORY(haltests)
 IF(BUILD_GTESTS)
        ADD_SUBDIRECTORY(gtest)
index 40853a0..b7bff2c 100755 (executable)
@@ -35,10 +35,12 @@ const char *netconfig_get_default_mac_address(void);
 unsigned int netconfig_get_default_frequency(void);
 const char *netconfig_wifi_get_connected_essid(const char *default_profile);
 gboolean netconfig_get_default_is_metered(void);
+gboolean netconfig_get_default_is_internet(void);
 
 void netconfig_set_default_ipaddress(const char *ipaddr);
 void netconfig_set_default_ipaddress6(const char *ipaddr);
 void netconfig_set_default_proxy(const char *proxy);
+void netconfig_set_default_is_internet(gboolean state);
 
 void netconfig_update_default(void);
 void netconfig_update_default_profile(void);
index 8c92136..885dca0 100755 (executable)
@@ -168,6 +168,12 @@ struct netconfig_bm_plugin_t {
        int (*get_feature_data) (bm_data_h *, bm_plugin_data_type_e);
 };
 
+struct netconfig_online_monitor_plugin_t {
+       int (*init) (void);
+       int (*deinit) (void);
+       int (*notify_online_state) (char *, gboolean);
+};
+
 typedef enum {
        SYS_EVT_NETWORK_STATUS = 0,
        SYS_EVT_WIFI_STATE = 1,
index 73f41c5..09e4359 100755 (executable)
@@ -132,6 +132,7 @@ void netconfig_plugin_init();
 void netconfig_plugin_deinit();
 gboolean netconfig_get_headed_plugin_flag();
 gboolean netconfig_get_telephony_plugin_flag();
+void netconfig_notify_online_state(char *ifname, gboolean online_state);
 
 void netconfig_convert_bytes_to_hexstr(const char* bin, int blen, gchar* hexstr);
 
index 817f96f..51ce1fa 100755 (executable)
@@ -1,7 +1,7 @@
 Name:          net-config
 Summary:       TIZEN Network Configuration service
-Version:       1.2.10
-Release:       3
+Version:       1.2.11
+Release:       1
 Group:         System/Network
 License:       Apache-2.0
 Source0:       %{name}-%{version}.tar.gz
@@ -96,6 +96,15 @@ Requires:       %{name} = %{version}-%{release}
 %description haltests
 TIZEN Network Configuration service extension for HAL test.
 
+%package plugin-online-monitor
+Summary:        net-config extension for advanced online monitoring
+BuildRequires:  connman-extension-bpf-devel
+Requires:       libelf0
+Requires:       connman-extension-bpf
+Requires:       %{name} = %{version}-%{release}
+%description plugin-online-monitor
+TIZEN Network Configuration service extension for advanced online monitoring.
+
 %prep
 %setup -q
 
@@ -107,6 +116,9 @@ cmake -DCMAKE_INSTALL_PREFIX=%{_prefix} \
        -DTIZEN_DEBUG_ENABLE=0 \
        -DTIZEN_WEARABLE=1 \
        -DTIZEN_CAPTIVE_PORTAL=1 \
+%if "%{?_lib}" == "lib64"
+       -DTIZEN_ARCH_64=1 \
+%endif
        -DLIB_PATH=%{_lib} \
        -DBIN_DIR=%{_bindir} \
        -DBUILD_GTESTS=%{?gtests:1}%{!?gtests:0} \
@@ -126,6 +138,9 @@ cmake -DCMAKE_INSTALL_PREFIX=%{_prefix} \
        -DTIZEN_DEBUG_ENABLE=0 \
        -DTIZEN_WEARABLE=0 \
        -DTIZEN_CAPTIVE_PORTAL=0 \
+%if "%{?_lib}" == "lib64"
+       -DTIZEN_ARCH_64=1 \
+%endif
        -DLIB_PATH=%{_lib} \
        -DBIN_DIR=%{_bindir} \
        -DBUILD_GTESTS=%{?gtests:1}%{!?gtests:0} \
@@ -134,7 +149,6 @@ cmake -DCMAKE_INSTALL_PREFIX=%{_prefix} \
 
 make %{?_smp_mflags}
 
-
 %install
 %make_install
 
@@ -181,6 +195,9 @@ cp resources/usr/system/RestoreDir/softreset/network_softreset.sh %{buildroot}/u
 
 mv %{_builddir}/%{name}-%{version}/net-config.wearable %{buildroot}%{_bindir}
 
+#online-monitor
+cp plugin/online-monitor/online_monitor.conf %{buildroot}/%{_localstatedir}/lib/net-config
+
 %post
 chsmack -a 'System::Shared' %{_sysconfdir}/resolv.conf
 chsmack -a 'System::Shared' %{TZ_SYS_ETC}/resolv.conf
@@ -267,3 +284,8 @@ mv /var/lib/net-config/settings-robot /var/lib/net-config/settings
 %files haltests
 %manifest net-config.manifest
 %{_bindir}/hal/*haltests
+
+%files plugin-online-monitor
+%manifest net-config.manifest
+%attr(500,network_fw,network_fw) %{_libdir}/net-config-plugin-online-monitor.so
+%attr(644,root,root) %{_localstatedir}/lib/net-config/online_monitor.conf
diff --git a/plugin/online-monitor/CMakeLists.txt b/plugin/online-monitor/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..3d3652b
--- /dev/null
@@ -0,0 +1,43 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(net-config-plugin-online-monitor C)
+
+IF(TIZEN_WEARABLE)
+       ADD_DEFINITIONS(-DTIZEN_WEARABLE)
+ENDIF(TIZEN_WEARABLE)
+
+ADD_DEFINITIONS(-DUSE_NETCONFIG_LOG)
+
+# Set required packages
+INCLUDE(FindPkgConfig)
+PKG_CHECK_MODULES(pkgs_online_mon REQUIRED
+       dlog
+       glib-2.0
+       )
+
+FOREACH(flag ${pkgs_online_mon_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+INCLUDE_DIRECTORIES(
+       ${CMAKE_SOURCE_DIR}/include
+       ${INCDIR}/bpf
+)
+# INCLUDE_DIRECTORIES(SRCS include)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -g -Werror")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+
+SET(SRCS_ONLINE_MON
+       online-monitor.c
+       url-checker.c
+       report-manager.c
+       )
+
+# library build
+ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS_ONLINE_MON})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_online_mon_LDFLAGS} "-lbpf")
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES PREFIX "" OUTPUT_NAME ${PROJECT_NAME})
+
+# install
+INSTALL(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${LIBDIR})
diff --git a/plugin/online-monitor/online-monitor.c b/plugin/online-monitor/online-monitor.c
new file mode 100755 (executable)
index 0000000..b2bde47
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * Network Configuration Module
+ *
+ * Copyright (c) 2021 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.
+ *
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <bpf/linux/asm-generic/socket.h>
+#include <bpf/linux/bpf.h>
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
+#include <linux/if_ether.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#include <arpa/inet.h>
+
+#include "online-monitor.h"
+
+#define BPF_FILE_PATH        "/var/lib/connman/bpf_code"
+#define BPF_MAP_INTERVAL     3
+#define DNS_NO_RESPONSE_MAX  4
+#define DETECTION_INTERVAL   4
+
+static struct {
+       struct bpf_object *obj;
+       int prog_fd;
+       int map_fd;
+       int sock;
+       int timer;
+} bpf_info;
+
+static struct {
+       __u32 unreachable;
+       __u32 dns_query;
+       __u32 dns_response;
+       __u32 dns_refused;
+       __u32 no_response_count;
+       __u32 detection_interval_count;
+} bpf_map_info;
+
+static GSList *notifier_list = NULL;
+static char def_ifname[32] = {0, };
+static online_monitor_state_e g_state = ONLINE_MONITOR_STATE_UNINITIALIZED;
+static online_monitor_config_t online_monitor_config;
+
+static void stop_monitoring(void);
+
+static int open_raw_socket(const char *ifname)
+{
+       struct sockaddr_ll sock_ll;
+       int sock;
+
+       sock = socket(PF_PACKET, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, htons(ETH_P_ALL));
+       if (sock < 0) {
+               ERR("raw socket creation failed\n");
+               return -1;
+       }
+
+       memset(&sock_ll, 0, sizeof(sock_ll));
+       sock_ll.sll_family = AF_PACKET;
+       sock_ll.sll_ifindex = if_nametoindex(ifname);
+       sock_ll.sll_protocol = htons(ETH_P_ALL);
+
+       if (bind(sock, (struct sockaddr *)&sock_ll, sizeof(sock_ll)) < 0) {
+               ERR("bind failed, ifname %s error %s\n", ifname, strerror(errno));
+               close(sock);
+               return -1;
+       }
+
+       return sock;
+}
+
+static void notify_monitoring_state(online_monitor_state_e state, online_monitor_detection_e reason)
+{
+       GSList *list;
+
+       DBG("state %d, ifname %s, reason %d", state, def_ifname, reason);
+
+       for (list = notifier_list; list; list = list->next) {
+               const online_monitor_state_chaged_cb notifier = list->data;
+
+               if (notifier)
+                       notifier(state, def_ifname, reason);
+       }
+}
+
+static gboolean check_bpf_map(gpointer data)
+{
+       __u32 unreachable = 0;
+       __u32 dns_query = 0;
+       __u32 dns_response = 0;
+       __u32 dns_refused = 0;
+       __u32 key;
+       gboolean detected = FALSE;
+       gboolean skip_detection = FALSE;
+       online_monitor_detection_e reason = ONLINE_MONITOR_DETECTION_NONE;
+
+       if (g_state == ONLINE_MONITOR_STATE_OFFLINE_DETECTED)
+               return TRUE;
+
+       if (g_state == ONLINE_MONITOR_STATE_URL_CHECK_SUCCEEDED) {
+               if (bpf_map_info.detection_interval_count < DETECTION_INTERVAL) {
+                       bpf_map_info.detection_interval_count++;
+                       return TRUE;
+               } else {
+                       bpf_map_info.detection_interval_count = 0;
+                       g_state = ONLINE_MONITOR_STATE_MONITORING_STARTED;
+                       skip_detection = TRUE;
+               }
+       }
+
+       key = 1;
+       if (bpf_map_lookup_elem(bpf_info.map_fd, &key, &unreachable) != 0) {
+               ERR("Failed to get unreachable count from bpf map");
+               bpf_info.timer = 0;
+               return FALSE;
+       }
+
+       key = 2;
+       if (bpf_map_lookup_elem(bpf_info.map_fd, &key, &dns_query) != 0) {
+               ERR("Failed to get dns_query count from bpf map");
+               bpf_info.timer = 0;
+               return FALSE;
+       }
+
+       key = 3;
+       if (bpf_map_lookup_elem(bpf_info.map_fd, &key, &dns_response) != 0) {
+               ERR("Failed to get dns_response count from bpf map");
+               bpf_info.timer = 0;
+               return FALSE;
+       }
+
+       key = 4;
+       if (bpf_map_lookup_elem(bpf_info.map_fd, &key, &dns_refused) != 0) {
+               ERR("Failed to get dns_refused count from bpf map");
+               bpf_info.timer = 0;
+               return FALSE;
+       }
+
+       DBG("unreachable %u dns_query %u dns_response %u dns_refused %u",
+                       unreachable, dns_query, dns_response, dns_refused);
+
+       if (skip_detection) {
+               skip_detection = FALSE;
+               goto update;
+       }
+
+       if (bpf_map_info.unreachable < unreachable) {
+               detected = TRUE;
+               reason = ONLINE_MONITOR_DETECTION_UNREACHABLE;
+       } else if (bpf_map_info.dns_refused < dns_refused) {
+               detected = TRUE;
+               reason = ONLINE_MONITOR_DETECTION_DNS_REFUSED;
+       } else if (bpf_map_info.no_response_count == 0
+                       && bpf_map_info.dns_query < dns_query
+                       && bpf_map_info.dns_response == dns_response) {
+               bpf_map_info.no_response_count++;
+       } else if (bpf_map_info.no_response_count > 0) {
+               if (bpf_map_info.dns_response == dns_response)
+                       bpf_map_info.no_response_count++;
+               else
+                       bpf_map_info.no_response_count = 0;
+
+               if (bpf_map_info.no_response_count > DNS_NO_RESPONSE_MAX) {
+                       detected = TRUE;
+                       reason = ONLINE_MONITOR_DETECTION_NO_DNS_RESPONSE;
+               }
+       }
+
+       if (detected) {
+               bpf_map_info.no_response_count = 0;
+               g_state = ONLINE_MONITOR_STATE_OFFLINE_DETECTED;
+               notify_monitoring_state(ONLINE_MONITOR_STATE_OFFLINE_DETECTED, reason);
+       }
+
+update:
+       bpf_map_info.unreachable = unreachable;
+       bpf_map_info.dns_query = dns_query;
+       bpf_map_info.dns_response = dns_response;
+       bpf_map_info.dns_refused = dns_refused;
+
+       return TRUE;
+}
+
+void online_monitor_url_check_result(gboolean result)
+{
+       DBG("url_check result %s", result ? "TRUE" : "FALSE");
+
+       if (result) {
+               notify_monitoring_state(ONLINE_MONITOR_STATE_URL_CHECK_SUCCEEDED, ONLINE_MONITOR_DETECTION_NONE);
+               g_state = ONLINE_MONITOR_STATE_URL_CHECK_SUCCEEDED;
+       } else {
+               notify_monitoring_state(ONLINE_MONITOR_STATE_URL_CHECK_FAILED, ONLINE_MONITOR_DETECTION_NONE);
+               g_state = ONLINE_MONITOR_STATE_URL_CHECK_FAILED;
+               stop_monitoring();
+       }
+}
+
+void online_monitor_notifier_register(online_monitor_state_chaged_cb notifier)
+{
+       DBG("notifier %p", notifier);
+
+       notifier_list = g_slist_prepend(notifier_list, (void*)notifier);
+}
+
+void online_monitor_notifier_unregister(online_monitor_state_chaged_cb notifier)
+{
+       DBG("notifier %p", notifier);
+
+       notifier_list = g_slist_remove(notifier_list, notifier);
+}
+
+online_monitor_config_t *online_monitor_get_configuration(void)
+{
+       return &online_monitor_config;
+}
+
+static void start_monitoring(void)
+{
+       int rv = 0;
+       char bpf_file[256];
+
+       if (def_ifname[0] == 0)
+               return;
+
+       if (g_state != ONLINE_MONITOR_STATE_MONITORING_STOPPED
+                       && g_state != ONLINE_MONITOR_STATE_INITIALIZED
+                       && g_state != ONLINE_MONITOR_STATE_UNINITIALIZED)
+               return;
+
+       DBG("ifname %s", def_ifname);
+
+       snprintf(bpf_file, sizeof(bpf_file), BPF_FILE_PATH);
+
+       rv = bpf_prog_load(bpf_file, BPF_PROG_TYPE_SOCKET_FILTER,
+                               &bpf_info.obj, &bpf_info.prog_fd);
+
+       if (rv) {
+               ERR("bpf_prog_load failed %d", rv);
+               return;
+       }
+
+       bpf_info.map_fd = bpf_object__find_map_fd_by_name(bpf_info.obj, "countmap");
+
+       bpf_info.sock = open_raw_socket(def_ifname);
+
+       if (setsockopt(bpf_info.sock, SOL_SOCKET, SO_ATTACH_BPF, &bpf_info.prog_fd,
+                       sizeof(bpf_info.prog_fd)) != 0) {
+               close(bpf_info.sock);
+               ERR("setsockopt failed");
+               return;
+       }
+
+       memset(&bpf_map_info, 0, sizeof(bpf_map_info));
+       bpf_info.timer = g_timeout_add_seconds(BPF_MAP_INTERVAL, check_bpf_map, NULL);
+
+       g_state = ONLINE_MONITOR_STATE_MONITORING_STARTED;
+       notify_monitoring_state(ONLINE_MONITOR_STATE_MONITORING_STARTED, ONLINE_MONITOR_DETECTION_NONE);
+
+       DBG("start_monitoring finished");
+}
+
+static void stop_monitoring(void)
+{
+       if (def_ifname[0] == 0)
+               return;
+
+       if (g_state == ONLINE_MONITOR_STATE_MONITORING_STOPPED
+                       || g_state == ONLINE_MONITOR_STATE_INITIALIZED
+                       || g_state == ONLINE_MONITOR_STATE_UNINITIALIZED)
+               return;
+
+       DBG("ifname %s", def_ifname);
+
+       g_source_remove(bpf_info.timer);
+       bpf_info.timer = 0;
+
+       close(bpf_info.sock);
+
+       g_state = ONLINE_MONITOR_STATE_MONITORING_STOPPED;
+       notify_monitoring_state(ONLINE_MONITOR_STATE_MONITORING_STOPPED, ONLINE_MONITOR_DETECTION_NONE);
+}
+
+static GKeyFile *load_keyfile(const char *pathname)
+{
+       GKeyFile *keyfile = NULL;
+       GError *error = NULL;
+
+       keyfile = g_key_file_new();
+       if (g_key_file_load_from_file(keyfile, pathname, 0, &error) != TRUE) {
+               DBG("Unable to open %s, error %s", pathname, error->message);
+               g_error_free(error);
+
+               g_key_file_free(keyfile);
+               keyfile = NULL;
+       }
+
+       DBG("loaded keyfile %s", pathname);
+       return keyfile;
+}
+
+static int load_configuration(GKeyFile *keyfile)
+{
+       char **pos;
+       char **str_list;
+       gsize length;
+
+       memset(&online_monitor_config, 0, sizeof(online_monitor_config));
+
+       online_monitor_config.is_enabled = g_key_file_get_boolean(keyfile, "General", "Enable", NULL);
+
+       if (!online_monitor_config.is_enabled)
+               return -1;
+
+       online_monitor_config.common_info = g_key_file_get_boolean(keyfile, "General", "CommonInfo", NULL);
+       online_monitor_config.dlog = g_key_file_get_boolean(keyfile, "General", "Dlog", NULL);
+       online_monitor_config.supplicant_log = g_key_file_get_boolean(keyfile, "General", "SuppLog", NULL);
+       online_monitor_config.packet_dump = g_key_file_get_boolean(keyfile, "General", "PacketDump", NULL);
+       online_monitor_config.max_report_count = g_key_file_get_integer(keyfile, "General", "MaxReportCount", NULL);
+
+       if (!online_monitor_config.max_report_count)
+               return -1;
+
+       str_list = g_key_file_get_string_list(keyfile, "General", "URLs", &length, NULL);
+
+       if (!str_list)
+               return -1;
+
+       if (length == 0) {
+               g_strfreev(str_list);
+               str_list = NULL;
+               return -1;
+       }
+
+       pos = str_list;
+
+       while (*pos) {
+               *pos = g_strstrip(*pos);
+               pos++;
+       }
+
+       online_monitor_config.url_list = str_list;
+
+       DBG("Enable %d, CommonInfo %d, Dlog %d, SuppLog %d, PacketDump %d, MaxReportCount %d",
+                       online_monitor_config.is_enabled,
+                       online_monitor_config.common_info,
+                       online_monitor_config.dlog,
+                       online_monitor_config.supplicant_log,
+                       online_monitor_config.packet_dump,
+                       online_monitor_config.max_report_count);
+
+       while (*str_list) {
+               DBG("URL: %s", *str_list);
+               str_list++;
+       }
+
+       return 0;
+}
+
+static int init(void)
+{
+       GKeyFile *keyfile = NULL;
+
+       INFO("Load online_monitor config file [%s]", ONLINE_MONITOR_CONF);
+
+       keyfile = load_keyfile(ONLINE_MONITOR_CONF);
+       if (keyfile == NULL) {
+               ERR("Fail to load online_monitor config file");
+               return -1;
+       }
+
+       if (load_configuration(keyfile) != 0) {
+               ERR("load_configuration failed");
+               return -1;
+       }
+
+       g_key_file_free(keyfile);
+
+       if (url_checker_init() != 0) {
+               ERR("url_checker_init failed");
+               return -1;
+       }
+
+       if (report_manager_init() != 0) {
+               url_checker_deinit();
+               ERR("report_manager_init failed");
+               return -1;
+       }
+
+       DBG("online_monitor_plugin initialized");
+       g_state = ONLINE_MONITOR_STATE_INITIALIZED;
+
+       return 0;
+}
+
+static int deinit(void)
+{
+       report_manager_deinit();
+       url_checker_deinit();
+
+       if (online_monitor_config.url_list)
+               g_strfreev(online_monitor_config.url_list);
+
+       g_slist_free(notifier_list);
+       notifier_list = NULL;
+
+       DBG("online_monitor_plugin deinitialized");
+       g_state = ONLINE_MONITOR_STATE_UNINITIALIZED;
+
+       return 0;
+}
+
+static int notify_online_state(char *ifname, gboolean state)
+{
+       if (g_state == ONLINE_MONITOR_STATE_UNINITIALIZED) {
+               ERR("Not initialized");
+               return -1;
+       }
+
+       if (ifname == NULL) {
+               ERR("Invalid parameter");
+               return -1;
+       }
+
+       DBG("notify_online_state ifname %s state %s", ifname, state ? "TRUE" : "FALSE");
+
+       if (state) {
+               if (g_strcmp0(def_ifname, ifname) != 0) {
+                       stop_monitoring();
+                       g_strlcpy(def_ifname, ifname, sizeof(def_ifname));
+               }
+
+               if (g_state != ONLINE_MONITOR_STATE_MONITORING_STARTED)
+                       start_monitoring();
+
+       } else {
+               if (g_strcmp0(def_ifname, ifname) == 0) {
+                       stop_monitoring();
+                       def_ifname[0] = 0;
+               }
+       }
+
+       return 0;
+}
+
+extern struct netconfig_online_monitor_plugin_t netconfig_online_monitor_plugin
+               __attribute__ ((visibility("default")));
+struct netconfig_online_monitor_plugin_t netconfig_online_monitor_plugin = {
+       init,
+       deinit,
+       notify_online_state
+};
diff --git a/plugin/online-monitor/online-monitor.h b/plugin/online-monitor/online-monitor.h
new file mode 100644 (file)
index 0000000..312eae1
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Network Configuration Module
+ *
+ * Copyright (c) 2021 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.
+ *
+ */
+
+#include "plugin.h"
+#include "util.h"
+
+#ifdef USE_NETCONFIG_LOG
+#include "log.h"
+#else
+#include <dlog.h>
+
+#define NETCONFIG_TAG          "NETCONFIG"
+#define __LOG(level, format, arg...) \
+       do { \
+               SLOG(level, NETCONFIG_TAG, format, ## arg); \
+       } while (0)
+
+#define DBG(format, arg...)    __LOG(LOG_DEBUG, format, ## arg)
+#define ERR(format, arg...)    __LOG(LOG_ERROR, format, ## arg)
+#endif
+
+#define ONLINE_MONITOR_CONF            "/var/lib/net-config/online_monitor.conf"
+
+typedef enum {
+       ONLINE_MONITOR_STATE_UNINITIALIZED = 0,
+       ONLINE_MONITOR_STATE_INITIALIZED = 1,
+       ONLINE_MONITOR_STATE_MONITORING_STARTED = 2,
+       ONLINE_MONITOR_STATE_MONITORING_STOPPED = 3,
+       ONLINE_MONITOR_STATE_OFFLINE_DETECTED = 4,
+       ONLINE_MONITOR_STATE_URL_CHECK_SUCCEEDED = 5,
+       ONLINE_MONITOR_STATE_URL_CHECK_FAILED = 6,
+} online_monitor_state_e;
+
+typedef enum {
+       ONLINE_MONITOR_DETECTION_NONE = 0,
+       ONLINE_MONITOR_DETECTION_UNREACHABLE = 1,
+       ONLINE_MONITOR_DETECTION_DNS_REFUSED = 2,
+       ONLINE_MONITOR_DETECTION_NO_DNS_RESPONSE = 3,
+} online_monitor_detection_e;
+
+typedef struct {
+       gboolean is_enabled;
+       gboolean common_info;
+       gboolean dlog;
+       gboolean supplicant_log;
+       gboolean packet_dump;
+       char **url_list;
+       int max_report_count;
+} online_monitor_config_t;
+
+typedef void(*online_monitor_state_chaged_cb)
+               (online_monitor_state_e state, char *ifname, online_monitor_detection_e reason);
+
+void online_monitor_url_check_result(gboolean result);
+void online_monitor_notifier_register(online_monitor_state_chaged_cb notifier);
+void online_monitor_notifier_unregister(online_monitor_state_chaged_cb notifier);
+online_monitor_config_t *online_monitor_get_configuration(void);
+
+int report_manager_init(void);
+int report_manager_deinit(void);
+int url_checker_init(void);
+int url_checker_deinit(void);
+
+
diff --git a/plugin/online-monitor/online_monitor.conf b/plugin/online-monitor/online_monitor.conf
new file mode 100644 (file)
index 0000000..9dc8bbb
--- /dev/null
@@ -0,0 +1,8 @@
+[General]
+Enable=true
+CommonInfo=true
+Dlog=true
+SuppLog=true
+PacketDump=true
+URLs=www.google.com;www.msn.com;www.yahoo.com;m.google.com;www.amazon.com;www.youtube.com
+MaxReportCount=3
diff --git a/plugin/online-monitor/report-manager.c b/plugin/online-monitor/report-manager.c
new file mode 100755 (executable)
index 0000000..a825ebf
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Network Configuration Module
+ *
+ * Copyright (c) 2021 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.
+ *
+ */
+
+#include "online-monitor.h"
+
+static void report_manager_state_chaged_cb(online_monitor_state_e state,
+                               char *ifname, online_monitor_detection_e reason)
+{
+       DBG("state %d, ifname %s, reason %d", state, ifname, reason);
+}
+
+int report_manager_init(void)
+{
+       online_monitor_notifier_register(report_manager_state_chaged_cb);
+       DBG("report_manager initialized");
+       return 0;
+}
+
+int report_manager_deinit(void)
+{
+       online_monitor_notifier_unregister(report_manager_state_chaged_cb);
+       DBG("report_manager deinitialized");
+       return 0;
+}
diff --git a/plugin/online-monitor/url-checker.c b/plugin/online-monitor/url-checker.c
new file mode 100755 (executable)
index 0000000..a0029e8
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Network Configuration Module
+ *
+ * Copyright (c) 2021 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.
+ *
+ */
+
+#include "online-monitor.h"
+
+static void url_checker_state_chaged_cb(online_monitor_state_e state,
+                               char* ifname, online_monitor_detection_e reason)
+{
+       DBG("state %d, ifname %s, reason %d", state, ifname, reason);
+}
+
+int url_checker_init(void)
+{
+       online_monitor_notifier_register(url_checker_state_chaged_cb);
+       DBG("url_checker initialized");
+       return 0;
+}
+
+int url_checker_deinit(void)
+{
+       online_monitor_notifier_unregister(url_checker_state_chaged_cb);
+       DBG("url_checker deinitialized");
+       return 0;
+}
index f807231..a137aff 100755 (executable)
@@ -112,6 +112,7 @@ struct netconfig_default_connection {
        char *essid;
        unsigned int freq;
        gboolean is_metered;
+       gboolean is_internet;
 };
 
 static struct netconfig_default_connection
@@ -380,6 +381,8 @@ static void __netconfig_clear_default_connection_info(void)
 
        if (netconfig_default_connection_info.profile != NULL) {
 
+               netconfig_notify_online_state(netconfig_default_connection_info.ifname, FALSE);
+
                if (netconfig_is_wifi_profile(netconfig_default_connection_info.profile))
                        __netconfig_reset_ipv4_socket(netconfig_default_connection_info.ifname);
 
@@ -406,6 +409,7 @@ static void __netconfig_clear_default_connection_info(void)
 
                netconfig_default_connection_info.freq = 0;
                netconfig_default_connection_info.is_metered = FALSE;
+               netconfig_default_connection_info.is_internet = FALSE;
 
                g_free(netconfig_default_connection_info.essid);
                netconfig_default_connection_info.essid = NULL;
@@ -459,6 +463,15 @@ static gboolean __netconfig_get_default_connection_info(void)
 
                                netconfig_default_connection_info.essid = g_strdup(value);
                        }
+               } else if (g_strcmp0(key, "State") == 0) {
+                       if (g_variant_is_of_type(var, G_VARIANT_TYPE_STRING)) {
+                               value = g_variant_get_string(var, NULL);
+
+                               if (g_strcmp0(value, "online") == 0) {
+                                       netconfig_default_connection_info.is_internet = TRUE;
+                                       netconfig_notify_online_state(netconfig_default_connection_info.ifname, TRUE);
+                               }
+                       }
                } else if (g_strcmp0(key, "Ethernet") == 0) {
                        g_variant_get(var, "a{sv}", &iter1);
                        if (iter1 == NULL)
@@ -1160,6 +1173,11 @@ gboolean netconfig_get_default_is_metered(void)
        return netconfig_default_connection_info.is_metered;
 }
 
+gboolean netconfig_get_default_is_internet(void)
+{
+       return netconfig_default_connection_info.is_internet;
+}
+
 void netconfig_set_default_ipaddress(const char *ipaddr)
 {
        netconfig_default_connection_info.ipaddress = g_strdup(ipaddr);
@@ -1175,6 +1193,12 @@ void netconfig_set_default_proxy(const char *proxy)
        netconfig_default_connection_info.proxy = g_strdup(proxy);
 }
 
+void netconfig_set_default_is_internet(gboolean state)
+{
+       netconfig_default_connection_info.is_internet = state;
+       netconfig_notify_online_state(netconfig_default_connection_info.ifname, state);
+}
+
 void netconfig_update_default_profile(void)
 {
        if (__netconfig_get_default_connection_info())
index b627f7d..8e214a2 100755 (executable)
@@ -529,13 +529,18 @@ static void _service_signal_cb(GDBusConnection *conn,
 
                if (netconfig_is_wifi_profile(path) || netconfig_is_ethernet_profile(path)) {
                        if (g_strcmp0(property, "ready") == 0) {
+                               if (g_strcmp0(path, netconfig_get_default_profile()) == 0
+                                               && netconfig_get_default_is_internet())
+                                       netconfig_set_default_is_internet(FALSE);
+
                                for (idx = 0; idx < MAX_SOCKET_OPEN_RETRY; idx++) {
                                        sd = start_ip_conflict_mon();
                                        if (sd != NULL)
                                                break;
                                }
                        } else if (g_strcmp0(property, "online") == 0) {
-                               // do nothing
+                               if (g_strcmp0(path, netconfig_get_default_profile()) == 0)
+                                       netconfig_set_default_is_internet(TRUE);
                        } else {
                                stop_ip_conflict_mon();
                        }
index a6d44a5..1a18a4a 100755 (executable)
 #include "wifi-state.h"
 #include "netdbus.h"
 
-#define DBUS_SERVICE_DBUS              "org.freedesktop.DBus"
-#define DBUS_INTERFACE_DBUS            "org.freedesktop.DBus"
-#define MAC_INFO_FILEPATH              tzplatform_mkpath(TZ_SYS_ETC, "/.mac.info")
-#define MAC_ADDRESS_FILEPATH   "/sys/class/net/wlan0/address"
-#define HEADED_PLUGIN_FILEPATH         "/usr/lib/net-config-plugin-headed.so"
-#define TELEPHONY_PLUGIN_FILEPATH      "/usr/lib/net-config-plugin-telephony.so"
-#define STC_PLUGIN_FILEPATH            "/usr/lib/net-config-plugin-stc.so"
-#define BATTERY_PLUGIN_FILEPATH            "/usr/lib/net-config-plugin-battery.so"
-#define CONNMAN_MAINFILE                       "/etc/connman/main.conf"
-#define CONNMAN_WIFI_DEF_IFNAME                "DefaultWifiInterface"
+#define DBUS_SERVICE_DBUS              "org.freedesktop.DBus"
+#define DBUS_INTERFACE_DBUS            "org.freedesktop.DBus"
+#define MAC_INFO_FILEPATH              tzplatform_mkpath(TZ_SYS_ETC, "/.mac.info")
+#define MAC_ADDRESS_FILEPATH           "/sys/class/net/wlan0/address"
+#if defined(TIZEN_ARCH_64)
+#define HEADED_PLUGIN_FILEPATH         "/usr/lib64/net-config-plugin-headed.so"
+#define TELEPHONY_PLUGIN_FILEPATH      "/usr/lib64/net-config-plugin-telephony.so"
+#define STC_PLUGIN_FILEPATH            "/usr/lib64/net-config-plugin-stc.so"
+#define BATTERY_PLUGIN_FILEPATH        "/usr/lib64/net-config-plugin-battery.so"
+#define ONLINE_MONITOR_PLUGIN_FILEPATH "/usr/lib64/net-config-plugin-online-monitor.so"
+#else
+#define HEADED_PLUGIN_FILEPATH         "/usr/lib/net-config-plugin-headed.so"
+#define TELEPHONY_PLUGIN_FILEPATH      "/usr/lib/net-config-plugin-telephony.so"
+#define STC_PLUGIN_FILEPATH            "/usr/lib/net-config-plugin-stc.so"
+#define BATTERY_PLUGIN_FILEPATH        "/usr/lib/net-config-plugin-battery.so"
+#define ONLINE_MONITOR_PLUGIN_FILEPATH "/usr/lib/net-config-plugin-online-monitor.so"
+#endif
+#define CONNMAN_MAINFILE               "/etc/connman/main.conf"
+#define CONNMAN_WIFI_DEF_IFNAME        "DefaultWifiInterface"
 
 static gboolean netconfig_device_picker_test = FALSE;
 typedef struct {
@@ -67,14 +76,17 @@ static gboolean netconfig_plugin_headed_enabled = FALSE;
 static gboolean netconfig_plugin_telephony_enabled = FALSE;
 static gboolean netconfig_plugin_stc_enabled = FALSE;
 static gboolean netconfig_plugin_battery_enabled = FALSE;
+static gboolean netconfig_plugin_online_monitor_enabled = FALSE;
 static void *handle_headed;
 static void *handle_telephony;
 static void *handle_stc;
 static void *handle_battery;
+static void *handle_online_monitor;
 static struct netconfig_headed_plugin_t *headed_plugin;
 static struct netconfig_telephony_plugin_t *telephony_plugin;
 static struct netconfig_stc_plugin_t *stc_plugin;
 static struct netconfig_battery_plugin_t *battery_plugin;
+static struct netconfig_online_monitor_plugin_t *online_monitor_plugin;
 
 static bool is_feature_checked[NETCONFIG_SUPPORTED_FEATURE_MAX] = {0, };
 static bool feature_supported[NETCONFIG_SUPPORTED_FEATURE_MAX] = {0, };
@@ -1213,6 +1225,17 @@ void netconfig_battery_get_wifi_list(void *data)
        return battery_plugin->get_battery_wifi_list(data, __netconfig_stc_get_wifi_stats);
 }
 
+void netconfig_notify_online_state(char *ifname, gboolean online_state)
+{
+       if (!netconfig_plugin_online_monitor_enabled)
+               return;
+
+       if (!online_monitor_plugin)
+               return;
+
+       online_monitor_plugin->notify_online_state(ifname, online_state);
+}
+
 void netconfig_set_vconf_int(const char * key, int value, gboolean log)
 {
        int ret = 0;
@@ -1547,6 +1570,19 @@ void netconfig_plugin_init()
                }
        }
 
+       handle_online_monitor = dlopen(ONLINE_MONITOR_PLUGIN_FILEPATH, RTLD_NOW);
+       if (!handle_online_monitor) {
+               ERR("Can't load %s: %s", ONLINE_MONITOR_PLUGIN_FILEPATH, dlerror());
+       } else {
+               online_monitor_plugin = dlsym(handle_online_monitor, "netconfig_online_monitor_plugin");
+               if (!online_monitor_plugin) {
+                       ERR("Can't load symbol: %s", dlerror());
+                       dlclose(handle_online_monitor);
+               } else {
+                       if (online_monitor_plugin->init() == 0)
+                               netconfig_plugin_online_monitor_enabled = TRUE;
+               }
+       }
 }
 
 void netconfig_plugin_deinit()
@@ -1571,6 +1607,12 @@ void netconfig_plugin_deinit()
                dlclose(handle_battery);
        }
 
+       if (netconfig_plugin_online_monitor_enabled) {
+               netconfig_plugin_online_monitor_enabled = FALSE;
+               if (online_monitor_plugin)
+                       online_monitor_plugin->deinit();
+               dlclose(handle_online_monitor);
+       }
 }
 
 gboolean netconfig_get_headed_plugin_flag()