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