network: Let the gateway code handle the READY transition
[platform/upstream/connman.git] / src / connection.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *  Copyright (C) 2011  BMW Car IT GmbH. All rights reserved.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 2 as
10  *  published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <errno.h>
28 #include <string.h>
29 #include <net/if.h>
30
31 #include <gdbus.h>
32
33 #include "connman.h"
34
35 struct gateway_config {
36         gboolean active;
37         char *gateway;
38
39         /* VPN extra data */
40         gboolean vpn;
41         char *vpn_ip;
42         int vpn_phy_index;
43 };
44
45 struct gateway_data {
46         int index;
47         struct connman_service *service;
48         unsigned int order;
49         struct gateway_config *ipv4_gateway;
50         struct gateway_config *ipv6_gateway;
51 };
52
53 static GHashTable *gateway_hash = NULL;
54
55 static struct gateway_config *find_gateway(int index, const char *gateway)
56 {
57         GHashTableIter iter;
58         gpointer value, key;
59
60         if (gateway == NULL)
61                 return NULL;
62
63         g_hash_table_iter_init(&iter, gateway_hash);
64
65         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
66                 struct gateway_data *data = value;
67
68                 if (data->ipv4_gateway != NULL && data->index == index &&
69                                 g_str_equal(data->ipv4_gateway->gateway,
70                                         gateway) == TRUE)
71                         return data->ipv4_gateway;
72
73                 if (data->ipv6_gateway != NULL && data->index == index &&
74                                 g_str_equal(data->ipv6_gateway->gateway,
75                                         gateway) == TRUE)
76                         return data->ipv6_gateway;
77         }
78
79         return NULL;
80 }
81
82 static int del_routes(struct gateway_data *data,
83                         enum connman_ipconfig_type type)
84 {
85         int status4 = 0, status6 = 0;
86         int do_ipv4 = FALSE, do_ipv6 = FALSE;
87
88         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
89                 do_ipv4 = TRUE;
90         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
91                 do_ipv6 = TRUE;
92         else
93                 do_ipv4 = do_ipv6 = TRUE;
94
95         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL) {
96                 if (data->ipv4_gateway->vpn == TRUE) {
97                         if (data->ipv4_gateway->vpn_phy_index >= 0)
98                                 connman_inet_del_host_route(
99                                         data->ipv4_gateway->vpn_phy_index,
100                                         data->ipv4_gateway->gateway);
101
102                         status4 = connman_inet_clear_gateway_address(
103                                                 data->index,
104                                                 data->ipv4_gateway->vpn_ip);
105
106                 } else if (g_strcmp0(data->ipv4_gateway->gateway,
107                                                         "0.0.0.0") == 0) {
108                         status4 = connman_inet_clear_gateway_interface(
109                                                                 data->index);
110                 } else {
111                         connman_inet_del_host_route(data->index,
112                                                 data->ipv4_gateway->gateway);
113                         status4 = connman_inet_clear_gateway_address(
114                                                 data->index,
115                                                 data->ipv4_gateway->gateway);
116                 }
117         }
118
119         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL) {
120                 if (data->ipv6_gateway->vpn == TRUE) {
121                         if (data->ipv6_gateway->vpn_phy_index >= 0)
122                                 connman_inet_del_host_route(
123                                         data->ipv6_gateway->vpn_phy_index,
124                                         data->ipv6_gateway->gateway);
125
126                         status6 = connman_inet_clear_ipv6_gateway_address(
127                                                 data->index,
128                                                 data->ipv6_gateway->vpn_ip);
129
130                 } else if (g_strcmp0(data->ipv6_gateway->gateway, "::") == 0) {
131                         status6 = connman_inet_clear_ipv6_gateway_interface(
132                                                                 data->index);
133                 } else {
134                         connman_inet_del_ipv6_host_route(data->index,
135                                                 data->ipv6_gateway->gateway);
136                         status6 = connman_inet_clear_ipv6_gateway_address(
137                                                 data->index,
138                                                 data->ipv6_gateway->gateway);
139                 }
140         }
141
142         return (status4 < 0 ? status4 : status6);
143 }
144
145 static int disable_gateway(struct gateway_data *data,
146                         enum connman_ipconfig_type type)
147 {
148         gboolean active = FALSE;
149
150         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
151                 if (data->ipv4_gateway != NULL)
152                         active = data->ipv4_gateway->active;
153         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
154                 if (data->ipv6_gateway != NULL)
155                         active = data->ipv6_gateway->active;
156         } else
157                 active = TRUE;
158
159         DBG("type %d active %d", type, active);
160
161         if (active == TRUE)
162                 return del_routes(data, type);
163
164         return 0;
165 }
166
167 static struct gateway_data *add_gateway(struct connman_service *service,
168                                         int index, const char *gateway,
169                                         enum connman_ipconfig_type type)
170 {
171         struct gateway_data *data, *old;
172         struct gateway_config *config;
173
174         if (gateway == NULL || strlen(gateway) == 0)
175                 return NULL;
176
177         data = g_try_new0(struct gateway_data, 1);
178         if (data == NULL)
179                 return NULL;
180
181         data->index = index;
182
183         config = g_try_new0(struct gateway_config, 1);
184         if (config == NULL) {
185                 g_free(data);
186                 return NULL;
187         }
188
189         config->gateway = g_strdup(gateway);
190         config->vpn_ip = NULL;
191         config->vpn = FALSE;
192         config->vpn_phy_index = -1;
193         config->active = FALSE;
194
195         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
196                 data->ipv4_gateway = config;
197         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
198                 data->ipv6_gateway = config;
199         else {
200                 g_free(config->gateway);
201                 g_free(config);
202                 g_free(data);
203                 return NULL;
204         }
205
206         data->service = service;
207
208         data->order = __connman_service_get_order(service);
209
210         /*
211          * If the service is already in the hash, then we
212          * must not replace it blindly but disable the gateway
213          * of the type we are replacing and take the other type
214          * from old gateway settings.
215          */
216         old = g_hash_table_lookup(gateway_hash, service);
217         if (old != NULL) {
218                 DBG("Replacing gw %p ipv4 %p ipv6 %p", old,
219                         old->ipv4_gateway, old->ipv6_gateway);
220                 disable_gateway(old, type);
221                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
222                         data->ipv6_gateway = old->ipv6_gateway;
223                         old->ipv6_gateway = NULL;
224                 } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
225                         data->ipv4_gateway = old->ipv4_gateway;
226                         old->ipv4_gateway = NULL;
227                 }
228         }
229
230         g_hash_table_replace(gateway_hash, service, data);
231
232         return data;
233 }
234
235 static void connection_newgateway(int index, const char *gateway)
236 {
237         struct gateway_config *config;
238
239         DBG("index %d gateway %s", index, gateway);
240
241         config = find_gateway(index, gateway);
242         if (config == NULL)
243                 return;
244
245         config->active = TRUE;
246 }
247
248 static void set_default_gateway(struct gateway_data *data,
249                                 enum connman_ipconfig_type type)
250 {
251         int index;
252         int status4 = 0, status6 = 0;
253         int do_ipv4 = FALSE, do_ipv6 = FALSE;
254
255         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
256                 do_ipv4 = TRUE;
257         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
258                 do_ipv6 = TRUE;
259         else
260                 do_ipv4 = do_ipv6 = TRUE;
261
262         DBG("type %d gateway ipv4 %p ipv6 %p", type, data->ipv4_gateway,
263                                                 data->ipv6_gateway);
264
265         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
266                                         data->ipv4_gateway->vpn == TRUE) {
267                 connman_inet_set_gateway_address(data->index,
268                                                 data->ipv4_gateway->vpn_ip);
269                 data->ipv4_gateway->active = TRUE;
270
271                 __connman_service_indicate_default(data->service);
272
273                 return;
274         }
275
276         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
277                                         data->ipv6_gateway->vpn == TRUE) {
278                 connman_inet_set_ipv6_gateway_address(data->index,
279                                                 data->ipv6_gateway->vpn_ip);
280                 data->ipv6_gateway->active = TRUE;
281
282                 __connman_service_indicate_default(data->service);
283
284                 return;
285         }
286
287         index = __connman_service_get_index(data->service);
288
289         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
290                         g_strcmp0(data->ipv4_gateway->gateway,
291                                                         "0.0.0.0") == 0) {
292                 if (connman_inet_set_gateway_interface(index) < 0)
293                         return;
294                 goto done;
295         }
296
297         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
298                         g_strcmp0(data->ipv6_gateway->gateway,
299                                                         "::") == 0) {
300                 if (connman_inet_set_ipv6_gateway_interface(index) < 0)
301                         return;
302                 goto done;
303         }
304
305         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL)
306                 status6 = connman_inet_set_ipv6_gateway_address(index,
307                                                 data->ipv6_gateway->gateway);
308
309         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL)
310                 status4 = connman_inet_set_gateway_address(index,
311                                                 data->ipv4_gateway->gateway);
312
313         if (status4 < 0 || status6 < 0)
314                 return;
315
316 done:
317         __connman_service_indicate_default(data->service);
318 }
319
320 static struct gateway_data *find_default_gateway(void)
321 {
322         struct gateway_data *found = NULL;
323         unsigned int order = 0;
324         GHashTableIter iter;
325         gpointer value, key;
326
327         g_hash_table_iter_init(&iter, gateway_hash);
328
329         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
330                 struct gateway_data *data = value;
331
332                 if (found == NULL || data->order > order) {
333                         found = data;
334                         order = data->order;
335                 }
336         }
337
338         return found;
339 }
340
341 static void remove_gateway(gpointer user_data)
342 {
343         struct gateway_data *data = user_data;
344
345         DBG("gateway ipv4 %p ipv6 %p", data->ipv4_gateway, data->ipv6_gateway);
346
347         if (data->ipv4_gateway != NULL) {
348                 g_free(data->ipv4_gateway->gateway);
349                 g_free(data->ipv4_gateway->vpn_ip);
350                 g_free(data->ipv4_gateway);
351         }
352
353         if (data->ipv6_gateway != NULL) {
354                 g_free(data->ipv6_gateway->gateway);
355                 g_free(data->ipv6_gateway->vpn_ip);
356                 g_free(data->ipv6_gateway);
357         }
358
359         g_free(data);
360 }
361
362 static void connection_delgateway(int index, const char *gateway)
363 {
364         struct gateway_config *config;
365         struct gateway_data *data;
366
367         DBG("index %d gateway %s", index, gateway);
368
369         config = find_gateway(index, gateway);
370         if (config != NULL)
371                 config->active = FALSE;
372
373         data = find_default_gateway();
374         if (data != NULL)
375                 set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_ALL);
376 }
377
378 static struct connman_rtnl connection_rtnl = {
379         .name           = "connection",
380         .newgateway     = connection_newgateway,
381         .delgateway     = connection_delgateway,
382 };
383
384 static struct gateway_data *find_active_gateway(void)
385 {
386         GHashTableIter iter;
387         gpointer value, key;
388
389         DBG("");
390
391         g_hash_table_iter_init(&iter, gateway_hash);
392
393         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
394                 struct gateway_data *data = value;
395
396                 if (data->ipv4_gateway != NULL &&
397                                 data->ipv4_gateway->active == TRUE)
398                         return data;
399
400                 if (data->ipv6_gateway != NULL &&
401                                 data->ipv6_gateway->active == TRUE)
402                         return data;
403         }
404
405         return NULL;
406 }
407
408 static void update_order(void)
409 {
410         GHashTableIter iter;
411         gpointer value, key;
412
413         DBG("");
414
415         g_hash_table_iter_init(&iter, gateway_hash);
416
417         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
418                 struct gateway_data *data = value;
419
420                 data->order = __connman_service_get_order(data->service);
421         }
422 }
423
424 void __connman_connection_gateway_activate(struct connman_service *service,
425                                         enum connman_ipconfig_type type)
426 {
427         struct gateway_data *data = NULL;
428
429         data = g_hash_table_lookup(gateway_hash, service);
430         if (data == NULL)
431                 return;
432
433         DBG("gateway %p/%p type %d", data->ipv4_gateway,
434                                         data->ipv6_gateway, type);
435
436         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
437                 data->ipv4_gateway->active = TRUE;
438         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
439                 data->ipv6_gateway->active = TRUE;
440 }
441
442 int __connman_connection_gateway_add(struct connman_service *service,
443                                         const char *gateway,
444                                         enum connman_ipconfig_type type,
445                                         const char *peer)
446 {
447         struct gateway_data *active_gateway = NULL;
448         struct gateway_data *new_gateway = NULL;
449         int index;
450
451         index = __connman_service_get_index(service);
452
453         DBG("service %p index %d gateway %s vpn ip %s type %d",
454                 service, index, gateway, peer, type);
455
456         active_gateway = find_active_gateway();
457         new_gateway = add_gateway(service, index, gateway, type);
458         if (new_gateway == NULL)
459                 return -EINVAL;
460
461         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
462                         new_gateway->ipv6_gateway != NULL &&
463                         g_strcmp0(new_gateway->ipv6_gateway->gateway,
464                                                                 "::") != 0)
465                 connman_inet_add_ipv6_host_route(index,
466                                         new_gateway->ipv6_gateway->gateway,
467                                         NULL);
468
469         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
470                         new_gateway->ipv4_gateway != NULL &&
471                         g_strcmp0(new_gateway->ipv4_gateway->gateway,
472                                                         "0.0.0.0") != 0)
473                 connman_inet_add_host_route(index,
474                                         new_gateway->ipv4_gateway->gateway,
475                                         NULL);
476
477         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
478                                 new_gateway->ipv4_gateway != NULL) {
479                 __connman_service_nameserver_add_routes(service,
480                                         new_gateway->ipv4_gateway->gateway);
481                 __connman_service_ipconfig_indicate_state(service,
482                                                 CONNMAN_SERVICE_STATE_READY,
483                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
484         }
485
486         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
487                                 new_gateway->ipv6_gateway != NULL) {
488                 __connman_service_nameserver_add_routes(service,
489                                         new_gateway->ipv6_gateway->gateway);
490                 __connman_service_ipconfig_indicate_state(service,
491                                                 CONNMAN_SERVICE_STATE_READY,
492                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
493         }
494
495         if (connman_service_get_type(service) == CONNMAN_SERVICE_TYPE_VPN) {
496                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
497                                         new_gateway->ipv4_gateway != NULL) {
498                         new_gateway->ipv4_gateway->vpn = TRUE;
499                         if (peer != NULL)
500                                 new_gateway->ipv4_gateway->vpn_ip =
501                                                         g_strdup(peer);
502                         else if (gateway != NULL)
503                                 new_gateway->ipv4_gateway->vpn_ip =
504                                                         g_strdup(gateway);
505                         if (active_gateway)
506                                 new_gateway->ipv4_gateway->vpn_phy_index =
507                                                         active_gateway->index;
508
509                 } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
510                                         new_gateway->ipv6_gateway != NULL) {
511                         new_gateway->ipv6_gateway->vpn = TRUE;
512                         if (peer != NULL)
513                                 new_gateway->ipv6_gateway->vpn_ip =
514                                                         g_strdup(peer);
515                         else if (gateway != NULL)
516                                 new_gateway->ipv6_gateway->vpn_ip =
517                                                         g_strdup(gateway);
518                         if (active_gateway)
519                                 new_gateway->ipv6_gateway->vpn_phy_index =
520                                                         active_gateway->index;
521                 }
522         } else {
523                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
524                                         new_gateway->ipv4_gateway != NULL)
525                         new_gateway->ipv4_gateway->vpn = FALSE;
526
527                 if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
528                                         new_gateway->ipv6_gateway != NULL)
529                         new_gateway->ipv6_gateway->vpn = FALSE;
530         }
531
532         if (active_gateway == NULL) {
533                 set_default_gateway(new_gateway, type);
534                 return 0;
535         }
536
537         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
538                                 new_gateway->ipv4_gateway != NULL &&
539                                 new_gateway->ipv4_gateway->vpn == TRUE) {
540                 connman_inet_add_host_route(active_gateway->index,
541                                         new_gateway->ipv4_gateway->gateway,
542                                         active_gateway->ipv4_gateway->gateway);
543                 connman_inet_clear_gateway_address(active_gateway->index,
544                                         active_gateway->ipv4_gateway->gateway);
545         }
546
547         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
548                                 new_gateway->ipv6_gateway != NULL &&
549                                 new_gateway->ipv6_gateway->vpn == TRUE) {
550                 connman_inet_add_ipv6_host_route(active_gateway->index,
551                                         new_gateway->ipv6_gateway->gateway,
552                                         active_gateway->ipv6_gateway->gateway);
553                 connman_inet_clear_ipv6_gateway_address(active_gateway->index,
554                                         active_gateway->ipv6_gateway->gateway);
555         }
556
557         return 0;
558 }
559
560 void __connman_connection_gateway_remove(struct connman_service *service,
561                                         enum connman_ipconfig_type type)
562 {
563         struct gateway_data *data = NULL;
564         gboolean set_default4 = FALSE, set_default6 = FALSE;
565         int do_ipv4 = FALSE, do_ipv6 = FALSE;
566         int err;
567
568         DBG("service %p type %d", service, type);
569
570         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
571                 do_ipv4 = TRUE;
572         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
573                 do_ipv6 = TRUE;
574         else
575                 do_ipv4 = do_ipv6 = TRUE;
576
577         __connman_service_nameserver_del_routes(service);
578
579         data = g_hash_table_lookup(gateway_hash, service);
580         if (data == NULL)
581                 return;
582
583         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL)
584                 set_default4 = data->ipv4_gateway->vpn;
585
586         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL)
587                 set_default6 = data->ipv6_gateway->vpn;
588
589         DBG("ipv4 gateway %s ipv6 gateway %s vpn %d/%d",
590                 data->ipv4_gateway ? data->ipv4_gateway->gateway : "<null>",
591                 data->ipv6_gateway ? data->ipv6_gateway->gateway : "<null>",
592                 set_default4, set_default6);
593
594         if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
595                         data->ipv4_gateway->vpn == TRUE && data->index >= 0)
596                 connman_inet_del_host_route(data->index,
597                                                 data->ipv4_gateway->gateway);
598
599         if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
600                         data->ipv6_gateway->vpn == TRUE && data->index >= 0)
601                 connman_inet_del_ipv6_host_route(data->index,
602                                                 data->ipv6_gateway->gateway);
603
604         __connman_service_nameserver_del_routes(service);
605
606         err = disable_gateway(data, type);
607
608         /*
609          * We remove the service from the hash only if all the gateway
610          * settings are to be removed.
611          */
612         if (do_ipv4 == do_ipv6 ||
613                 (data->ipv4_gateway != NULL && data->ipv6_gateway == NULL
614                         && do_ipv4 == TRUE) ||
615                 (data->ipv6_gateway != NULL && data->ipv4_gateway == NULL
616                         && do_ipv6 == TRUE)
617                 )
618                 g_hash_table_remove(gateway_hash, service);
619         else
620                 DBG("Not yet removing gw ipv4 %p/%d ipv6 %p/%d",
621                         data->ipv4_gateway, do_ipv4,
622                         data->ipv6_gateway, do_ipv6);
623
624         /* with vpn this will be called after the network was deleted,
625          * we need to call set_default here because we will not recieve any
626          * gateway delete notification.
627          * We hit the same issue if remove_gateway() fails.
628          */
629         if (set_default4 || set_default6 || err < 0) {
630                 data = find_default_gateway();
631                 if (data != NULL)
632                         set_default_gateway(data, type);
633         }
634 }
635
636 gboolean __connman_connection_update_gateway(void)
637 {
638         struct gateway_data *active_gateway, *default_gateway;
639         gboolean updated = FALSE;
640
641         if (gateway_hash == NULL)
642                 return updated;
643
644         update_order();
645
646         active_gateway = find_active_gateway();
647         default_gateway = find_default_gateway();
648
649         if (active_gateway && active_gateway != default_gateway)
650                 updated = TRUE;
651
652         return updated;
653 }
654
655 int __connman_connection_init(void)
656 {
657         int err;
658
659         DBG("");
660
661         gateway_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
662                                                         NULL, remove_gateway);
663
664         err = connman_rtnl_register(&connection_rtnl);
665         if (err < 0)
666                 connman_error("Failed to setup RTNL gateway driver");
667
668         return err;
669 }
670
671 void __connman_connection_cleanup(void)
672 {
673         GHashTableIter iter;
674         gpointer value, key;
675
676         DBG("");
677
678         connman_rtnl_unregister(&connection_rtnl);
679
680         g_hash_table_iter_init(&iter, gateway_hash);
681
682         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
683                 struct gateway_data *data = value;
684
685                 disable_gateway(data, CONNMAN_IPCONFIG_TYPE_ALL);
686         }
687
688         g_hash_table_destroy(gateway_hash);
689         gateway_hash = NULL;
690 }