connection: Do not set host routes in VPN case
[framework/connectivity/connman.git] / src / connection.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *  Copyright (C) 2011  BMW Car IT GmbH. All rights reserved.
7  *
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.
11  *
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.
16  *
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
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <errno.h>
28 #include <string.h>
29 #include <net/if.h>
30
31 #include <gdbus.h>
32
33 #include "connman.h"
34
35 struct gateway_config {
36         gboolean active;
37         char *gateway;
38
39         /* VPN extra data */
40         gboolean vpn;
41         char *vpn_ip;
42         int vpn_phy_index;
43         char *vpn_phy_ip;
44 };
45
46 struct gateway_data {
47         int index;
48         struct connman_service *service;
49         unsigned int order;
50         struct gateway_config *ipv4_gateway;
51         struct gateway_config *ipv6_gateway;
52 };
53
54 static GHashTable *gateway_hash = NULL;
55
56 static struct gateway_config *find_gateway(int index, const char *gateway)
57 {
58         GHashTableIter iter;
59         gpointer value, key;
60
61         if (gateway == NULL)
62                 return NULL;
63
64         g_hash_table_iter_init(&iter, gateway_hash);
65
66         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
67                 struct gateway_data *data = value;
68
69                 if (data->ipv4_gateway != NULL && data->index == index &&
70                                 g_str_equal(data->ipv4_gateway->gateway,
71                                         gateway) == TRUE)
72                         return data->ipv4_gateway;
73
74                 if (data->ipv6_gateway != NULL && data->index == index &&
75                                 g_str_equal(data->ipv6_gateway->gateway,
76                                         gateway) == TRUE)
77                         return data->ipv6_gateway;
78         }
79
80         return NULL;
81 }
82
83 static int del_routes(struct gateway_data *data,
84                         enum connman_ipconfig_type type)
85 {
86         int status4 = 0, status6 = 0;
87         int do_ipv4 = FALSE, do_ipv6 = FALSE;
88
89         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
90                 do_ipv4 = TRUE;
91         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
92                 do_ipv6 = TRUE;
93         else
94                 do_ipv4 = do_ipv6 = TRUE;
95
96         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL) {
97                 if (data->ipv4_gateway->vpn == TRUE) {
98                         status4 = connman_inet_clear_gateway_address(
99                                                 data->index,
100                                                 data->ipv4_gateway->vpn_ip);
101
102                 } else if (g_strcmp0(data->ipv4_gateway->gateway,
103                                                         "0.0.0.0") == 0) {
104                         status4 = connman_inet_clear_gateway_interface(
105                                                                 data->index);
106                 } else {
107                         connman_inet_del_host_route(data->index,
108                                                 data->ipv4_gateway->gateway);
109                         status4 = connman_inet_clear_gateway_address(
110                                                 data->index,
111                                                 data->ipv4_gateway->gateway);
112                 }
113         }
114
115         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL) {
116                 if (data->ipv6_gateway->vpn == TRUE) {
117                         status6 = connman_inet_clear_ipv6_gateway_address(
118                                                 data->index,
119                                                 data->ipv6_gateway->vpn_ip);
120
121                 } else if (g_strcmp0(data->ipv6_gateway->gateway, "::") == 0) {
122                         status6 = connman_inet_clear_ipv6_gateway_interface(
123                                                                 data->index);
124                 } else {
125                         connman_inet_del_ipv6_host_route(data->index,
126                                                 data->ipv6_gateway->gateway);
127                         status6 = connman_inet_clear_ipv6_gateway_address(
128                                                 data->index,
129                                                 data->ipv6_gateway->gateway);
130                 }
131         }
132
133         return (status4 < 0 ? status4 : status6);
134 }
135
136 static int disable_gateway(struct gateway_data *data,
137                         enum connman_ipconfig_type type)
138 {
139         gboolean active = FALSE;
140
141         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
142                 if (data->ipv4_gateway != NULL)
143                         active = data->ipv4_gateway->active;
144         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
145                 if (data->ipv6_gateway != NULL)
146                         active = data->ipv6_gateway->active;
147         } else
148                 active = TRUE;
149
150         DBG("type %d active %d", type, active);
151
152         if (active == TRUE)
153                 return del_routes(data, type);
154
155         return 0;
156 }
157
158 static struct gateway_data *add_gateway(struct connman_service *service,
159                                         int index, const char *gateway,
160                                         enum connman_ipconfig_type type)
161 {
162         struct gateway_data *data, *old;
163         struct gateway_config *config;
164
165         if (gateway == NULL || strlen(gateway) == 0)
166                 return NULL;
167
168         data = g_try_new0(struct gateway_data, 1);
169         if (data == NULL)
170                 return NULL;
171
172         data->index = index;
173
174         config = g_try_new0(struct gateway_config, 1);
175         if (config == NULL) {
176                 g_free(data);
177                 return NULL;
178         }
179
180         config->gateway = g_strdup(gateway);
181         config->vpn_ip = NULL;
182         config->vpn_phy_ip = NULL;
183         config->vpn = FALSE;
184         config->vpn_phy_index = -1;
185         config->active = FALSE;
186
187         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
188                 data->ipv4_gateway = config;
189         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
190                 data->ipv6_gateway = config;
191         else {
192                 g_free(config->gateway);
193                 g_free(config);
194                 g_free(data);
195                 return NULL;
196         }
197
198         data->service = service;
199
200         data->order = __connman_service_get_order(service);
201
202         /*
203          * If the service is already in the hash, then we
204          * must not replace it blindly but disable the gateway
205          * of the type we are replacing and take the other type
206          * from old gateway settings.
207          */
208         old = g_hash_table_lookup(gateway_hash, service);
209         if (old != NULL) {
210                 DBG("Replacing gw %p ipv4 %p ipv6 %p", old,
211                         old->ipv4_gateway, old->ipv6_gateway);
212                 disable_gateway(old, type);
213                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
214                         data->ipv6_gateway = old->ipv6_gateway;
215                         old->ipv6_gateway = NULL;
216                 } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
217                         data->ipv4_gateway = old->ipv4_gateway;
218                         old->ipv4_gateway = NULL;
219                 }
220         } else {
221                 /*
222                  * Only take a ref if we are adding new stuff to hash.
223                  */
224                 connman_service_ref(service);
225         }
226
227         g_hash_table_replace(gateway_hash, service, data);
228
229         return data;
230 }
231
232 static void connection_newgateway(int index, const char *gateway)
233 {
234         struct gateway_config *config;
235
236         DBG("index %d gateway %s", index, gateway);
237
238         config = find_gateway(index, gateway);
239         if (config == NULL)
240                 return;
241
242         config->active = TRUE;
243 }
244
245 static void set_default_gateway(struct gateway_data *data,
246                                 enum connman_ipconfig_type type)
247 {
248         int index;
249         int status4 = 0, status6 = 0;
250         int do_ipv4 = FALSE, do_ipv6 = FALSE;
251
252         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
253                 do_ipv4 = TRUE;
254         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
255                 do_ipv6 = TRUE;
256         else
257                 do_ipv4 = do_ipv6 = TRUE;
258
259         DBG("type %d gateway ipv4 %p ipv6 %p", type, data->ipv4_gateway,
260                                                 data->ipv6_gateway);
261
262         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
263                                         data->ipv4_gateway->vpn == TRUE) {
264                 connman_inet_set_gateway_address(data->index,
265                                                 data->ipv4_gateway->vpn_ip);
266                 data->ipv4_gateway->active = TRUE;
267
268                 DBG("set %p index %d vpn %s index %d phy %s",
269                         data, data->index, data->ipv4_gateway->vpn_ip,
270                         data->ipv4_gateway->vpn_phy_index,
271                         data->ipv4_gateway->vpn_phy_ip);
272
273                 __connman_service_indicate_default(data->service);
274
275                 return;
276         }
277
278         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
279                                         data->ipv6_gateway->vpn == TRUE) {
280                 connman_inet_set_ipv6_gateway_address(data->index,
281                                                 data->ipv6_gateway->vpn_ip);
282                 data->ipv6_gateway->active = TRUE;
283
284                 DBG("set %p index %d vpn %s index %d phy %s",
285                         data, data->index, data->ipv6_gateway->vpn_ip,
286                         data->ipv6_gateway->vpn_phy_index,
287                         data->ipv6_gateway->vpn_phy_ip);
288
289                 __connman_service_indicate_default(data->service);
290
291                 return;
292         }
293
294         index = __connman_service_get_index(data->service);
295
296         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
297                         g_strcmp0(data->ipv4_gateway->gateway,
298                                                         "0.0.0.0") == 0) {
299                 if (connman_inet_set_gateway_interface(index) < 0)
300                         return;
301                 goto done;
302         }
303
304         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
305                         g_strcmp0(data->ipv6_gateway->gateway,
306                                                         "::") == 0) {
307                 if (connman_inet_set_ipv6_gateway_interface(index) < 0)
308                         return;
309                 goto done;
310         }
311
312         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL)
313                 status6 = connman_inet_set_ipv6_gateway_address(index,
314                                                 data->ipv6_gateway->gateway);
315
316         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL)
317                 status4 = connman_inet_set_gateway_address(index,
318                                                 data->ipv4_gateway->gateway);
319
320         if (status4 < 0 || status6 < 0)
321                 return;
322
323 done:
324         __connman_service_indicate_default(data->service);
325 }
326
327 static void unset_default_gateway(struct gateway_data *data,
328                                 enum connman_ipconfig_type type)
329 {
330         int index;
331         int do_ipv4 = FALSE, do_ipv6 = FALSE;
332
333         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
334                 do_ipv4 = TRUE;
335         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
336                 do_ipv6 = TRUE;
337         else
338                 do_ipv4 = do_ipv6 = TRUE;
339
340         DBG("type %d gateway ipv4 %p ipv6 %p", type, data->ipv4_gateway,
341                                                 data->ipv6_gateway);
342
343         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
344                                         data->ipv4_gateway->vpn == TRUE) {
345                 connman_inet_del_host_route(data->index,
346                                                 data->ipv4_gateway->vpn_ip);
347                 connman_inet_clear_gateway_address(data->index,
348                                                 data->ipv4_gateway->vpn_ip);
349                 data->ipv4_gateway->active = FALSE;
350
351                 DBG("unset %p index %d vpn %s index %d phy %s",
352                         data, data->index, data->ipv4_gateway->vpn_ip,
353                         data->ipv4_gateway->vpn_phy_index,
354                         data->ipv4_gateway->vpn_phy_ip);
355
356                 return;
357         }
358
359         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
360                                         data->ipv6_gateway->vpn == TRUE) {
361                 connman_inet_del_ipv6_host_route(data->index,
362                                                 data->ipv6_gateway->vpn_ip);
363                 connman_inet_clear_ipv6_gateway_address(data->index,
364                                                 data->ipv6_gateway->vpn_ip);
365                 data->ipv6_gateway->active = FALSE;
366
367                 DBG("unset %p index %d vpn %s index %d phy %s",
368                         data, data->index, data->ipv6_gateway->vpn_ip,
369                         data->ipv6_gateway->vpn_phy_index,
370                         data->ipv6_gateway->vpn_phy_ip);
371
372                 return;
373         }
374
375         index = __connman_service_get_index(data->service);
376
377         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
378                         g_strcmp0(data->ipv4_gateway->gateway,
379                                                         "0.0.0.0") == 0) {
380                 connman_inet_clear_gateway_interface(index);
381                 return;
382         }
383
384         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
385                         g_strcmp0(data->ipv6_gateway->gateway,
386                                                         "::") == 0) {
387                 connman_inet_clear_ipv6_gateway_interface(index);
388                 return;
389         }
390
391         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL)
392                 connman_inet_clear_ipv6_gateway_address(index,
393                                                 data->ipv6_gateway->gateway);
394
395         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL)
396                 connman_inet_clear_gateway_address(index,
397                                                 data->ipv4_gateway->gateway);
398 }
399
400 static struct gateway_data *find_default_gateway(void)
401 {
402         struct gateway_data *found = NULL;
403         unsigned int order = 0;
404         GHashTableIter iter;
405         gpointer value, key;
406
407         g_hash_table_iter_init(&iter, gateway_hash);
408
409         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
410                 struct gateway_data *data = value;
411
412                 if (found == NULL || data->order > order) {
413                         found = data;
414                         order = data->order;
415
416                         DBG("default %p order %d", found, order);
417                 }
418         }
419
420         return found;
421 }
422
423 static void remove_gateway(gpointer user_data)
424 {
425         struct gateway_data *data = user_data;
426
427         DBG("gateway ipv4 %p ipv6 %p", data->ipv4_gateway, data->ipv6_gateway);
428
429         if (data->ipv4_gateway != NULL) {
430                 g_free(data->ipv4_gateway->gateway);
431                 g_free(data->ipv4_gateway->vpn_ip);
432                 g_free(data->ipv4_gateway->vpn_phy_ip);
433                 g_free(data->ipv4_gateway);
434         }
435
436         if (data->ipv6_gateway != NULL) {
437                 g_free(data->ipv6_gateway->gateway);
438                 g_free(data->ipv6_gateway->vpn_ip);
439                 g_free(data->ipv6_gateway->vpn_phy_ip);
440                 g_free(data->ipv6_gateway);
441         }
442
443         g_free(data);
444 }
445
446 static void connection_delgateway(int index, const char *gateway)
447 {
448         struct gateway_config *config;
449         struct gateway_data *data;
450
451         DBG("index %d gateway %s", index, gateway);
452
453         config = find_gateway(index, gateway);
454         if (config != NULL)
455                 config->active = FALSE;
456
457         data = find_default_gateway();
458         if (data != NULL)
459                 set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_ALL);
460 }
461
462 static struct connman_rtnl connection_rtnl = {
463         .name           = "connection",
464         .newgateway     = connection_newgateway,
465         .delgateway     = connection_delgateway,
466 };
467
468 static struct gateway_data *find_active_gateway(void)
469 {
470         GHashTableIter iter;
471         gpointer value, key;
472
473         DBG("");
474
475         g_hash_table_iter_init(&iter, gateway_hash);
476
477         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
478                 struct gateway_data *data = value;
479
480                 if (data->ipv4_gateway != NULL &&
481                                 data->ipv4_gateway->active == TRUE)
482                         return data;
483
484                 if (data->ipv6_gateway != NULL &&
485                                 data->ipv6_gateway->active == TRUE)
486                         return data;
487         }
488
489         return NULL;
490 }
491
492 static void update_order(void)
493 {
494         GHashTableIter iter;
495         gpointer value, key;
496
497         DBG("");
498
499         g_hash_table_iter_init(&iter, gateway_hash);
500
501         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
502                 struct gateway_data *data = value;
503
504                 data->order = __connman_service_get_order(data->service);
505         }
506 }
507
508 void __connman_connection_gateway_activate(struct connman_service *service,
509                                         enum connman_ipconfig_type type)
510 {
511         struct gateway_data *data = NULL;
512
513         data = g_hash_table_lookup(gateway_hash, service);
514         if (data == NULL)
515                 return;
516
517         DBG("gateway %p/%p type %d", data->ipv4_gateway,
518                                         data->ipv6_gateway, type);
519
520         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
521                 data->ipv4_gateway->active = TRUE;
522         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
523                 data->ipv6_gateway->active = TRUE;
524 }
525
526 int __connman_connection_gateway_add(struct connman_service *service,
527                                         const char *gateway,
528                                         enum connman_ipconfig_type type,
529                                         const char *peer)
530 {
531         struct gateway_data *active_gateway = NULL;
532         struct gateway_data *new_gateway = NULL;
533         enum connman_ipconfig_type type4 = CONNMAN_IPCONFIG_TYPE_UNKNOWN,
534                 type6 = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
535         int index;
536
537         index = __connman_service_get_index(service);
538
539         /*
540          * If gateway is NULL, it's a point to point link and the default
541          * gateway for ipv4 is 0.0.0.0 and for ipv6 is ::, meaning the
542          * interface
543          */
544         if (gateway == NULL && type == CONNMAN_IPCONFIG_TYPE_IPV4)
545                 gateway = "0.0.0.0";
546
547         if (gateway == NULL && type == CONNMAN_IPCONFIG_TYPE_IPV6)
548                 gateway = "::";
549
550         DBG("service %p index %d gateway %s vpn ip %s type %d",
551                 service, index, gateway, peer, type);
552
553         new_gateway = add_gateway(service, index, gateway, type);
554         if (new_gateway == NULL)
555                 return -EINVAL;
556
557         active_gateway = find_active_gateway();
558
559         DBG("active %p index %d new %p", active_gateway,
560                 active_gateway ? active_gateway->index : -1, new_gateway);
561
562         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
563                         new_gateway->ipv6_gateway != NULL &&
564                         g_strcmp0(new_gateway->ipv6_gateway->gateway,
565                                                                 "::") != 0)
566                 connman_inet_add_ipv6_host_route(index,
567                                         new_gateway->ipv6_gateway->gateway,
568                                         NULL);
569
570         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
571                         new_gateway->ipv4_gateway != NULL &&
572                         g_strcmp0(new_gateway->ipv4_gateway->gateway,
573                                                         "0.0.0.0") != 0)
574                 connman_inet_add_host_route(index,
575                                         new_gateway->ipv4_gateway->gateway,
576                                         NULL);
577
578         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
579                                 new_gateway->ipv4_gateway != NULL) {
580                 __connman_service_nameserver_add_routes(service,
581                                         new_gateway->ipv4_gateway->gateway);
582                 type4 = CONNMAN_IPCONFIG_TYPE_IPV4;
583         }
584
585         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
586                                 new_gateway->ipv6_gateway != NULL) {
587                 __connman_service_nameserver_add_routes(service,
588                                         new_gateway->ipv6_gateway->gateway);
589                 type6 = CONNMAN_IPCONFIG_TYPE_IPV6;
590         }
591
592         if (connman_service_get_type(service) == CONNMAN_SERVICE_TYPE_VPN) {
593                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
594                                         new_gateway->ipv4_gateway != NULL) {
595                         new_gateway->ipv4_gateway->vpn = TRUE;
596                         if (peer != NULL)
597                                 new_gateway->ipv4_gateway->vpn_ip =
598                                                         g_strdup(peer);
599                         else if (gateway != NULL)
600                                 new_gateway->ipv4_gateway->vpn_ip =
601                                                         g_strdup(gateway);
602                         if (active_gateway) {
603                                 const char *new_ipv4_gateway;
604
605                                 new_ipv4_gateway =
606                                         active_gateway->ipv4_gateway->gateway;
607                                 if (new_ipv4_gateway != NULL &&
608                                          g_strcmp0(new_ipv4_gateway,
609                                                         "0.0.0.0") != 0)
610                                         new_gateway->ipv4_gateway->vpn_phy_ip =
611                                                 g_strdup(new_ipv4_gateway);
612
613                                 new_gateway->ipv4_gateway->vpn_phy_index =
614                                                         active_gateway->index;
615                         }
616
617                         DBG("vpn %s phy %s index %d",
618                                 new_gateway->ipv4_gateway->vpn_ip,
619                                 new_gateway->ipv4_gateway->vpn_phy_ip,
620                                 new_gateway->ipv4_gateway->vpn_phy_index);
621
622                 } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
623                                         new_gateway->ipv6_gateway != NULL) {
624                         new_gateway->ipv6_gateway->vpn = TRUE;
625                         if (peer != NULL)
626                                 new_gateway->ipv6_gateway->vpn_ip =
627                                                         g_strdup(peer);
628                         else if (gateway != NULL)
629                                 new_gateway->ipv6_gateway->vpn_ip =
630                                                         g_strdup(gateway);
631                         if (active_gateway) {
632                                 const char *new_ipv6_gateway;
633
634                                 new_ipv6_gateway =
635                                         active_gateway->ipv6_gateway->gateway;
636                                 if (new_ipv6_gateway != NULL &&
637                                         g_strcmp0(new_ipv6_gateway, "::") != 0)
638                                         new_gateway->ipv6_gateway->vpn_phy_ip =
639                                                 g_strdup(new_ipv6_gateway);
640
641                                 new_gateway->ipv6_gateway->vpn_phy_index =
642                                                         active_gateway->index;
643                         }
644
645                         DBG("vpn %s phy %s index %d",
646                                 new_gateway->ipv6_gateway->vpn_ip,
647                                 new_gateway->ipv6_gateway->vpn_phy_ip,
648                                 new_gateway->ipv6_gateway->vpn_phy_index);
649                 }
650         } else {
651                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
652                                         new_gateway->ipv4_gateway != NULL)
653                         new_gateway->ipv4_gateway->vpn = FALSE;
654
655                 if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
656                                         new_gateway->ipv6_gateway != NULL)
657                         new_gateway->ipv6_gateway->vpn = FALSE;
658         }
659
660         if (active_gateway == NULL) {
661                 set_default_gateway(new_gateway, type);
662                 goto done;
663         }
664
665         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
666                                 new_gateway->ipv4_gateway != NULL &&
667                                 new_gateway->ipv4_gateway->vpn == TRUE) {
668                 connman_inet_add_host_route(active_gateway->index,
669                                         new_gateway->ipv4_gateway->gateway,
670                                         active_gateway->ipv4_gateway->gateway);
671                 connman_inet_clear_gateway_address(active_gateway->index,
672                                         active_gateway->ipv4_gateway->gateway);
673         }
674
675         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
676                                 new_gateway->ipv6_gateway != NULL &&
677                                 new_gateway->ipv6_gateway->vpn == TRUE) {
678                 connman_inet_add_ipv6_host_route(active_gateway->index,
679                                         new_gateway->ipv6_gateway->gateway,
680                                         active_gateway->ipv6_gateway->gateway);
681                 connman_inet_clear_ipv6_gateway_address(active_gateway->index,
682                                         active_gateway->ipv6_gateway->gateway);
683         }
684
685 done:
686         if (type4 == CONNMAN_IPCONFIG_TYPE_IPV4)
687                 __connman_service_ipconfig_indicate_state(service,
688                                                 CONNMAN_SERVICE_STATE_READY,
689                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
690
691         if (type6 == CONNMAN_IPCONFIG_TYPE_IPV6)
692                 __connman_service_ipconfig_indicate_state(service,
693                                                 CONNMAN_SERVICE_STATE_READY,
694                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
695         return 0;
696 }
697
698 void __connman_connection_gateway_remove(struct connman_service *service,
699                                         enum connman_ipconfig_type type)
700 {
701         struct gateway_data *data = NULL;
702         gboolean set_default4 = FALSE, set_default6 = FALSE;
703         int do_ipv4 = FALSE, do_ipv6 = FALSE;
704         int err;
705
706         DBG("service %p type %d", service, type);
707
708         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
709                 do_ipv4 = TRUE;
710         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
711                 do_ipv6 = TRUE;
712         else
713                 do_ipv4 = do_ipv6 = TRUE;
714
715         __connman_service_nameserver_del_routes(service, type);
716
717         data = g_hash_table_lookup(gateway_hash, service);
718         if (data == NULL)
719                 return;
720
721         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL)
722                 set_default4 = data->ipv4_gateway->vpn;
723
724         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL)
725                 set_default6 = data->ipv6_gateway->vpn;
726
727         DBG("ipv4 gateway %s ipv6 gateway %s vpn %d/%d",
728                 data->ipv4_gateway ? data->ipv4_gateway->gateway : "<null>",
729                 data->ipv6_gateway ? data->ipv6_gateway->gateway : "<null>",
730                 set_default4, set_default6);
731
732         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
733                         data->ipv4_gateway->vpn == TRUE && data->index >= 0)
734                 connman_inet_del_host_route(data->index,
735                                                 data->ipv4_gateway->gateway);
736
737         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
738                         data->ipv6_gateway->vpn == TRUE && data->index >= 0)
739                 connman_inet_del_ipv6_host_route(data->index,
740                                                 data->ipv6_gateway->gateway);
741
742         err = disable_gateway(data, type);
743
744         /*
745          * We remove the service from the hash only if all the gateway
746          * settings are to be removed.
747          */
748         if (do_ipv4 == do_ipv6 ||
749                 (data->ipv4_gateway != NULL && data->ipv6_gateway == NULL
750                         && do_ipv4 == TRUE) ||
751                 (data->ipv6_gateway != NULL && data->ipv4_gateway == NULL
752                         && do_ipv6 == TRUE)
753                 ) {
754                 connman_service_unref(service);
755                 g_hash_table_remove(gateway_hash, service);
756         } else
757                 DBG("Not yet removing gw ipv4 %p/%d ipv6 %p/%d",
758                         data->ipv4_gateway, do_ipv4,
759                         data->ipv6_gateway, do_ipv6);
760
761         /* with vpn this will be called after the network was deleted,
762          * we need to call set_default here because we will not recieve any
763          * gateway delete notification.
764          * We hit the same issue if remove_gateway() fails.
765          */
766         if (set_default4 || set_default6 || err < 0) {
767                 data = find_default_gateway();
768                 if (data != NULL)
769                         set_default_gateway(data, type);
770         }
771 }
772
773 gboolean __connman_connection_update_gateway(void)
774 {
775         struct gateway_data *active_gateway, *default_gateway;
776         gboolean updated = FALSE;
777
778         if (gateway_hash == NULL)
779                 return updated;
780
781         active_gateway = find_active_gateway();
782
783         update_order();
784
785         default_gateway = find_default_gateway();
786
787         DBG("active %p default %p", active_gateway, default_gateway);
788
789         if (active_gateway && active_gateway != default_gateway) {
790                 updated = TRUE;
791
792                 if (active_gateway->ipv4_gateway)
793                         unset_default_gateway(active_gateway,
794                                         CONNMAN_IPCONFIG_TYPE_IPV4);
795
796                 if (active_gateway->ipv6_gateway)
797                         unset_default_gateway(active_gateway,
798                                         CONNMAN_IPCONFIG_TYPE_IPV6);
799
800                 if (default_gateway) {
801                         if (default_gateway->ipv4_gateway)
802                                 set_default_gateway(default_gateway,
803                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
804
805                         if (default_gateway->ipv6_gateway)
806                                 set_default_gateway(default_gateway,
807                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
808                 }
809         }
810
811         return updated;
812 }
813
814 int __connman_connection_init(void)
815 {
816         int err;
817
818         DBG("");
819
820         gateway_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
821                                                         NULL, remove_gateway);
822
823         err = connman_rtnl_register(&connection_rtnl);
824         if (err < 0)
825                 connman_error("Failed to setup RTNL gateway driver");
826
827         return err;
828 }
829
830 void __connman_connection_cleanup(void)
831 {
832         GHashTableIter iter;
833         gpointer value, key;
834
835         DBG("");
836
837         connman_rtnl_unregister(&connection_rtnl);
838
839         g_hash_table_iter_init(&iter, gateway_hash);
840
841         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
842                 struct gateway_data *data = value;
843
844                 disable_gateway(data, CONNMAN_IPCONFIG_TYPE_ALL);
845         }
846
847         g_hash_table_destroy(gateway_hash);
848         gateway_hash = NULL;
849 }