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
29 #include <sys/ioctl.h>
30 #include <arpa/inet.h>
32 #include <net/route.h>
41 struct connman_element *element;
49 static GSList *gateway_list = NULL;
51 static struct gateway_data *find_gateway(int index, const char *gateway)
58 for (list = gateway_list; list; list = list->next) {
59 struct gateway_data *data = list->data;
61 if (data->gateway == NULL)
64 if (data->index == index &&
65 g_str_equal(data->gateway, gateway) == TRUE)
72 static int add_vpn_host(struct connman_element *element,
78 struct sockaddr_in addr;
81 DBG("element %p", element);
83 sk = socket(PF_INET, SOCK_DGRAM, 0);
87 memset(&ifr, 0, sizeof(ifr));
88 ifr.ifr_ifindex = element->index;
90 if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
94 DBG("ifname %s", ifr.ifr_name);
96 memset(&rt, 0, sizeof(rt));
97 rt.rt_flags = RTF_UP | RTF_HOST | RTF_GATEWAY;
99 memset(&addr, 0, sizeof(addr));
100 addr.sin_family = AF_INET;
101 addr.sin_addr.s_addr = inet_addr(host);
102 memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
104 memset(&addr, 0, sizeof(addr));
105 addr.sin_family = AF_INET;
106 addr.sin_addr.s_addr = inet_addr(gateway);
107 memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
109 memset(&addr, 0, sizeof(addr));
110 addr.sin_family = AF_INET;
111 addr.sin_addr.s_addr = INADDR_NONE;
112 memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
114 rt.rt_dev = ifr.ifr_name;
116 err = ioctl(sk, SIOCADDRT, &rt);
118 connman_error("Setting VPN host failed (%s)",
126 static int del_vpn_host(const char *host)
129 struct sockaddr_in addr;
132 sk = socket(PF_INET, SOCK_DGRAM, 0);
136 memset(&rt, 0, sizeof(rt));
137 rt.rt_flags = RTF_UP | RTF_HOST;
139 memset(&addr, 0, sizeof(addr));
140 addr.sin_family = AF_INET;
141 addr.sin_addr.s_addr = inet_addr(host);
142 memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
144 err = ioctl(sk, SIOCDELRT, &rt);
146 connman_error("Del vpn route failed (%s)",
154 static int set_vpn_route(struct connman_element *element, const char *gateway)
158 struct sockaddr_in addr;
161 DBG("set_rout1: element %p", element);
163 sk = socket(PF_INET, SOCK_DGRAM, 0);
167 memset(&ifr, 0, sizeof(ifr));
168 ifr.ifr_ifindex = element->index;
170 if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
175 DBG("ifname %s", ifr.ifr_name);
177 memset(&ifr, 0, sizeof(ifr));
178 ifr.ifr_ifindex = element->index;
180 memset(&rt, 0, sizeof(rt));
181 rt.rt_flags = RTF_UP | RTF_GATEWAY;
183 memset(&addr, 0, sizeof(addr));
184 addr.sin_family = AF_INET;
185 addr.sin_addr.s_addr = INADDR_ANY;
186 memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
188 memset(&addr, 0, sizeof(addr));
189 addr.sin_family = AF_INET;
190 addr.sin_addr.s_addr = inet_addr(gateway);
191 memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
193 memset(&addr, 0, sizeof(addr));
194 addr.sin_family = AF_INET;
195 addr.sin_addr.s_addr = INADDR_ANY;
196 memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
198 err = ioctl(sk, SIOCADDRT, &rt);
200 connman_error("Setting VPN route failed (%s)",
208 static int set_route(struct connman_element *element, const char *gateway)
212 struct sockaddr_in addr;
215 DBG("element %p", element);
217 sk = socket(PF_INET, SOCK_DGRAM, 0);
221 memset(&ifr, 0, sizeof(ifr));
222 ifr.ifr_ifindex = element->index;
224 if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
228 DBG("ifname %s", ifr.ifr_name);
230 memset(&rt, 0, sizeof(rt));
231 rt.rt_flags = RTF_UP | RTF_HOST;
233 memset(&addr, 0, sizeof(addr));
234 addr.sin_family = AF_INET;
235 addr.sin_addr.s_addr = inet_addr(gateway);
236 memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
238 memset(&addr, 0, sizeof(addr));
239 addr.sin_family = AF_INET;
240 addr.sin_addr.s_addr = INADDR_ANY;
241 memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
243 memset(&addr, 0, sizeof(addr));
244 addr.sin_family = AF_INET;
245 addr.sin_addr.s_addr = INADDR_ANY;
246 memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
248 rt.rt_dev = ifr.ifr_name;
250 err = ioctl(sk, SIOCADDRT, &rt);
252 connman_error("Setting host gateway route failed (%s)",
254 memset(&rt, 0, sizeof(rt));
255 rt.rt_flags = RTF_UP | RTF_GATEWAY;
257 memset(&addr, 0, sizeof(addr));
258 addr.sin_family = AF_INET;
259 addr.sin_addr.s_addr = INADDR_ANY;
260 memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
262 memset(&addr, 0, sizeof(addr));
263 addr.sin_family = AF_INET;
264 addr.sin_addr.s_addr = inet_addr(gateway);
265 memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
267 memset(&addr, 0, sizeof(addr));
268 addr.sin_family = AF_INET;
269 addr.sin_addr.s_addr = INADDR_ANY;
270 memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
272 err = ioctl(sk, SIOCADDRT, &rt);
274 connman_error("Setting default route failed (%s)",
282 static int del_route(struct connman_element *element, const char *gateway)
286 struct sockaddr_in addr;
289 DBG("element %p", element);
291 sk = socket(PF_INET, SOCK_DGRAM, 0);
295 memset(&ifr, 0, sizeof(ifr));
296 ifr.ifr_ifindex = element->index;
298 if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
303 DBG("ifname %s", ifr.ifr_name);
305 memset(&rt, 0, sizeof(rt));
306 rt.rt_flags = RTF_UP | RTF_GATEWAY;
308 memset(&addr, 0, sizeof(addr));
309 addr.sin_family = AF_INET;
310 addr.sin_addr.s_addr = INADDR_ANY;
311 memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
313 memset(&addr, 0, sizeof(addr));
314 addr.sin_family = AF_INET;
315 addr.sin_addr.s_addr = inet_addr(gateway);
316 memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
318 memset(&addr, 0, sizeof(addr));
319 addr.sin_family = AF_INET;
320 addr.sin_addr.s_addr = INADDR_ANY;
321 memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
323 err = ioctl(sk, SIOCDELRT, &rt);
325 connman_error("Removing default route failed (%s)",
333 static int del_route_all(struct gateway_data *data)
338 del_vpn_host(data->gateway);
340 err = del_route(data->element, data->vpn_ip);
342 err = del_route(data->element, data->gateway);
347 static void find_element(struct connman_element *element, gpointer user_data)
349 struct gateway_data *data = user_data;
351 DBG("element %p name %s", element, element->name);
353 if (data->element != NULL)
356 if (element->index != data->index)
359 data->element = element;
362 static struct gateway_data *add_gateway(int index, const char *gateway)
364 struct gateway_data *data;
365 struct connman_service *service;
367 data = g_try_new0(struct gateway_data, 1);
372 data->gateway = g_strdup(gateway);
373 data->active = FALSE;
374 data->element = NULL;
378 __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION,
381 service = __connman_element_get_service(data->element);
382 data->order = __connman_service_get_order(service);
384 gateway_list = g_slist_append(gateway_list, data);
389 static void connection_newgateway(int index, const char *gateway)
391 struct gateway_data *data;
393 DBG("index %d gateway %s", index, gateway);
395 data = find_gateway(index, gateway);
402 static void set_default_gateway(struct gateway_data *data)
404 struct connman_element *element = data->element;
405 struct connman_service *service = NULL;
407 DBG("gateway %s", data->gateway);
409 if (data->vpn == TRUE) {
411 set_vpn_route(element, data->vpn_ip);
412 /* vpn gateway going away no changes in services */
415 if (set_route(element, data->gateway) < 0)
418 service = __connman_element_get_service(element);
419 __connman_service_indicate_default(service);
422 static struct gateway_data *find_default_gateway(void)
424 struct gateway_data *found = NULL;
425 unsigned int order = 0;
428 for (list = gateway_list; list; list = list->next) {
429 struct gateway_data *data = list->data;
431 if (found == NULL || data->order > order) {
440 static void remove_gateway(struct gateway_data *data)
442 DBG("gateway %s", data->gateway);
444 gateway_list = g_slist_remove(gateway_list, data);
446 if (data->active == TRUE)
449 g_free(data->gateway);
450 g_free(data->vpn_ip);
454 static void connection_delgateway(int index, const char *gateway)
456 struct gateway_data *data;
458 DBG("index %d gateway %s", index, gateway);
460 data = find_gateway(index, gateway);
462 data->active = FALSE;
464 data = find_default_gateway();
466 set_default_gateway(data);
469 static struct connman_rtnl connection_rtnl = {
470 .name = "connection",
471 .newgateway = connection_newgateway,
472 .delgateway = connection_delgateway,
475 static struct gateway_data *find_active_gateway(void)
481 for (list = gateway_list; list; list = list->next) {
482 struct gateway_data *data = list->data;
483 if (data->active == TRUE)
490 static int connection_probe(struct connman_element *element)
492 struct connman_service *service = NULL;
493 const char *gateway = NULL;
494 const char *vpn_ip = NULL;
495 struct gateway_data *active_gateway = NULL;
496 struct gateway_data *new_gateway = NULL;
498 DBG("element %p name %s", element, element->name);
500 if (element->parent == NULL)
503 if (element->parent->type != CONNMAN_ELEMENT_TYPE_IPV4)
506 connman_element_get_value(element,
507 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
509 connman_element_get_value(element,
510 CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &vpn_ip);
512 DBG("gateway %s", gateway);
514 service = __connman_element_get_service(element);
515 __connman_service_indicate_state(service,
516 CONNMAN_SERVICE_STATE_READY);
518 connman_element_set_enabled(element, TRUE);
523 active_gateway = find_active_gateway();
524 new_gateway = add_gateway(element->index, gateway);
526 if (service == NULL) {
527 new_gateway->vpn = TRUE;
528 new_gateway->vpn_ip = g_strdup(vpn_ip);
529 /* make sure vpn gateway are at higher priority */
530 new_gateway->order = 10;
532 new_gateway->vpn = FALSE;
534 if (active_gateway == NULL) {
535 set_default_gateway(new_gateway);
539 if (new_gateway->vpn == TRUE) {
540 add_vpn_host(active_gateway->element,
541 active_gateway->gateway,
542 new_gateway->gateway);
546 if (new_gateway->order >= active_gateway->order) {
547 del_route_all(active_gateway);
554 static void connection_remove(struct connman_element *element)
556 struct connman_service *service;
557 const char *gateway = NULL;
558 struct gateway_data *data = NULL;
559 gboolean set_default = FALSE;
561 DBG("element %p name %s", element, element->name);
563 service = __connman_element_get_service(element);
564 __connman_service_indicate_state(service,
565 CONNMAN_SERVICE_STATE_DISCONNECT);
567 connman_element_set_enabled(element, FALSE);
569 connman_element_get_value(element,
570 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
572 DBG("gateway %s", gateway);
577 data = find_gateway(element->index, gateway);
581 set_default = data->vpn;
583 if (data->vpn == TRUE)
584 del_vpn_host(data->gateway);
586 remove_gateway(data);
588 /* with vpn this will be called after the network was deleted,
589 * we need to call set_default here because we will not recieve any
590 * gateway delete notification.
593 data = find_default_gateway();
595 set_default_gateway(data);
599 static struct connman_driver connection_driver = {
600 .name = "connection",
601 .type = CONNMAN_ELEMENT_TYPE_CONNECTION,
602 .priority = CONNMAN_DRIVER_PRIORITY_LOW,
603 .probe = connection_probe,
604 .remove = connection_remove,
607 int __connman_connection_init(void)
611 if (connman_rtnl_register(&connection_rtnl) < 0)
612 connman_error("Failed to setup RTNL gateway driver");
614 return connman_driver_register(&connection_driver);
617 void __connman_connection_cleanup(void)
623 connman_driver_unregister(&connection_driver);
625 connman_rtnl_unregister(&connection_rtnl);
627 for (list = gateway_list; list; list = list->next) {
628 struct gateway_data *data = list->data;
630 DBG("index %d gateway %s", data->index, data->gateway);
632 g_free(data->gateway);
637 g_slist_free(gateway_list);
641 static void update_order(void)
645 for (list = gateway_list; list; list = list->next) {
646 struct gateway_data *data = list->data;
647 struct connman_service *service;
649 /* vpn gataway is not attached to a service. */
653 service = __connman_element_get_service(data->element);
654 data->order = __connman_service_get_order(service);
658 gboolean __connman_connection_update_gateway(void)
660 struct gateway_data *active_gateway, *default_gateway;
661 gboolean updated = FALSE;
665 active_gateway = find_active_gateway();
666 default_gateway = find_default_gateway();
668 if (active_gateway && active_gateway != default_gateway) {
669 del_route_all(active_gateway);