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