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>
37 #include "ip-conflict-detect.h"
38 #include "network-state.h"
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 #define ARP_SOURCE_IP "0.0.0.0"
49 #define MIN_ARP_SEND_TIME 2000
50 #define MAX_ARP_SEND_TIME 32000
51 #define GRATUITOUS_ARP_MAC_ADDR "00:00:00:00:00:00"
52 #define UCHAR_TO_ADDRESS(hwaddr, buf) do {\
53 snprintf(buf, WLAN_MAC_ADDR_MAX,\
54 "%02X:%02X:%02X:%02X:%02X:%02X", hwaddr[0], hwaddr[1],\
55 hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);\
60 unsigned char h_dest[MAC_ADDRESS_LENGTH]; /* destination ether addr */
61 unsigned char h_source[MAC_ADDRESS_LENGTH]; /* source ether addr */
62 unsigned short h_proto; /* packet type ID field */
65 unsigned short hw_type; /* hardware type(ARPHRD_ETHER) */
66 unsigned short p_type; /* protocol type(ETH_P_IP) */
67 unsigned char hw_len; /* hardware address length */
68 unsigned char p_len; /* protocol address length */
69 unsigned short operation; /* ARP opcode */
70 unsigned char s_hwaddr[MAC_ADDRESS_LENGTH]; /* sender hardware address */
71 unsigned char s_IPaddr[IP_ADDRESS_LENGTH]; /* sender IP address */
72 unsigned char t_hwaddr[MAC_ADDRESS_LENGTH]; /* target hardware address */
73 unsigned char t_IPaddr[IP_ADDRESS_LENGTH]; /* target IP address */
74 unsigned char pad[18]; /* pad for min. Ethernet payload (60 bytes) */
78 NETCONFIG_IP_CONFLICT_STATE_UNKNOWN,
79 NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED,
80 NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED
81 } ip_conflict_state_e;
87 static struct timer_data td = {
88 MIN_ARP_SEND_TIME, MIN_ARP_SEND_TIME
92 bool is_ip_conflict_detect_enabled = true;
93 static gboolean send_arp(gpointer data);
94 static void __netconfig_wifi_notify_ip_conflict(char *state, char *mac);
95 ip_conflict_state_e conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
99 typedef unsigned int in_addr_t;
101 union uchar_to_uint {
103 unsigned char uchar[IP_ADDRESS_LENGTH];
106 static unsigned int __convert_uchar_to_uint(unsigned char b[IP_ADDRESS_LENGTH])
109 union uchar_to_uint u;
110 for (; idx < IP_ADDRESS_LENGTH; ++idx)
111 u.uchar[idx] = b[idx];
116 static gboolean __arp_reply_timeout_cb(gpointer data)
119 INFO("Ignore timeout cb");
120 return G_SOURCE_REMOVE;
124 sd->arp_reply_timer = -1;
125 if (sd->timer_id != -1)
126 g_source_remove(sd->timer_id);
128 if (conflict_state != NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED && sd->iteration == 5) {
130 conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
131 __netconfig_wifi_notify_ip_conflict("resolved", GRATUITOUS_ARP_MAC_ADDR);
134 sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
135 return G_SOURCE_REMOVE;
138 static gboolean __netconfig_check_arp_receive(GIOChannel *source,
139 GIOCondition condition, gpointer data)
141 struct sock_data *sd = data;
142 gchar buffer[ARP_PACKET_SIZE] = {0, };
143 gsize bytes_read = 0;
144 struct arp_message arp_recv;
145 char sbuf[WLAN_MAC_ADDR_MAX];
146 char tbuf[WLAN_MAC_ADDR_MAX];
147 const char *default_ip = NULL;
149 if (g_io_channel_read_chars(source, buffer, ARP_PACKET_SIZE,
150 &bytes_read, NULL) == G_IO_STATUS_NORMAL) {
151 unsigned int target_ip = 0;
153 memset(&arp_recv, 0, sizeof(arp_recv));
154 memcpy(&arp_recv, buffer, sizeof(buffer));
156 default_ip = netconfig_get_default_ipaddress();
157 if (default_ip == NULL) {
158 INFO("ip address is not set yet");
161 target_ip = inet_addr(default_ip);
164 /* Only handle ARP replies */
165 if (arp_recv.operation != htons(ARPOP_REPLY))
168 UCHAR_TO_ADDRESS(arp_recv.t_hwaddr, tbuf);
169 UCHAR_TO_ADDRESS(arp_recv.s_hwaddr, sbuf);
171 int zero_mac = strcmp(tbuf , GRATUITOUS_ARP_MAC_ADDR);
173 DBG("Broadcast packet.\n");
176 DBG("our mac= %s source mac= %s target mac= %s", netconfig_get_default_mac_address(), sbuf, tbuf);
177 int mac_cmp = strcmp(tbuf , netconfig_get_default_mac_address());
179 INFO("Packet not intended to us.\n");
183 mac_cmp = strcmp(sbuf, netconfig_get_default_mac_address());
184 DBG("target ip = %d source ip = %d", target_ip, __convert_uchar_to_uint(arp_recv.s_IPaddr));
185 if ((mac_cmp != 0) && (__convert_uchar_to_uint(arp_recv.s_IPaddr) == target_ip)) {
187 if (conflict_state != NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED) {
188 INFO("ip conflict is detected !\n");
189 conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_DETECTED;
190 __netconfig_wifi_notify_ip_conflict("conflict", sbuf);
193 if (sd->arp_reply_timer != -1) {
194 g_source_remove(sd->arp_reply_timer);
195 sd->arp_reply_timer = -1;
199 g_source_remove(sd->timer_id);
200 sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
209 static gboolean send_arp(gpointer data)
211 struct sock_data *sd = data;
212 struct ether_addr *source_mac = NULL;
213 struct arp_message arp;
214 char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
215 unsigned int source_ip = 0;
216 unsigned int target_ip = 0;
217 const unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
218 struct sockaddr_ll addr = {0};
219 struct ifreq net_ifr;
222 const char *default_ip = NULL;
224 const char *mac = netconfig_get_default_mac_address();
227 source_mac = ether_aton(mac);
228 if (source_mac == NULL) {
229 INFO("Mac address is NULL");
233 memset(&arp, 0, sizeof(arp));
235 unsigned char broadcast_mac_addr[MAC_ADDRESS_LENGTH];
236 memset(broadcast_mac_addr, 0xff, sizeof(broadcast_mac_addr));
237 memcpy(arp.h_dest, broadcast_mac_addr, MAC_ADDRESS_LENGTH); /* MAC dest */
238 memcpy(arp.h_source, source_mac, MAC_ADDRESS_LENGTH); /* MAC source */
240 arp.h_proto = htons(ETH_P_ARP); /* protocol type (Ethernet) */
241 arp.hw_type = htons(ARPHRD_ETHER); /* hardware type */
242 arp.p_type = htons(ETH_P_IP); /* protocol type (ARP message) */
243 arp.hw_len = MAC_ADDRESS_LENGTH; /* hardware address length */
244 arp.p_len = IP_ADDRESS_LENGTH; /* protocol address length */
245 arp.operation = htons(ARPOP_REQUEST); /* ARP op code */
246 default_ip = netconfig_get_default_ipaddress();
247 if (default_ip == NULL) {
248 INFO("ip address is not set yet");
252 source_ip = inet_addr(ARP_SOURCE_IP);
253 target_ip = inet_addr(default_ip);
254 memcpy(arp.s_IPaddr, &source_ip, IP_ADDRESS_LENGTH); /* source IP address */
255 memcpy(arp.s_hwaddr, source_mac, MAC_ADDRESS_LENGTH); /* source hardware address */
256 memcpy(arp.t_IPaddr, &target_ip, IP_ADDRESS_LENGTH); /* target IP addressshek" */
258 memset(&net_ifr, 0, sizeof(net_ifr));
259 /* ifreq structure creation */
260 size_t if_name_len = strlen(netconfig_get_default_ifname());
261 if (if_name_len < sizeof(net_ifr.ifr_name)) {
262 memcpy(net_ifr.ifr_name, netconfig_get_default_ifname(), if_name_len);
263 net_ifr.ifr_name[if_name_len] = 0;
265 INFO("Error : Interface name is too long");
269 if (ioctl(sd->chk_conflict_sd, SIOCGIFINDEX, &net_ifr) == -1) {
270 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
271 INFO("ioctl Failed. Error..... = %s\n", error_buf);
275 ifindex = net_ifr.ifr_ifindex;
276 /* Construct the destination address */
277 addr.sll_family = AF_PACKET;
278 addr.sll_ifindex = ifindex;
279 addr.sll_halen = ETHER_ADDR_LEN;
280 addr.sll_protocol = htons(ETH_P_ARP);
281 memcpy(addr.sll_addr, broadcast_addr, ETHER_ADDR_LEN);
283 if (sendto(sd->chk_conflict_sd, &arp, sizeof(arp), 0, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
284 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
285 INFO("Sending ARP Packet Failed. Error. = %s\n", error_buf);
287 if (-1 < sd->chk_conflict_sd) {
288 close(sd->chk_conflict_sd);
289 sd->chk_conflict_sd = -1;
293 if ((sd->chk_conflict_sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) == -1) {
294 INFO("socket %d", sd->chk_conflict_sd);
295 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
296 INFO("socket Failed. Error = %s\n", error_buf);
300 DBG("Sent ARP Packet \n");
303 g_source_remove(sd->timer_id);
305 sd->timeout = td.initial_time;
307 /* Adding timeout callback for arp request */
308 sd->arp_reply_timer = g_timeout_add(1000, __arp_reply_timeout_cb,
309 (gpointer) &sd->arp_reply_timer);
313 g_source_remove(sd->timer_id);
314 sd->timer_id = g_timeout_add(sd->timeout, send_arp, sd);
318 struct sock_data * start_ip_conflict_mon(void)
320 if (is_ip_conflict_detect_enabled == false) {
321 INFO("detection mode is set to false");
325 char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
327 sd = g_try_malloc0(sizeof(struct sock_data));
329 INFO("Failed to malloc sock_data");
332 sd->chk_conflict_data_id = -1;
333 sd->chk_conflict_sd = -1;
337 if ((sd->chk_conflict_sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) == -1) {
338 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
339 INFO("socket Failed. Error = %s\n", error_buf);
343 sd->chk_conflict_sock_io = g_io_channel_unix_new(sd->chk_conflict_sd);
344 if (sd->chk_conflict_sock_io == NULL) {
345 INFO("Failed to create channel");
351 g_io_channel_set_close_on_unref(sd->chk_conflict_sock_io, TRUE);
353 if (G_IO_STATUS_NORMAL != g_io_channel_set_encoding(sd->chk_conflict_sock_io,
355 INFO("Failed to set encoding NULL on io channel");
356 if (G_IO_STATUS_NORMAL != g_io_channel_set_flags(sd->chk_conflict_sock_io,
357 G_IO_FLAG_NONBLOCK, NULL))
358 INFO("Failed to set flags on io channel");
359 sd->chk_conflict_data_id = g_io_add_watch(sd->chk_conflict_sock_io, G_IO_IN,
360 __netconfig_check_arp_receive, sd);
361 DBG("socket %d", sd->chk_conflict_sd);
363 sd->timeout = td.initial_time;
369 void stop_ip_conflict_mon()
372 GError* error = NULL;
377 if (-1 < sd->chk_conflict_sd) {
378 if (G_IO_STATUS_NORMAL !=
379 g_io_channel_shutdown(sd->chk_conflict_sock_io, FALSE,
381 INFO("Failure received while shutdown io channel[%d]:[%s]", error->code, error->message);
384 g_io_channel_unref(sd->chk_conflict_sock_io);
385 g_source_remove(sd->chk_conflict_data_id);
386 sd->chk_conflict_data_id = -1;
387 close(sd->chk_conflict_sd);
388 sd->chk_conflict_sd = -1;
390 if (sd->timer_id > 0) {
391 g_source_remove(sd->timer_id);
396 INFO("Monitoring stopped");
399 static void __netconfig_wifi_notify_ip_conflict(char *state, char *mac)
401 GVariantBuilder *builder = NULL;
403 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
404 g_variant_builder_add(builder, "{sv}", "state", g_variant_new_string(state));
405 g_variant_builder_add(builder, "{sv}", "mac", g_variant_new_string(mac));
407 wifi_emit_ip_conflict_event((Wifi *)get_wifi_object(), g_variant_builder_end(builder));
408 g_variant_builder_unref(builder);
413 gboolean handle_ip_conflict_set_enable(Wifi *wifi, GDBusMethodInvocation *context,
416 g_return_val_if_fail(wifi != NULL, FALSE);
419 if (detect == false) {
420 is_ip_conflict_detect_enabled = false;
421 conflict_state = NETCONFIG_IP_CONFLICT_STATE_UNKNOWN;
423 stop_ip_conflict_mon();
425 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AlreadyExists");
426 wifi_complete_ip_conflict_set_enable(wifi, context);
430 is_ip_conflict_detect_enabled = true;
431 conflict_state = NETCONFIG_IP_CONFLICT_STATE_CONFLICT_NOT_DETECTED;
433 if (start_ip_conflict_mon() == NULL) {
434 INFO("Failed to start IP conflict monitoring");
435 netconfig_error_dbus_method_return(context,
436 NETCONFIG_ERROR_INTERNAL, "Failed");
437 wifi_complete_ip_conflict_set_enable(wifi, context);
441 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AlreadyExists");
442 wifi_complete_ip_conflict_set_enable(wifi, context);
447 wifi_complete_ip_conflict_set_enable(wifi, context);
451 gboolean handle_is_ip_conflict_detect_enabled(Wifi *wifi, GDBusMethodInvocation *context)
453 g_return_val_if_fail(wifi != NULL, FALSE);
454 GVariant *param = NULL;
455 param = g_variant_new("(b)", is_ip_conflict_detect_enabled);
456 g_dbus_method_invocation_return_value(context, param);
460 gboolean handle_set_ip_conflict_period(Wifi *wifi, GDBusMethodInvocation *context, guint initial_time)
462 g_return_val_if_fail(wifi != NULL, FALSE);
463 if (initial_time < MAX_ARP_SEND_TIME && initial_time > MIN_ARP_SEND_TIME)
466 td.initial_time = 1000 * initial_time;
468 stop_ip_conflict_mon();
469 start_ip_conflict_mon();
470 wifi_complete_set_ip_conflict_period(wifi, context);
474 gboolean handle_get_ip_conflict_state(Wifi *wifi, GDBusMethodInvocation *context)
476 g_return_val_if_fail(wifi != NULL, FALSE);
477 GVariant *param = NULL;
478 param = g_variant_new("(u)", conflict_state);
479 g_dbus_method_invocation_return_value(context, param);
483 gboolean handle_get_ip_conflict_period(Wifi *wifi, GDBusMethodInvocation *context)
485 g_return_val_if_fail(wifi != NULL, FALSE);
486 GVariant *param = NULL;
487 param = g_variant_new("(u)", td.initial_time/1000);
488 g_dbus_method_invocation_return_value(context, param);