Added IP conflict detection monitoring for conflict CAPI's. 74/151974/11
authorAbhishek Sansanwal <abhishek.s94@samsung.com>
Fri, 22 Sep 2017 14:16:41 +0000 (19:46 +0530)
committerAbhishek Sansanwal <abhishek.s94@samsung.com>
Wed, 8 Nov 2017 06:45:58 +0000 (12:15 +0530)
Change-Id: I4af7bd59b91f20d93415e49eb41ee2910f98dfd1
Signed-off-by: Abhishek Sansanwal <abhishek.s94@samsung.com>
CMakeLists.txt
include/ip-conflict-detect.h [new file with mode: 0644]
include/network-state.h
interfaces/netconfig-iface-wifi.xml
resources/etc/dbus-1/system.d/net-config.conf
src/ip-conflict-detect.c [new file with mode: 0644]
src/network-state.c
src/signal-handler.c
src/wifi.c

index 8546f90..1069cdd 100755 (executable)
@@ -39,6 +39,7 @@ SET(SRCS
        src/wifi-background-scan.c
        src/wifi-config.c
        src/wifi-extension.c
+       src/ip-conflict-detect.c
        )
 
 IF("${CMAKE_BUILD_TYPE}" STREQUAL "")
diff --git a/include/ip-conflict-detect.h b/include/ip-conflict-detect.h
new file mode 100644 (file)
index 0000000..6cd9608
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Network Configuration Module
+ *
+ * Copyright (c) 2000 - 2012 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 __NETCONFIG_IP_CONFLICT_DETECT_H__
+#define __NETCONFIG_IP_CONFLICT_DETECT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include "wifi.h"
+
+struct sock_data {
+       guint timer_id;
+       int chk_conflict_data_id;
+       GIOChannel *chk_conflict_sock_io;
+       int chk_conflict_sd;
+       guint timeout;
+       guint arp_reply_timer;
+       int iteration;
+};
+
+struct sock_data * start_ip_conflict_mon(void);
+void stop_ip_conflict_mon();
+gboolean handle_ip_conflict_set_enable(Wifi *wifi, GDBusMethodInvocation *context,
+               bool detect);
+gboolean handle_is_ip_conflict_detect_enabled(Wifi *wifi, GDBusMethodInvocation *context);
+gboolean handle_set_ip_conflict_mode(Wifi *wifi, GDBusMethodInvocation *context,
+               guint mode, guint initial_time);
+gboolean handle_get_ip_conflict_state(Wifi *wifi, GDBusMethodInvocation
+                                     *context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __NETCONFIG_IP_CONFLICT_DETECT_H__ */
index a1bdd0d..a38b1af 100755 (executable)
@@ -26,18 +26,19 @@ extern "C" {
 
 void netconfig_network_notify_ethernet_cable_state(const char *key);
 
-const char             *netconfig_get_default_profile(void);
-const char             *netconfig_get_default_ifname(void);
-const char             *netconfig_get_default_ipaddress(void);
-const char             *netconfig_get_default_ipaddress6(void);
-const char             *netconfig_get_default_proxy(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);
-
-void                   netconfig_update_default(void);
-void                   netconfig_update_default_profile(const char *profile);
-char                   *netconfig_get_ifname(const char *profile);
+const char *netconfig_get_default_profile(void);
+const char *netconfig_get_default_ifname(void);
+const char *netconfig_get_default_ipaddress(void);
+const char *netconfig_get_default_ipaddress6(void);
+const char *netconfig_get_default_proxy(void);
+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);
+
+void netconfig_update_default(void);
+void netconfig_update_default_profile(const char *profile);
+char *netconfig_get_ifname(const char *profile);
 
 void state_object_create_and_init(void);
 void state_object_deinit(void);
index c1d46e6..023659c 100755 (executable)
@@ -17,6 +17,9 @@
                <method name="GetWifiState">
                        <arg type="s" name="state" direction="out"/>
                </method>
+               <method name="IsIpConflictDetectEnabled">
+                       <arg type="b" name="state" direction="out"/>
+               </method>
                <method name="SetBgscan">
                        <arg type="u" name="ScanMode" direction="in"/>
                </method>
@@ -31,6 +34,9 @@
                <method name="GetAutoscan">
                        <arg type="b" name="autoscan" direction="out"/>
                </method>
+               <method name="GetIpConflictState">
+                       <arg type="u" name="state" direction="out"/>
+               </method>
                <method name="GetAutoscanmode">
                        <arg type="u" name="autoscanmode" direction="out"/>
                </method>
                        <arg type="s" name="config_id" direction="in"/>
                        <arg type="a{sv}" name="Configuration" direction="in"/>
                </method>
+               <method name="SetIpConflictMode">
+                       <arg type="u" name="mode" direction="in"/>
+                       <arg type="u" name="initial_time" direction="in"/>
+               </method>
                <method name="RemoveConfiguration">
                        <arg type="s" name="config_id" direction="in"/>
                </method>
@@ -85,6 +95,9 @@
                <method name="DeleteEapConfig">
                        <arg type="s" name="Profile" direction="in"/>
                </method>
+               <method name="IpConflictSetEnable">
+                       <arg type="b" name="detect" direction="in"/>
+               </method>
                <method name="GetSimImsi">
                        <arg type="s" name="imsi_data" direction="out"/>
                </method>
                <signal name="BssidScanCompleted">
                        <arg type="a{sv}" name="Fields" direction="out"/>
                </signal>
+               <signal name="IpConflictEvent">
+                       <arg type="a{sv}" name="Fields" direction="out"/>
+               </signal>
        </interface>
        <interface name="net.connman.Agent">
                <method name="SetField">
index ef94c1d..5355c87 100755 (executable)
                <check send_destination="net.netconfig" send_interface="net.netconfig.network_statistics" send_member="ResetWifiTotalTxBytes" privilege="http://tizen.org/privilege/network.set" />
 
                <check send_destination="net.netconfig" send_interface="net.netconfig.wifi" send_member="DeleteEapConfig" privilege="http://tizen.org/privilege/network.profile" />
+               <check send_destination="net.netconfig" send_interface="net.netconfig.wifi" send_member="RequestSpecificScan" privilege="http://tizen.org/privilege/network.set" />
+               <check send_destination="net.netconfig" send_interface="net.netconfig.wifi" send_member="IpConflictSetEnable" privilege="http://tizen.org/privilege/network.set" />
+               <check send_destination="net.netconfig" send_interface="net.netconfig.wifi" send_member="IsIpConflictDetectEnabled" privilege="http://tizen.org/privilege/network.get" />
+               <check send_destination="net.netconfig" send_interface="net.netconfig.wifi" send_member="GetIpConflictState" privilege="http://tizen.org/privilege/network.get" />
                <check send_destination="net.netconfig" send_interface="net.netconfig.wifi" send_member="RequestBssidScan" privilege="http://tizen.org/privilege/network.set" />
                <check send_destination="net.netconfig" send_interface="net.netconfig.wifi" send_member="RequestWpsCancel" privilege="http://tizen.org/privilege/network.set" />
                <check send_destination="net.netconfig" send_interface="net.netconfig.wifi" send_member="RequestWpsConnect" privilege="http://tizen.org/privilege/network.set" />
@@ -69,6 +73,7 @@
                <check send_destination="net.netconfig" send_interface="net.netconfig.wifi" send_member="PowerOffCompleted" privilege="http://tizen.org/privilege/network.get" />
                <check send_destination="net.netconfig" send_interface="net.netconfig.wifi" send_member="SpecificScanCompleted" privilege="http://tizen.org/privilege/network.get" />
                <check send_destination="net.netconfig" send_interface="net.netconfig.wifi" send_member="BssidScanCompleted" privilege="http://tizen.org/privilege/network.get" />
+               <check send_destination="net.netconfig" send_interface="net.netconfig.wifi" send_member="IPConflictEvent" privilege="http://tizen.org/privilege/network.get" />
                <check send_destination="net.netconfig" send_interface="net.netconfig.wifi" send_member="TdlsDisconnect" privilege="http://tizen.org/privilege/network.set" />
                <check send_destination="net.netconfig" send_interface="net.netconfig.wifi" send_member="TdlsConnectedPeer" privilege="http://tizen.org/privilege/network.get" />
 
diff --git a/src/ip-conflict-detect.c b/src/ip-conflict-detect.c
new file mode 100644 (file)
index 0000000..414298a
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * Network Configuration Module
+ *
+ * Copyright (c) 2000 - 2012 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 <stdio.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/ether.h>
+#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <glib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include "ip-conflict-detect.h"
+#include "network-state.h"
+#include "log.h"
+#include "neterror.h"
+
+#define ARP_PACKET_SIZE 60
+#define MAX_SIZE_ERROR_BUFFER 256
+#define IP_ADDRESS_LENGTH 4
+#define MAC_ADDRESS_LENGTH 6
+#define WLAN_MAC_ADDR_MAX 20
+
+#define MIN_ARP_SEND_TIME 2000
+#define MAX_ARP_SEND_TIME 32000
+#define GRATUITOUS_ARP_MAC_ADDR "00:00:00:00:00:00"
+#define UCHAR_TO_ADDRESS(hwaddr, buf) do {\
+               snprintf(buf, WLAN_MAC_ADDR_MAX,\
+               "%02X:%02X:%02X:%02X:%02X:%02X", hwaddr[0], hwaddr[1],\
+               hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);\
+               } while (0)
+
+struct arp_message {
+       /* Ethernet header */
+       unsigned char   h_dest[MAC_ADDRESS_LENGTH];     /* destination ether addr */
+       unsigned char   h_source[MAC_ADDRESS_LENGTH];   /* source ether addr */
+       unsigned short  h_proto;                                /* packet type ID field */
+
+       /* ARP packet */
+       unsigned short hw_type;                         /* hardware type(ARPHRD_ETHER) */
+       unsigned short p_type;                          /* protocol type(ETH_P_IP) */
+       unsigned char  hw_len;                          /* hardware address length */
+       unsigned char  p_len;                                   /* protocol address length */
+       unsigned short operation;                               /* ARP opcode */
+       unsigned char  s_hwaddr[MAC_ADDRESS_LENGTH];            /* sender hardware address */
+       unsigned char  s_IPaddr[IP_ADDRESS_LENGTH];             /* sender IP address */
+       unsigned char  t_hwaddr[MAC_ADDRESS_LENGTH];            /* target hardware address */
+       unsigned char  t_IPaddr[IP_ADDRESS_LENGTH];             /* target IP address */
+       unsigned char  pad[18];                         /* pad for min. Ethernet payload (60 bytes) */
+};
+
+typedef enum {
+       IP_CONFLICT_MODE_EXPONENTIAL = 0x00,
+       IP_CONFLICT_MODE_PERIODIC,
+       IP_CONFLICT_MODE_MAX
+} ip_conflict_mode_e;
+
+typedef enum {
+       NETCONFIG_IP_CONFLICT_STATE_UNKNOWN,
+       NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED,
+       NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED
+} ip_conflict_state_e;
+
+struct timer_data {
+       guint initial_time;
+       guint timeout;
+       ip_conflict_mode_e mode;
+};
+static struct timer_data td = {
+       MIN_ARP_SEND_TIME, MIN_ARP_SEND_TIME, IP_CONFLICT_MODE_PERIODIC
+};
+
+int ioctl_sock;
+bool is_ip_conflict_detect_enabled = true;
+static gboolean send_arp(gpointer data);
+static void __netconfig_wifi_notify_ip_conflict(char *state, char *mac);
+ip_conflict_state_e conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
+
+struct sock_data *sd;
+
+typedef unsigned int in_addr_t;
+
+union uchar_to_uint {
+       unsigned int uint;
+       unsigned char uchar[IP_ADDRESS_LENGTH];
+};
+
+static unsigned int __convert_uchar_to_uint(unsigned char b[IP_ADDRESS_LENGTH])
+{
+       int idx = 0;
+       union uchar_to_uint u;
+       for (; idx < IP_ADDRESS_LENGTH; ++idx)
+               u.uchar[idx] = b[idx];
+
+       return u.uint;
+}
+
+static gboolean __arp_reply_timeout_cb(gpointer data)
+{
+       sd->iteration++;
+       sd->arp_reply_timer = -1;
+       if (sd->timer_id != -1)
+               g_source_remove(sd->timer_id);
+
+       if (conflict_state != NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED && sd->iteration == 5) {
+               sd->iteration = 0;
+               conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
+               __netconfig_wifi_notify_ip_conflict("resolved", GRATUITOUS_ARP_MAC_ADDR);
+       }
+
+       sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
+       return G_SOURCE_REMOVE;
+}
+
+static gboolean __netconfig_check_arp_receive(GIOChannel *source,
+                                                 GIOCondition condition, gpointer data)
+{
+       struct sock_data *sd = data;
+       gchar buffer[ARP_PACKET_SIZE] = {0, };
+       gsize bytes_read = 0;
+       struct arp_message arp_recv;
+       char sbuf[WLAN_MAC_ADDR_MAX];
+       char tbuf[WLAN_MAC_ADDR_MAX];
+       const char *default_ip = NULL;
+
+       if (g_io_channel_read_chars(source, buffer, ARP_PACKET_SIZE,
+                               &bytes_read, NULL) == G_IO_STATUS_NORMAL) {
+               unsigned int target_ip = 0;
+
+               memset(&arp_recv, 0, sizeof(arp_recv));
+               memcpy(&arp_recv, buffer, sizeof(buffer));
+
+               default_ip = netconfig_get_default_ipaddress();
+               if (default_ip == NULL) {
+                       INFO("ip address is not set yet");
+                       goto out;
+               }
+               target_ip = inet_addr(default_ip);
+
+
+               /* Only handle ARP replies */
+               if (arp_recv.operation != htons(ARPOP_REPLY))
+                       goto out;
+
+               UCHAR_TO_ADDRESS(arp_recv.t_hwaddr, tbuf);
+               UCHAR_TO_ADDRESS(arp_recv.s_hwaddr, sbuf);
+
+               int zero_mac = strcmp(tbuf , GRATUITOUS_ARP_MAC_ADDR);
+               if (zero_mac == 0) {
+                       DBG("Broadcast packet.\n");
+                       goto skip;
+               }
+               DBG("our mac= %s source mac= %s target mac= %s", netconfig_get_default_mac_address(), sbuf, tbuf);
+               int mac_cmp = strcmp(tbuf , netconfig_get_default_mac_address());
+               if (mac_cmp != 0) {
+                       INFO("Packet not intended to us.\n");
+                       goto out;
+               }
+skip:
+               mac_cmp = strcmp(sbuf, netconfig_get_default_mac_address());
+               DBG("target ip = %d source ip = %d", target_ip, __convert_uchar_to_uint(arp_recv.s_IPaddr));
+               if ((mac_cmp != 0) && (__convert_uchar_to_uint(arp_recv.s_IPaddr) == target_ip)) {
+                       sd->iteration = 0;
+                       if (conflict_state != NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED) {
+                               INFO("ip conflict is detected !\n");
+                               conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED;
+                               __netconfig_wifi_notify_ip_conflict("conflict", sbuf);
+                       }
+
+                       if (sd->arp_reply_timer != -1) {
+                               g_source_remove(sd->arp_reply_timer);
+                               sd->arp_reply_timer = -1;
+                       }
+
+                       if (sd->timer_id)
+                               g_source_remove(sd->timer_id);
+                       sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
+
+               }
+       }
+
+out:
+       return TRUE;
+}
+
+static gboolean send_arp(gpointer data)
+{
+       struct sock_data *sd = data;
+       struct ether_addr *source_mac = NULL;
+       struct arp_message arp;
+       char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
+       unsigned int source_ip = 0;
+       unsigned int target_ip = 0;
+       const unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+       struct sockaddr_ll addr = {0};
+       struct ifreq net_ifr;
+       int ifindex = 0;
+       errno = 0;
+       const char *default_ip = NULL;
+
+       const char *mac = netconfig_get_default_mac_address();
+       if (mac == NULL)
+               goto err;
+       source_mac = ether_aton(mac);
+       if (source_mac == NULL) {
+               INFO("Mac address is NULL");
+               goto err;
+       }
+
+       memset(&arp, 0, sizeof(arp));
+
+       unsigned char  broadcast_mac_addr[MAC_ADDRESS_LENGTH];
+       memset(broadcast_mac_addr, 0xff, sizeof(broadcast_mac_addr));
+       memcpy(arp.h_dest, broadcast_mac_addr, MAC_ADDRESS_LENGTH);             /* MAC dest */
+       memcpy(arp.h_source, source_mac, MAC_ADDRESS_LENGTH);                   /* MAC source */
+
+       arp.h_proto = htons(ETH_P_ARP);                                         /* protocol type (Ethernet) */
+       arp.hw_type = htons(ARPHRD_ETHER);                                      /* hardware type */
+       arp.p_type = htons(ETH_P_IP);                                           /* protocol type (ARP message) */
+       arp.hw_len = MAC_ADDRESS_LENGTH;                                        /* hardware address length */
+       arp.p_len = IP_ADDRESS_LENGTH;                                          /* protocol address length */
+       arp.operation = htons(ARPOP_REQUEST);                                   /* ARP op code */
+       default_ip = netconfig_get_default_ipaddress();
+       if (default_ip == NULL) {
+               INFO("ip address is not set yet");
+               goto err;
+       }
+
+       source_ip = inet_addr(default_ip);
+       target_ip = inet_addr(default_ip);
+       memcpy(arp.s_IPaddr, &source_ip, IP_ADDRESS_LENGTH);                    /* source IP address */
+       memcpy(arp.s_hwaddr, source_mac, MAC_ADDRESS_LENGTH);                   /* source hardware address */
+       memcpy(arp.t_IPaddr, &target_ip, IP_ADDRESS_LENGTH);                    /* target IP addressshek" */
+
+       memset(&net_ifr, 0, sizeof(net_ifr));
+       /* ifreq structure creation */
+       size_t if_name_len = strlen(netconfig_get_default_ifname());
+       if (if_name_len < sizeof(net_ifr.ifr_name)) {
+               memcpy(net_ifr.ifr_name, netconfig_get_default_ifname(), if_name_len);
+               net_ifr.ifr_name[if_name_len] = 0;
+       } else {
+               INFO("Error : Interface name is too long");
+               goto err;
+       }
+
+       if (ioctl(sd->chk_conflict_sd, SIOCGIFINDEX, &net_ifr) == -1) {
+               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+               INFO("ioctl Failed. Error..... = %s\n", error_buf);
+               goto err;
+       }
+
+       ifindex = net_ifr.ifr_ifindex;
+       /* Construct the destination address */
+       addr.sll_family = AF_PACKET;
+       addr.sll_ifindex = ifindex;
+       addr.sll_halen = ETHER_ADDR_LEN;
+       addr.sll_protocol = htons(ETH_P_ARP);
+       memcpy(addr.sll_addr, broadcast_addr, ETHER_ADDR_LEN);
+
+       if (sendto(sd->chk_conflict_sd, &arp, sizeof(arp), 0, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+               INFO("Sending ARP Packet Failed. Error. = %s\n", error_buf);
+               /* close socket */
+               if (-1 < sd->chk_conflict_sd) {
+                       close(sd->chk_conflict_sd);
+                       sd->chk_conflict_sd = -1;
+               }
+
+               /* reopen socket */
+               if ((sd->chk_conflict_sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) == -1) {
+                       INFO("socket %d", sd->chk_conflict_sd);
+                       strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+                       INFO("socket Failed. Error = %s\n", error_buf);
+               }
+               goto err;
+       } else {
+               DBG("Sent ARP Packet \n");
+       }
+
+       g_source_remove(sd->timer_id);
+       if (td.mode == IP_CONFLICT_MODE_PERIODIC)
+               sd->timeout = td.initial_time;
+       else if (td.mode == IP_CONFLICT_MODE_EXPONENTIAL && 2*sd->timeout < MAX_ARP_SEND_TIME)
+               sd->timeout *= 2;
+
+       /* Adding timeout callback for arp request */
+       sd->arp_reply_timer = g_timeout_add(1000, __arp_reply_timeout_cb,
+                                       (gpointer) &sd->arp_reply_timer);
+       return FALSE;
+err:
+       if (sd->timer_id)
+               g_source_remove(sd->timer_id);
+       sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
+       return FALSE;
+}
+
+struct sock_data * start_ip_conflict_mon(void)
+{
+       if (is_ip_conflict_detect_enabled == false) {
+               INFO("detection mode is set to false");
+               return NULL;
+       }
+
+       char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
+
+       sd = g_try_malloc0(sizeof(struct sock_data));
+       if (sd == NULL) {
+               INFO("Failed to malloc sock_data");
+               return NULL;
+       }
+       sd->chk_conflict_data_id = -1;
+       sd->chk_conflict_sd = -1;
+       sd->timer_id = 0;
+       sd->iteration = 0;
+
+       if ((sd->chk_conflict_sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) == -1) {
+               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+               INFO("socket Failed. Error = %s\n", error_buf);
+               g_free(sd);
+               return NULL;
+       } else {
+               sd->chk_conflict_sock_io = g_io_channel_unix_new(sd->chk_conflict_sd);
+               if (sd->chk_conflict_sock_io == NULL) {
+                       INFO("Failed to create channel");
+                       INFO("Exit");
+                       g_free(sd);
+                       return NULL;
+               }
+
+               g_io_channel_set_close_on_unref(sd->chk_conflict_sock_io, TRUE);
+
+               if (G_IO_STATUS_NORMAL != g_io_channel_set_encoding(sd->chk_conflict_sock_io,
+                                                                  NULL, NULL))
+                       INFO("Failed to set encoding NULL on io channel");
+               if (G_IO_STATUS_NORMAL != g_io_channel_set_flags(sd->chk_conflict_sock_io,
+                                                               G_IO_FLAG_NONBLOCK, NULL))
+                       INFO("Failed to set flags on io channel");
+               sd->chk_conflict_data_id = g_io_add_watch(sd->chk_conflict_sock_io, G_IO_IN,
+                                                         __netconfig_check_arp_receive, sd);
+               DBG("socket %d", sd->chk_conflict_sd);
+
+               sd->timeout = td.initial_time;
+               send_arp(sd);
+               return sd;
+       }
+}
+
+void stop_ip_conflict_mon()
+{
+       INFO("+");
+       GError* error = NULL;
+       if (sd == NULL) {
+               INFO("sd is NULL");
+               return;
+       }
+       if (-1 < sd->chk_conflict_sd) {
+               if (G_IO_STATUS_NORMAL !=
+                   g_io_channel_shutdown(sd->chk_conflict_sock_io, FALSE,
+                                         &error)) {
+                       INFO("Failure received while shutdown io channel[%d]:[%s]", error->code, error->message);
+                       g_error_free(error);
+               }
+               g_io_channel_unref(sd->chk_conflict_sock_io);
+               g_source_remove(sd->chk_conflict_data_id);
+               sd->chk_conflict_data_id = -1;
+               close(sd->chk_conflict_sd);
+               sd->chk_conflict_sd = -1;
+       }
+       if (sd->timer_id > 0) {
+               g_source_remove(sd->timer_id);
+               sd->timer_id = 0;
+       }
+       g_free(sd);
+       sd = NULL;
+       INFO("Monitoring stopped");
+}
+
+static void __netconfig_wifi_notify_ip_conflict(char *state, char *mac)
+{
+       GVariantBuilder *builder = NULL;
+
+       builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+       g_variant_builder_add(builder, "{sv}", "state", g_variant_new_string(state));
+       g_variant_builder_add(builder, "{sv}", "mac", g_variant_new_string(mac));
+
+       wifi_emit_ip_conflict_event((Wifi *)get_wifi_object(), g_variant_builder_end(builder));
+       g_variant_builder_unref(builder);
+
+       return;
+}
+
+gboolean handle_ip_conflict_set_enable(Wifi *wifi, GDBusMethodInvocation *context,
+                                      bool detect)
+{
+       g_return_val_if_fail(wifi != NULL, FALSE);
+
+
+       if (detect == false) {
+               is_ip_conflict_detect_enabled = false;
+               conflict_state = NETCONFIG_IP_CONFLICT_STATE_UNKNOWN;
+               if (sd != NULL)
+                       stop_ip_conflict_mon();
+               else {
+                       netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AlreadyExists");
+                       wifi_complete_ip_conflict_set_enable(wifi, context);
+                       return FALSE;
+               }
+       } else {
+               is_ip_conflict_detect_enabled = true;
+               conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
+               if (sd == NULL) {
+                       if (start_ip_conflict_mon() == NULL) {
+                               INFO("Failed to start IP conflict monitoring");
+                               netconfig_error_dbus_method_return(context,
+                                               NETCONFIG_ERROR_INTERNAL, "Failed");
+                               wifi_complete_ip_conflict_set_enable(wifi, context);
+                               return FALSE;
+                       }
+               } else {
+                       netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AlreadyExists");
+                       wifi_complete_ip_conflict_set_enable(wifi, context);
+                       return FALSE;
+               }
+       }
+
+       wifi_complete_ip_conflict_set_enable(wifi, context);
+       return TRUE;
+}
+
+gboolean handle_is_ip_conflict_detect_enabled(Wifi *wifi, GDBusMethodInvocation *context)
+{
+       g_return_val_if_fail(wifi != NULL, FALSE);
+       GVariant *param = NULL;
+       param = g_variant_new("(b)", is_ip_conflict_detect_enabled);
+       g_dbus_method_invocation_return_value(context, param);
+       return TRUE;
+}
+
+gboolean handle_set_ip_conflict_mode(Wifi *wifi, GDBusMethodInvocation *context,
+                                    guint mode, guint initial_time)
+{
+       g_return_val_if_fail(wifi != NULL, FALSE);
+       if (initial_time < MAX_ARP_SEND_TIME && initial_time > MIN_ARP_SEND_TIME)
+               return FALSE;
+
+       td.initial_time = 1000 * initial_time;
+       td.mode = mode;
+       // remove timer
+       stop_ip_conflict_mon();
+       start_ip_conflict_mon();
+       wifi_complete_set_ip_conflict_mode(wifi, context);
+       return TRUE;
+}
+
+gboolean handle_get_ip_conflict_state(Wifi *wifi, GDBusMethodInvocation *context)
+{
+       g_return_val_if_fail(wifi != NULL, FALSE);
+       GVariant *param = NULL;
+       param = g_variant_new("(u)", conflict_state);
+       g_dbus_method_invocation_return_value(context, param);
+       return TRUE;
+}
index 0fb0280..c2f5e92 100755 (executable)
@@ -92,6 +92,7 @@ static Network *netconfigstate = NULL;
 struct netconfig_default_connection {
        char *profile;
        char *ifname;
+       char *mac_address;
        char *ipaddress;
        char *ipaddress6;
        char *proxy;
@@ -409,6 +410,9 @@ static void __netconfig_get_default_connection_info(const char *profile)
                                if (g_strcmp0(key1, "Interface") == 0) {
                                        value = g_variant_get_string(variant, NULL);
                                        netconfig_default_connection_info.ifname = g_strdup(value);
+                               } else if (g_strcmp0(key1, "Address") == 0) {
+                                       value = g_variant_get_string(variant, NULL);
+                                       netconfig_default_connection_info.mac_address = g_strdup(value);
                                }
                        }
                        g_variant_iter_free(iter1);
@@ -913,6 +917,11 @@ unsigned int netconfig_get_default_frequency(void)
        return netconfig_default_connection_info.freq;
 }
 
+const char *netconfig_get_default_mac_address(void)
+{
+       return netconfig_default_connection_info.mac_address;
+}
+
 const char *netconfig_wifi_get_connected_essid(const char *default_profile)
 {
        if (default_profile == NULL)
@@ -1009,6 +1018,9 @@ void netconfig_update_default_profile(const char *profile)
                g_free(netconfig_default_connection_info.proxy);
                netconfig_default_connection_info.proxy = NULL;
 
+               g_free(netconfig_default_connection_info.mac_address);
+               netconfig_default_connection_info.mac_address = NULL;
+
                netconfig_default_connection_info.freq = 0;
                netconfig_default_connection_info.is_metered = FALSE;
 
index e3ee51f..0bd5689 100755 (executable)
@@ -38,6 +38,7 @@
 #include "signal-handler.h"
 #include "wifi-background-scan.h"
 #include "wifi-tdls.h"
+#include "ip-conflict-detect.h"
 
 #define DBUS_SERVICE_DBUS                      "org.freedesktop.DBus"
 #define DBUS_INTERFACE_DBUS                    "org.freedesktop.DBus"
@@ -61,6 +62,7 @@
 
 #define MAX_SIG_LEN 64
 #define TOTAL_CONN_SIGNALS 5
+#define MAX_SOCKET_OPEN_RETRY 5
 
 typedef enum {
        SIG_INTERFACE_REMOVED = 0,
@@ -194,6 +196,8 @@ static void _service_signal_cb(GDBusConnection *conn,
        GVariant *variant = NULL, *var;
        GVariantIter *iter;
        const gchar *value = NULL;
+       struct sock_data *sd = NULL;
+       int idx = 0;
 
        if (path == NULL || param == NULL)
                goto done;
@@ -208,6 +212,18 @@ static void _service_signal_cb(GDBusConnection *conn,
        if (g_strcmp0(sigvalue, "State") == 0) {
                g_variant_get(variant, "s", &property);
 
+       if (g_strcmp0(property, "ready") == 0) {
+               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
+       } else {
+               stop_ip_conflict_mon();
+       }
+
                DBG("[%s] %s", property, path);
                if (netconfig_is_wifi_profile(path) == TRUE) {
                        int wifi_state = 0;
index ef8db47..0fdc0ba 100755 (executable)
@@ -38,6 +38,7 @@
 #include "wifi-passpoint.h"
 #include "wifi-eap-config.h"
 #include "wifi-background-scan.h"
+#include "ip-conflict-detect.h"
 #include "wifi-config.h"
 #include "wifi-tdls.h"
 #include "wifi-extension.h"
@@ -190,6 +191,16 @@ void wifi_object_create_and_init(void)
        g_signal_connect(wifi_object, "handle-remove-vsie",
                        G_CALLBACK(handle_remove_vsie), NULL);
 
+       /* IP conflict methods */
+       g_signal_connect(wifi_object, "handle-ip-conflict-set-enable",
+                       G_CALLBACK(handle_ip_conflict_set_enable), NULL);
+       g_signal_connect(wifi_object, "handle-is-ip-conflict-detect-enabled",
+                       G_CALLBACK(handle_is_ip_conflict_detect_enabled), NULL);
+       g_signal_connect(wifi_object, "handle-set-ip-conflict-mode",
+                       G_CALLBACK(handle_set_ip_conflict_mode), NULL);
+       g_signal_connect(wifi_object, "handle-get-ip-conflict-state",
+                       G_CALLBACK(handle_get_ip_conflict_state), NULL);
+
        /* WIFI configuration */
        g_signal_connect(wifi_object, "handle-save-configuration",
                        G_CALLBACK(handle_save_configuration), NULL);