2 * Network Configuration Module
4 * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
38 #include "ip-conflict-detect.h"
39 #include "network-state.h"
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
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]);\
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 */
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) */
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;
92 static struct timer_data td = {
93 MIN_ARP_SEND_TIME, MIN_ARP_SEND_TIME
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;
105 struct sock_data *sd;
107 typedef unsigned int in_addr_t;
109 union uchar_to_uint {
111 unsigned char uchar[IP_ADDRESS_LENGTH];
114 static unsigned int __convert_uchar_to_uint(unsigned char b[IP_ADDRESS_LENGTH])
117 union uchar_to_uint u;
118 for (; idx < IP_ADDRESS_LENGTH; ++idx)
119 u.uchar[idx] = b[idx];
124 static gboolean __arp_reply_timeout_cb(gpointer data)
127 INFO("Ignore timeout cb");
128 return G_SOURCE_REMOVE;
132 sd->arp_reply_timer = -1;
134 if (conflict_state != NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED &&
135 sd->iteration == CONFLICT_REMOVE_ITERATION_LIMIT) {
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;
144 g_source_remove(sd->timer_id);
145 sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
146 return G_SOURCE_REMOVE;
149 static gboolean __netconfig_check_arp_receive(GIOChannel *source,
150 GIOCondition condition, gpointer data)
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;
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;
165 memset(&arp_recv, 0, sizeof(arp_recv));
166 memcpy(&arp_recv, buffer, sizeof(buffer));
168 default_ip = netconfig_get_default_ipaddress();
169 if (default_ip == NULL) {
170 INFO("ip address is not set yet");
173 target_ip = inet_addr(default_ip);
176 /* Only handle ARP replies */
177 if (arp_recv.operation != htons(ARPOP_REPLY))
180 UCHAR_TO_ADDRESS(arp_recv.t_hwaddr, tbuf);
181 UCHAR_TO_ADDRESS(arp_recv.s_hwaddr, sbuf);
183 int zero_mac = strcmp(tbuf , GRATUITOUS_ARP_MAC_ADDR);
185 DBG("Broadcast packet.");
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());
191 INFO("Packet not intended to us.");
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)) {
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(),
205 sd->timeout = BURST_ARP_SEND_TIME;
208 if (sd->arp_reply_timer != -1) {
209 g_source_remove(sd->arp_reply_timer);
210 sd->arp_reply_timer = -1;
214 g_source_remove(sd->timer_id);
215 sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
223 static void __close_channel_and_sock(struct sock_data *sd)
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;
232 close(sd->chk_conflict_sd);
233 sd->chk_conflict_sd = -1;
236 static int __open_channel_and_sock(struct sock_data *sd)
241 if ((sd->chk_conflict_sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) == -1) {
242 INFO("socket Failed.");
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;
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");
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");
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);
267 static gboolean send_arp(gpointer data)
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;
280 const char *default_ip = NULL;
281 const char *if_name = NULL;
282 static int initial_send_arp_count = 0;
284 if (initial_bursts && initial_send_arp_count >= INITIAL_BURST_ARP_COUNT) {
285 initial_bursts = false;
286 initial_send_arp_count = 0;
290 initial_send_arp_count++;
292 const char *mac = netconfig_get_default_mac_address();
295 source_mac = ether_aton(mac);
296 if (source_mac == NULL) {
297 INFO("Mac address is NULL");
301 memset(&arp, 0, sizeof(arp));
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 */
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");
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" */
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);
331 if (if_name_len == 0) {
332 INFO("Error : Unable to get interface name ");
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;
340 INFO("Error : Interface name is too long");
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));
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);
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");
367 /* DBG("Sent ARP Packet"); */
371 g_source_remove(sd->timer_id);
375 if (conflict_state == NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED || initial_bursts)
376 sd->timeout = BURST_ARP_SEND_TIME;
378 sd->timeout = td.initial_time;
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);
386 g_source_remove(sd->timer_id);
387 sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
391 struct sock_data * start_ip_conflict_mon(void)
393 if (is_ip_conflict_detect_enabled == false) {
394 INFO("ip_conflict_detect is disabled");
398 if (is_ip_conflict_detect_running == true) {
399 INFO("detection mode is set to true");
403 initial_bursts = true;
405 sd = g_try_malloc0(sizeof(struct sock_data));
407 INFO("Failed to malloc sock_data");
410 sd->chk_conflict_data_id = -1;
411 sd->chk_conflict_sd = -1;
413 if (__open_channel_and_sock(sd) == -1) {
414 INFO("__open_channel_and_sock failed");
420 sd->timeout = td.initial_time;
422 is_ip_conflict_detect_running = true;
423 conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
428 void stop_ip_conflict_mon()
436 if (-1 < sd->chk_conflict_sd)
437 __close_channel_and_sock(sd);
440 g_source_remove(sd->timer_id);
444 is_ip_conflict_detect_running = false;
445 conflict_state = NETCONFIG_IP_CONFLICT_STATE_UNKNOWN;
446 INFO("Monitoring stopped");
449 static void __netconfig_wifi_notify_ip_conflict(const char *interface_name,
450 char *state, char *mac)
452 GVariantBuilder *builder = NULL;
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));
458 wifi_emit_ip_conflict_event((Wifi *)get_wifi_object(),
459 interface_name, g_variant_builder_end(builder));
460 g_variant_builder_unref(builder);
462 /* send notification using net-popup */
463 if (!strcmp(state, "conflict"))
464 netconfig_send_notification_to_net_popup(NETCONFIG_ADD_IP_CONFLICT_NOTI, mac);
466 netconfig_send_notification_to_net_popup(NETCONFIG_DEL_IP_CONFLICT_NOTI, mac);
471 gboolean handle_ip_conflict_set_enable(Wifi *wifi, GDBusMethodInvocation *context,
472 const gchar *ifname, bool detect)
474 g_return_val_if_fail(wifi != NULL, TRUE);
476 if (detect == false) {
477 if (is_ip_conflict_detect_enabled == true) {
478 stop_ip_conflict_mon();
479 is_ip_conflict_detect_enabled = false;
481 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AlreadyExists");
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");
498 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AlreadyExists");
503 wifi_complete_ip_conflict_set_enable(wifi, context);
507 gboolean handle_is_ip_conflict_detect_enabled(Wifi *wifi, GDBusMethodInvocation *context,
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);
517 gboolean handle_set_ip_conflict_period(Wifi *wifi, GDBusMethodInvocation *context,
518 const gchar *ifname, guint initial_time)
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");
528 td.initial_time = 1000 * initial_time;
530 stop_ip_conflict_mon();
531 start_ip_conflict_mon();
532 wifi_complete_set_ip_conflict_period(wifi, context);
536 gboolean handle_get_ip_conflict_state(Wifi *wifi, GDBusMethodInvocation *context,
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);
546 gboolean handle_get_ip_conflict_period(Wifi *wifi, GDBusMethodInvocation *context,
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);