Merge "Remove RW upgrade script" into tizen
[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                 data->ipv4_gateway->active = true;
464                 goto done;
465         }
466
467         if (do_ipv6 && data->ipv6_gateway &&
468                         g_strcmp0(data->ipv6_gateway->gateway,
469                                                         "::") == 0) {
470                 if (connman_inet_set_ipv6_gateway_interface(index) < 0)
471                         return;
472                 data->ipv6_gateway->active = true;
473                 goto done;
474         }
475
476         if (do_ipv6 && data->ipv6_gateway)
477                 status6 = __connman_inet_add_default_to_table(RT_TABLE_MAIN,
478                                         index, data->ipv6_gateway->gateway);
479
480         if (do_ipv4 && data->ipv4_gateway)
481                 status4 = __connman_inet_add_default_to_table(RT_TABLE_MAIN,
482                                         index, data->ipv4_gateway->gateway);
483
484         if (status4 < 0 || status6 < 0)
485                 return;
486
487 done:
488         __connman_service_indicate_default(data->service);
489 }
490
491 static void unset_default_gateway(struct gateway_data *data,
492                                 enum connman_ipconfig_type type)
493 {
494         int index;
495         bool do_ipv4 = false, do_ipv6 = false;
496
497         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
498                 do_ipv4 = true;
499         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
500                 do_ipv6 = true;
501         else
502                 do_ipv4 = do_ipv6 = true;
503
504         DBG("type %d gateway ipv4 %p ipv6 %p", type, data->ipv4_gateway,
505                                                 data->ipv6_gateway);
506
507         if (do_ipv4 && data->ipv4_gateway &&
508                                         data->ipv4_gateway->vpn) {
509                 connman_inet_clear_gateway_interface(data->index);
510                 data->ipv4_gateway->active = false;
511
512                 DBG("unset %p index %d vpn %s index %d phy %s",
513                         data, data->index, data->ipv4_gateway->vpn_ip,
514                         data->ipv4_gateway->vpn_phy_index,
515                         data->ipv4_gateway->vpn_phy_ip);
516
517                 return;
518         }
519
520         if (do_ipv6 && data->ipv6_gateway &&
521                                         data->ipv6_gateway->vpn) {
522                 connman_inet_clear_ipv6_gateway_interface(data->index);
523                 data->ipv6_gateway->active = false;
524
525                 DBG("unset %p index %d vpn %s index %d phy %s",
526                         data, data->index, data->ipv6_gateway->vpn_ip,
527                         data->ipv6_gateway->vpn_phy_index,
528                         data->ipv6_gateway->vpn_phy_ip);
529
530                 return;
531         }
532
533         index = __connman_service_get_index(data->service);
534
535         if (do_ipv4 && data->ipv4_gateway &&
536                         g_strcmp0(data->ipv4_gateway->gateway,
537                                                         "0.0.0.0") == 0) {
538                 connman_inet_clear_gateway_interface(index);
539                 data->ipv4_gateway->active = false;
540                 return;
541         }
542
543         if (do_ipv6 && data->ipv6_gateway &&
544                         g_strcmp0(data->ipv6_gateway->gateway,
545                                                         "::") == 0) {
546                 connman_inet_clear_ipv6_gateway_interface(index);
547                 data->ipv6_gateway->active = false;
548                 return;
549         }
550
551         if (do_ipv6 && data->ipv6_gateway)
552                 connman_inet_clear_ipv6_gateway_address(index,
553                                                 data->ipv6_gateway->gateway);
554
555         if (do_ipv4 && data->ipv4_gateway)
556                 connman_inet_clear_gateway_address(index,
557                                                 data->ipv4_gateway->gateway);
558 }
559
560 static struct gateway_data *find_default_gateway(void)
561 {
562         struct connman_service *service;
563
564         service = connman_service_get_default();
565         if (!service)
566                 return NULL;
567
568         return g_hash_table_lookup(gateway_hash, service);
569 }
570
571 static bool choose_default_gateway(struct gateway_data *data,
572                                         struct gateway_data *candidate)
573 {
574         bool downgraded = false;
575
576         /*
577          * If the current default is not active, then we mark
578          * this one as default. If the other one is already active
579          * we mark this one as non default.
580          */
581         if (data->ipv4_gateway && candidate->ipv4_gateway) {
582
583                 if (!candidate->ipv4_gateway->active) {
584                         DBG("ipv4 downgrading %p", candidate);
585                         unset_default_gateway(candidate,
586                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
587                 }
588
589                 if (candidate->ipv4_gateway->active &&
590                                 __connman_service_compare(candidate->service,
591                                                         data->service) < 0) {
592                         DBG("ipv4 downgrading this %p", data);
593                         unset_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV4);
594                         downgraded = true;
595                 }
596         }
597
598         if (data->ipv6_gateway && candidate->ipv6_gateway) {
599                 if (!candidate->ipv6_gateway->active) {
600                         DBG("ipv6 downgrading %p", candidate);
601                         unset_default_gateway(candidate,
602                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
603                 }
604
605                 if (candidate->ipv6_gateway->active &&
606                         __connman_service_compare(candidate->service,
607                                                 data->service) < 0) {
608                         DBG("ipv6 downgrading this %p", data);
609                         unset_default_gateway(data, 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         bool found = false;
624
625         DBG("index %d gateway %s", index, gateway);
626
627         config = find_gateway(index, gateway);
628         if (!config)
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)
640                 return;
641
642         if (data->default_checked)
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)) {
653                 struct gateway_data *candidate = value;
654
655                 if (candidate == data)
656                         continue;
657
658                 found = choose_default_gateway(data, candidate);
659                 if (found)
660                         break;
661         }
662
663         if (!found) {
664 #if defined TIZEN_EXT
665                 if (data->ipv4_gateway != NULL){
666                         set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV4);
667                         connman_check_proxy_setup_and_wispr_start(data->service);
668                 }
669 #else
670                 if (data->ipv4_gateway)
671                         set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV4);
672 #endif
673
674                 if (data->ipv6_gateway)
675                         set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV6);
676         }
677
678         data->default_checked = true;
679 }
680
681 static void remove_gateway(gpointer user_data)
682 {
683         struct gateway_data *data = user_data;
684
685         DBG("gateway ipv4 %p ipv6 %p", data->ipv4_gateway, data->ipv6_gateway);
686
687         if (data->ipv4_gateway) {
688                 g_free(data->ipv4_gateway->gateway);
689                 g_free(data->ipv4_gateway->vpn_ip);
690                 g_free(data->ipv4_gateway->vpn_phy_ip);
691                 g_free(data->ipv4_gateway);
692         }
693
694         if (data->ipv6_gateway) {
695                 g_free(data->ipv6_gateway->gateway);
696                 g_free(data->ipv6_gateway->vpn_ip);
697                 g_free(data->ipv6_gateway->vpn_phy_ip);
698                 g_free(data->ipv6_gateway);
699         }
700
701         connman_service_unref(data->service);
702
703         g_free(data);
704 }
705
706 static void connection_delgateway(int index, const char *gateway)
707 {
708         struct gateway_config *config;
709         struct gateway_data *data;
710
711         DBG("index %d gateway %s", index, gateway);
712
713         config = find_gateway(index, gateway);
714         if (config)
715                 config->active = false;
716
717         data = find_default_gateway();
718         if (data)
719                 set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_ALL);
720 }
721
722 static struct connman_rtnl connection_rtnl = {
723         .name           = "connection",
724         .newgateway     = connection_newgateway,
725         .delgateway     = connection_delgateway,
726 };
727
728 static struct gateway_data *find_active_gateway(void)
729 {
730         GHashTableIter iter;
731         gpointer value, key;
732
733         DBG("");
734
735         g_hash_table_iter_init(&iter, gateway_hash);
736
737         while (g_hash_table_iter_next(&iter, &key, &value)) {
738                 struct gateway_data *data = value;
739
740                 if (data->ipv4_gateway &&
741                                 data->ipv4_gateway->active)
742                         return data;
743
744                 if (data->ipv6_gateway &&
745                                 data->ipv6_gateway->active)
746                         return data;
747         }
748
749         return NULL;
750 }
751
752 static void add_host_route(int family, int index, const char *gateway,
753                         enum connman_service_type service_type)
754 {
755         switch (family) {
756         case AF_INET:
757                 if (g_strcmp0(gateway, "0.0.0.0") != 0) {
758                         /*
759                          * We must not set route to the phy dev gateway in
760                          * VPN link. The packets to VPN link might be routed
761                          * back to itself and not routed into phy link gateway.
762                          */
763                         if (service_type != CONNMAN_SERVICE_TYPE_VPN)
764                                 connman_inet_add_host_route(index, gateway,
765                                                                         NULL);
766                 } else {
767                         /*
768                          * Add host route to P-t-P link so that services can
769                          * be moved around and we can have some link to P-t-P
770                          * network (although those P-t-P links have limited
771                          * usage if default route is not directed to them)
772                          */
773                         char *dest;
774                         if (connman_inet_get_dest_addr(index, &dest) == 0) {
775                                 connman_inet_add_host_route(index, dest, NULL);
776                                 g_free(dest);
777                         }
778                 }
779                 break;
780
781         case AF_INET6:
782                 if (g_strcmp0(gateway, "::") != 0) {
783                         if (service_type != CONNMAN_SERVICE_TYPE_VPN)
784                                 connman_inet_add_ipv6_host_route(index,
785                                                                 gateway, NULL);
786                 } else {
787                         /* P-t-P link, add route to destination */
788                         char *dest;
789                         if (connman_inet_ipv6_get_dest_addr(index,
790                                                                 &dest) == 0) {
791                                 connman_inet_add_ipv6_host_route(index, dest,
792                                                                 NULL);
793                                 g_free(dest);
794                         }
795                 }
796                 break;
797         }
798 }
799
800 #if defined TIZEN_EXT
801 static bool __connman_service_is_not_cellular_internet_profile(
802                 struct connman_service *cellular)
803 {
804         char *suffix;
805         const char *path;
806         const char internet_suffix[] = "_1";
807         const char prepaid_internet_suffix[] = "_3";
808
809         if (connman_service_get_type(cellular) != CONNMAN_SERVICE_TYPE_CELLULAR)
810                 return FALSE;
811
812         path = __connman_service_get_path(cellular);
813
814         suffix = strrchr(path, '_');
815
816         if (g_strcmp0(suffix, internet_suffix) != 0 &&
817                         g_strcmp0(suffix, prepaid_internet_suffix) != 0) {
818                 DBG("not internet service profile: %s", path);
819                 return TRUE;
820         }
821
822         return FALSE;
823 }
824 #endif
825
826 int __connman_connection_gateway_add(struct connman_service *service,
827                                         const char *gateway,
828                                         enum connman_ipconfig_type type,
829                                         const char *peer)
830 {
831         struct gateway_data *active_gateway = NULL;
832         struct gateway_data *new_gateway = NULL;
833         enum connman_ipconfig_type type4 = CONNMAN_IPCONFIG_TYPE_UNKNOWN,
834                 type6 = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
835         enum connman_service_type service_type =
836                                         connman_service_get_type(service);
837         int index;
838
839         index = __connman_service_get_index(service);
840
841         /*
842          * If gateway is NULL, it's a point to point link and the default
843          * gateway for ipv4 is 0.0.0.0 and for ipv6 is ::, meaning the
844          * interface
845          */
846         if (!gateway && type == CONNMAN_IPCONFIG_TYPE_IPV4)
847                 gateway = "0.0.0.0";
848
849         if (!gateway && type == CONNMAN_IPCONFIG_TYPE_IPV6)
850                 gateway = "::";
851
852 #if defined TIZEN_EXT
853         if (__connman_service_is_not_cellular_internet_profile(service) == TRUE) {
854                 /* not internet service should not be default gateway */
855
856                 DBG("no internet service %p index %d gateway %s vpn ip %s type %d",
857                         service, index, gateway, peer, type);
858
859                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
860                         add_host_route(AF_INET, index, gateway, service_type);
861                         __connman_service_nameserver_add_routes(service, gateway);
862                         type4 = CONNMAN_IPCONFIG_TYPE_IPV4;
863                 }
864
865                 if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
866                         add_host_route(AF_INET6, index, gateway, service_type);
867                         __connman_service_nameserver_add_routes(service, gateway);
868                         type6 = CONNMAN_IPCONFIG_TYPE_IPV6;
869                 }
870
871                 goto done;
872         }
873 #endif
874         DBG("service %p index %d gateway %s vpn ip %s type %d",
875                 service, index, gateway, peer, type);
876
877         new_gateway = add_gateway(service, index, gateway, type);
878         if (!new_gateway)
879                 return -EINVAL;
880
881         active_gateway = find_active_gateway();
882
883         DBG("active %p index %d new %p", active_gateway,
884                 active_gateway ? active_gateway->index : -1, new_gateway);
885
886         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
887                                 new_gateway->ipv4_gateway) {
888                 add_host_route(AF_INET, index, gateway, service_type);
889                 __connman_service_nameserver_add_routes(service,
890                                         new_gateway->ipv4_gateway->gateway);
891                 type4 = CONNMAN_IPCONFIG_TYPE_IPV4;
892         }
893
894         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
895                                 new_gateway->ipv6_gateway) {
896                 add_host_route(AF_INET6, index, gateway, service_type);
897                 __connman_service_nameserver_add_routes(service,
898                                         new_gateway->ipv6_gateway->gateway);
899                 type6 = CONNMAN_IPCONFIG_TYPE_IPV6;
900         }
901
902         if (service_type == CONNMAN_SERVICE_TYPE_VPN) {
903
904                 set_vpn_routes(new_gateway, service, gateway, type, peer,
905                                                         active_gateway);
906
907         } else {
908                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
909                                         new_gateway->ipv4_gateway)
910                         new_gateway->ipv4_gateway->vpn = false;
911
912                 if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
913                                         new_gateway->ipv6_gateway)
914                         new_gateway->ipv6_gateway->vpn = false;
915         }
916
917         if (!active_gateway) {
918 #if defined TIZEN_EXT
919                 if(new_gateway->ipv4_gateway)
920                         DBG("ConnMan, Set default gateway[%s], active[%d]",
921                                 new_gateway->ipv4_gateway->gateway,
922                                 new_gateway->ipv4_gateway->active);
923 #endif
924                 set_default_gateway(new_gateway, type);
925                 goto done;
926         }
927
928         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
929                                 new_gateway->ipv4_gateway &&
930                                 new_gateway->ipv4_gateway->vpn) {
931                 if (!__connman_service_is_split_routing(new_gateway->service))
932                         connman_inet_clear_gateway_address(
933                                         active_gateway->index,
934                                         active_gateway->ipv4_gateway->gateway);
935         }
936
937         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
938                                 new_gateway->ipv6_gateway &&
939                                 new_gateway->ipv6_gateway->vpn) {
940                 if (!__connman_service_is_split_routing(new_gateway->service))
941                         connman_inet_clear_ipv6_gateway_address(
942                                         active_gateway->index,
943                                         active_gateway->ipv6_gateway->gateway);
944         }
945
946 done:
947         if (type4 == CONNMAN_IPCONFIG_TYPE_IPV4)
948                 __connman_service_ipconfig_indicate_state(service,
949                                                 CONNMAN_SERVICE_STATE_READY,
950                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
951
952         if (type6 == CONNMAN_IPCONFIG_TYPE_IPV6)
953                 __connman_service_ipconfig_indicate_state(service,
954                                                 CONNMAN_SERVICE_STATE_READY,
955                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
956         return 0;
957 }
958
959 void __connman_connection_gateway_remove(struct connman_service *service,
960                                         enum connman_ipconfig_type type)
961 {
962         struct gateway_data *data = NULL;
963         bool set_default4 = false, set_default6 = false;
964         bool do_ipv4 = false, do_ipv6 = false;
965         int err;
966
967         DBG("service %p type %d", service, type);
968
969         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
970                 do_ipv4 = true;
971         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
972                 do_ipv6 = true;
973         else
974                 do_ipv4 = do_ipv6 = true;
975
976         __connman_service_nameserver_del_routes(service, type);
977
978         data = g_hash_table_lookup(gateway_hash, service);
979         if (!data)
980                 return;
981
982         if (do_ipv4 && data->ipv4_gateway)
983                 set_default4 = data->ipv4_gateway->vpn;
984
985         if (do_ipv6 && data->ipv6_gateway)
986                 set_default6 = data->ipv6_gateway->vpn;
987
988         DBG("ipv4 gateway %s ipv6 gateway %s vpn %d/%d",
989                 data->ipv4_gateway ? data->ipv4_gateway->gateway : "<null>",
990                 data->ipv6_gateway ? data->ipv6_gateway->gateway : "<null>",
991                 set_default4, set_default6);
992
993         if (do_ipv4 && data->ipv4_gateway &&
994                         data->ipv4_gateway->vpn && data->index >= 0)
995                 connman_inet_del_host_route(data->ipv4_gateway->vpn_phy_index,
996                                                 data->ipv4_gateway->gateway);
997
998         if (do_ipv6 && data->ipv6_gateway &&
999                         data->ipv6_gateway->vpn && data->index >= 0)
1000                 connman_inet_del_ipv6_host_route(
1001                                         data->ipv6_gateway->vpn_phy_index,
1002                                                 data->ipv6_gateway->gateway);
1003
1004         err = disable_gateway(data, type);
1005
1006         /*
1007          * We remove the service from the hash only if all the gateway
1008          * settings are to be removed.
1009          */
1010         if (do_ipv4 == do_ipv6 ||
1011                 (data->ipv4_gateway && !data->ipv6_gateway
1012                         && do_ipv4) ||
1013                 (data->ipv6_gateway && !data->ipv4_gateway
1014                         && do_ipv6)) {
1015                 g_hash_table_remove(gateway_hash, service);
1016         } else
1017                 DBG("Not yet removing gw ipv4 %p/%d ipv6 %p/%d",
1018                         data->ipv4_gateway, do_ipv4,
1019                         data->ipv6_gateway, do_ipv6);
1020
1021         /* with vpn this will be called after the network was deleted,
1022          * we need to call set_default here because we will not recieve any
1023          * gateway delete notification.
1024          * We hit the same issue if remove_gateway() fails.
1025          */
1026         if (set_default4 || set_default6 || err < 0) {
1027                 data = find_default_gateway();
1028                 if (data)
1029                         set_default_gateway(data, type);
1030         }
1031 }
1032
1033 bool __connman_connection_update_gateway(void)
1034 {
1035         struct gateway_data *default_gateway;
1036         bool updated = false;
1037         GHashTableIter iter;
1038         gpointer value, key;
1039 #if defined TIZEN_EXT
1040         static struct gateway_data *old_default = NULL;
1041 #endif
1042
1043         if (!gateway_hash)
1044                 return updated;
1045
1046         default_gateway = find_default_gateway();
1047
1048         DBG("default %p", default_gateway);
1049
1050         /*
1051          * There can be multiple active gateways so we need to
1052          * check them all.
1053          */
1054         g_hash_table_iter_init(&iter, gateway_hash);
1055
1056         while (g_hash_table_iter_next(&iter, &key, &value)) {
1057                 struct gateway_data *active_gateway = value;
1058
1059                 if (active_gateway == default_gateway)
1060                         continue;
1061
1062                 if (active_gateway->ipv4_gateway &&
1063                                 active_gateway->ipv4_gateway->active) {
1064
1065                         unset_default_gateway(active_gateway,
1066                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
1067                         updated = true;
1068                 }
1069
1070                 if (active_gateway->ipv6_gateway &&
1071                                 active_gateway->ipv6_gateway->active) {
1072
1073                         unset_default_gateway(active_gateway,
1074                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
1075                         updated = true;
1076                 }
1077         }
1078
1079 #if defined TIZEN_EXT
1080         if (updated == false && old_default != default_gateway) {
1081                 updated = true;
1082                 old_default = default_gateway;
1083         }
1084 #endif
1085         /*
1086          * Set default gateway if it has been updated or if it has not been
1087          * set as active yet.
1088          */
1089         if (default_gateway) {
1090                 if (default_gateway->ipv4_gateway &&
1091                         (updated || !default_gateway->ipv4_gateway->active))
1092                         set_default_gateway(default_gateway,
1093                                         CONNMAN_IPCONFIG_TYPE_IPV4);
1094
1095                 if (default_gateway->ipv6_gateway &&
1096                         (updated || !default_gateway->ipv6_gateway->active))
1097                         set_default_gateway(default_gateway,
1098                                         CONNMAN_IPCONFIG_TYPE_IPV6);
1099         }
1100
1101         return updated;
1102 }
1103
1104 int __connman_connection_get_vpn_index(int phy_index)
1105 {
1106         GHashTableIter iter;
1107         gpointer value, key;
1108
1109         g_hash_table_iter_init(&iter, gateway_hash);
1110
1111         while (g_hash_table_iter_next(&iter, &key, &value)) {
1112                 struct gateway_data *data = value;
1113
1114                 if (data->ipv4_gateway &&
1115                                 data->ipv4_gateway->vpn_phy_index == phy_index)
1116                         return data->index;
1117
1118                 if (data->ipv6_gateway &&
1119                                 data->ipv6_gateway->vpn_phy_index == phy_index)
1120                         return data->index;
1121         }
1122
1123         return -1;
1124 }
1125
1126 int __connman_connection_init(void)
1127 {
1128         int err;
1129
1130         DBG("");
1131
1132         gateway_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1133                                                         NULL, remove_gateway);
1134
1135         err = connman_rtnl_register(&connection_rtnl);
1136         if (err < 0)
1137                 connman_error("Failed to setup RTNL gateway driver");
1138
1139         return err;
1140 }
1141
1142 void __connman_connection_cleanup(void)
1143 {
1144         GHashTableIter iter;
1145         gpointer value, key;
1146
1147         DBG("");
1148
1149         connman_rtnl_unregister(&connection_rtnl);
1150
1151         g_hash_table_iter_init(&iter, gateway_hash);
1152
1153         while (g_hash_table_iter_next(&iter, &key, &value)) {
1154                 struct gateway_data *data = value;
1155
1156                 disable_gateway(data, CONNMAN_IPCONFIG_TYPE_ALL);
1157         }
1158
1159         g_hash_table_destroy(gateway_hash);
1160         gateway_hash = NULL;
1161 }