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