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