Added IP conflict detection monitoring for conflict CAPI's.
[platform/core/connectivity/net-config.git] / src / ip-conflict-detect.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <stdio.h>
21 #include <net/if.h>
22 #include <linux/if_packet.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25 #include <arpa/inet.h>
26 #include <netinet/ether.h>
27 #include <net/ethernet.h>
28 #include <netinet/in.h>
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <errno.h>
32 #include <glib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <stdbool.h>
36
37 #include "ip-conflict-detect.h"
38 #include "network-state.h"
39 #include "log.h"
40 #include "neterror.h"
41
42 #define ARP_PACKET_SIZE 60
43 #define MAX_SIZE_ERROR_BUFFER 256
44 #define IP_ADDRESS_LENGTH 4
45 #define MAC_ADDRESS_LENGTH 6
46 #define WLAN_MAC_ADDR_MAX 20
47
48 #define MIN_ARP_SEND_TIME 2000
49 #define MAX_ARP_SEND_TIME 32000
50 #define GRATUITOUS_ARP_MAC_ADDR "00:00:00:00:00:00"
51 #define UCHAR_TO_ADDRESS(hwaddr, buf) do {\
52                 snprintf(buf, WLAN_MAC_ADDR_MAX,\
53                 "%02X:%02X:%02X:%02X:%02X:%02X", hwaddr[0], hwaddr[1],\
54                 hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);\
55                 } while (0)
56
57 struct arp_message {
58         /* Ethernet header */
59         unsigned char   h_dest[MAC_ADDRESS_LENGTH];     /* destination ether addr */
60         unsigned char   h_source[MAC_ADDRESS_LENGTH];   /* source ether addr */
61         unsigned short  h_proto;                                /* packet type ID field */
62
63         /* ARP packet */
64         unsigned short hw_type;                         /* hardware type(ARPHRD_ETHER) */
65         unsigned short p_type;                          /* protocol type(ETH_P_IP) */
66         unsigned char  hw_len;                          /* hardware address length */
67         unsigned char  p_len;                                   /* protocol address length */
68         unsigned short operation;                               /* ARP opcode */
69         unsigned char  s_hwaddr[MAC_ADDRESS_LENGTH];            /* sender hardware address */
70         unsigned char  s_IPaddr[IP_ADDRESS_LENGTH];             /* sender IP address */
71         unsigned char  t_hwaddr[MAC_ADDRESS_LENGTH];            /* target hardware address */
72         unsigned char  t_IPaddr[IP_ADDRESS_LENGTH];             /* target IP address */
73         unsigned char  pad[18];                         /* pad for min. Ethernet payload (60 bytes) */
74 };
75
76 typedef enum {
77         IP_CONFLICT_MODE_EXPONENTIAL = 0x00,
78         IP_CONFLICT_MODE_PERIODIC,
79         IP_CONFLICT_MODE_MAX
80 } ip_conflict_mode_e;
81
82 typedef enum {
83         NETCONFIG_IP_CONFLICT_STATE_UNKNOWN,
84         NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED,
85         NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED
86 } ip_conflict_state_e;
87
88 struct timer_data {
89         guint initial_time;
90         guint timeout;
91         ip_conflict_mode_e mode;
92 };
93 static struct timer_data td = {
94         MIN_ARP_SEND_TIME, MIN_ARP_SEND_TIME, IP_CONFLICT_MODE_PERIODIC
95 };
96
97 int ioctl_sock;
98 bool is_ip_conflict_detect_enabled = true;
99 static gboolean send_arp(gpointer data);
100 static void __netconfig_wifi_notify_ip_conflict(char *state, char *mac);
101 ip_conflict_state_e conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
102
103 struct sock_data *sd;
104
105 typedef unsigned int in_addr_t;
106
107 union uchar_to_uint {
108         unsigned int uint;
109         unsigned char uchar[IP_ADDRESS_LENGTH];
110 };
111
112 static unsigned int __convert_uchar_to_uint(unsigned char b[IP_ADDRESS_LENGTH])
113 {
114         int idx = 0;
115         union uchar_to_uint u;
116         for (; idx < IP_ADDRESS_LENGTH; ++idx)
117                 u.uchar[idx] = b[idx];
118
119         return u.uint;
120 }
121
122 static gboolean __arp_reply_timeout_cb(gpointer data)
123 {
124         sd->iteration++;
125         sd->arp_reply_timer = -1;
126         if (sd->timer_id != -1)
127                 g_source_remove(sd->timer_id);
128
129         if (conflict_state != NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED && sd->iteration == 5) {
130                 sd->iteration = 0;
131                 conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
132                 __netconfig_wifi_notify_ip_conflict("resolved", GRATUITOUS_ARP_MAC_ADDR);
133         }
134
135         sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
136         return G_SOURCE_REMOVE;
137 }
138
139 static gboolean __netconfig_check_arp_receive(GIOChannel *source,
140                                                   GIOCondition condition, gpointer data)
141 {
142         struct sock_data *sd = data;
143         gchar buffer[ARP_PACKET_SIZE] = {0, };
144         gsize bytes_read = 0;
145         struct arp_message arp_recv;
146         char sbuf[WLAN_MAC_ADDR_MAX];
147         char tbuf[WLAN_MAC_ADDR_MAX];
148         const char *default_ip = NULL;
149
150         if (g_io_channel_read_chars(source, buffer, ARP_PACKET_SIZE,
151                                 &bytes_read, NULL) == G_IO_STATUS_NORMAL) {
152                 unsigned int target_ip = 0;
153
154                 memset(&arp_recv, 0, sizeof(arp_recv));
155                 memcpy(&arp_recv, buffer, sizeof(buffer));
156
157                 default_ip = netconfig_get_default_ipaddress();
158                 if (default_ip == NULL) {
159                         INFO("ip address is not set yet");
160                         goto out;
161                 }
162                 target_ip = inet_addr(default_ip);
163
164
165                 /* Only handle ARP replies */
166                 if (arp_recv.operation != htons(ARPOP_REPLY))
167                         goto out;
168
169                 UCHAR_TO_ADDRESS(arp_recv.t_hwaddr, tbuf);
170                 UCHAR_TO_ADDRESS(arp_recv.s_hwaddr, sbuf);
171
172                 int zero_mac = strcmp(tbuf , GRATUITOUS_ARP_MAC_ADDR);
173                 if (zero_mac == 0) {
174                         DBG("Broadcast packet.\n");
175                         goto skip;
176                 }
177                 DBG("our mac= %s source mac= %s target mac= %s", netconfig_get_default_mac_address(), sbuf, tbuf);
178                 int mac_cmp = strcmp(tbuf , netconfig_get_default_mac_address());
179                 if (mac_cmp != 0) {
180                         INFO("Packet not intended to us.\n");
181                         goto out;
182                 }
183 skip:
184                 mac_cmp = strcmp(sbuf, netconfig_get_default_mac_address());
185                 DBG("target ip = %d source ip = %d", target_ip, __convert_uchar_to_uint(arp_recv.s_IPaddr));
186                 if ((mac_cmp != 0) && (__convert_uchar_to_uint(arp_recv.s_IPaddr) == target_ip)) {
187                         sd->iteration = 0;
188                         if (conflict_state != NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED) {
189                                 INFO("ip conflict is detected !\n");
190                                 conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED;
191                                 __netconfig_wifi_notify_ip_conflict("conflict", sbuf);
192                         }
193
194                         if (sd->arp_reply_timer != -1) {
195                                 g_source_remove(sd->arp_reply_timer);
196                                 sd->arp_reply_timer = -1;
197                         }
198
199                         if (sd->timer_id)
200                                 g_source_remove(sd->timer_id);
201                         sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
202
203                 }
204         }
205
206 out:
207         return TRUE;
208 }
209
210 static gboolean send_arp(gpointer data)
211 {
212         struct sock_data *sd = data;
213         struct ether_addr *source_mac = NULL;
214         struct arp_message arp;
215         char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
216         unsigned int source_ip = 0;
217         unsigned int target_ip = 0;
218         const unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
219         struct sockaddr_ll addr = {0};
220         struct ifreq net_ifr;
221         int ifindex = 0;
222         errno = 0;
223         const char *default_ip = NULL;
224
225         const char *mac = netconfig_get_default_mac_address();
226         if (mac == NULL)
227                 goto err;
228         source_mac = ether_aton(mac);
229         if (source_mac == NULL) {
230                 INFO("Mac address is NULL");
231                 goto err;
232         }
233
234         memset(&arp, 0, sizeof(arp));
235
236         unsigned char  broadcast_mac_addr[MAC_ADDRESS_LENGTH];
237         memset(broadcast_mac_addr, 0xff, sizeof(broadcast_mac_addr));
238         memcpy(arp.h_dest, broadcast_mac_addr, MAC_ADDRESS_LENGTH);             /* MAC dest */
239         memcpy(arp.h_source, source_mac, MAC_ADDRESS_LENGTH);                   /* MAC source */
240
241         arp.h_proto = htons(ETH_P_ARP);                                         /* protocol type (Ethernet) */
242         arp.hw_type = htons(ARPHRD_ETHER);                                      /* hardware type */
243         arp.p_type = htons(ETH_P_IP);                                           /* protocol type (ARP message) */
244         arp.hw_len = MAC_ADDRESS_LENGTH;                                        /* hardware address length */
245         arp.p_len = IP_ADDRESS_LENGTH;                                          /* protocol address length */
246         arp.operation = htons(ARPOP_REQUEST);                                   /* ARP op code */
247         default_ip = netconfig_get_default_ipaddress();
248         if (default_ip == NULL) {
249                 INFO("ip address is not set yet");
250                 goto err;
251         }
252
253         source_ip = inet_addr(default_ip);
254         target_ip = inet_addr(default_ip);
255         memcpy(arp.s_IPaddr, &source_ip, IP_ADDRESS_LENGTH);                    /* source IP address */
256         memcpy(arp.s_hwaddr, source_mac, MAC_ADDRESS_LENGTH);                   /* source hardware address */
257         memcpy(arp.t_IPaddr, &target_ip, IP_ADDRESS_LENGTH);                    /* target IP addressshek" */
258
259         memset(&net_ifr, 0, sizeof(net_ifr));
260         /* ifreq structure creation */
261         size_t if_name_len = strlen(netconfig_get_default_ifname());
262         if (if_name_len < sizeof(net_ifr.ifr_name)) {
263                 memcpy(net_ifr.ifr_name, netconfig_get_default_ifname(), if_name_len);
264                 net_ifr.ifr_name[if_name_len] = 0;
265         } else {
266                 INFO("Error : Interface name is too long");
267                 goto err;
268         }
269
270         if (ioctl(sd->chk_conflict_sd, SIOCGIFINDEX, &net_ifr) == -1) {
271                 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
272                 INFO("ioctl Failed. Error..... = %s\n", error_buf);
273                 goto err;
274         }
275
276         ifindex = net_ifr.ifr_ifindex;
277         /* Construct the destination address */
278         addr.sll_family = AF_PACKET;
279         addr.sll_ifindex = ifindex;
280         addr.sll_halen = ETHER_ADDR_LEN;
281         addr.sll_protocol = htons(ETH_P_ARP);
282         memcpy(addr.sll_addr, broadcast_addr, ETHER_ADDR_LEN);
283
284         if (sendto(sd->chk_conflict_sd, &arp, sizeof(arp), 0, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
285                 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
286                 INFO("Sending ARP Packet Failed. Error. = %s\n", error_buf);
287                 /* close socket */
288                 if (-1 < sd->chk_conflict_sd) {
289                         close(sd->chk_conflict_sd);
290                         sd->chk_conflict_sd = -1;
291                 }
292
293                 /* reopen socket */
294                 if ((sd->chk_conflict_sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) == -1) {
295                         INFO("socket %d", sd->chk_conflict_sd);
296                         strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
297                         INFO("socket Failed. Error = %s\n", error_buf);
298                 }
299                 goto err;
300         } else {
301                 DBG("Sent ARP Packet \n");
302         }
303
304         g_source_remove(sd->timer_id);
305         if (td.mode == IP_CONFLICT_MODE_PERIODIC)
306                 sd->timeout = td.initial_time;
307         else if (td.mode == IP_CONFLICT_MODE_EXPONENTIAL && 2*sd->timeout < MAX_ARP_SEND_TIME)
308                 sd->timeout *= 2;
309
310         /* Adding timeout callback for arp request */
311         sd->arp_reply_timer = g_timeout_add(1000, __arp_reply_timeout_cb,
312                                         (gpointer) &sd->arp_reply_timer);
313         return FALSE;
314 err:
315         if (sd->timer_id)
316                 g_source_remove(sd->timer_id);
317         sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
318         return FALSE;
319 }
320
321 struct sock_data * start_ip_conflict_mon(void)
322 {
323         if (is_ip_conflict_detect_enabled == false) {
324                 INFO("detection mode is set to false");
325                 return NULL;
326         }
327
328         char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
329
330         sd = g_try_malloc0(sizeof(struct sock_data));
331         if (sd == NULL) {
332                 INFO("Failed to malloc sock_data");
333                 return NULL;
334         }
335         sd->chk_conflict_data_id = -1;
336         sd->chk_conflict_sd = -1;
337         sd->timer_id = 0;
338         sd->iteration = 0;
339
340         if ((sd->chk_conflict_sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) == -1) {
341                 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
342                 INFO("socket Failed. Error = %s\n", error_buf);
343                 g_free(sd);
344                 return NULL;
345         } else {
346                 sd->chk_conflict_sock_io = g_io_channel_unix_new(sd->chk_conflict_sd);
347                 if (sd->chk_conflict_sock_io == NULL) {
348                         INFO("Failed to create channel");
349                         INFO("Exit");
350                         g_free(sd);
351                         return NULL;
352                 }
353
354                 g_io_channel_set_close_on_unref(sd->chk_conflict_sock_io, TRUE);
355
356                 if (G_IO_STATUS_NORMAL != g_io_channel_set_encoding(sd->chk_conflict_sock_io,
357                                                                    NULL, NULL))
358                         INFO("Failed to set encoding NULL on io channel");
359                 if (G_IO_STATUS_NORMAL != g_io_channel_set_flags(sd->chk_conflict_sock_io,
360                                                                 G_IO_FLAG_NONBLOCK, NULL))
361                         INFO("Failed to set flags on io channel");
362                 sd->chk_conflict_data_id = g_io_add_watch(sd->chk_conflict_sock_io, G_IO_IN,
363                                                           __netconfig_check_arp_receive, sd);
364                 DBG("socket %d", sd->chk_conflict_sd);
365
366                 sd->timeout = td.initial_time;
367                 send_arp(sd);
368                 return sd;
369         }
370 }
371
372 void stop_ip_conflict_mon()
373 {
374         INFO("+");
375         GError* error = NULL;
376         if (sd == NULL) {
377                 INFO("sd is NULL");
378                 return;
379         }
380         if (-1 < sd->chk_conflict_sd) {
381                 if (G_IO_STATUS_NORMAL !=
382                     g_io_channel_shutdown(sd->chk_conflict_sock_io, FALSE,
383                                           &error)) {
384                         INFO("Failure received while shutdown io channel[%d]:[%s]", error->code, error->message);
385                         g_error_free(error);
386                 }
387                 g_io_channel_unref(sd->chk_conflict_sock_io);
388                 g_source_remove(sd->chk_conflict_data_id);
389                 sd->chk_conflict_data_id = -1;
390                 close(sd->chk_conflict_sd);
391                 sd->chk_conflict_sd = -1;
392         }
393         if (sd->timer_id > 0) {
394                 g_source_remove(sd->timer_id);
395                 sd->timer_id = 0;
396         }
397         g_free(sd);
398         sd = NULL;
399         INFO("Monitoring stopped");
400 }
401
402 static void __netconfig_wifi_notify_ip_conflict(char *state, char *mac)
403 {
404         GVariantBuilder *builder = NULL;
405
406         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
407         g_variant_builder_add(builder, "{sv}", "state", g_variant_new_string(state));
408         g_variant_builder_add(builder, "{sv}", "mac", g_variant_new_string(mac));
409
410         wifi_emit_ip_conflict_event((Wifi *)get_wifi_object(), g_variant_builder_end(builder));
411         g_variant_builder_unref(builder);
412
413         return;
414 }
415
416 gboolean handle_ip_conflict_set_enable(Wifi *wifi, GDBusMethodInvocation *context,
417                                        bool detect)
418 {
419         g_return_val_if_fail(wifi != NULL, FALSE);
420
421
422         if (detect == false) {
423                 is_ip_conflict_detect_enabled = false;
424                 conflict_state = NETCONFIG_IP_CONFLICT_STATE_UNKNOWN;
425                 if (sd != NULL)
426                         stop_ip_conflict_mon();
427                 else {
428                         netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AlreadyExists");
429                         wifi_complete_ip_conflict_set_enable(wifi, context);
430                         return FALSE;
431                 }
432         } else {
433                 is_ip_conflict_detect_enabled = true;
434                 conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
435                 if (sd == NULL) {
436                         if (start_ip_conflict_mon() == NULL) {
437                                 INFO("Failed to start IP conflict monitoring");
438                                 netconfig_error_dbus_method_return(context,
439                                                 NETCONFIG_ERROR_INTERNAL, "Failed");
440                                 wifi_complete_ip_conflict_set_enable(wifi, context);
441                                 return FALSE;
442                         }
443                 } else {
444                         netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AlreadyExists");
445                         wifi_complete_ip_conflict_set_enable(wifi, context);
446                         return FALSE;
447                 }
448         }
449
450         wifi_complete_ip_conflict_set_enable(wifi, context);
451         return TRUE;
452 }
453
454 gboolean handle_is_ip_conflict_detect_enabled(Wifi *wifi, GDBusMethodInvocation *context)
455 {
456         g_return_val_if_fail(wifi != NULL, FALSE);
457         GVariant *param = NULL;
458         param = g_variant_new("(b)", is_ip_conflict_detect_enabled);
459         g_dbus_method_invocation_return_value(context, param);
460         return TRUE;
461 }
462
463 gboolean handle_set_ip_conflict_mode(Wifi *wifi, GDBusMethodInvocation *context,
464                                      guint mode, guint initial_time)
465 {
466         g_return_val_if_fail(wifi != NULL, FALSE);
467         if (initial_time < MAX_ARP_SEND_TIME && initial_time > MIN_ARP_SEND_TIME)
468                 return FALSE;
469
470         td.initial_time = 1000 * initial_time;
471         td.mode = mode;
472         // remove timer
473         stop_ip_conflict_mon();
474         start_ip_conflict_mon();
475         wifi_complete_set_ip_conflict_mode(wifi, context);
476         return TRUE;
477 }
478
479 gboolean handle_get_ip_conflict_state(Wifi *wifi, GDBusMethodInvocation *context)
480 {
481         g_return_val_if_fail(wifi != NULL, FALSE);
482         GVariant *param = NULL;
483         param = g_variant_new("(u)", conflict_state);
484         g_dbus_method_invocation_return_value(context, param);
485         return TRUE;
486 }