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