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