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