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