5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
6 * Copyright (C) 2011 BMW Car IT GmbH. All rights reserved.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
36 struct connman_service *service;
47 static GHashTable *gateway_hash = NULL;
49 static struct gateway_data *find_gateway(int index, const char *gateway)
57 g_hash_table_iter_init(&iter, gateway_hash);
59 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
60 struct gateway_data *data = value;
62 if (data->ipv4_gateway == NULL)
65 if (data->index == index &&
66 g_str_equal(data->ipv4_gateway, gateway)
74 static int del_routes(struct gateway_data *data)
77 if (data->vpn_phy_index >= 0)
78 connman_inet_del_host_route(data->vpn_phy_index,
80 return connman_inet_clear_gateway_address(data->index,
82 } else if (g_strcmp0(data->ipv4_gateway, "0.0.0.0") == 0) {
83 return connman_inet_clear_gateway_interface(data->index);
85 connman_inet_del_ipv6_host_route(data->index,
87 connman_inet_clear_ipv6_gateway_address(data->index,
89 connman_inet_del_host_route(data->index, data->ipv4_gateway);
90 return connman_inet_clear_gateway_address(data->index,
95 static struct gateway_data *add_gateway(struct connman_service *service,
96 int index, const char *ipv4_gateway,
97 const char *ipv6_gateway)
99 struct gateway_data *data;
101 if (strlen(ipv4_gateway) == 0)
104 data = g_try_new0(struct gateway_data, 1);
109 data->ipv4_gateway = g_strdup(ipv4_gateway);
110 data->ipv6_gateway = g_strdup(ipv6_gateway);
111 data->active = FALSE;
114 data->vpn_phy_index = -1;
115 data->service = service;
117 data->order = __connman_service_get_order(service);
119 g_hash_table_replace(gateway_hash, service, data);
124 static void connection_newgateway(int index, const char *gateway)
126 struct gateway_data *data;
128 DBG("index %d gateway %s", index, gateway);
130 data = find_gateway(index, gateway);
137 static void set_default_gateway(struct gateway_data *data)
141 DBG("gateway %s", data->ipv4_gateway);
143 if (data->vpn == TRUE) {
144 connman_inet_set_gateway_address(data->index,
148 __connman_service_indicate_default(data->service);
153 index = __connman_service_get_index(data->service);
155 if (g_strcmp0(data->ipv4_gateway, "0.0.0.0") == 0) {
156 if (connman_inet_set_gateway_interface(index) < 0)
161 connman_inet_set_ipv6_gateway_address(index, data->ipv6_gateway);
162 if (connman_inet_set_gateway_address(index, data->ipv4_gateway) < 0)
166 __connman_service_indicate_default(data->service);
169 static struct gateway_data *find_default_gateway(void)
171 struct gateway_data *found = NULL;
172 unsigned int order = 0;
176 g_hash_table_iter_init(&iter, gateway_hash);
178 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
179 struct gateway_data *data = value;
181 if (found == NULL || data->order > order) {
190 static int disable_gateway(struct gateway_data *data)
192 if (data->active == TRUE)
193 return del_routes(data);
198 static void remove_gateway(gpointer user_data)
200 struct gateway_data *data = user_data;
202 DBG("gateway %s", data->ipv4_gateway);
204 g_free(data->ipv4_gateway);
205 g_free(data->ipv6_gateway);
206 g_free(data->vpn_ip);
210 static void connection_delgateway(int index, const char *gateway)
212 struct gateway_data *data;
214 DBG("index %d gateway %s", index, gateway);
216 data = find_gateway(index, gateway);
218 data->active = FALSE;
220 data = find_default_gateway();
222 set_default_gateway(data);
225 static struct connman_rtnl connection_rtnl = {
226 .name = "connection",
227 .newgateway = connection_newgateway,
228 .delgateway = connection_delgateway,
231 static struct gateway_data *find_active_gateway(void)
238 g_hash_table_iter_init(&iter, gateway_hash);
240 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
241 struct gateway_data *data = value;
243 if (data->active == TRUE)
250 static void update_order(void)
257 g_hash_table_iter_init(&iter, gateway_hash);
259 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
260 struct gateway_data *data = value;
262 data->order = __connman_service_get_order(data->service);
266 int __connman_connection_gateway_add(struct connman_service *service,
267 const char *ipv4_gateway,
268 const char *ipv6_gateway,
271 struct gateway_data *active_gateway = NULL;
272 struct gateway_data *new_gateway = NULL;
275 index = __connman_service_get_index(service);
277 DBG("service %p index %d ipv4 gateway %s ipv6 gateway %s vpn ip %s",
278 service, index, ipv4_gateway, ipv6_gateway, peer);
281 * If gateway is NULL, it's a point to point link and the default
282 * gateway is 0.0.0.0, meaning the interface.
284 if (ipv4_gateway == NULL)
285 ipv4_gateway = "0.0.0.0";
287 active_gateway = find_active_gateway();
288 new_gateway = add_gateway(service, index, ipv4_gateway, ipv6_gateway);
289 if (new_gateway == NULL)
292 if (new_gateway->ipv6_gateway) {
293 connman_inet_add_ipv6_host_route(index,
294 new_gateway->ipv6_gateway,
298 if (g_strcmp0(new_gateway->ipv4_gateway, "0.0.0.0") != 0) {
299 connman_inet_add_host_route(index,
300 new_gateway->ipv4_gateway,
304 __connman_service_nameserver_add_routes(service,
305 new_gateway->ipv4_gateway);
307 __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY,
308 CONNMAN_IPCONFIG_TYPE_IPV4);
310 if (connman_service_get_type(service) == CONNMAN_SERVICE_TYPE_VPN) {
311 new_gateway->vpn = TRUE;
313 new_gateway->vpn_ip = g_strdup(peer);
314 else if (ipv4_gateway != NULL)
315 new_gateway->vpn_ip = g_strdup(ipv4_gateway);
317 new_gateway->vpn_ip = g_strdup(ipv6_gateway);
320 new_gateway->vpn_phy_index = active_gateway->index;
322 new_gateway->vpn = FALSE;
325 if (active_gateway == NULL) {
326 set_default_gateway(new_gateway);
330 if (new_gateway->vpn == TRUE) {
331 connman_inet_add_host_route(active_gateway->index,
332 new_gateway->ipv4_gateway,
333 active_gateway->ipv4_gateway);
334 connman_inet_clear_gateway_address(active_gateway->index,
335 active_gateway->ipv4_gateway);
341 void __connman_connection_gateway_remove(struct connman_service *service)
343 struct gateway_data *data = NULL;
344 gboolean set_default = FALSE;
347 DBG("service %p", service);
349 __connman_service_nameserver_del_routes(service);
351 data = g_hash_table_lookup(gateway_hash, service);
355 set_default = data->vpn;
357 if (data->vpn == TRUE && data->index >= 0) {
358 connman_inet_del_host_route(data->index,
362 __connman_service_nameserver_del_routes(service);
364 err = disable_gateway(data);
365 g_hash_table_remove(gateway_hash, service);
367 /* with vpn this will be called after the network was deleted,
368 * we need to call set_default here because we will not recieve any
369 * gateway delete notification.
370 * We hit the same issue if remove_gateway() fails.
372 if (set_default || err < 0) {
373 data = find_default_gateway();
375 set_default_gateway(data);
379 gboolean __connman_connection_update_gateway(void)
381 struct gateway_data *active_gateway, *default_gateway;
382 gboolean updated = FALSE;
384 if (gateway_hash == NULL)
389 active_gateway = find_active_gateway();
390 default_gateway = find_default_gateway();
392 if (active_gateway && active_gateway != default_gateway)
398 int __connman_connection_init(void)
404 gateway_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
405 NULL, remove_gateway);
407 err = connman_rtnl_register(&connection_rtnl);
409 connman_error("Failed to setup RTNL gateway driver");
414 void __connman_connection_cleanup(void)
421 connman_rtnl_unregister(&connection_rtnl);
423 g_hash_table_iter_init(&iter, gateway_hash);
425 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
426 struct gateway_data *data = value;
428 disable_gateway(data);
431 g_hash_table_destroy(gateway_hash);