connection: Set additional point-to-point route
[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 static void add_host_route(int family, int index, const char *gateway)
729 {
730         switch (family) {
731         case AF_INET:
732                 if (g_strcmp0(gateway, "0.0.0.0") != 0)
733                         connman_inet_add_host_route(index, gateway, NULL);
734                 else {
735                         /*
736                          * Add host route to P-t-P link so that services can
737                          * be moved around and we can have some link to P-t-P
738                          * network (although those P-t-P links have limited
739                          * usage if default route is not directed to them)
740                          */
741                         char *dest;
742                         if (connman_inet_get_dest_addr(index, &dest) == 0) {
743                                 connman_inet_add_host_route(index, dest, NULL);
744                                 g_free(dest);
745                         }
746                 }
747                 break;
748
749         case AF_INET6:
750                 if (g_strcmp0(gateway, "::") != 0)
751                         connman_inet_add_ipv6_host_route(index, gateway, NULL);
752                 else {
753                         /* P-t-P link, add route to destination */
754                         char *dest;
755                         if (connman_inet_ipv6_get_dest_addr(index,
756                                                                 &dest) == 0) {
757                                 connman_inet_add_ipv6_host_route(index, dest,
758                                                                 NULL);
759                                 g_free(dest);
760                         }
761                 }
762                 break;
763         }
764 }
765
766 int __connman_connection_gateway_add(struct connman_service *service,
767                                         const char *gateway,
768                                         enum connman_ipconfig_type type,
769                                         const char *peer)
770 {
771         struct gateway_data *active_gateway = NULL;
772         struct gateway_data *new_gateway = NULL;
773         enum connman_ipconfig_type type4 = CONNMAN_IPCONFIG_TYPE_UNKNOWN,
774                 type6 = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
775         int index;
776
777         index = __connman_service_get_index(service);
778
779         /*
780          * If gateway is NULL, it's a point to point link and the default
781          * gateway for ipv4 is 0.0.0.0 and for ipv6 is ::, meaning the
782          * interface
783          */
784         if (gateway == NULL && type == CONNMAN_IPCONFIG_TYPE_IPV4)
785                 gateway = "0.0.0.0";
786
787         if (gateway == NULL && type == CONNMAN_IPCONFIG_TYPE_IPV6)
788                 gateway = "::";
789
790         DBG("service %p index %d gateway %s vpn ip %s type %d",
791                 service, index, gateway, peer, type);
792
793         new_gateway = add_gateway(service, index, gateway, type);
794         if (new_gateway == NULL)
795                 return -EINVAL;
796
797         active_gateway = find_active_gateway();
798
799         DBG("active %p index %d new %p", active_gateway,
800                 active_gateway ? active_gateway->index : -1, new_gateway);
801
802         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
803                                 new_gateway->ipv4_gateway != NULL) {
804                 add_host_route(AF_INET, index, gateway);
805                 __connman_service_nameserver_add_routes(service,
806                                         new_gateway->ipv4_gateway->gateway);
807                 type4 = CONNMAN_IPCONFIG_TYPE_IPV4;
808         }
809
810         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
811                                 new_gateway->ipv6_gateway != NULL) {
812                 add_host_route(AF_INET6, index, gateway);
813                 __connman_service_nameserver_add_routes(service,
814                                         new_gateway->ipv6_gateway->gateway);
815                 type6 = CONNMAN_IPCONFIG_TYPE_IPV6;
816         }
817
818         if (connman_service_get_type(service) == CONNMAN_SERVICE_TYPE_VPN) {
819                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
820                                         new_gateway->ipv4_gateway != NULL)
821                         set_vpn_routes(new_gateway->ipv4_gateway,
822                                 service, gateway, type, peer);
823
824                 else if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
825                                         new_gateway->ipv6_gateway != NULL)
826                         set_vpn_routes(new_gateway->ipv6_gateway,
827                                 service, gateway, type, peer);
828
829         } else {
830                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
831                                         new_gateway->ipv4_gateway != NULL)
832                         new_gateway->ipv4_gateway->vpn = FALSE;
833
834                 if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
835                                         new_gateway->ipv6_gateway != NULL)
836                         new_gateway->ipv6_gateway->vpn = FALSE;
837         }
838
839         if (active_gateway == NULL) {
840                 set_default_gateway(new_gateway, type);
841                 goto done;
842         }
843
844         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
845                                 new_gateway->ipv4_gateway != NULL &&
846                                 new_gateway->ipv4_gateway->vpn == TRUE) {
847                 if (__connman_service_is_split_routing(new_gateway->service) ==
848                                                                         FALSE)
849                         connman_inet_clear_gateway_address(
850                                         active_gateway->index,
851                                         active_gateway->ipv4_gateway->gateway);
852         }
853
854         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
855                                 new_gateway->ipv6_gateway != NULL &&
856                                 new_gateway->ipv6_gateway->vpn == TRUE) {
857                 if (__connman_service_is_split_routing(new_gateway->service) ==
858                                                                         FALSE)
859                         connman_inet_clear_ipv6_gateway_address(
860                                         active_gateway->index,
861                                         active_gateway->ipv6_gateway->gateway);
862         }
863
864 done:
865         if (type4 == CONNMAN_IPCONFIG_TYPE_IPV4)
866                 __connman_service_ipconfig_indicate_state(service,
867                                                 CONNMAN_SERVICE_STATE_READY,
868                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
869
870         if (type6 == CONNMAN_IPCONFIG_TYPE_IPV6)
871                 __connman_service_ipconfig_indicate_state(service,
872                                                 CONNMAN_SERVICE_STATE_READY,
873                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
874         return 0;
875 }
876
877 void __connman_connection_gateway_remove(struct connman_service *service,
878                                         enum connman_ipconfig_type type)
879 {
880         struct gateway_data *data = NULL;
881         gboolean set_default4 = FALSE, set_default6 = FALSE;
882         int do_ipv4 = FALSE, do_ipv6 = FALSE;
883         int err;
884
885         DBG("service %p type %d", service, type);
886
887         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
888                 do_ipv4 = TRUE;
889         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
890                 do_ipv6 = TRUE;
891         else
892                 do_ipv4 = do_ipv6 = TRUE;
893
894         __connman_service_nameserver_del_routes(service, type);
895
896         data = g_hash_table_lookup(gateway_hash, service);
897         if (data == NULL)
898                 return;
899
900         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL)
901                 set_default4 = data->ipv4_gateway->vpn;
902
903         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL)
904                 set_default6 = data->ipv6_gateway->vpn;
905
906         DBG("ipv4 gateway %s ipv6 gateway %s vpn %d/%d",
907                 data->ipv4_gateway ? data->ipv4_gateway->gateway : "<null>",
908                 data->ipv6_gateway ? data->ipv6_gateway->gateway : "<null>",
909                 set_default4, set_default6);
910
911         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
912                         data->ipv4_gateway->vpn == TRUE && data->index >= 0)
913                 connman_inet_del_host_route(data->index,
914                                                 data->ipv4_gateway->gateway);
915
916         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
917                         data->ipv6_gateway->vpn == TRUE && data->index >= 0)
918                 connman_inet_del_ipv6_host_route(data->index,
919                                                 data->ipv6_gateway->gateway);
920
921         err = disable_gateway(data, type);
922
923         /*
924          * We remove the service from the hash only if all the gateway
925          * settings are to be removed.
926          */
927         if (do_ipv4 == do_ipv6 ||
928                 (data->ipv4_gateway != NULL && data->ipv6_gateway == NULL
929                         && do_ipv4 == TRUE) ||
930                 (data->ipv6_gateway != NULL && data->ipv4_gateway == NULL
931                         && do_ipv6 == TRUE)
932                 ) {
933                 connman_service_unref(service);
934                 g_hash_table_remove(gateway_hash, service);
935         } else
936                 DBG("Not yet removing gw ipv4 %p/%d ipv6 %p/%d",
937                         data->ipv4_gateway, do_ipv4,
938                         data->ipv6_gateway, do_ipv6);
939
940         /* with vpn this will be called after the network was deleted,
941          * we need to call set_default here because we will not recieve any
942          * gateway delete notification.
943          * We hit the same issue if remove_gateway() fails.
944          */
945         if (set_default4 || set_default6 || err < 0) {
946                 data = find_default_gateway();
947                 if (data != NULL)
948                         set_default_gateway(data, type);
949         }
950 }
951
952 gboolean __connman_connection_update_gateway(void)
953 {
954         struct gateway_data *default_gateway;
955         gboolean updated = FALSE;
956         GHashTableIter iter;
957         gpointer value, key;
958
959         if (gateway_hash == NULL)
960                 return updated;
961
962         update_order();
963
964         default_gateway = find_default_gateway();
965
966         __connman_service_update_ordering();
967
968         DBG("default %p", default_gateway);
969
970         /*
971          * There can be multiple active gateways so we need to
972          * check them all.
973          */
974         g_hash_table_iter_init(&iter, gateway_hash);
975
976         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
977                 struct gateway_data *active_gateway = value;
978
979                 if (active_gateway == default_gateway)
980                         continue;
981
982                 if (active_gateway->ipv4_gateway != NULL &&
983                                 active_gateway->ipv4_gateway->active == TRUE) {
984
985                         unset_default_gateway(active_gateway,
986                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
987                         updated = TRUE;
988                 }
989
990                 if (active_gateway->ipv6_gateway != NULL &&
991                                 active_gateway->ipv6_gateway->active == TRUE) {
992
993                         unset_default_gateway(active_gateway,
994                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
995                         updated = TRUE;
996                 }
997         }
998
999         if (updated && default_gateway != NULL) {
1000                 if (default_gateway->ipv4_gateway)
1001                         set_default_gateway(default_gateway,
1002                                         CONNMAN_IPCONFIG_TYPE_IPV4);
1003
1004                 if (default_gateway->ipv6_gateway)
1005                         set_default_gateway(default_gateway,
1006                                         CONNMAN_IPCONFIG_TYPE_IPV6);
1007         }
1008
1009         return updated;
1010 }
1011
1012 int __connman_connection_init(void)
1013 {
1014         int err;
1015
1016         DBG("");
1017
1018         gateway_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1019                                                         NULL, remove_gateway);
1020
1021         err = connman_rtnl_register(&connection_rtnl);
1022         if (err < 0)
1023                 connman_error("Failed to setup RTNL gateway driver");
1024
1025         return err;
1026 }
1027
1028 void __connman_connection_cleanup(void)
1029 {
1030         GHashTableIter iter;
1031         gpointer value, key;
1032
1033         DBG("");
1034
1035         connman_rtnl_unregister(&connection_rtnl);
1036
1037         g_hash_table_iter_init(&iter, gateway_hash);
1038
1039         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1040                 struct gateway_data *data = value;
1041
1042                 disable_gateway(data, CONNMAN_IPCONFIG_TYPE_ALL);
1043         }
1044
1045         g_hash_table_destroy(gateway_hash);
1046         gateway_hash = NULL;
1047 }