Added initial monitoring service for external interface
authorsaerome.kim <saerome.kim@samsung.com>
Fri, 30 Jun 2017 04:07:57 +0000 (13:07 +0900)
committersaerome.kim <saerome.kim@samsung.com>
Mon, 17 Jul 2017 02:35:37 +0000 (11:35 +0900)
Signed-off-by: saerome.kim <saerome.kim@samsung.com>
CMakeLists.txt
include/mesh-device-monitor.h [new file with mode: 0644]
include/mesh-peer-monitor.h [moved from include/mesh-monitor.h with 85% similarity]
include/mesh.h
packaging/meshd.spec
src/mesh-device-monitor.c [new file with mode: 0644]
src/mesh-interface.c
src/mesh-peer-monitor.c [moved from src/mesh-monitor.c with 77% similarity]
src/mesh-service-interface.c

index a5d32a9..a7d116f 100644 (file)
@@ -10,6 +10,7 @@ INCLUDE(FindPkgConfig)
 SET(PKG_MODULES
                gio-2.0
                gio-unix-2.0
+#              gudev-1.0
                dlog
                libnl-3.0
                libnl-genl-3.0
@@ -32,6 +33,15 @@ SET(CMAKE_C_FLAGS_RELEASE "-fPIE")
 ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
 ADD_DEFINITIONS("-DUSE_DLOG")
 ADD_DEFINITIONS("-DTIZEN_DEBUG_ENABLE")
+IF(USE_UDEV_MONITOR)
+       ADD_DEFINITIONS(-DUSE_UDEV_MONITOR)
+ENDIF(USE_UDEV_MONITOR)
+IF(USE_NETLINK_MONITOR)
+       ADD_DEFINITIONS(-DUSE_NETLINK_MONITOR)
+ENDIF(USE_NETLINK_MONITOR)
+IF(USE_IOCTL_MONITOR)
+       ADD_DEFINITIONS(-DUSE_IOCTL_MONITOR)
+ENDIF(USE_IOCTL_MONITOR)
 IF(TIZEN_FEATURE_MESH_ON_DEMAND)
        ADD_DEFINITIONS(-DTIZEN_FEATURE_MESH_ON_DEMAND)
 ENDIF(TIZEN_FEATURE_MESH_ON_DEMAND)
diff --git a/include/mesh-device-monitor.h b/include/mesh-device-monitor.h
new file mode 100644 (file)
index 0000000..e7f2048
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Network Configuration Module
+ *
+ * Copyright (c) 2017 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 __MESH_DEVICE_MONITOR_H__
+#define __MESH_DEVICE_MONITOR_H__
+
+#ifdef USE_IOCTL_MONITOR
+#define ETH_REG_BMSR 0x01
+#define BMSR_LINK_VALID 0x0004
+
+#define SIOCGMIIPHY 0x8947 /* Get address of MII PHY in use. */
+#define SIOCGMIIREG 0x8948 /* Read MII PHY register */
+
+struct _stMData {
+       unsigned short phy_id;
+       unsigned short reg_num;
+       unsigned short val_in;
+       unsigned short val_out;
+};
+int mesh_get_ethernet_cable_state(int *status);
+#endif /* USE_IOCTL_MONITOR */
+
+#ifdef USE_NETLINK_MONITOR
+int mesh_device_monitor(void *pdata);
+#endif /* USE_NETLINK_MONITOR */
+
+#endif /* __MESH_DEVICE_MONITOR_H__ */
similarity index 85%
rename from include/mesh-monitor.h
rename to include/mesh-peer-monitor.h
index d9d6dc3..441ee3f 100644 (file)
@@ -19,8 +19,8 @@
 #ifndef __MESH_MONITOR_H__
 #define __MESH_MONITOR_H__
 
-int mesh_start_peer_monitor(void *pdata);
+int mesh_start_monitor_service(void *pdata);
 
-int mesh_stop_peer_monitor(void *pdata);
+int mesh_stop_monitor_service(void *pdata);
 
 #endif /* __MESH_MONITOR_H__ */
\ No newline at end of file
index 89416f0..8949e9d 100644 (file)
@@ -21,6 +21,9 @@
 
 #include <glib.h>
 #include <gio/gio.h>
+#ifdef USE_UDEV_MONITOR
+#include <gudev/gudev.h>
+#endif /* USE_UDEV_MONITOR */
 #include <tizen.h>
 
 /**< Internal error code with mesh daemon. It should be matched with API side */
@@ -56,9 +59,13 @@ typedef struct {
        gchar *mesh_interface; /**< The name of mesh network interface */
        gchar *softap_interface; /**< The name of SoftAP network interface */
        gchar *external_interface; /**< The name of external network interface */
+       gboolean can_be_gate; /**< Whether this device can be Mesh Gate */
 
        gchar *mesh_id; /**< Mesh ID */
        gint mesh_channel; /**< The channel number of mesh network */
+#ifdef USE_UDEV_MONITOR
+       GUdevClient *udev_client; /**< The udev event client */
+#endif /* USE_UDEV_MONITOR */
 } mesh_interface_s;
 
 /**< Saved mesh network list structure */
@@ -161,6 +168,8 @@ typedef struct _mesh_service {
 
        GList *station_list; /**< Mesh station list */
        GList *mpath_list; /**< MPath list */
+       int netlink_fd; /**< Netlink event socket file descriptor */
+       int monitor_timer; /**< Timer ID for peer monitoring service */
 } mesh_service;
 
  #endif /* __MESH_H__ */
index 801908b..74f6dad 100644 (file)
@@ -1,4 +1,7 @@
 %define CHECK_MESH_PRIVILEGE False
+%define UDEV_MONITOR False
+%define NETLINK_MONITOR False
+%define IOCTL_MONITOR False
 
 Name:          meshd
 Summary:       mesh network daemon
@@ -13,6 +16,7 @@ Source3:      meshd.service
 BuildRequires: pkgconfig(glib-2.0)
 BuildRequires: pkgconfig(gio-2.0)
 BuildRequires: pkgconfig(gio-unix-2.0)
+#BuildRequires: pkgconfig(gudev-1.0)
 BuildRequires: pkgconfig(dlog)
 BuildRequires: pkgconfig(libnl-3.0)
 BuildRequires: pkgconfig(dbus-1)
diff --git a/src/mesh-device-monitor.c b/src/mesh-device-monitor.c
new file mode 100644 (file)
index 0000000..aab4b7f
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Network Configuration Module
+ *
+ * Copyright (c) 2017 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 <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#ifdef USE_IOCTL_MONITOR
+#include <sys/ioctl.h>
+#endif
+#ifdef USE_NETLINK_MONITOR
+#include <asm/types.h>
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <net/if_arp.h>
+#endif /* USE_NETLINK_MONITOR */
+
+#include "mesh.h"
+#include "mesh-log.h"
+#include "mesh-util.h"
+#include "mesh-device-monitor.h"
+
+#ifdef USE_NETLINK_MONITOR
+static void mesh_read_netlink_msg(void *pdata)
+{
+       int len;
+       int buf[1024];
+
+       struct sockaddr_nl sa;
+       struct nlmsghdr *nh;
+       struct ifinfomsg *ifimsg;
+       struct rtattr *attribute;
+       struct iovec iov = { buf, sizeof(buf) };
+       struct msghdr msg = { (void *)&sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
+
+       mesh_interface_s *info = NULL;
+       mesh_service *service = (mesh_service *)pdata;
+       meshd_check_null_ret("service", service);
+       info = service->interface_info;
+       meshd_check_null_ret("info", info);
+
+       len = recvmsg(service->netlink_fd, &msg, 0);
+       if(-1 == len) {
+               MESH_LOGE("recvmsg error");
+               return;
+       }
+
+       for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
+               if (nh->nlmsg_type == NLMSG_ERROR) {
+                       MESH_LOGE("Read Netlink Message Error!!");
+                       continue;
+               }
+               if (nh->nlmsg_type == NLMSG_DONE) {
+                       MESH_LOGD("Read Netlink Message Done");
+                       return;
+               }
+
+               ifimsg = NLMSG_DATA(nh);
+               MESH_LOGD("Message : [%u %u %u 0x%X 0x%X]",
+                       ifimsg->ifi_family,
+                       ifimsg->ifi_type,
+                       ifimsg->ifi_index,
+                       ifimsg->ifi_flags,
+                       ifimsg->ifi_change);
+               /* Monitor external interface state change */
+               if (ARPHRD_ETHER != ifimsg->ifi_type)
+                       return;
+
+               attribute = IFLA_RTA(ifimsg);
+               if (IFLA_IFNAME == attribute->rta_type) {
+                       if (!g_strcmp0(info->external_interface, RTA_DATA(attribute))) {
+                               MESH_LOGD("Event from external interface : [%s]", RTA_DATA(attribute));
+                               if (RTM_NEWLINK == nh->nlmsg_type && false == info->can_be_gate &&
+                                       IFF_LOWER_UP == (ifimsg->ifi_flags & IFF_LOWER_UP)) {
+                                       MESH_LOGD("RTM_NEWLINK : [%s]", RTA_DATA(attribute));
+                                       info->can_be_gate = true;
+                               } else if (RTM_DELLINK == nh->nlmsg_type) {
+                                       MESH_LOGD("RTM_DELLINK : [%s]", RTA_DATA(attribute));
+                                       info->can_be_gate = false;
+                               }
+                       }
+               }
+       }
+}
+
+static gboolean _on_socket_msg_received(GIOChannel *source,
+               GIOCondition condition, gpointer data)
+{
+       NOTUSED(source);
+       NOTUSED(condition);
+
+       mesh_read_netlink_msg(data);
+
+       /* Do not remove I/O source */
+       return TRUE;
+}
+
+int mesh_device_monitor(void *pdata)
+{
+       struct sockaddr_nl sa;
+       guint event_source;
+       GIOChannel *recv_channel = NULL;
+
+       mesh_service *service = (mesh_service *)pdata;
+       meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
+
+       memset(&sa, 0, sizeof(sa));
+       sa.nl_family = AF_NETLINK;
+       sa.nl_groups = RTMGRP_LINK;
+
+       service->netlink_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+       if(-1 == service->netlink_fd) {
+               MESH_LOGE("Netlink socket creation error");
+               return MESHD_ERROR_OPERATION_FAILED;
+       }
+
+       if(bind(service->netlink_fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
+               MESH_LOGE("bind error");
+               return MESHD_ERROR_OPERATION_FAILED;
+       }
+
+       recv_channel = g_io_channel_unix_new(service->netlink_fd);
+       event_source = g_io_add_watch(recv_channel,     (G_IO_IN | G_IO_ERR),
+                                       _on_socket_msg_received, (gpointer)service);
+       g_io_channel_unref(recv_channel);
+
+    return 0;
+}
+#endif /* USE_NETLINK_MONITOR */
+
+#ifdef USE_IOCTL_MONITOR
+/* Check send notification status */
+static gboolean g_chk_eth_send_notification = FALSE;
+#define MAX_SIZE_ERROR_BUFFER 128
+
+static int _ethernet_cable_plugin_status_check()
+{
+       struct ifreq ifr;
+       int soketfd = -1;
+       int error = 0;
+       int ret = 0;
+       struct _stMData *mdata;
+       struct timeval tv;
+       char error_buf[MAX_SIZE_ERROR_BUFFER] = {};
+
+       soketfd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+       if (soketfd < 0) {
+               MESH_LOGE("Failed to create socket");
+               return -errno;
+       }
+
+       /* Set Timeout for IOCTL Call */
+       tv.tv_sec = 1;
+       tv.tv_usec = 0;
+
+       if (setsockopt(soketfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
+               sizeof(struct timeval)) < 0) {
+
+               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+               MESH_LOGE("Failed to set socket option : [%d] [%s]", -errno, error_buf);
+               goto done;
+       }
+
+       memset(&ifr, 0, sizeof(ifr));
+       g_strlcpy(ifr.ifr_name, "eth0", IFNAMSIZ);
+       if (ioctl(soketfd, SIOCGMIIPHY, &ifr) < 0){
+               error = -errno;
+               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+               MESH_LOGE("SIOCGMIIPHY on eth0 failed : [%d] [%s]", errno, error_buf);
+               goto done;
+       }
+
+       mdata = (struct _stMData *)&ifr.ifr_data;
+       mdata->reg_num = ETH_REG_BMSR;
+
+       if (ioctl(soketfd, SIOCGMIIREG, &ifr) < 0){
+               error = -errno;
+               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+               MESH_LOGE("SIOCGMIIREG on %s failed , [%d] [%s] ", ifr.ifr_name,errno,error_buf);
+               goto done;
+       }
+       ret = mdata->val_out;
+       ret = ret & BMSR_LINK_VALID;
+
+       MESH_LOGD("value of ret : %d",ret);
+
+       if (ret == 4) {
+               if (!g_chk_eth_send_notification) {
+                       MESH_LOGE("Return Value : [%d]", ret);
+               }
+               g_chk_eth_send_notification = TRUE;
+               } else if (ret == 0) {
+                       if (g_chk_eth_send_notification) {
+                       MESH_LOGE("Return Value : [%d]", ret);
+               }
+               g_chk_eth_send_notification = FALSE;
+       }
+
+
+       error = 0;
+done:
+       close(soketfd);
+       return error;
+}
+
+int mesh_get_ethernet_cable_state(int *status)
+{
+       int error = 0;
+       meshd_check_null_ret_error("status", status, MESHD_ERROR_INVALID_PARAMETER);
+
+       if ((error = _ethernet_cable_plugin_status_check()) != 0) {
+               MESH_LOGE("Error !!! Failed to check ethernet cable status [%d]\n", error);
+               return error;
+       }
+
+       if (g_chk_eth_send_notification == TRUE)
+               *status = 1;            /* Ethernet cable Attached */
+       else
+               *status = 0;            /* Ethernet cable Deattached */
+       return MESHD_ERROR_NONE;
+}
+#endif
index 15ee3a3..cef4287 100644 (file)
@@ -18,7 +18,9 @@
  */
 #include <glib.h>
 #include <gio/gio.h>
-
+#ifdef USE_UDEV_MONITOR
+#include <gudev/gudev.h>
+#endif /* USE_UDEV_MONITOR */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -245,6 +247,25 @@ char* mesh_interface_get_address(const char* if_name)
        return result;
 }
 
+#ifdef USE_UDEV_MONITOR
+static void __on_uevent(GUdevClient *client, gchar *action, GUdevDevice *device, gpointer user_data)
+{
+       NOTUSED(client);
+       NOTUSED(device);
+       NOTUSED(user_data);
+
+       MESH_LOGD("KSR : action:[%s]", action);
+}
+
+static void _interface_status_monitor_init(mesh_interface_s *info)
+{
+       const gchar *subsystem[] = {"net", NULL};
+
+       info->udev_client = g_udev_client_new(subsystem);
+       g_signal_connect(info->udev_client, "uevent", G_CALLBACK(__on_uevent), info);
+}
+#endif /* USE_UDEV_MONITOR */
+
 int mesh_interface_initialize(mesh_interface_s *info)
 {
        if (NULL == info) {
@@ -280,6 +301,9 @@ int mesh_interface_initialize(mesh_interface_s *info)
        MESH_LOGD("  SoftAP  : [%s]", info->softap_interface);
        MESH_LOGD("  External: [%s]", info->external_interface);
 
+#ifdef USE_UDEV_MONITOR
+       _interface_status_monitor_init(info);
+#endif /* USE_UDEV_MONITOR */
        return MESHD_ERROR_NONE;
 }
 
@@ -393,3 +417,4 @@ int mesh_interface_check_bridge_interface_exists(const char* bridge, const char*
 
        return MESHD_ERROR_NONE;
 }
+
similarity index 77%
rename from src/mesh-monitor.c
rename to src/mesh-peer-monitor.c
index 55f3b90..535ed40 100644 (file)
 #include "mesh-util.h"
 #include "mesh-request.h"
 #include "mesh-netlink.h"
-#include "mesh-monitor.h"
+#include "mesh-interface.h"
+#include "mesh-peer-monitor.h"
+#include "mesh-device-monitor.h"
 
 #define MESH_MONITORING_TIME 5
 #define MESH_MAXIMUM_BEACON_LOST_COUNT 10
 
-static guint g_timer = 0;
-
 static void _on_station_list_destroy(gpointer data)
 {
        mesh_station_info_s *info = (mesh_station_info_s*)data;
@@ -191,42 +191,73 @@ static gboolean _get_mpath_info(void *pdata)
 #endif
 static gboolean _on_mesh_monitor_cb(gpointer pdata)
 {
+       int ret;
+#ifdef USE_IOCTL_MONITOR
+       int state;
+#else
+       bool state;
+#endif /* USE_IOCTL_MONITOR */
        mesh_service *service = (mesh_service *)pdata;
-
-       MESH_LOGD("Evaluting...");
+       if (service) {
+               mesh_interface_s *info = service->interface_info;
+               if (info) {
+                       /* Exceptionally, checking external interface processes here. */
+#ifdef USE_IOCTL_MONITOR
+                       ret = mesh_get_ethernet_cable_state(&state);
+#else
+                       ret = mesh_interface_check_external_exists(info->external_interface, &state);
+#endif /* USE_IOCTL_MONITOR */
+                       MESH_LOGE("Status : %d %d %d", ret, info->can_be_gate, state);
+                       if (MESHD_ERROR_NONE == ret) {
+                               if (info->can_be_gate != state) {
+                                       /* Detect external network state (i.e. Ethernet)
+                                               and decide to make gate enabled */
+                                       if (state)
+                                               mesh_request_set_mesh_gate(info->bridge_interface,
+                                                               info->mesh_interface, info->external_interface);
+                                       else
+                                               mesh_request_unset_mesh_gate(info->bridge_interface,
+                                                               info->mesh_interface, info->external_interface);
+
+                                       MESH_LOGD("External interface state has been changed : [%d]", state);
+                                       info->can_be_gate = state;
+                               }
+                       }
 #if 0
-       _get_mpath_info(service);
+                       _get_mpath_info(service);
 #endif
-       _get_station_info(service);
+                       _get_station_info(service);
+               }
+       }
 
        return G_SOURCE_CONTINUE;
 }
 
-int mesh_start_peer_monitor(void *pdata)
+int mesh_start_monitor_service(void *pdata)
 {
        int ret = MESHD_ERROR_NONE;
        mesh_service *service = (mesh_service *)pdata;
+       meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
 
-       if (g_timer)
-               mesh_stop_peer_monitor(pdata);
+       if (service->monitor_timer)
+               mesh_stop_monitor_service(pdata);
 
-       g_timer = g_timeout_add_seconds(MESH_MONITORING_TIME, _on_mesh_monitor_cb, service);
+       service->monitor_timer = g_timeout_add_seconds(MESH_MONITORING_TIME, _on_mesh_monitor_cb, service);
 
        MESH_LOGD("Peer Monitoring Service Started");
 
        return ret;
 }
 
-int mesh_stop_peer_monitor(void *pdata)
+int mesh_stop_monitor_service(void *pdata)
 {
        int ret = MESHD_ERROR_NONE;
        mesh_service *service = (mesh_service *)pdata;
+       meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
 
-       NOTUSED(service);
-
-       if (g_timer) {
-               g_source_remove(g_timer);
-               g_timer = 0;
+       if (service->monitor_timer) {
+               g_source_remove(service->monitor_timer);
+               service->monitor_timer = 0;
        }
 
        MESH_LOGD("Peer Monitoring Service Stopped");
index eb771d0..5e904c1 100644 (file)
@@ -27,7 +27,8 @@
 #include "mesh-util.h"
 #include "mesh-gdbus.h"
 #include "mesh-service.h"
-#include "mesh-monitor.h"
+#include "mesh-peer-monitor.h"
+#include "mesh-device-monitor.h"
 #include "mesh-service-interface.h"
 #include "mesh-generated-code.h"
 
@@ -370,18 +371,10 @@ static gboolean _meshd_dbus_handle_enable_mesh(NetMesh *object,
        if (MESHD_ERROR_NONE != ret)
                MESH_LOGE("Failed to mesh_request_enable_network [%d]", ret);
 
-#if 0
-       /* Detect external network state (i.e. Ethernet)
-                       and decide to make gate enabled */
-       ret = mesh_request_set_mesh_gate(info->bridge_interface,
-                       info->mesh_interface, info->external_interface);
-       if (MESHD_ERROR_NONE != ret)
-               MESH_LOGE("Failed to mesh_request_set_mesh_gate [%d]", ret);
-#endif
-
-       if (MESHD_ERROR_NONE == ret)
-               mesh_start_peer_monitor(service);
-
+       mesh_start_monitor_service(service);
+#ifdef USE_NETLINK_MONITOR
+       mesh_device_monitor(service);
+#endif /* USE_NETLINK_MONITOR */
        net_mesh_complete_enable_mesh(object, invocation, ret);
 
        return TRUE;
@@ -409,8 +402,7 @@ static gboolean _meshd_dbus_handle_disable_mesh(NetMesh *object,
                MESH_LOGE("Failed to disable mesh network !");
 
        /* Stop Mesh Node Monitoring Service */
-       mesh_stop_peer_monitor(service);
-
+       mesh_stop_monitor_service(service);
        /* Make response */
        net_mesh_complete_disable_mesh(object, invocation, ret);