Use rand_r() instead of rand()
[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 "netdbus.h"
38 #include "ip-conflict-detect.h"
39 #include "network-state.h"
40 #include "log.h"
41 #include "neterror.h"
42 #include "util.h"
43
44 #define ARP_PACKET_SIZE 60
45 #define MAX_SIZE_ERROR_BUFFER 256
46 #define IP_ADDRESS_LENGTH 4
47 #define MAC_ADDRESS_LENGTH 6
48 #define WLAN_MAC_ADDR_MAX 20
49 #define ARP_SOURCE_IP "0.0.0.0"
50 #define INITIAL_BURST_ARP_COUNT 5
51
52 #define CONFLICT_REMOVE_ITERATION_LIMIT 4
53 #define MIN_ARP_SEND_TIME 20000
54 #define BURST_ARP_SEND_TIME 3000
55 #define MAX_ARP_SEND_TIME 32000
56 #define GRATUITOUS_ARP_MAC_ADDR "00:00:00:00:00:00"
57 #define UCHAR_TO_ADDRESS(hwaddr, buf) do {\
58                 snprintf(buf, WLAN_MAC_ADDR_MAX,\
59                 "%02X:%02X:%02X:%02X:%02X:%02X", hwaddr[0], hwaddr[1],\
60                 hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);\
61                 } while (0)
62
63 struct arp_message {
64         /* Ethernet header */
65         unsigned char   h_dest[MAC_ADDRESS_LENGTH];     /* destination ether addr */
66         unsigned char   h_source[MAC_ADDRESS_LENGTH];   /* source ether addr */
67         unsigned short  h_proto;                                /* packet type ID field */
68
69         /* ARP packet */
70         unsigned short hw_type;                         /* hardware type(ARPHRD_ETHER) */
71         unsigned short p_type;                          /* protocol type(ETH_P_IP) */
72         unsigned char  hw_len;                          /* hardware address length */
73         unsigned char  p_len;                                   /* protocol address length */
74         unsigned short operation;                               /* ARP opcode */
75         unsigned char  s_hwaddr[MAC_ADDRESS_LENGTH];            /* sender hardware address */
76         unsigned char  s_IPaddr[IP_ADDRESS_LENGTH];             /* sender IP address */
77         unsigned char  t_hwaddr[MAC_ADDRESS_LENGTH];            /* target hardware address */
78         unsigned char  t_IPaddr[IP_ADDRESS_LENGTH];             /* target IP address */
79         unsigned char  pad[22];                         /* pad for min. Ethernet payload (64 bytes) */
80 };
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 };
92 static struct timer_data td = {
93         MIN_ARP_SEND_TIME, MIN_ARP_SEND_TIME
94 };
95
96 int ioctl_sock;
97 static bool initial_bursts = true;
98 bool is_ip_conflict_detect_enabled = false;
99 bool is_ip_conflict_detect_running = false;
100 static gboolean send_arp(gpointer data);
101 static void __netconfig_wifi_notify_ip_conflict(const char *interface_name,
102                         char *state, char *mac);
103 ip_conflict_state_e conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
104
105 struct sock_data *sd;
106
107 typedef unsigned int in_addr_t;
108
109 union uchar_to_uint {
110         unsigned int uint;
111         unsigned char uchar[IP_ADDRESS_LENGTH];
112 };
113
114 static unsigned int __convert_uchar_to_uint(unsigned char b[IP_ADDRESS_LENGTH])
115 {
116         int idx = 0;
117         union uchar_to_uint u;
118         for (; idx < IP_ADDRESS_LENGTH; ++idx)
119                 u.uchar[idx] = b[idx];
120
121         return u.uint;
122 }
123
124 static gboolean __arp_reply_timeout_cb(gpointer data)
125 {
126         if (sd == NULL) {
127                 INFO("Ignore timeout cb");
128                 return G_SOURCE_REMOVE;
129         }
130
131         sd->iteration++;
132         sd->arp_reply_timer = -1;
133
134         if (conflict_state != NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED &&
135                         sd->iteration == CONFLICT_REMOVE_ITERATION_LIMIT) {
136                 sd->iteration = 0;
137                 conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
138                 __netconfig_wifi_notify_ip_conflict(netconfig_get_default_ifname(),
139                         "resolved", GRATUITOUS_ARP_MAC_ADDR);
140                 initial_bursts = true;
141         }
142
143         if (sd->timer_id)
144                 g_source_remove(sd->timer_id);
145         sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
146         return G_SOURCE_REMOVE;
147 }
148
149 static gboolean __netconfig_check_arp_receive(GIOChannel *source,
150                                                   GIOCondition condition, gpointer data)
151 {
152         struct sock_data *sd = data;
153         gchar buffer[ARP_PACKET_SIZE] = {0, };
154         gsize bytes_read = 0;
155         struct arp_message arp_recv;
156         char sbuf[WLAN_MAC_ADDR_MAX];
157         char tbuf[WLAN_MAC_ADDR_MAX];
158         const char *default_ip = NULL;
159         int mac_cmp = 0;
160
161         if (g_io_channel_read_chars(source, buffer, ARP_PACKET_SIZE,
162                                 &bytes_read, NULL) == G_IO_STATUS_NORMAL) {
163                 unsigned int target_ip = 0;
164
165                 memset(&arp_recv, 0, sizeof(arp_recv));
166                 memcpy(&arp_recv, buffer, sizeof(buffer));
167
168                 default_ip = netconfig_get_default_ipaddress();
169                 if (default_ip == NULL) {
170                         INFO("ip address is not set yet");
171                         goto out;
172                 }
173                 target_ip = inet_addr(default_ip);
174
175
176                 /* Only handle ARP replies */
177                 if (arp_recv.operation != htons(ARPOP_REPLY))
178                         goto out;
179
180                 UCHAR_TO_ADDRESS(arp_recv.t_hwaddr, tbuf);
181                 UCHAR_TO_ADDRESS(arp_recv.s_hwaddr, sbuf);
182
183                 int zero_mac = strcmp(tbuf , GRATUITOUS_ARP_MAC_ADDR);
184                 if (zero_mac == 0) {
185                         DBG("Broadcast packet.");
186                         goto skip;
187                 }
188                 DBG("our mac= %s source mac= %s target mac= %s", netconfig_get_default_mac_address(), sbuf, tbuf);
189                 mac_cmp = strcmp(tbuf , netconfig_get_default_mac_address());
190                 if (mac_cmp != 0) {
191                         INFO("Packet not intended to us.");
192                         goto out;
193                 }
194 skip:
195                 mac_cmp = strcmp(sbuf, netconfig_get_default_mac_address());
196                 DBG("target ip = %d source ip = %d", target_ip, __convert_uchar_to_uint(arp_recv.s_IPaddr));
197                 if ((mac_cmp != 0) && (__convert_uchar_to_uint(arp_recv.s_IPaddr) == target_ip)) {
198                         sd->iteration = 0;
199                         if (conflict_state != NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED) {
200                                 INFO("ip conflict is detected !");
201                                 conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED;
202                                 __netconfig_wifi_notify_ip_conflict(
203                                         netconfig_get_default_ifname(),
204                                         "conflict", sbuf);
205                                 sd->timeout = BURST_ARP_SEND_TIME;
206                         }
207
208                         if (sd->arp_reply_timer != -1) {
209                                 g_source_remove(sd->arp_reply_timer);
210                                 sd->arp_reply_timer = -1;
211                         }
212
213                         if (sd->timer_id)
214                                 g_source_remove(sd->timer_id);
215                         sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
216                 }
217         }
218
219 out:
220         return TRUE;
221 }
222
223 static void __close_channel_and_sock(struct sock_data *sd)
224 {
225         if (sd == NULL)
226                 return;
227
228         g_io_channel_unref(sd->chk_conflict_sock_io);
229         g_source_remove(sd->chk_conflict_data_id);
230         sd->chk_conflict_data_id = -1;
231
232         close(sd->chk_conflict_sd);
233         sd->chk_conflict_sd = -1;
234 }
235
236 static int __open_channel_and_sock(struct sock_data *sd)
237 {
238         if (sd == NULL)
239                 return -1;
240
241         if ((sd->chk_conflict_sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) == -1) {
242                 INFO("socket Failed.");
243                 return -1;
244         }
245
246         sd->chk_conflict_sock_io = g_io_channel_unix_new(sd->chk_conflict_sd);
247         if (sd->chk_conflict_sock_io == NULL) {
248                 INFO("Failed to create channel");
249                 close(sd->chk_conflict_sd);
250                 sd->chk_conflict_sd = -1;
251                 return -1;
252         }
253
254         if (G_IO_STATUS_NORMAL != g_io_channel_set_encoding(sd->chk_conflict_sock_io, NULL, NULL))
255                 INFO("Failed to set encoding NULL on io channel");
256
257         if (G_IO_STATUS_NORMAL != g_io_channel_set_flags(sd->chk_conflict_sock_io,
258                                 G_IO_FLAG_NONBLOCK, NULL))
259                 INFO("Failed to set flags on io channel");
260
261         sd->chk_conflict_data_id = g_io_add_watch(sd->chk_conflict_sock_io, G_IO_IN,
262                         __netconfig_check_arp_receive, sd);
263         DBG("socket %d", sd->chk_conflict_sd);
264         return 0;
265 }
266
267 static gboolean send_arp(gpointer data)
268 {
269         struct sock_data *sd = data;
270         struct ether_addr *source_mac = NULL;
271         struct arp_message arp;
272         char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
273         unsigned int source_ip = 0;
274         unsigned int target_ip = 0;
275         const unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
276         struct sockaddr_ll addr = {0};
277         struct ifreq net_ifr;
278         int ifindex = 0;
279         errno = 0;
280         const char *default_ip = NULL;
281         const char *if_name = NULL;
282         static int initial_send_arp_count = 0;
283
284         if (initial_bursts && initial_send_arp_count >= INITIAL_BURST_ARP_COUNT) {
285                 initial_bursts = false;
286                 initial_send_arp_count = 0;
287         }
288
289         if (initial_bursts)
290                 initial_send_arp_count++;
291
292         const char *mac = netconfig_get_default_mac_address();
293         if (mac == NULL)
294                 goto err;
295         source_mac = ether_aton(mac);
296         if (source_mac == NULL) {
297                 INFO("Mac address is NULL");
298                 goto err;
299         }
300
301         memset(&arp, 0, sizeof(arp));
302
303         unsigned char  broadcast_mac_addr[MAC_ADDRESS_LENGTH];
304         memset(broadcast_mac_addr, 0xff, sizeof(broadcast_mac_addr));
305         memcpy(arp.h_dest, broadcast_mac_addr, MAC_ADDRESS_LENGTH);             /* MAC dest */
306         memcpy(arp.h_source, source_mac, MAC_ADDRESS_LENGTH);                   /* MAC source */
307
308         arp.h_proto = htons(ETH_P_ARP);                                         /* protocol type (Ethernet) */
309         arp.hw_type = htons(ARPHRD_ETHER);                                      /* hardware type */
310         arp.p_type = htons(ETH_P_IP);                                           /* protocol type (ARP message) */
311         arp.hw_len = MAC_ADDRESS_LENGTH;                                        /* hardware address length */
312         arp.p_len = IP_ADDRESS_LENGTH;                                          /* protocol address length */
313         arp.operation = htons(ARPOP_REQUEST);                                   /* ARP op code */
314         default_ip = netconfig_get_default_ipaddress();
315         if (default_ip == NULL) {
316                 INFO("ip address is not set yet");
317                 goto err;
318         }
319
320         source_ip = inet_addr(ARP_SOURCE_IP);
321         target_ip = inet_addr(default_ip);
322         memcpy(arp.s_IPaddr, &source_ip, IP_ADDRESS_LENGTH);                    /* source IP address */
323         memcpy(arp.s_hwaddr, source_mac, MAC_ADDRESS_LENGTH);                   /* source hardware address */
324         memcpy(arp.t_IPaddr, &target_ip, IP_ADDRESS_LENGTH);                    /* target IP addressshek" */
325
326         memset(&net_ifr, 0, sizeof(net_ifr));
327         /* ifreq structure creation */
328         if_name = netconfig_get_default_ifname();
329         size_t if_name_len = strlen(if_name);
330
331         if (if_name_len == 0) {
332                 INFO("Error : Unable to get interface name ");
333                 goto err;
334         }
335
336         if (if_name_len < sizeof(net_ifr.ifr_name)) {
337                 memcpy(net_ifr.ifr_name, netconfig_get_default_ifname(), if_name_len);
338                 net_ifr.ifr_name[if_name_len] = 0;
339         } else {
340                 INFO("Error : Interface name is too long");
341                 goto err;
342         }
343
344         if (ioctl(sd->chk_conflict_sd, SIOCGIFINDEX, &net_ifr) == -1) {
345                 INFO("ioctl Failed. Error..... = %s",
346                                 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
347                 goto err;
348         }
349
350         ifindex = net_ifr.ifr_ifindex;
351         /* Construct the destination address */
352         addr.sll_family = AF_PACKET;
353         addr.sll_ifindex = ifindex;
354         addr.sll_halen = ETHER_ADDR_LEN;
355         addr.sll_protocol = htons(ETH_P_ARP);
356         memcpy(addr.sll_addr, broadcast_addr, ETHER_ADDR_LEN);
357
358         if (sendto(sd->chk_conflict_sd, &arp, sizeof(arp), 0,
359                                 (struct sockaddr*)&addr, sizeof(addr)) < 0) {
360                 INFO("Sending ARP Packet Failed. Error. = %s",
361                                 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
362                 __close_channel_and_sock(sd);
363                 if (__open_channel_and_sock(sd) == -1)
364                         INFO("__open_channel_and_sock failed");
365                 goto err;
366         } else {
367                 /* DBG("Sent ARP Packet"); */
368         }
369
370         if (sd->timer_id) {
371                 g_source_remove(sd->timer_id);
372                 sd->timer_id = 0;
373         }
374
375         if (conflict_state == NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED || initial_bursts)
376                 sd->timeout = BURST_ARP_SEND_TIME;
377         else
378                 sd->timeout = td.initial_time;
379
380         /* Adding timeout callback for arp request */
381         sd->arp_reply_timer = g_timeout_add(1000, __arp_reply_timeout_cb,
382                                         (gpointer) &sd->arp_reply_timer);
383         return FALSE;
384 err:
385         if (sd->timer_id)
386                 g_source_remove(sd->timer_id);
387         sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
388         return FALSE;
389 }
390
391 struct sock_data * start_ip_conflict_mon(void)
392 {
393         if (is_ip_conflict_detect_enabled == false) {
394                 INFO("ip_conflict_detect is disabled");
395                 return NULL;
396         }
397
398         if (is_ip_conflict_detect_running == true) {
399                 INFO("detection mode is set to true");
400                 return NULL;
401         }
402
403         initial_bursts = true;
404
405         sd = g_try_malloc0(sizeof(struct sock_data));
406         if (sd == NULL) {
407                 INFO("Failed to malloc sock_data");
408                 return NULL;
409         }
410         sd->chk_conflict_data_id = -1;
411         sd->chk_conflict_sd = -1;
412
413         if (__open_channel_and_sock(sd) == -1) {
414                 INFO("__open_channel_and_sock failed");
415                 g_free(sd);
416                 sd = NULL;
417                 return NULL;
418         }
419
420         sd->timeout = td.initial_time;
421         send_arp(sd);
422         is_ip_conflict_detect_running = true;
423         conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
424
425         return sd;
426 }
427
428 void stop_ip_conflict_mon()
429 {
430         INFO("+");
431         if (sd == NULL) {
432                 INFO("sd is NULL");
433                 return;
434         }
435
436         if (-1 < sd->chk_conflict_sd)
437                 __close_channel_and_sock(sd);
438
439         if (sd->timer_id) {
440                 g_source_remove(sd->timer_id);
441         }
442         g_free(sd);
443         sd = NULL;
444         is_ip_conflict_detect_running = false;
445         conflict_state = NETCONFIG_IP_CONFLICT_STATE_UNKNOWN;
446         INFO("Monitoring stopped");
447 }
448
449 static void __netconfig_wifi_notify_ip_conflict(const char *interface_name,
450                         char *state, char *mac)
451 {
452         GVariantBuilder *builder = NULL;
453
454         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
455         g_variant_builder_add(builder, "{sv}", "state", g_variant_new_string(state));
456         g_variant_builder_add(builder, "{sv}", "mac", g_variant_new_string(mac));
457
458         wifi_emit_ip_conflict_event((Wifi *)get_wifi_object(),
459                 interface_name, g_variant_builder_end(builder));
460         g_variant_builder_unref(builder);
461
462         /* send notification using net-popup */
463         if (!strcmp(state, "conflict"))
464                 netconfig_send_notification_to_net_popup(NETCONFIG_ADD_IP_CONFLICT_NOTI, mac);
465         else
466                 netconfig_send_notification_to_net_popup(NETCONFIG_DEL_IP_CONFLICT_NOTI, mac);
467
468         return;
469 }
470
471 gboolean handle_ip_conflict_set_enable(Wifi *wifi, GDBusMethodInvocation *context,
472                         const gchar *ifname, bool detect)
473 {
474         g_return_val_if_fail(wifi != NULL, TRUE);
475
476         if (detect == false) {
477                 if (is_ip_conflict_detect_enabled == true) {
478                         stop_ip_conflict_mon();
479                         is_ip_conflict_detect_enabled = false;
480                 } else {
481                         netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AlreadyExists");
482                         return TRUE;
483                 }
484         } else {
485                 if (is_ip_conflict_detect_enabled == false) {
486                         is_ip_conflict_detect_enabled = true;
487                         const char *def_profile = netconfig_get_default_profile();
488                         if (netconfig_is_wifi_profile(def_profile) ||
489                                         netconfig_is_ethernet_profile(def_profile)) {
490                                 if (start_ip_conflict_mon() == NULL) {
491                                         INFO("Failed to start IP conflict monitoring");
492                                         netconfig_error_dbus_method_return(context,
493                                                         NETCONFIG_ERROR_INTERNAL, "Failed");
494                                         return TRUE;
495                                 }
496                         }
497                 } else {
498                         netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AlreadyExists");
499                         return TRUE;
500                 }
501         }
502
503         wifi_complete_ip_conflict_set_enable(wifi, context);
504         return TRUE;
505 }
506
507 gboolean handle_is_ip_conflict_detect_enabled(Wifi *wifi, GDBusMethodInvocation *context,
508                         const gchar *ifname)
509 {
510         g_return_val_if_fail(wifi != NULL, TRUE);
511         GVariant *param = NULL;
512         param = g_variant_new("(b)", is_ip_conflict_detect_enabled);
513         g_dbus_method_invocation_return_value(context, param);
514         return TRUE;
515 }
516
517 gboolean handle_set_ip_conflict_period(Wifi *wifi, GDBusMethodInvocation *context,
518                         const gchar *ifname, guint initial_time)
519 {
520         g_return_val_if_fail(wifi != NULL, TRUE);
521         INFO("%d", initial_time);
522         if (initial_time > MAX_ARP_SEND_TIME || initial_time < MIN_ARP_SEND_TIME) {
523                 netconfig_error_dbus_method_return(context,
524                                                 NETCONFIG_ERROR_INTERNAL, "Failed");
525                 return TRUE;
526         }
527
528         td.initial_time = 1000 * initial_time;
529         // remove timer
530         stop_ip_conflict_mon();
531         start_ip_conflict_mon();
532         wifi_complete_set_ip_conflict_period(wifi, context);
533         return TRUE;
534 }
535
536 gboolean handle_get_ip_conflict_state(Wifi *wifi, GDBusMethodInvocation *context,
537                         const gchar *ifname)
538 {
539         g_return_val_if_fail(wifi != NULL, TRUE);
540         GVariant *param = NULL;
541         param = g_variant_new("(u)", conflict_state);
542         g_dbus_method_invocation_return_value(context, param);
543         return TRUE;
544 }
545
546 gboolean handle_get_ip_conflict_period(Wifi *wifi, GDBusMethodInvocation *context,
547                         const gchar *ifname)
548 {
549         g_return_val_if_fail(wifi != NULL, TRUE);
550         GVariant *param = NULL;
551         param = g_variant_new("(u)", td.initial_time/1000);
552         g_dbus_method_invocation_return_value(context, param);
553         return TRUE;
554 }