Return a proper order value for the default service
[platform/upstream/connman.git] / src / connection.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <sys/ioctl.h>
30 #include <arpa/inet.h>
31 #include <net/if.h>
32 #include <net/route.h>
33
34 #include <gdbus.h>
35
36 #include "connman.h"
37
38 struct gateway_data {
39         int index;
40         char *gateway;
41         struct connman_element *element;
42         unsigned int order;
43         gboolean active;
44 };
45
46 static GSList *gateway_list = NULL;
47
48 static struct gateway_data *find_gateway(int index, const char *gateway)
49 {
50         GSList *list;
51
52         if (gateway == NULL)
53                 return NULL;
54
55         for (list = gateway_list; list; list = list->next) {
56                 struct gateway_data *data = list->data;
57
58                 if (data->gateway == NULL)
59                         continue;
60
61                 if (data->index == index &&
62                                 g_str_equal(data->gateway, gateway) == TRUE)
63                         return data;
64         }
65
66         return NULL;
67 }
68
69 static int set_route(struct connman_element *element, const char *gateway)
70 {
71         struct ifreq ifr;
72         struct rtentry rt;
73         struct sockaddr_in *addr;
74         int sk, err;
75
76         DBG("element %p", element);
77
78         sk = socket(PF_INET, SOCK_DGRAM, 0);
79         if (sk < 0)
80                 return -1;
81
82         memset(&ifr, 0, sizeof(ifr));
83         ifr.ifr_ifindex = element->index;
84
85         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
86                 close(sk);
87                 return -1;
88         }
89
90         DBG("ifname %s", ifr.ifr_name);
91
92         memset(&rt, 0, sizeof(rt));
93         rt.rt_flags = RTF_UP | RTF_HOST;
94
95         addr = (struct sockaddr_in *) &rt.rt_dst;
96         addr->sin_family = AF_INET;
97         addr->sin_addr.s_addr = inet_addr(gateway);
98
99         addr = (struct sockaddr_in *) &rt.rt_gateway;
100         addr->sin_family = AF_INET;
101         addr->sin_addr.s_addr = INADDR_ANY;
102
103         addr = (struct sockaddr_in *) &rt.rt_genmask;
104         addr->sin_family = AF_INET;
105         addr->sin_addr.s_addr = INADDR_ANY;
106
107         rt.rt_dev = ifr.ifr_name;
108
109         err = ioctl(sk, SIOCADDRT, &rt);
110         if (err < 0)
111                 connman_error("Setting host gateway route failed (%s)",
112                                                         strerror(errno));
113
114         memset(&rt, 0, sizeof(rt));
115         rt.rt_flags = RTF_UP | RTF_GATEWAY;
116
117         addr = (struct sockaddr_in *) &rt.rt_dst;
118         addr->sin_family = AF_INET;
119         addr->sin_addr.s_addr = INADDR_ANY;
120
121         addr = (struct sockaddr_in *) &rt.rt_gateway;
122         addr->sin_family = AF_INET;
123         addr->sin_addr.s_addr = inet_addr(gateway);
124
125         addr = (struct sockaddr_in *) &rt.rt_genmask;
126         addr->sin_family = AF_INET;
127         addr->sin_addr.s_addr = INADDR_ANY;
128
129         err = ioctl(sk, SIOCADDRT, &rt);
130         if (err < 0)
131                 connman_error("Setting default route failed (%s)",
132                                                         strerror(errno));
133
134         close(sk);
135
136         return err;
137 }
138
139 static int del_route(struct connman_element *element, const char *gateway)
140 {
141         struct ifreq ifr;
142         struct rtentry rt;
143         struct sockaddr_in *addr;
144         int sk, err;
145
146         DBG("element %p", element);
147
148         sk = socket(PF_INET, SOCK_DGRAM, 0);
149         if (sk < 0)
150                 return -1;
151
152         memset(&ifr, 0, sizeof(ifr));
153         ifr.ifr_ifindex = element->index;
154
155         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
156                 close(sk);
157                 return -1;
158         }
159
160         DBG("ifname %s", ifr.ifr_name);
161
162         memset(&rt, 0, sizeof(rt));
163         rt.rt_flags = RTF_UP | RTF_GATEWAY;
164
165         addr = (struct sockaddr_in *) &rt.rt_dst;
166         addr->sin_family = AF_INET;
167         addr->sin_addr.s_addr = INADDR_ANY;
168
169         addr = (struct sockaddr_in *) &rt.rt_gateway;
170         addr->sin_family = AF_INET;
171         addr->sin_addr.s_addr = inet_addr(gateway);
172
173         addr = (struct sockaddr_in *) &rt.rt_genmask;
174         addr->sin_family = AF_INET;
175         addr->sin_addr.s_addr = INADDR_ANY;
176
177         err = ioctl(sk, SIOCDELRT, &rt);
178         if (err < 0)
179                 connman_error("Removing default route failed (%s)",
180                                                         strerror(errno));
181
182         close(sk);
183
184         return err;
185 }
186
187 static DBusConnection *connection;
188
189 static void emit_default_signal(struct connman_element *element)
190 {
191         DBusMessage *signal;
192         DBusMessageIter entry, value;
193         const char *key = "Default";
194
195         signal = dbus_message_new_signal(element->path,
196                         CONNMAN_CONNECTION_INTERFACE, "PropertyChanged");
197         if (signal == NULL)
198                 return;
199
200         dbus_message_iter_init_append(signal, &entry);
201
202         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
203
204         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
205                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
206         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN,
207                                                         &element->enabled);
208         dbus_message_iter_close_container(&entry, &value);
209
210         g_dbus_send_message(connection, signal);
211 }
212
213 static void find_element(struct connman_element *element, gpointer user_data)
214 {
215         struct gateway_data *data = user_data;
216
217         DBG("element %p name %s", element, element->name);
218
219         if (data->element != NULL)
220                 return;
221
222         if (element->index != data->index)
223                 return;
224
225         data->element = element;
226 }
227
228 static struct gateway_data *add_gateway(int index, const char *gateway)
229 {
230         struct gateway_data *data;
231         struct connman_service *service;
232
233         data = g_try_new0(struct gateway_data, 1);
234         if (data == NULL)
235                 return NULL;
236
237         data->index = index;
238         data->gateway = g_strdup(gateway);
239         data->active = FALSE;
240         data->element = NULL;
241
242         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION,
243                                                         find_element, data);
244
245         service = __connman_element_get_service(data->element);
246         data->order = __connman_service_get_order(service);
247
248         gateway_list = g_slist_append(gateway_list, data);
249
250         return data;
251 }
252
253 static void connection_newgateway(int index, const char *gateway)
254 {
255         struct gateway_data *data;
256
257         DBG("index %d gateway %s", index, gateway);
258
259         data = find_gateway(index, gateway);
260         if (data == NULL)
261                 return;
262
263         data->active = TRUE;
264 }
265
266 static void set_default_gateway(struct gateway_data *data)
267 {
268         struct connman_element *element = data->element;
269         struct connman_service *service = NULL;
270
271         DBG("gateway %s", data->gateway);
272
273         if (set_route(element, data->gateway) < 0)
274                 return;
275
276         service = __connman_element_get_service(element);
277         __connman_service_indicate_default(service);
278 }
279
280 static struct gateway_data *find_default_gateway(void)
281 {
282         struct gateway_data *found = NULL;
283         unsigned int order = 0;
284         GSList *list;
285
286         for (list = gateway_list; list; list = list->next) {
287                 struct gateway_data *data = list->data;
288
289                 if (found == NULL || data->order > order) {
290                         found = data;
291                         order = data->order;
292                 }
293         }
294
295         return found;
296 }
297
298 static void remove_gateway(struct gateway_data *data)
299 {
300         DBG("gateway %s", data->gateway);
301
302         gateway_list = g_slist_remove(gateway_list, data);
303
304         if (data->active == TRUE)
305                 del_route(data->element, data->gateway);
306
307         g_free(data->gateway);
308         g_free(data);
309 }
310
311 static void connection_delgateway(int index, const char *gateway)
312 {
313         struct gateway_data *data;
314
315         DBG("index %d gateway %s", index, gateway);
316
317         data = find_gateway(index, gateway);
318         if (data != NULL)
319                 data->active = FALSE;
320
321         data = find_default_gateway();
322         if (data != NULL)
323                 set_default_gateway(data);
324 }
325
326 static struct connman_rtnl connection_rtnl = {
327         .name           = "connection",
328         .newgateway     = connection_newgateway,
329         .delgateway     = connection_delgateway,
330 };
331
332 static DBusMessage *get_properties(DBusConnection *conn,
333                                         DBusMessage *msg, void *data)
334 {
335         struct connman_element *element = data;
336         DBusMessage *reply;
337         DBusMessageIter array, dict;
338         connman_uint8_t strength;
339         const char *device, *network;
340         const char *type;
341
342         DBG("conn %p", conn);
343
344         if (__connman_security_check_privilege(msg,
345                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
346                 return __connman_error_permission_denied(msg);
347
348         reply = dbus_message_new_method_return(msg);
349         if (reply == NULL)
350                 return NULL;
351
352         dbus_message_iter_init_append(reply, &array);
353
354         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
355                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
356                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
357                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
358
359         type = connman_element_get_string(element, "Type");
360         if (type != NULL)
361                 connman_dbus_dict_append_variant(&dict, "Type",
362                                                 DBUS_TYPE_STRING, &type);
363
364         strength = connman_element_get_uint8(element, "Strength");
365         if (strength > 0)
366                 connman_dbus_dict_append_variant(&dict, "Strength",
367                                                 DBUS_TYPE_BYTE, &strength);
368
369         if (element->devname != NULL)
370                 connman_dbus_dict_append_variant(&dict, "Interface",
371                                         DBUS_TYPE_STRING, &element->devname);
372
373         connman_dbus_dict_append_variant(&dict, "Default",
374                                         DBUS_TYPE_BOOLEAN, &element->enabled);
375
376         device = __connman_element_get_device_path(element);
377         if (device != NULL)
378                 connman_dbus_dict_append_variant(&dict, "Device",
379                                         DBUS_TYPE_OBJECT_PATH, &device);
380
381         network = __connman_element_get_network_path(element);
382         if (network != NULL)
383                 connman_dbus_dict_append_variant(&dict, "Network",
384                                         DBUS_TYPE_OBJECT_PATH, &network);
385
386         __connman_element_append_ipv4(element, &dict);
387
388         dbus_message_iter_close_container(&array, &dict);
389
390         return reply;
391 }
392
393 static DBusMessage *set_property(DBusConnection *conn,
394                                         DBusMessage *msg, void *data)
395 {
396         DBusMessageIter iter, value;
397         const char *name;
398         int type;
399
400         DBG("conn %p", conn);
401
402         if (dbus_message_iter_init(msg, &iter) == FALSE)
403                 return __connman_error_invalid_arguments(msg);
404
405         dbus_message_iter_get_basic(&iter, &name);
406         dbus_message_iter_next(&iter);
407         dbus_message_iter_recurse(&iter, &value);
408
409         if (__connman_security_check_privilege(msg,
410                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
411                 return __connman_error_permission_denied(msg);
412
413         type = dbus_message_iter_get_arg_type(&value);
414
415         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
416 }
417
418 static GDBusMethodTable connection_methods[] = {
419         { "GetProperties", "",   "a{sv}", get_properties },
420         { "SetProperty",   "sv", "",      set_property   },
421         { },
422 };
423
424 static GDBusSignalTable connection_signals[] = {
425         { "PropertyChanged", "sv" },
426         { },
427 };
428
429 static void append_connections(DBusMessageIter *entry)
430 {
431         DBusMessageIter value, iter;
432         const char *key = "Connections";
433
434         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
435
436         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
437                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
438                                                                 &value);
439
440         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
441                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
442         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
443         dbus_message_iter_close_container(&value, &iter);
444
445         dbus_message_iter_close_container(entry, &value);
446 }
447
448 static void emit_connections_signal(void)
449 {
450         DBusMessage *signal;
451         DBusMessageIter entry;
452
453         DBG("");
454
455         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
456                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
457         if (signal == NULL)
458                 return;
459
460         dbus_message_iter_init_append(signal, &entry);
461
462         append_connections(&entry);
463
464         g_dbus_send_message(connection, signal);
465 }
466
467 static int register_interface(struct connman_element *element)
468 {
469         DBG("element %p name %s path %s",
470                                 element, element->name, element->path);
471
472         if (g_dbus_register_interface(connection, element->path,
473                                         CONNMAN_CONNECTION_INTERFACE,
474                                         connection_methods, connection_signals,
475                                         NULL, element, NULL) == FALSE) {
476                 connman_error("Failed to register %s connection", element->path);
477                 return -EIO;
478         }
479
480         emit_connections_signal();
481
482         return 0;
483 }
484
485 static void unregister_interface(struct connman_element *element)
486 {
487         DBG("element %p name %s", element, element->name);
488
489         emit_connections_signal();
490
491         g_dbus_unregister_interface(connection, element->path,
492                                                 CONNMAN_CONNECTION_INTERFACE);
493 }
494
495 static struct gateway_data *find_active_gateway(void)
496 {
497         GSList *list;
498
499         DBG("");
500
501         for (list = gateway_list; list; list = list->next) {
502                 struct gateway_data *data = list->data;
503                 if (data->active == TRUE)
504                         return data;
505         }
506
507         return NULL;
508 }
509
510 static int connection_probe(struct connman_element *element)
511 {
512         struct connman_service *service = NULL;
513         const char *gateway = NULL;
514         struct gateway_data *active_gateway = NULL;
515         struct gateway_data *new_gateway = NULL;
516
517         DBG("element %p name %s", element, element->name);
518
519         if (element->parent == NULL)
520                 return -ENODEV;
521
522         if (element->parent->type != CONNMAN_ELEMENT_TYPE_IPV4)
523                 return -ENODEV;
524
525         connman_element_get_value(element,
526                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
527
528         DBG("gateway %s", gateway);
529
530         if (register_interface(element) < 0)
531                 return -ENODEV;
532         service = __connman_element_get_service(element);
533         __connman_service_indicate_state(service,
534                                         CONNMAN_SERVICE_STATE_READY);
535         connman_element_set_enabled(element, TRUE);
536         emit_default_signal(element);
537
538         if (gateway == NULL)
539                 return 0;
540
541         active_gateway = find_active_gateway();
542         new_gateway = add_gateway(element->index, gateway);
543
544         if (active_gateway == NULL) {
545                 set_default_gateway(new_gateway);
546                 return 0;
547         }
548
549         if (new_gateway->order >= active_gateway->order) {
550                 del_route(active_gateway->element, active_gateway->gateway);
551                 return 0;
552         }
553
554         return 0;
555 }
556
557 static void connection_remove(struct connman_element *element)
558 {
559         struct connman_service *service;
560         const char *gateway = NULL;
561         struct gateway_data *data = NULL;
562
563         DBG("element %p name %s", element, element->name);
564
565         service = __connman_element_get_service(element);
566         __connman_service_indicate_state(service,
567                                         CONNMAN_SERVICE_STATE_DISCONNECT);
568
569         connman_element_set_enabled(element, FALSE);
570         emit_default_signal(element);
571
572         unregister_interface(element);
573
574         connman_element_get_value(element,
575                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
576
577         DBG("gateway %s", gateway);
578
579         if (gateway == NULL)
580                 return;
581
582         data = find_gateway(element->index, gateway);
583         if (data == NULL)
584                 return;
585
586         remove_gateway(data);
587 }
588
589 static struct connman_driver connection_driver = {
590         .name           = "connection",
591         .type           = CONNMAN_ELEMENT_TYPE_CONNECTION,
592         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
593         .probe          = connection_probe,
594         .remove         = connection_remove,
595 };
596
597 int __connman_connection_init(void)
598 {
599         DBG("");
600
601         connection = connman_dbus_get_connection();
602
603         if (connman_rtnl_register(&connection_rtnl) < 0)
604                 connman_error("Failed to setup RTNL gateway driver");
605
606         connman_rtnl_send_getroute();
607
608         return connman_driver_register(&connection_driver);
609 }
610
611 void __connman_connection_cleanup(void)
612 {
613         GSList *list;
614
615         DBG("");
616
617         connman_driver_unregister(&connection_driver);
618
619         connman_rtnl_unregister(&connection_rtnl);
620
621         for (list = gateway_list; list; list = list->next) {
622                 struct gateway_data *data = list->data;
623
624                 DBG("index %d gateway %s", data->index, data->gateway);
625
626                 g_free(data->gateway);
627                 g_free(data);
628                 list->data = NULL;
629         }
630
631         g_slist_free(gateway_list);
632         gateway_list = NULL;
633
634         dbus_connection_unref(connection);
635 }
636
637 static void update_order(void)
638 {
639         GSList *list = NULL;
640
641         for (list = gateway_list; list; list = list->next) {
642                 struct gateway_data *data = list->data;
643                 struct connman_service *service;
644
645                 service = __connman_element_get_service(data->element);
646                 data->order = __connman_service_get_order(service);
647         }
648 }
649
650 void __connman_connection_update_gateway(void)
651 {
652         struct gateway_data *active_gateway, *default_gateway;
653
654         update_order();
655
656         active_gateway = find_active_gateway();
657         default_gateway = find_default_gateway();
658
659         if (active_gateway && active_gateway != default_gateway)
660                 del_route(active_gateway->element, active_gateway->gateway);
661 }