connection: Default gateway is changed when reorganizing services
[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                         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         }
231
232         g_hash_table_replace(gateway_hash, service, data);
233
234         return data;
235 }
236
237 static void connection_newgateway(int index, const char *gateway)
238 {
239         struct gateway_config *config;
240
241         DBG("index %d gateway %s", index, gateway);
242
243         config = find_gateway(index, gateway);
244         if (config == NULL)
245                 return;
246
247         config->active = TRUE;
248 }
249
250 static void set_default_gateway(struct gateway_data *data,
251                                 enum connman_ipconfig_type type)
252 {
253         int index;
254         int status4 = 0, status6 = 0;
255         int do_ipv4 = FALSE, do_ipv6 = FALSE;
256
257         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
258                 do_ipv4 = TRUE;
259         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
260                 do_ipv6 = TRUE;
261         else
262                 do_ipv4 = do_ipv6 = TRUE;
263
264         DBG("type %d gateway ipv4 %p ipv6 %p", type, data->ipv4_gateway,
265                                                 data->ipv6_gateway);
266
267         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
268                                         data->ipv4_gateway->vpn == TRUE) {
269                 connman_inet_set_gateway_address(data->index,
270                                                 data->ipv4_gateway->vpn_ip);
271                 connman_inet_add_host_route(data->ipv4_gateway->vpn_phy_index,
272                                         data->ipv4_gateway->vpn_ip,
273                                         data->ipv4_gateway->vpn_phy_ip);
274                 data->ipv4_gateway->active = TRUE;
275
276                 __connman_service_indicate_default(data->service);
277
278                 return;
279         }
280
281         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
282                                         data->ipv6_gateway->vpn == TRUE) {
283                 connman_inet_set_ipv6_gateway_address(data->index,
284                                                 data->ipv6_gateway->vpn_ip);
285                 connman_inet_add_ipv6_host_route(
286                                         data->ipv6_gateway->vpn_phy_index,
287                                         data->ipv6_gateway->vpn_ip,
288                                         data->ipv6_gateway->vpn_phy_ip);
289                 data->ipv6_gateway->active = TRUE;
290
291                 __connman_service_indicate_default(data->service);
292
293                 return;
294         }
295
296         index = __connman_service_get_index(data->service);
297
298         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
299                         g_strcmp0(data->ipv4_gateway->gateway,
300                                                         "0.0.0.0") == 0) {
301                 if (connman_inet_set_gateway_interface(index) < 0)
302                         return;
303                 goto done;
304         }
305
306         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
307                         g_strcmp0(data->ipv6_gateway->gateway,
308                                                         "::") == 0) {
309                 if (connman_inet_set_ipv6_gateway_interface(index) < 0)
310                         return;
311                 goto done;
312         }
313
314         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL)
315                 status6 = connman_inet_set_ipv6_gateway_address(index,
316                                                 data->ipv6_gateway->gateway);
317
318         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL)
319                 status4 = connman_inet_set_gateway_address(index,
320                                                 data->ipv4_gateway->gateway);
321
322         if (status4 < 0 || status6 < 0)
323                 return;
324
325 done:
326         __connman_service_indicate_default(data->service);
327 }
328
329 static void unset_default_gateway(struct gateway_data *data,
330                                 enum connman_ipconfig_type type)
331 {
332         int index;
333         int do_ipv4 = FALSE, do_ipv6 = FALSE;
334
335         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
336                 do_ipv4 = TRUE;
337         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
338                 do_ipv6 = TRUE;
339         else
340                 do_ipv4 = do_ipv6 = TRUE;
341
342         DBG("type %d gateway ipv4 %p ipv6 %p", type, data->ipv4_gateway,
343                                                 data->ipv6_gateway);
344
345         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
346                                         data->ipv4_gateway->vpn == TRUE) {
347                 connman_inet_del_host_route(data->index,
348                                                 data->ipv4_gateway->vpn_ip);
349                 connman_inet_clear_gateway_address(data->index,
350                                                 data->ipv4_gateway->vpn_ip);
351                 data->ipv4_gateway->active = FALSE;
352
353                 return;
354         }
355
356         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
357                                         data->ipv6_gateway->vpn == TRUE) {
358                 connman_inet_del_ipv6_host_route(data->index,
359                                                 data->ipv6_gateway->vpn_ip);
360                 connman_inet_clear_ipv6_gateway_address(data->index,
361                                                 data->ipv6_gateway->vpn_ip);
362                 data->ipv6_gateway->active = FALSE;
363
364                 return;
365         }
366
367         index = __connman_service_get_index(data->service);
368
369         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
370                         g_strcmp0(data->ipv4_gateway->gateway,
371                                                         "0.0.0.0") == 0) {
372                 connman_inet_clear_gateway_interface(index);
373                 return;
374         }
375
376         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
377                         g_strcmp0(data->ipv6_gateway->gateway,
378                                                         "::") == 0) {
379                 connman_inet_clear_ipv6_gateway_interface(index);
380                 return;
381         }
382
383         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL)
384                 connman_inet_clear_ipv6_gateway_address(index,
385                                                 data->ipv6_gateway->gateway);
386
387         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL)
388                 connman_inet_clear_gateway_address(index,
389                                                 data->ipv4_gateway->gateway);
390 }
391
392 static struct gateway_data *find_default_gateway(void)
393 {
394         struct gateway_data *found = NULL;
395         unsigned int order = 0;
396         GHashTableIter iter;
397         gpointer value, key;
398
399         g_hash_table_iter_init(&iter, gateway_hash);
400
401         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
402                 struct gateway_data *data = value;
403
404                 if (found == NULL || data->order > order) {
405                         found = data;
406                         order = data->order;
407                 }
408         }
409
410         return found;
411 }
412
413 static void remove_gateway(gpointer user_data)
414 {
415         struct gateway_data *data = user_data;
416
417         DBG("gateway ipv4 %p ipv6 %p", data->ipv4_gateway, data->ipv6_gateway);
418
419         if (data->ipv4_gateway != NULL) {
420                 g_free(data->ipv4_gateway->gateway);
421                 g_free(data->ipv4_gateway->vpn_ip);
422                 g_free(data->ipv4_gateway->vpn_phy_ip);
423                 g_free(data->ipv4_gateway);
424         }
425
426         if (data->ipv6_gateway != NULL) {
427                 g_free(data->ipv6_gateway->gateway);
428                 g_free(data->ipv6_gateway->vpn_ip);
429                 g_free(data->ipv6_gateway->vpn_phy_ip);
430                 g_free(data->ipv6_gateway);
431         }
432
433         g_free(data);
434 }
435
436 static void connection_delgateway(int index, const char *gateway)
437 {
438         struct gateway_config *config;
439         struct gateway_data *data;
440
441         DBG("index %d gateway %s", index, gateway);
442
443         config = find_gateway(index, gateway);
444         if (config != NULL)
445                 config->active = FALSE;
446
447         data = find_default_gateway();
448         if (data != NULL)
449                 set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_ALL);
450 }
451
452 static struct connman_rtnl connection_rtnl = {
453         .name           = "connection",
454         .newgateway     = connection_newgateway,
455         .delgateway     = connection_delgateway,
456 };
457
458 static struct gateway_data *find_active_gateway(void)
459 {
460         GHashTableIter iter;
461         gpointer value, key;
462
463         DBG("");
464
465         g_hash_table_iter_init(&iter, gateway_hash);
466
467         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
468                 struct gateway_data *data = value;
469
470                 if (data->ipv4_gateway != NULL &&
471                                 data->ipv4_gateway->active == TRUE)
472                         return data;
473
474                 if (data->ipv6_gateway != NULL &&
475                                 data->ipv6_gateway->active == TRUE)
476                         return data;
477         }
478
479         return NULL;
480 }
481
482 static void update_order(void)
483 {
484         GHashTableIter iter;
485         gpointer value, key;
486
487         DBG("");
488
489         g_hash_table_iter_init(&iter, gateway_hash);
490
491         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
492                 struct gateway_data *data = value;
493
494                 data->order = __connman_service_get_order(data->service);
495         }
496 }
497
498 void __connman_connection_gateway_activate(struct connman_service *service,
499                                         enum connman_ipconfig_type type)
500 {
501         struct gateway_data *data = NULL;
502
503         data = g_hash_table_lookup(gateway_hash, service);
504         if (data == NULL)
505                 return;
506
507         DBG("gateway %p/%p type %d", data->ipv4_gateway,
508                                         data->ipv6_gateway, type);
509
510         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
511                 data->ipv4_gateway->active = TRUE;
512         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
513                 data->ipv6_gateway->active = TRUE;
514 }
515
516 int __connman_connection_gateway_add(struct connman_service *service,
517                                         const char *gateway,
518                                         enum connman_ipconfig_type type,
519                                         const char *peer)
520 {
521         struct gateway_data *active_gateway = NULL;
522         struct gateway_data *new_gateway = NULL;
523         int index;
524
525         index = __connman_service_get_index(service);
526
527         DBG("service %p index %d gateway %s vpn ip %s type %d",
528                 service, index, gateway, peer, type);
529
530         /*
531          * If gateway is NULL, it's a point to point link and the default
532          * gateway for ipv4 is 0.0.0.0 and for ipv6 is ::, meaning the
533          * interface
534          */
535         if (gateway == NULL && type == CONNMAN_IPCONFIG_TYPE_IPV4)
536                 gateway = "0.0.0.0";
537
538         if (gateway == NULL && type == CONNMAN_IPCONFIG_TYPE_IPV6)
539                 gateway = "::";
540
541         active_gateway = find_active_gateway();
542         new_gateway = add_gateway(service, index, gateway, type);
543         if (new_gateway == NULL)
544                 return -EINVAL;
545
546         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
547                         new_gateway->ipv6_gateway != NULL &&
548                         g_strcmp0(new_gateway->ipv6_gateway->gateway,
549                                                                 "::") != 0)
550                 connman_inet_add_ipv6_host_route(index,
551                                         new_gateway->ipv6_gateway->gateway,
552                                         NULL);
553
554         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
555                         new_gateway->ipv4_gateway != NULL &&
556                         g_strcmp0(new_gateway->ipv4_gateway->gateway,
557                                                         "0.0.0.0") != 0)
558                 connman_inet_add_host_route(index,
559                                         new_gateway->ipv4_gateway->gateway,
560                                         NULL);
561
562         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
563                                 new_gateway->ipv4_gateway != NULL) {
564                 __connman_service_nameserver_add_routes(service,
565                                         new_gateway->ipv4_gateway->gateway);
566                 __connman_service_ipconfig_indicate_state(service,
567                                                 CONNMAN_SERVICE_STATE_READY,
568                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
569         }
570
571         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
572                                 new_gateway->ipv6_gateway != NULL) {
573                 __connman_service_nameserver_add_routes(service,
574                                         new_gateway->ipv6_gateway->gateway);
575                 __connman_service_ipconfig_indicate_state(service,
576                                                 CONNMAN_SERVICE_STATE_READY,
577                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
578         }
579
580         if (connman_service_get_type(service) == CONNMAN_SERVICE_TYPE_VPN) {
581                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
582                                         new_gateway->ipv4_gateway != NULL) {
583                         new_gateway->ipv4_gateway->vpn = TRUE;
584                         if (peer != NULL)
585                                 new_gateway->ipv4_gateway->vpn_ip =
586                                                         g_strdup(peer);
587                         else if (gateway != NULL)
588                                 new_gateway->ipv4_gateway->vpn_ip =
589                                                         g_strdup(gateway);
590                         if (active_gateway) {
591                                 const char *new_ipv4_gateway;
592
593                                 new_ipv4_gateway =
594                                         active_gateway->ipv4_gateway->gateway;
595                                 if (new_ipv4_gateway != NULL &&
596                                          g_strcmp0(new_ipv4_gateway,
597                                                         "0.0.0.0") != 0)
598                                         new_gateway->ipv4_gateway->vpn_phy_ip =
599                                                 g_strdup(new_ipv4_gateway);
600
601                                 new_gateway->ipv4_gateway->vpn_phy_index =
602                                                         active_gateway->index;
603                         }
604
605                 } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
606                                         new_gateway->ipv6_gateway != NULL) {
607                         new_gateway->ipv6_gateway->vpn = TRUE;
608                         if (peer != NULL)
609                                 new_gateway->ipv6_gateway->vpn_ip =
610                                                         g_strdup(peer);
611                         else if (gateway != NULL)
612                                 new_gateway->ipv6_gateway->vpn_ip =
613                                                         g_strdup(gateway);
614                         if (active_gateway) {
615                                 const char *new_ipv6_gateway;
616
617                                 new_ipv6_gateway =
618                                         active_gateway->ipv6_gateway->gateway;
619                                 if (new_ipv6_gateway != NULL &&
620                                         g_strcmp0(new_ipv6_gateway, "::") != 0)
621                                         new_gateway->ipv6_gateway->vpn_phy_ip =
622                                                 g_strdup(new_ipv6_gateway);
623
624                                 new_gateway->ipv6_gateway->vpn_phy_index =
625                                                         active_gateway->index;
626                         }
627                 }
628         } else {
629                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
630                                         new_gateway->ipv4_gateway != NULL)
631                         new_gateway->ipv4_gateway->vpn = FALSE;
632
633                 if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
634                                         new_gateway->ipv6_gateway != NULL)
635                         new_gateway->ipv6_gateway->vpn = FALSE;
636         }
637
638         if (active_gateway == NULL) {
639                 set_default_gateway(new_gateway, type);
640                 return 0;
641         }
642
643         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
644                                 new_gateway->ipv4_gateway != NULL &&
645                                 new_gateway->ipv4_gateway->vpn == TRUE) {
646                 connman_inet_add_host_route(active_gateway->index,
647                                         new_gateway->ipv4_gateway->gateway,
648                                         active_gateway->ipv4_gateway->gateway);
649                 connman_inet_clear_gateway_address(active_gateway->index,
650                                         active_gateway->ipv4_gateway->gateway);
651         }
652
653         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
654                                 new_gateway->ipv6_gateway != NULL &&
655                                 new_gateway->ipv6_gateway->vpn == TRUE) {
656                 connman_inet_add_ipv6_host_route(active_gateway->index,
657                                         new_gateway->ipv6_gateway->gateway,
658                                         active_gateway->ipv6_gateway->gateway);
659                 connman_inet_clear_ipv6_gateway_address(active_gateway->index,
660                                         active_gateway->ipv6_gateway->gateway);
661         }
662
663         return 0;
664 }
665
666 void __connman_connection_gateway_remove(struct connman_service *service,
667                                         enum connman_ipconfig_type type)
668 {
669         struct gateway_data *data = NULL;
670         gboolean set_default4 = FALSE, set_default6 = FALSE;
671         int do_ipv4 = FALSE, do_ipv6 = FALSE;
672         int err;
673
674         DBG("service %p type %d", service, type);
675
676         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
677                 do_ipv4 = TRUE;
678         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
679                 do_ipv6 = TRUE;
680         else
681                 do_ipv4 = do_ipv6 = TRUE;
682
683         __connman_service_nameserver_del_routes(service);
684
685         data = g_hash_table_lookup(gateway_hash, service);
686         if (data == NULL)
687                 return;
688
689         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL)
690                 set_default4 = data->ipv4_gateway->vpn;
691
692         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL)
693                 set_default6 = data->ipv6_gateway->vpn;
694
695         DBG("ipv4 gateway %s ipv6 gateway %s vpn %d/%d",
696                 data->ipv4_gateway ? data->ipv4_gateway->gateway : "<null>",
697                 data->ipv6_gateway ? data->ipv6_gateway->gateway : "<null>",
698                 set_default4, set_default6);
699
700         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
701                         data->ipv4_gateway->vpn == TRUE && data->index >= 0)
702                 connman_inet_del_host_route(data->index,
703                                                 data->ipv4_gateway->gateway);
704
705         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
706                         data->ipv6_gateway->vpn == TRUE && data->index >= 0)
707                 connman_inet_del_ipv6_host_route(data->index,
708                                                 data->ipv6_gateway->gateway);
709
710         __connman_service_nameserver_del_routes(service);
711
712         err = disable_gateway(data, type);
713
714         /*
715          * We remove the service from the hash only if all the gateway
716          * settings are to be removed.
717          */
718         if (do_ipv4 == do_ipv6 ||
719                 (data->ipv4_gateway != NULL && data->ipv6_gateway == NULL
720                         && do_ipv4 == TRUE) ||
721                 (data->ipv6_gateway != NULL && data->ipv4_gateway == NULL
722                         && do_ipv6 == TRUE)
723                 )
724                 g_hash_table_remove(gateway_hash, service);
725         else
726                 DBG("Not yet removing gw ipv4 %p/%d ipv6 %p/%d",
727                         data->ipv4_gateway, do_ipv4,
728                         data->ipv6_gateway, do_ipv6);
729
730         /* with vpn this will be called after the network was deleted,
731          * we need to call set_default here because we will not recieve any
732          * gateway delete notification.
733          * We hit the same issue if remove_gateway() fails.
734          */
735         if (set_default4 || set_default6 || err < 0) {
736                 data = find_default_gateway();
737                 if (data != NULL)
738                         set_default_gateway(data, type);
739         }
740 }
741
742 gboolean __connman_connection_update_gateway(void)
743 {
744         struct gateway_data *active_gateway, *default_gateway;
745         gboolean updated = FALSE;
746
747         if (gateway_hash == NULL)
748                 return updated;
749
750         active_gateway = find_active_gateway();
751
752         update_order();
753
754         default_gateway = find_default_gateway();
755
756         if (active_gateway && active_gateway != default_gateway) {
757                 updated = TRUE;
758
759                 if (active_gateway->ipv4_gateway)
760                         unset_default_gateway(active_gateway,
761                                         CONNMAN_IPCONFIG_TYPE_IPV4);
762
763                 if (active_gateway->ipv6_gateway)
764                         unset_default_gateway(active_gateway,
765                                         CONNMAN_IPCONFIG_TYPE_IPV6);
766
767                 __connman_service_downgrade_state(active_gateway->service);
768
769                 if (default_gateway) {
770                         if (default_gateway->ipv4_gateway)
771                                 set_default_gateway(default_gateway,
772                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
773
774                         if (default_gateway->ipv6_gateway)
775                                 set_default_gateway(default_gateway,
776                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
777                 }
778         }
779
780         return updated;
781 }
782
783 int __connman_connection_init(void)
784 {
785         int err;
786
787         DBG("");
788
789         gateway_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
790                                                         NULL, remove_gateway);
791
792         err = connman_rtnl_register(&connection_rtnl);
793         if (err < 0)
794                 connman_error("Failed to setup RTNL gateway driver");
795
796         return err;
797 }
798
799 void __connman_connection_cleanup(void)
800 {
801         GHashTableIter iter;
802         gpointer value, key;
803
804         DBG("");
805
806         connman_rtnl_unregister(&connection_rtnl);
807
808         g_hash_table_iter_init(&iter, gateway_hash);
809
810         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
811                 struct gateway_data *data = value;
812
813                 disable_gateway(data, CONNMAN_IPCONFIG_TYPE_ALL);
814         }
815
816         g_hash_table_destroy(gateway_hash);
817         gateway_hash = NULL;
818 }