5 * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 #include <sys/ioctl.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
33 #include <net/route.h>
35 #include <linux/netlink.h>
36 #include <linux/rtnetlink.h>
38 #define CONNMAN_API_SUBJECT_TO_CHANGE
39 #include <connman/plugin.h>
40 #include <connman/driver.h>
41 #include <connman/resolver.h>
42 #include <connman/rtnl.h>
43 #include <connman/log.h>
47 enum connman_ipv4_method {
48 CONNMAN_IPV4_METHOD_UNKNOWN = 0,
49 CONNMAN_IPV4_METHOD_OFF = 1,
50 CONNMAN_IPV4_METHOD_STATIC = 2,
51 CONNMAN_IPV4_METHOD_DHCP = 3,
55 enum connman_ipv4_method method;
56 struct in_addr address;
57 struct in_addr netmask;
58 struct in_addr broadcast;
66 static GSList *gateway_list = NULL;
68 static struct gateway_data *find_gateway(int index, const char *gateway)
75 for (list = gateway_list; list; list = list->next) {
76 struct gateway_data *data = list->data;
78 if (data->gateway == NULL)
81 if (data->index == index &&
82 g_str_equal(data->gateway, gateway) == TRUE)
89 static int set_ipv4(struct connman_element *element,
90 struct connman_ipv4 *ipv4, const char *nameserver)
93 struct sockaddr_in *addr;
96 DBG("element %p ipv4 %p", element, ipv4);
98 sk = socket(PF_INET, SOCK_DGRAM, 0);
102 memset(&ifr, 0, sizeof(ifr));
103 ifr.ifr_ifindex = element->index;
105 if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
110 DBG("ifname %s", ifr.ifr_name);
112 addr = (struct sockaddr_in *) &ifr.ifr_addr;
113 addr->sin_family = AF_INET;
114 addr->sin_addr = ipv4->address;
116 err = ioctl(sk, SIOCSIFADDR, &ifr);
119 DBG("address setting failed (%s)", strerror(errno));
121 addr = (struct sockaddr_in *) &ifr.ifr_netmask;
122 addr->sin_family = AF_INET;
123 addr->sin_addr = ipv4->netmask;
125 err = ioctl(sk, SIOCSIFNETMASK, &ifr);
128 DBG("netmask setting failed (%s)", strerror(errno));
130 addr = (struct sockaddr_in *) &ifr.ifr_broadaddr;
131 addr->sin_family = AF_INET;
132 addr->sin_addr = ipv4->broadcast;
134 err = ioctl(sk, SIOCSIFBRDADDR, &ifr);
137 DBG("broadcast setting failed (%s)", strerror(errno));
141 connman_resolver_append(ifr.ifr_name, NULL, nameserver);
146 static int clear_ipv4(struct connman_element *element)
149 struct sockaddr_in *addr;
152 DBG("element %p", element);
154 sk = socket(PF_INET, SOCK_DGRAM, 0);
158 memset(&ifr, 0, sizeof(ifr));
159 ifr.ifr_ifindex = element->index;
161 if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
166 DBG("ifname %s", ifr.ifr_name);
168 connman_resolver_remove_all(ifr.ifr_name);
170 addr = (struct sockaddr_in *) &ifr.ifr_addr;
171 addr->sin_family = AF_INET;
172 addr->sin_addr.s_addr = INADDR_ANY;
174 //err = ioctl(sk, SIOCDIFADDR, &ifr);
175 err = ioctl(sk, SIOCSIFADDR, &ifr);
179 if (err < 0 && errno != EADDRNOTAVAIL) {
180 DBG("address removal failed (%s)", strerror(errno));
187 static int set_route(struct connman_element *element, const char *gateway)
191 struct sockaddr_in *addr;
194 DBG("element %p", element);
196 sk = socket(PF_INET, SOCK_DGRAM, 0);
200 memset(&ifr, 0, sizeof(ifr));
201 ifr.ifr_ifindex = element->index;
203 if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
208 DBG("ifname %s", ifr.ifr_name);
210 memset(&rt, 0, sizeof(rt));
211 rt.rt_flags = RTF_UP | RTF_GATEWAY;
213 addr = (struct sockaddr_in *) &rt.rt_dst;
214 addr->sin_family = AF_INET;
215 addr->sin_addr.s_addr = INADDR_ANY;
217 addr = (struct sockaddr_in *) &rt.rt_gateway;
218 addr->sin_family = AF_INET;
219 addr->sin_addr.s_addr = inet_addr(gateway);
221 addr = (struct sockaddr_in *) &rt.rt_genmask;
222 addr->sin_family = AF_INET;
223 addr->sin_addr.s_addr = INADDR_ANY;
225 err = ioctl(sk, SIOCADDRT, &rt);
227 DBG("default route setting failed (%s)", strerror(errno));
234 static int del_route(struct connman_element *element, const char *gateway)
238 struct sockaddr_in *addr;
241 DBG("element %p", element);
243 sk = socket(PF_INET, SOCK_DGRAM, 0);
247 memset(&ifr, 0, sizeof(ifr));
248 ifr.ifr_ifindex = element->index;
250 if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
255 DBG("ifname %s", ifr.ifr_name);
257 memset(&rt, 0, sizeof(rt));
258 rt.rt_flags = RTF_UP | RTF_GATEWAY;
260 addr = (struct sockaddr_in *) &rt.rt_dst;
261 addr->sin_family = AF_INET;
262 addr->sin_addr.s_addr = INADDR_ANY;
264 addr = (struct sockaddr_in *) &rt.rt_gateway;
265 addr->sin_family = AF_INET;
266 addr->sin_addr.s_addr = inet_addr(gateway);
268 addr = (struct sockaddr_in *) &rt.rt_genmask;
269 addr->sin_family = AF_INET;
270 addr->sin_addr.s_addr = INADDR_ANY;
272 err = ioctl(sk, SIOCDELRT, &rt);
274 DBG("default route removal failed (%s)", strerror(errno));
281 static int conn_probe(struct connman_element *element)
283 const char *gateway = NULL;
285 DBG("element %p name %s", element, element->name);
287 if (element->parent == NULL)
290 if (element->parent->type != CONNMAN_ELEMENT_TYPE_IPV4)
293 connman_element_get_value(element,
294 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
296 DBG("gateway %s", gateway);
301 if (g_slist_length(gateway_list) > 0) {
302 DBG("default already present");
306 set_route(element, gateway);
308 connman_element_set_enabled(element, TRUE);
313 static void conn_remove(struct connman_element *element)
315 DBG("element %p name %s", element, element->name);
318 static int conn_enable(struct connman_element *element)
320 const char *gateway = NULL;
322 DBG("element %p name %s", element, element->name);
324 connman_element_get_value(element,
325 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
327 DBG("gateway %s", gateway);
332 set_route(element, gateway);
337 static int conn_disable(struct connman_element *element)
339 const char *gateway = NULL;
341 DBG("element %p name %s", element, element->name);
343 connman_element_get_value(element,
344 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
346 DBG("gateway %s", gateway);
351 del_route(element, gateway);
356 static struct connman_driver conn_driver = {
357 .name = "ipv4-connection",
358 .type = CONNMAN_ELEMENT_TYPE_CONNECTION,
360 .remove = conn_remove,
361 .enable = conn_enable,
362 .disable = conn_disable,
365 static int ipv4_probe(struct connman_element *element)
367 struct connman_element *connection;
368 struct connman_ipv4 ipv4;
369 const char *address = NULL, *netmask = NULL, *broadcast = NULL;
370 const char *nameserver = NULL;
372 DBG("element %p name %s", element, element->name);
374 connman_element_get_value(element,
375 CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address);
376 connman_element_get_value(element,
377 CONNMAN_PROPERTY_ID_IPV4_NETMASK, &netmask);
378 connman_element_get_value(element,
379 CONNMAN_PROPERTY_ID_IPV4_BROADCAST, &broadcast);
381 connman_element_get_value(element,
382 CONNMAN_PROPERTY_ID_IPV4_NAMESERVER, &nameserver);
384 DBG("address %s", address);
385 DBG("netmask %s", netmask);
386 DBG("broadcast %s", broadcast);
388 if (address == NULL || netmask == NULL)
391 memset(&ipv4, 0, sizeof(ipv4));
392 ipv4.address.s_addr = inet_addr(address);
393 ipv4.netmask.s_addr = inet_addr(netmask);
394 ipv4.broadcast.s_addr = inet_addr(broadcast);
396 set_ipv4(element, &ipv4, nameserver);
398 connection = connman_element_create(NULL);
400 connection->type = CONNMAN_ELEMENT_TYPE_CONNECTION;
401 connection->index = element->index;
402 connection->devname = inet_index2name(element->index);
404 if (connman_element_register(connection, element) < 0)
405 connman_element_unref(connection);
410 static void ipv4_remove(struct connman_element *element)
412 DBG("element %p name %s", element, element->name);
417 static struct connman_driver ipv4_driver = {
418 .name = "ipv4-address",
419 .type = CONNMAN_ELEMENT_TYPE_IPV4,
421 .remove = ipv4_remove,
424 static void ipv4_newgateway(int index, const char *gateway)
426 struct gateway_data *data;
428 DBG("index %d gateway %s", index, gateway);
430 data = find_gateway(index, gateway);
434 data = g_try_new0(struct gateway_data, 1);
439 data->gateway = g_strdup(gateway);
441 gateway_list = g_slist_append(gateway_list, data);
444 static void ipv4_delgateway(int index, const char *gateway)
446 struct gateway_data *data;
448 DBG("index %d gateway %s", index, gateway);
450 data = find_gateway(index, gateway);
454 gateway_list = g_slist_remove(gateway_list, data);
456 g_free(data->gateway);
460 static struct connman_rtnl ipv4_rtnl = {
462 .newgateway = ipv4_newgateway,
463 .delgateway = ipv4_delgateway,
466 static int ipv4_init(void)
470 err = connman_rtnl_register(&ipv4_rtnl);
474 connman_rtnl_send_getroute();
476 err = connman_driver_register(&conn_driver);
478 connman_rtnl_unregister(&ipv4_rtnl);
482 err = connman_driver_register(&ipv4_driver);
484 connman_driver_unregister(&conn_driver);
485 connman_rtnl_unregister(&ipv4_rtnl);
491 static void ipv4_exit(void)
495 connman_driver_unregister(&conn_driver);
496 connman_driver_unregister(&ipv4_driver);
498 connman_rtnl_unregister(&ipv4_rtnl);
500 for (list = gateway_list; list; list = list->next) {
501 struct gateway_data *data = list->data;
503 DBG("index %d gateway %s", data->index, data->gateway);
505 g_free(data->gateway);
510 g_slist_free(gateway_list);
514 CONNMAN_PLUGIN_DEFINE(ipv4, "IPv4 configuration plugin", VERSION,
515 ipv4_init, ipv4_exit)