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
35 struct connman_element *element;
44 static GSList *gateway_list = NULL;
46 static struct gateway_data *find_gateway(int index, const char *gateway)
53 for (list = gateway_list; list; list = list->next) {
54 struct gateway_data *data = list->data;
56 if (data->gateway == NULL)
59 if (data->index == index &&
60 g_str_equal(data->gateway, gateway) == TRUE)
67 static int del_routes(struct gateway_data *data)
70 if (data->vpn_phy_index >= 0)
71 connman_inet_del_host_route(data->vpn_phy_index,
73 return connman_inet_clear_gateway_address(data->index,
75 } else if (g_strcmp0(data->gateway, "0.0.0.0") == 0) {
76 return connman_inet_clear_gateway_interface(data->index);
78 connman_inet_del_host_route(data->index, data->gateway);
79 return connman_inet_clear_gateway_address(data->index,
84 static void find_element(struct connman_element *element, gpointer user_data)
86 struct gateway_data *data = user_data;
88 DBG("element %p name %s", element, element->name);
90 if (data->element != NULL)
93 if (element->index != data->index)
96 data->element = element;
99 static struct gateway_data *add_gateway(int index, const char *gateway)
101 struct gateway_data *data;
102 struct connman_service *service;
104 data = g_try_new0(struct gateway_data, 1);
109 data->gateway = g_strdup(gateway);
110 data->active = FALSE;
111 data->element = NULL;
114 data->vpn_phy_index = -1;
116 __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION,
119 service = __connman_element_get_service(data->element);
120 data->order = __connman_service_get_order(service);
122 gateway_list = g_slist_append(gateway_list, data);
127 static void connection_newgateway(int index, const char *gateway)
129 struct gateway_data *data;
131 DBG("index %d gateway %s", index, gateway);
133 data = find_gateway(index, gateway);
140 static void set_default_gateway(struct gateway_data *data)
142 struct connman_element *element = data->element;
143 struct connman_service *service = NULL;
145 DBG("gateway %s", data->gateway);
147 if (data->vpn == TRUE) {
148 connman_inet_set_gateway_address(data->index, data->vpn_ip);
150 /* vpn gateway going away no changes in services */
154 if (g_strcmp0(data->gateway, "0.0.0.0") == 0) {
155 if (connman_inet_set_gateway_interface(element->index) < 0)
160 connman_inet_add_host_route(element->index, data->gateway, NULL);
162 if (connman_inet_set_gateway_address(element->index, data->gateway) < 0)
166 service = __connman_element_get_service(element);
167 __connman_service_indicate_default(service);
170 static struct gateway_data *find_default_gateway(void)
172 struct gateway_data *found = NULL;
173 unsigned int order = 0;
176 for (list = gateway_list; list; list = list->next) {
177 struct gateway_data *data = list->data;
179 if (found == NULL || data->order > order) {
188 static int remove_gateway(struct gateway_data *data)
192 DBG("gateway %s", data->gateway);
194 gateway_list = g_slist_remove(gateway_list, data);
196 if (data->active == TRUE)
197 err = del_routes(data);
201 g_free(data->gateway);
202 g_free(data->vpn_ip);
208 static void connection_delgateway(int index, const char *gateway)
210 struct gateway_data *data;
212 DBG("index %d gateway %s", index, gateway);
214 data = find_gateway(index, gateway);
216 data->active = FALSE;
218 data = find_default_gateway();
220 set_default_gateway(data);
223 static struct connman_rtnl connection_rtnl = {
224 .name = "connection",
225 .newgateway = connection_newgateway,
226 .delgateway = connection_delgateway,
229 static struct gateway_data *find_active_gateway(void)
235 for (list = gateway_list; list; list = list->next) {
236 struct gateway_data *data = list->data;
238 if (data->active == TRUE)
245 static int connection_probe(struct connman_element *element)
247 struct connman_service *service = NULL;
248 const char *gateway = NULL;
249 const char *vpn_ip = NULL;
250 struct gateway_data *active_gateway = NULL;
251 struct gateway_data *new_gateway = NULL;
253 DBG("element %p name %s", element, element->name);
255 if (element->parent == NULL)
258 /* FIXME: Remove temporarily for the static gateway support */
259 /* if (element->parent->type != CONNMAN_ELEMENT_TYPE_IPV4)
262 connman_element_get_value(element,
263 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
265 connman_element_get_value(element,
266 CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &vpn_ip);
268 DBG("gateway %s", gateway);
271 * If gateway is NULL, it's a point to point link and the default
272 * gateway is 0.0.0.0, meaning the interface.
274 if (gateway == NULL) {
276 element->ipv4.gateway = g_strdup(gateway);
279 service = __connman_element_get_service(element);
280 __connman_service_indicate_state(service,
281 CONNMAN_SERVICE_STATE_READY);
283 connman_element_set_enabled(element, TRUE);
285 active_gateway = find_active_gateway();
286 new_gateway = add_gateway(element->index, gateway);
288 if (service == NULL) {
289 new_gateway->vpn = TRUE;
290 new_gateway->vpn_ip = g_strdup(vpn_ip);
291 /* make sure vpn gateway are at higher priority */
292 new_gateway->order = 10;
294 new_gateway->vpn_phy_index = active_gateway->index;
296 new_gateway->vpn = FALSE;
298 if (active_gateway == NULL) {
299 set_default_gateway(new_gateway);
303 if (new_gateway->vpn == TRUE) {
304 connman_inet_add_host_route(active_gateway->index,
305 new_gateway->gateway,
306 active_gateway->gateway);
309 if (new_gateway->order >= active_gateway->order) {
310 del_routes(active_gateway);
317 static void connection_remove(struct connman_element *element)
319 struct connman_service *service;
320 const char *gateway = NULL;
321 struct gateway_data *data = NULL;
322 gboolean set_default = FALSE;
325 DBG("element %p name %s", element, element->name);
327 service = __connman_element_get_service(element);
328 __connman_service_indicate_state(service,
329 CONNMAN_SERVICE_STATE_DISCONNECT);
331 connman_element_set_enabled(element, FALSE);
333 connman_element_get_value(element,
334 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
336 DBG("gateway %s", gateway);
341 data = find_gateway(element->index, gateway);
345 set_default = data->vpn;
347 if (data->vpn == TRUE && data->vpn_phy_index >= 0)
348 connman_inet_del_host_route(data->vpn_phy_index, data->gateway);
350 err = remove_gateway(data);
352 /* with vpn this will be called after the network was deleted,
353 * we need to call set_default here because we will not recieve any
354 * gateway delete notification.
355 * We hit the same issue if remove_gateway() fails.
357 if (set_default || err < 0) {
358 data = find_default_gateway();
360 set_default_gateway(data);
364 static struct connman_driver connection_driver = {
365 .name = "connection",
366 .type = CONNMAN_ELEMENT_TYPE_CONNECTION,
367 .priority = CONNMAN_DRIVER_PRIORITY_LOW,
368 .probe = connection_probe,
369 .remove = connection_remove,
372 int __connman_connection_init(void)
376 if (connman_rtnl_register(&connection_rtnl) < 0)
377 connman_error("Failed to setup RTNL gateway driver");
379 return connman_driver_register(&connection_driver);
382 void __connman_connection_cleanup(void)
388 connman_driver_unregister(&connection_driver);
390 connman_rtnl_unregister(&connection_rtnl);
392 for (list = gateway_list; list; list = list->next) {
393 struct gateway_data *data = list->data;
395 DBG("index %d gateway %s", data->index, data->gateway);
397 g_free(data->gateway);
402 g_slist_free(gateway_list);
406 static void update_order(void)
410 for (list = gateway_list; list; list = list->next) {
411 struct gateway_data *data = list->data;
412 struct connman_service *service;
414 /* vpn gataway is not attached to a service. */
418 service = __connman_element_get_service(data->element);
419 data->order = __connman_service_get_order(service);
423 gboolean __connman_connection_update_gateway(void)
425 struct gateway_data *active_gateway, *default_gateway;
426 gboolean updated = FALSE;
430 active_gateway = find_active_gateway();
431 default_gateway = find_default_gateway();
433 if (active_gateway && active_gateway != default_gateway) {
434 del_routes(active_gateway);