Remove storage of network information
[connman] / 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 };
42
43 static GSList *gateway_list = NULL;
44
45 static struct gateway_data *find_gateway(int index, const char *gateway)
46 {
47         GSList *list;
48
49         if (gateway == NULL)
50                 return NULL;
51
52         for (list = gateway_list; list; list = list->next) {
53                 struct gateway_data *data = list->data;
54
55                 if (data->gateway == NULL)
56                         continue;
57
58                 if (data->index == index &&
59                                 g_str_equal(data->gateway, gateway) == TRUE)
60                         return data;
61         }
62
63         return NULL;
64 }
65
66 static void remove_gateway(int index, const char *gateway)
67 {
68         struct gateway_data *data;
69
70         data = find_gateway(index, gateway);
71         if (data == NULL)
72                 return;
73
74         gateway_list = g_slist_remove(gateway_list, data);
75 }
76
77 static int set_route(struct connman_element *element, const char *gateway)
78 {
79         struct ifreq ifr;
80         struct rtentry rt;
81         struct sockaddr_in *addr;
82         int sk, err;
83
84         DBG("element %p", element);
85
86         sk = socket(PF_INET, SOCK_DGRAM, 0);
87         if (sk < 0)
88                 return -1;
89
90         memset(&ifr, 0, sizeof(ifr));
91         ifr.ifr_ifindex = element->index;
92
93         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
94                 close(sk);
95                 return -1;
96         }
97
98         DBG("ifname %s", ifr.ifr_name);
99
100         memset(&rt, 0, sizeof(rt));
101         rt.rt_flags = RTF_UP | RTF_GATEWAY;
102
103         addr = (struct sockaddr_in *) &rt.rt_dst;
104         addr->sin_family = AF_INET;
105         addr->sin_addr.s_addr = INADDR_ANY;
106
107         addr = (struct sockaddr_in *) &rt.rt_gateway;
108         addr->sin_family = AF_INET;
109         addr->sin_addr.s_addr = inet_addr(gateway);
110
111         addr = (struct sockaddr_in *) &rt.rt_genmask;
112         addr->sin_family = AF_INET;
113         addr->sin_addr.s_addr = INADDR_ANY;
114
115         err = ioctl(sk, SIOCADDRT, &rt);
116         if (err < 0)
117                 connman_error("Setting default route failed (%s)",
118                                                         strerror(errno));
119
120         close(sk);
121
122         return err;
123 }
124
125 static int del_route(struct connman_element *element, const char *gateway)
126 {
127         struct ifreq ifr;
128         struct rtentry rt;
129         struct sockaddr_in *addr;
130         int sk, err;
131
132         DBG("element %p", element);
133
134         sk = socket(PF_INET, SOCK_DGRAM, 0);
135         if (sk < 0)
136                 return -1;
137
138         memset(&ifr, 0, sizeof(ifr));
139         ifr.ifr_ifindex = element->index;
140
141         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
142                 close(sk);
143                 return -1;
144         }
145
146         DBG("ifname %s", ifr.ifr_name);
147
148         memset(&rt, 0, sizeof(rt));
149         rt.rt_flags = RTF_UP | RTF_GATEWAY;
150
151         addr = (struct sockaddr_in *) &rt.rt_dst;
152         addr->sin_family = AF_INET;
153         addr->sin_addr.s_addr = INADDR_ANY;
154
155         addr = (struct sockaddr_in *) &rt.rt_gateway;
156         addr->sin_family = AF_INET;
157         addr->sin_addr.s_addr = inet_addr(gateway);
158
159         addr = (struct sockaddr_in *) &rt.rt_genmask;
160         addr->sin_family = AF_INET;
161         addr->sin_addr.s_addr = INADDR_ANY;
162
163         err = ioctl(sk, SIOCDELRT, &rt);
164         if (err < 0)
165                 connman_error("Removing default route failed (%s)",
166                                                         strerror(errno));
167
168         close(sk);
169
170         return err;
171 }
172
173 static DBusConnection *connection;
174
175 static void emit_default_signal(struct connman_element *element)
176 {
177         DBusMessage *signal;
178         DBusMessageIter entry, value;
179         const char *key = "Default";
180
181         signal = dbus_message_new_signal(element->path,
182                         CONNMAN_CONNECTION_INTERFACE, "PropertyChanged");
183         if (signal == NULL)
184                 return;
185
186         dbus_message_iter_init_append(signal, &entry);
187
188         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
189
190         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
191                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
192         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN,
193                                                         &element->enabled);
194         dbus_message_iter_close_container(&entry, &value);
195
196         g_dbus_send_message(connection, signal);
197 }
198
199 static void set_default(struct connman_element *element, gpointer user_data)
200 {
201         struct gateway_data *data = user_data;
202
203         DBG("element %p name %s", element, element->name);
204
205         if (element->index != data->index)
206                 return;
207
208         if (element->enabled == TRUE)
209                 return;
210
211         connman_element_set_enabled(element, TRUE);
212         emit_default_signal(element);
213 }
214
215 static void del_default(struct connman_element *element, gpointer user_data)
216 {
217         struct gateway_data *data = user_data;
218
219         DBG("element %p name %s", element, element->name);
220
221         if (element->index != data->index)
222                 return;
223
224         if (element->enabled == FALSE)
225                 return;
226
227         connman_element_set_enabled(element, FALSE);
228         emit_default_signal(element);
229 }
230
231 static void new_default(struct connman_element *element, gpointer user_data)
232 {
233         struct connman_service *service;
234         const char *gateway;
235
236         DBG("element %p name %s", element, element->name);
237
238         if (g_slist_length(gateway_list) > 0)
239                 return;
240
241         connman_element_get_value(element,
242                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
243
244         DBG("gateway %s", gateway);
245
246         if (gateway == NULL)
247                 return;
248
249         if (set_route(element, gateway) < 0)
250                 return;
251
252         service = __connman_element_get_service(element);
253         __connman_service_indicate_default(service);
254
255         connman_element_set_enabled(element, TRUE);
256         emit_default_signal(element);
257 }
258
259 static void connection_newgateway(int index, const char *gateway)
260 {
261         struct gateway_data *data;
262
263         DBG("index %d gateway %s", index, gateway);
264
265         data = find_gateway(index, gateway);
266         if (data != NULL)
267                 return;
268
269         data = g_try_new0(struct gateway_data, 1);
270         if (data == NULL)
271                 return;
272
273         data->index = index;
274         data->gateway = g_strdup(gateway);
275
276         gateway_list = g_slist_append(gateway_list, data);
277
278         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION,
279                                                         set_default, data);
280 }
281
282 static void connection_delgateway(int index, const char *gateway)
283 {
284         struct gateway_data *data;
285
286         DBG("index %d gateway %s", index, gateway);
287
288         data = find_gateway(index, gateway);
289         if (data == NULL)
290                 return;
291
292         gateway_list = g_slist_remove(gateway_list, data);
293
294         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION,
295                                                         del_default, data);
296
297         g_free(data->gateway);
298         g_free(data);
299
300         if (g_slist_length(gateway_list) > 0)
301                 return;
302
303         DBG("selecting new default gateway");
304
305         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION,
306                                                         new_default, NULL);
307 }
308
309 static struct connman_rtnl connection_rtnl = {
310         .name           = "connection",
311         .newgateway     = connection_newgateway,
312         .delgateway     = connection_delgateway,
313 };
314
315 static DBusMessage *get_properties(DBusConnection *conn,
316                                         DBusMessage *msg, void *data)
317 {
318         struct connman_element *element = data;
319         DBusMessage *reply;
320         DBusMessageIter array, dict;
321         connman_uint8_t strength;
322         const char *device, *network;
323         const char *type;
324
325         DBG("conn %p", conn);
326
327         if (__connman_security_check_privilege(msg,
328                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
329                 return __connman_error_permission_denied(msg);
330
331         reply = dbus_message_new_method_return(msg);
332         if (reply == NULL)
333                 return NULL;
334
335         dbus_message_iter_init_append(reply, &array);
336
337         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
338                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
339                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
340                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
341
342         type = connman_element_get_string(element, "Type");
343         if (type != NULL)
344                 connman_dbus_dict_append_variant(&dict, "Type",
345                                                 DBUS_TYPE_STRING, &type);
346
347         strength = connman_element_get_uint8(element, "Strength");
348         if (strength > 0)
349                 connman_dbus_dict_append_variant(&dict, "Strength",
350                                                 DBUS_TYPE_BYTE, &strength);
351
352         if (element->devname != NULL)
353                 connman_dbus_dict_append_variant(&dict, "Interface",
354                                         DBUS_TYPE_STRING, &element->devname);
355
356         connman_dbus_dict_append_variant(&dict, "Default",
357                                         DBUS_TYPE_BOOLEAN, &element->enabled);
358
359         device = __connman_element_get_device_path(element);
360         if (device != NULL)
361                 connman_dbus_dict_append_variant(&dict, "Device",
362                                         DBUS_TYPE_OBJECT_PATH, &device);
363
364         network = __connman_element_get_network_path(element);
365         if (network != NULL)
366                 connman_dbus_dict_append_variant(&dict, "Network",
367                                         DBUS_TYPE_OBJECT_PATH, &network);
368
369         __connman_element_append_ipv4(element, &dict);
370
371         dbus_message_iter_close_container(&array, &dict);
372
373         return reply;
374 }
375
376 static DBusMessage *set_property(DBusConnection *conn,
377                                         DBusMessage *msg, void *data)
378 {
379         DBusMessageIter iter, value;
380         const char *name;
381         int type;
382
383         DBG("conn %p", conn);
384
385         if (dbus_message_iter_init(msg, &iter) == FALSE)
386                 return __connman_error_invalid_arguments(msg);
387
388         dbus_message_iter_get_basic(&iter, &name);
389         dbus_message_iter_next(&iter);
390         dbus_message_iter_recurse(&iter, &value);
391
392         if (__connman_security_check_privilege(msg,
393                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
394                 return __connman_error_permission_denied(msg);
395
396         type = dbus_message_iter_get_arg_type(&value);
397
398         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
399 }
400
401 static GDBusMethodTable connection_methods[] = {
402         { "GetProperties", "",   "a{sv}", get_properties },
403         { "SetProperty",   "sv", "",      set_property   },
404         { },
405 };
406
407 static GDBusSignalTable connection_signals[] = {
408         { "PropertyChanged", "sv" },
409         { },
410 };
411
412 static void append_connections(DBusMessageIter *entry)
413 {
414         DBusMessageIter value, iter;
415         const char *key = "Connections";
416
417         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
418
419         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
420                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
421                                                                 &value);
422
423         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
424                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
425         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
426         dbus_message_iter_close_container(&value, &iter);
427
428         dbus_message_iter_close_container(entry, &value);
429 }
430
431 static void emit_connections_signal(void)
432 {
433         DBusMessage *signal;
434         DBusMessageIter entry;
435
436         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
437                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
438         if (signal == NULL)
439                 return;
440
441         dbus_message_iter_init_append(signal, &entry);
442
443         append_connections(&entry);
444
445         g_dbus_send_message(connection, signal);
446 }
447
448 static int register_interface(struct connman_element *element)
449 {
450         DBG("element %p name %s", element, element->name);
451
452         if (g_dbus_register_interface(connection, element->path,
453                                         CONNMAN_CONNECTION_INTERFACE,
454                                         connection_methods, connection_signals,
455                                         NULL, element, NULL) == FALSE) {
456                 connman_error("Failed to register %s connection", element->path);
457                 return -EIO;
458         }
459
460         emit_connections_signal();
461
462         return 0;
463 }
464
465 static void unregister_interface(struct connman_element *element)
466 {
467         DBG("element %p name %s", element, element->name);
468
469         emit_connections_signal();
470
471         g_dbus_unregister_interface(connection, element->path,
472                                                 CONNMAN_CONNECTION_INTERFACE);
473 }
474
475 static int connection_probe(struct connman_element *element)
476 {
477         struct connman_service *service;
478         const char *gateway = NULL;
479
480         DBG("element %p name %s", element, element->name);
481
482         if (element->parent == NULL)
483                 return -ENODEV;
484
485         if (element->parent->type != CONNMAN_ELEMENT_TYPE_IPV4)
486                 return -ENODEV;
487
488         connman_element_get_value(element,
489                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
490
491         DBG("gateway %s", gateway);
492
493         if (register_interface(element) < 0)
494                 return -ENODEV;
495
496         service = __connman_element_get_service(element);
497         __connman_service_indicate_state(service,
498                                         CONNMAN_SERVICE_STATE_READY);
499
500         if (gateway == NULL)
501                 return 0;
502
503         if (find_gateway(element->index, gateway) != NULL) {
504                 DBG("previous gateway still present");
505                 goto done;
506         }
507
508         if (g_slist_length(gateway_list) > 0) {
509                 DBG("default gateway already present");
510                 return 0;
511         }
512
513         if (set_route(element, gateway) < 0)
514                 return 0;
515
516 done:
517         service = __connman_element_get_service(element);
518         __connman_service_indicate_default(service);
519
520         connman_element_set_enabled(element, TRUE);
521         emit_default_signal(element);
522
523         return 0;
524 }
525
526 static void connection_remove(struct connman_element *element)
527 {
528         struct connman_service *service;
529         const char *gateway = NULL;
530
531         DBG("element %p name %s", element, element->name);
532
533         service = __connman_element_get_service(element);
534         __connman_service_indicate_state(service,
535                                         CONNMAN_SERVICE_STATE_DISCONNECT);
536
537         unregister_interface(element);
538
539         connman_element_get_value(element,
540                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
541
542         DBG("gateway %s", gateway);
543
544         if (gateway == NULL)
545                 return;
546
547         remove_gateway(element->index, gateway);
548
549         connman_element_set_enabled(element, FALSE);
550         emit_default_signal(element);
551
552         del_route(element, gateway);
553 }
554
555 static struct connman_driver connection_driver = {
556         .name           = "connection",
557         .type           = CONNMAN_ELEMENT_TYPE_CONNECTION,
558         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
559         .probe          = connection_probe,
560         .remove         = connection_remove,
561 };
562
563 int __connman_connection_init(void)
564 {
565         DBG("");
566
567         connection = connman_dbus_get_connection();
568
569         if (connman_rtnl_register(&connection_rtnl) < 0)
570                 connman_error("Failed to setup RTNL gateway driver");
571
572         connman_rtnl_send_getroute();
573
574         return connman_driver_register(&connection_driver);
575 }
576
577 void __connman_connection_cleanup(void)
578 {
579         GSList *list;
580
581         DBG("");
582
583         connman_driver_unregister(&connection_driver);
584
585         connman_rtnl_unregister(&connection_rtnl);
586
587         for (list = gateway_list; list; list = list->next) {
588                 struct gateway_data *data = list->data;
589
590                 DBG("index %d gateway %s", data->index, data->gateway);
591
592                 g_free(data->gateway);
593                 g_free(data);
594                 list->data = NULL;
595         }
596
597         g_slist_free(gateway_list);
598         gateway_list = NULL;
599
600         dbus_connection_unref(connection);
601 }