5 * Copyright (C) 2007-2010 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
37 struct connman_element *element;
46 static GSList *gateway_list = NULL;
48 static struct gateway_data *find_gateway(int index, const char *gateway)
55 for (list = gateway_list; list; list = list->next) {
56 struct gateway_data *data = list->data;
58 if (data->ipv4_gateway == NULL)
61 if (data->index == index &&
62 g_str_equal(data->ipv4_gateway, gateway)
70 static int del_routes(struct gateway_data *data)
73 if (data->vpn_phy_index >= 0)
74 connman_inet_del_host_route(data->vpn_phy_index,
76 return connman_inet_clear_gateway_address(data->index,
78 } else if (g_strcmp0(data->ipv4_gateway, "0.0.0.0") == 0) {
79 return connman_inet_clear_gateway_interface(data->index);
81 connman_inet_del_ipv6_host_route(data->index,
83 connman_inet_clear_ipv6_gateway_address(data->index,
85 connman_inet_del_host_route(data->index, data->ipv4_gateway);
86 return connman_inet_clear_gateway_address(data->index,
91 static void find_element(struct connman_element *element, gpointer user_data)
93 struct gateway_data *data = user_data;
95 DBG("element %p name %s", element, element->name);
97 if (data->element != NULL)
100 if (element->index != data->index)
103 data->element = element;
106 static struct gateway_data *add_gateway(int index, const char *gateway,
107 const char *ipv6_gateway)
109 struct gateway_data *data;
110 struct connman_service *service;
112 DBG("index %d ipv4 gateway %s ipv6 gateway %s", index, gateway,
115 if (strlen(gateway) == 0)
118 data = g_try_new0(struct gateway_data, 1);
123 data->ipv4_gateway = g_strdup(gateway);
124 data->ipv6_gateway = g_strdup(ipv6_gateway);
125 data->active = FALSE;
126 data->element = NULL;
129 data->vpn_phy_index = -1;
131 __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION,
134 service = __connman_element_get_service(data->element);
135 data->order = __connman_service_get_order(service);
137 gateway_list = g_slist_append(gateway_list, data);
142 static void connection_newgateway(int index, const char *gateway)
144 struct gateway_data *data;
146 DBG("index %d gateway %s", index, gateway);
148 data = find_gateway(index, gateway);
155 static void set_default_gateway(struct gateway_data *data)
157 struct connman_element *element = data->element;
158 struct connman_service *service = NULL;
160 DBG("gateway %s", data->ipv4_gateway);
162 if (data->vpn == TRUE) {
163 connman_inet_set_gateway_address(data->index, data->vpn_ip);
166 service = __connman_service_lookup_from_index(data->index);
170 __connman_service_indicate_default(service);
175 if (g_strcmp0(data->ipv4_gateway, "0.0.0.0") == 0) {
176 if (connman_inet_set_gateway_interface(element->index) < 0)
181 connman_inet_set_ipv6_gateway_address(element->index,
183 if (connman_inet_set_gateway_address(element->index,
184 data->ipv4_gateway) < 0)
188 service = __connman_element_get_service(element);
189 __connman_service_indicate_default(service);
192 static struct gateway_data *find_default_gateway(void)
194 struct gateway_data *found = NULL;
195 unsigned int order = 0;
198 for (list = gateway_list; list; list = list->next) {
199 struct gateway_data *data = list->data;
201 if (found == NULL || data->order > order) {
210 static int remove_gateway(struct gateway_data *data)
214 DBG("gateway %s", data->ipv4_gateway);
216 gateway_list = g_slist_remove(gateway_list, data);
218 if (data->active == TRUE)
219 err = del_routes(data);
223 g_free(data->ipv4_gateway);
224 g_free(data->ipv6_gateway);
225 g_free(data->vpn_ip);
231 static void connection_delgateway(int index, const char *gateway)
233 struct gateway_data *data;
235 DBG("index %d gateway %s", index, gateway);
237 data = find_gateway(index, gateway);
239 data->active = FALSE;
241 data = find_default_gateway();
243 set_default_gateway(data);
246 static struct connman_rtnl connection_rtnl = {
247 .name = "connection",
248 .newgateway = connection_newgateway,
249 .delgateway = connection_delgateway,
252 static struct gateway_data *find_active_gateway(void)
258 for (list = gateway_list; list; list = list->next) {
259 struct gateway_data *data = list->data;
261 if (data->active == TRUE)
268 static int connection_probe(struct connman_element *element)
270 struct connman_service *service = NULL;
271 const char *gateway = NULL, *ipv6_gateway = NULL;
272 const char *vpn_ip = NULL;
273 const char *domainname = NULL;
274 struct gateway_data *active_gateway = NULL;
275 struct gateway_data *new_gateway = NULL;
277 DBG("element %p name %s", element, element->name);
279 if (element->parent == NULL)
282 /* FIXME: Remove temporarily for the static gateway support */
283 /* if (element->parent->type != CONNMAN_ELEMENT_TYPE_IPV4)
286 connman_element_get_value(element,
287 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
288 connman_element_get_value(element,
289 CONNMAN_PROPERTY_ID_IPV6_GATEWAY, &ipv6_gateway);
291 connman_element_get_value(element,
292 CONNMAN_PROPERTY_ID_IPV4_PEER, &vpn_ip);
295 connman_element_get_value(element,
296 CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &vpn_ip);
298 DBG("vpn_ip %s", vpn_ip);
300 connman_element_get_value(element,
301 CONNMAN_PROPERTY_ID_DOMAINNAME, &domainname);
303 DBG("ipv4 gateway %s ipv6 gateway %s domainname %s",
304 gateway, ipv6_gateway, domainname);
307 * If gateway is NULL, it's a point to point link and the default
308 * gateway is 0.0.0.0, meaning the interface.
310 if (gateway == NULL) {
312 element->ipv4.gateway = g_strdup(gateway);
315 connman_element_set_enabled(element, TRUE);
317 active_gateway = find_active_gateway();
318 new_gateway = add_gateway(element->index, gateway, ipv6_gateway);
319 if (new_gateway == NULL)
322 service = __connman_element_get_service(element);
324 if (new_gateway->ipv6_gateway)
325 connman_inet_add_ipv6_host_route(element->index,
326 new_gateway->ipv6_gateway, NULL);
328 if (g_strcmp0(new_gateway->ipv4_gateway, "0.0.0.0"))
329 connman_inet_add_host_route(element->index,
330 new_gateway->ipv4_gateway, NULL);
331 __connman_service_nameserver_add_routes(service,
332 new_gateway->ipv4_gateway);
333 __connman_service_set_domainname(service, domainname);
335 __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY,
336 CONNMAN_IPCONFIG_TYPE_IPV4);
338 if (service == NULL) {
339 new_gateway->vpn = TRUE;
340 new_gateway->vpn_ip = g_strdup(vpn_ip);
341 /* make sure vpn gateway are at higher priority */
342 new_gateway->order = 10;
344 new_gateway->vpn_phy_index = active_gateway->index;
346 new_gateway->vpn = FALSE;
348 if (active_gateway == NULL) {
349 set_default_gateway(new_gateway);
353 if (new_gateway->vpn == TRUE) {
354 connman_inet_add_host_route(active_gateway->index,
355 new_gateway->ipv4_gateway,
356 active_gateway->ipv4_gateway);
359 if (new_gateway->order >= active_gateway->order) {
360 del_routes(active_gateway);
367 static void connection_remove(struct connman_element *element)
369 struct connman_service *service;
370 const char *gateway = NULL;
371 struct gateway_data *data = NULL;
372 gboolean set_default = FALSE;
375 DBG("element %p name %s", element, element->name);
377 service = __connman_element_get_service(element);
378 __connman_service_nameserver_del_routes(service);
379 __connman_service_indicate_state(service,
380 CONNMAN_SERVICE_STATE_DISCONNECT,
381 CONNMAN_IPCONFIG_TYPE_IPV4);
383 connman_element_set_enabled(element, FALSE);
385 connman_element_get_value(element,
386 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
388 DBG("gateway %s", gateway);
393 data = find_gateway(element->index, gateway);
397 set_default = data->vpn;
399 if (data->vpn == TRUE && data->vpn_phy_index >= 0)
400 connman_inet_del_host_route(data->vpn_phy_index,
402 err = remove_gateway(data);
404 /* with vpn this will be called after the network was deleted,
405 * we need to call set_default here because we will not recieve any
406 * gateway delete notification.
407 * We hit the same issue if remove_gateway() fails.
409 if (set_default || err < 0) {
410 data = find_default_gateway();
412 set_default_gateway(data);
415 connman_element_unref(element);
418 static struct connman_driver connection_driver = {
419 .name = "connection",
420 .type = CONNMAN_ELEMENT_TYPE_CONNECTION,
421 .priority = CONNMAN_DRIVER_PRIORITY_LOW,
422 .probe = connection_probe,
423 .remove = connection_remove,
426 int __connman_connection_init(void)
430 if (connman_rtnl_register(&connection_rtnl) < 0)
431 connman_error("Failed to setup RTNL gateway driver");
433 return connman_driver_register(&connection_driver);
436 void __connman_connection_cleanup(void)
442 connman_driver_unregister(&connection_driver);
444 connman_rtnl_unregister(&connection_rtnl);
446 for (list = gateway_list; list; list = list->next) {
447 struct gateway_data *data = list->data;
449 DBG("index %d gateway %s", data->index, data->ipv4_gateway);
451 g_free(data->ipv4_gateway);
456 g_slist_free(gateway_list);
460 static void update_order(void)
464 for (list = gateway_list; list; list = list->next) {
465 struct gateway_data *data = list->data;
466 struct connman_service *service;
467 int index = data->index;
470 service = __connman_service_lookup_from_index(index);
472 service = __connman_element_get_service(data->element);
474 data->order = __connman_service_get_order(service);
478 gboolean __connman_connection_update_gateway(void)
480 struct gateway_data *active_gateway, *default_gateway;
481 gboolean updated = FALSE;
485 active_gateway = find_active_gateway();
486 default_gateway = find_default_gateway();
488 if (active_gateway && active_gateway != default_gateway) {
489 del_routes(active_gateway);