Merge "Add dbus method for getting wifi passphrase" into tizen
[platform/core/connectivity/net-config.git] / src / ip-conflict-detect.c
old mode 100644 (file)
new mode 100755 (executable)
index 53c1dd1..4e15614
 #include <unistd.h>
 #include <stdbool.h>
 
+#include "netdbus.h"
 #include "ip-conflict-detect.h"
 #include "network-state.h"
 #include "log.h"
 #include "neterror.h"
+#include "util.h"
 
 #define ARP_PACKET_SIZE 60
 #define MAX_SIZE_ERROR_BUFFER 256
 #define MAC_ADDRESS_LENGTH 6
 #define WLAN_MAC_ADDR_MAX 20
 #define ARP_SOURCE_IP "0.0.0.0"
+#define INITIAL_BURST_ARP_COUNT 5
 
-#define MIN_ARP_SEND_TIME 2000
+#define CONFLICT_REMOVE_ITERATION_LIMIT 4
+#define MIN_ARP_SEND_TIME 20000
+#define BURST_ARP_SEND_TIME 3000
 #define MAX_ARP_SEND_TIME 32000
 #define GRATUITOUS_ARP_MAC_ADDR "00:00:00:00:00:00"
 #define UCHAR_TO_ADDRESS(hwaddr, buf) do {\
@@ -71,7 +76,7 @@ struct arp_message {
        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) */
+       unsigned char  pad[22];                         /* pad for min. Ethernet payload (64 bytes) */
 };
 
 typedef enum {
@@ -89,9 +94,12 @@ static struct timer_data td = {
 };
 
 int ioctl_sock;
-bool is_ip_conflict_detect_enabled = true;
+static bool initial_bursts = true;
+bool is_ip_conflict_detect_enabled = false;
+bool is_ip_conflict_detect_running = false;
 static gboolean send_arp(gpointer data);
-static void __netconfig_wifi_notify_ip_conflict(char *state, char *mac);
+static void __netconfig_wifi_notify_ip_conflict(const char *interface_name,
+                       char *state, char *mac);
 ip_conflict_state_e conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
 
 struct sock_data *sd;
@@ -122,15 +130,18 @@ 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) {
+       if (conflict_state != NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED &&
+                       sd->iteration == CONFLICT_REMOVE_ITERATION_LIMIT) {
                sd->iteration = 0;
                conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
-               __netconfig_wifi_notify_ip_conflict("resolved", GRATUITOUS_ARP_MAC_ADDR);
+               __netconfig_wifi_notify_ip_conflict(netconfig_get_default_ifname(),
+                       "resolved", GRATUITOUS_ARP_MAC_ADDR);
+               initial_bursts = true;
        }
 
+       if (sd->timer_id)
+               g_source_remove(sd->timer_id);
        sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
        return G_SOURCE_REMOVE;
 }
@@ -145,6 +156,7 @@ static gboolean __netconfig_check_arp_receive(GIOChannel *source,
        char sbuf[WLAN_MAC_ADDR_MAX];
        char tbuf[WLAN_MAC_ADDR_MAX];
        const char *default_ip = NULL;
+       int mac_cmp = 0;
 
        if (g_io_channel_read_chars(source, buffer, ARP_PACKET_SIZE,
                                &bytes_read, NULL) == G_IO_STATUS_NORMAL) {
@@ -170,13 +182,13 @@ static gboolean __netconfig_check_arp_receive(GIOChannel *source,
 
                int zero_mac = strcmp(tbuf , GRATUITOUS_ARP_MAC_ADDR);
                if (zero_mac == 0) {
-                       DBG("Broadcast packet.\n");
+                       DBG("Broadcast packet.");
                        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());
+               mac_cmp = strcmp(tbuf , netconfig_get_default_mac_address());
                if (mac_cmp != 0) {
-                       INFO("Packet not intended to us.\n");
+                       INFO("Packet not intended to us.");
                        goto out;
                }
 skip:
@@ -185,9 +197,12 @@ skip:
                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");
+                               INFO("ip conflict is detected !");
                                conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED;
-                               __netconfig_wifi_notify_ip_conflict("conflict", sbuf);
+                               __netconfig_wifi_notify_ip_conflict(
+                                       netconfig_get_default_ifname(),
+                                       "conflict", sbuf);
+                               sd->timeout = BURST_ARP_SEND_TIME;
                        }
 
                        if (sd->arp_reply_timer != -1) {
@@ -198,7 +213,6 @@ skip:
                        if (sd->timer_id)
                                g_source_remove(sd->timer_id);
                        sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
-
                }
        }
 
@@ -206,6 +220,50 @@ out:
        return TRUE;
 }
 
+static void __close_channel_and_sock(struct sock_data *sd)
+{
+       if (sd == NULL)
+               return;
+
+       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;
+}
+
+static int __open_channel_and_sock(struct sock_data *sd)
+{
+       if (sd == NULL)
+               return -1;
+
+       if ((sd->chk_conflict_sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) == -1) {
+               INFO("socket Failed.");
+               return -1;
+       }
+
+       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");
+               close(sd->chk_conflict_sd);
+               sd->chk_conflict_sd = -1;
+               return -1;
+       }
+
+       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);
+       return 0;
+}
+
 static gboolean send_arp(gpointer data)
 {
        struct sock_data *sd = data;
@@ -220,6 +278,16 @@ static gboolean send_arp(gpointer data)
        int ifindex = 0;
        errno = 0;
        const char *default_ip = NULL;
+       const char *if_name = NULL;
+       static int initial_send_arp_count = 0;
+
+       if (initial_bursts && initial_send_arp_count >= INITIAL_BURST_ARP_COUNT) {
+               initial_bursts = false;
+               initial_send_arp_count = 0;
+       }
+
+       if (initial_bursts)
+               initial_send_arp_count++;
 
        const char *mac = netconfig_get_default_mac_address();
        if (mac == NULL)
@@ -257,7 +325,14 @@ static gboolean send_arp(gpointer data)
 
        memset(&net_ifr, 0, sizeof(net_ifr));
        /* ifreq structure creation */
-       size_t if_name_len = strlen(netconfig_get_default_ifname());
+       if_name = netconfig_get_default_ifname();
+       size_t if_name_len = strlen(if_name);
+
+       if (if_name_len == 0) {
+               INFO("Error : Unable to get interface name ");
+               goto err;
+       }
+
        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;
@@ -267,8 +342,8 @@ static gboolean send_arp(gpointer data)
        }
 
        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);
+               INFO("ioctl Failed. Error..... = %s",
+                               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
                goto err;
        }
 
@@ -280,29 +355,27 @@ static gboolean send_arp(gpointer data)
        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);
-               }
+       if (sendto(sd->chk_conflict_sd, &arp, sizeof(arp), 0,
+                               (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+               INFO("Sending ARP Packet Failed. Error. = %s",
+                               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
+               __close_channel_and_sock(sd);
+               if (__open_channel_and_sock(sd) == -1)
+                       INFO("__open_channel_and_sock failed");
                goto err;
        } else {
-               DBG("Sent ARP Packet \n");
+               /* DBG("Sent ARP Packet"); */
        }
 
-       g_source_remove(sd->timer_id);
+       if (sd->timer_id) {
+               g_source_remove(sd->timer_id);
+               sd->timer_id = 0;
+       }
 
-       sd->timeout = td.initial_time;
+       if (conflict_state == NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED || initial_bursts)
+               sd->timeout = BURST_ARP_SEND_TIME;
+       else
+               sd->timeout = td.initial_time;
 
        /* Adding timeout callback for arp request */
        sd->arp_reply_timer = g_timeout_add(1000, __arp_reply_timeout_cb,
@@ -318,11 +391,16 @@ err:
 struct sock_data * start_ip_conflict_mon(void)
 {
        if (is_ip_conflict_detect_enabled == false) {
-               INFO("detection mode is set to false");
+               INFO("ip_conflict_detect is disabled");
                return NULL;
        }
 
-       char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
+       if (is_ip_conflict_detect_running == true) {
+               INFO("detection mode is set to true");
+               return NULL;
+       }
+
+       initial_bursts = true;
 
        sd = g_try_malloc0(sizeof(struct sock_data));
        if (sd == NULL) {
@@ -331,72 +409,45 @@ struct sock_data * start_ip_conflict_mon(void)
        }
        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);
+       if (__open_channel_and_sock(sd) == -1) {
+               INFO("__open_channel_and_sock failed");
                g_free(sd);
+               sd = NULL;
                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);
+       is_ip_conflict_detect_running = true;
+       conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
 
-               sd->timeout = td.initial_time;
-               send_arp(sd);
-               return 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) {
+
+       if (-1 < sd->chk_conflict_sd)
+               __close_channel_and_sock(sd);
+
+       if (sd->timer_id) {
                g_source_remove(sd->timer_id);
-               sd->timer_id = 0;
        }
        g_free(sd);
        sd = NULL;
+       is_ip_conflict_detect_running = false;
+       conflict_state = NETCONFIG_IP_CONFLICT_STATE_UNKNOWN;
        INFO("Monitoring stopped");
 }
 
-static void __netconfig_wifi_notify_ip_conflict(char *state, char *mac)
+static void __netconfig_wifi_notify_ip_conflict(const char *interface_name,
+                       char *state, char *mac)
 {
        GVariantBuilder *builder = NULL;
 
@@ -404,43 +455,48 @@ static void __netconfig_wifi_notify_ip_conflict(char *state, char *mac)
        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));
+       wifi_emit_ip_conflict_event((Wifi *)get_wifi_object(),
+               interface_name, g_variant_builder_end(builder));
        g_variant_builder_unref(builder);
 
+       /* send notification using net-popup */
+       if (!strcmp(state, "conflict"))
+               netconfig_send_notification_to_net_popup(NETCONFIG_ADD_IP_CONFLICT_NOTI, mac);
+       else
+               netconfig_send_notification_to_net_popup(NETCONFIG_DEL_IP_CONFLICT_NOTI, mac);
+
        return;
 }
 
 gboolean handle_ip_conflict_set_enable(Wifi *wifi, GDBusMethodInvocation *context,
-                                      bool detect)
+                       const gchar *ifname, bool detect)
 {
-       g_return_val_if_fail(wifi != NULL, FALSE);
-
+       g_return_val_if_fail(wifi != NULL, TRUE);
 
        if (detect == false) {
-               is_ip_conflict_detect_enabled = false;
-               conflict_state = NETCONFIG_IP_CONFLICT_STATE_UNKNOWN;
-               if (sd != NULL)
+               if (is_ip_conflict_detect_enabled == true) {
                        stop_ip_conflict_mon();
-               else {
+                       is_ip_conflict_detect_enabled = false;
+               } else {
                        netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AlreadyExists");
-                       wifi_complete_ip_conflict_set_enable(wifi, context);
-                       return FALSE;
+                       return TRUE;
                }
        } 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;
+               if (is_ip_conflict_detect_enabled == false) {
+                       is_ip_conflict_detect_enabled = true;
+                       const char *def_profile = netconfig_get_default_profile();
+                       if (netconfig_is_wifi_profile(def_profile) ||
+                                       netconfig_is_ethernet_profile(def_profile)) {
+                               if (start_ip_conflict_mon() == NULL) {
+                                       INFO("Failed to start IP conflict monitoring");
+                                       netconfig_error_dbus_method_return(context,
+                                                       NETCONFIG_ERROR_INTERNAL, "Failed");
+                                       return TRUE;
+                               }
                        }
                } else {
                        netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AlreadyExists");
-                       wifi_complete_ip_conflict_set_enable(wifi, context);
-                       return FALSE;
+                       return TRUE;
                }
        }
 
@@ -448,20 +504,26 @@ gboolean handle_ip_conflict_set_enable(Wifi *wifi, GDBusMethodInvocation *contex
        return TRUE;
 }
 
-gboolean handle_is_ip_conflict_detect_enabled(Wifi *wifi, GDBusMethodInvocation *context)
+gboolean handle_is_ip_conflict_detect_enabled(Wifi *wifi, GDBusMethodInvocation *context,
+                       const gchar *ifname)
 {
-       g_return_val_if_fail(wifi != NULL, FALSE);
+       g_return_val_if_fail(wifi != NULL, TRUE);
        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_period(Wifi *wifi, GDBusMethodInvocation *context, guint initial_time)
+gboolean handle_set_ip_conflict_period(Wifi *wifi, GDBusMethodInvocation *context,
+                       const gchar *ifname, 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;
+       g_return_val_if_fail(wifi != NULL, TRUE);
+       INFO("%d", initial_time);
+       if (initial_time > MAX_ARP_SEND_TIME || initial_time < MIN_ARP_SEND_TIME) {
+               netconfig_error_dbus_method_return(context,
+                                               NETCONFIG_ERROR_INTERNAL, "Failed");
+               return TRUE;
+       }
 
        td.initial_time = 1000 * initial_time;
        // remove timer
@@ -471,18 +533,20 @@ gboolean handle_set_ip_conflict_period(Wifi *wifi, GDBusMethodInvocation *contex
        return TRUE;
 }
 
-gboolean handle_get_ip_conflict_state(Wifi *wifi, GDBusMethodInvocation *context)
+gboolean handle_get_ip_conflict_state(Wifi *wifi, GDBusMethodInvocation *context,
+                       const gchar *ifname)
 {
-       g_return_val_if_fail(wifi != NULL, FALSE);
+       g_return_val_if_fail(wifi != NULL, TRUE);
        GVariant *param = NULL;
        param = g_variant_new("(u)", conflict_state);
        g_dbus_method_invocation_return_value(context, param);
        return TRUE;
 }
 
-gboolean handle_get_ip_conflict_period(Wifi *wifi, GDBusMethodInvocation *context)
+gboolean handle_get_ip_conflict_period(Wifi *wifi, GDBusMethodInvocation *context,
+                       const gchar *ifname)
 {
-       g_return_val_if_fail(wifi != NULL, FALSE);
+       g_return_val_if_fail(wifi != NULL, TRUE);
        GVariant *param = NULL;
        param = g_variant_new("(u)", td.initial_time/1000);
        g_dbus_method_invocation_return_value(context, param);