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