Verify argument type before processing
[framework/connectivity/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 };
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 connection_newgateway(int index, const char *gateway)
67 {
68         struct gateway_data *data;
69
70         DBG("index %d gateway %s", index, gateway);
71
72         data = find_gateway(index, gateway);
73         if (data != NULL)
74                 return;
75
76         data = g_try_new0(struct gateway_data, 1);
77         if (data == NULL)
78                 return;
79
80         data->index = index;
81         data->gateway = g_strdup(gateway);
82
83         gateway_list = g_slist_append(gateway_list, data);
84 }
85
86 static void connection_delgateway(int index, const char *gateway)
87 {
88         struct gateway_data *data;
89
90         DBG("index %d gateway %s", index, gateway);
91
92         data = find_gateway(index, gateway);
93         if (data == NULL)
94                 return;
95
96         gateway_list = g_slist_remove(gateway_list, data);
97
98         g_free(data->gateway);
99         g_free(data);
100 }
101
102 static struct connman_rtnl connection_rtnl = {
103         .name           = "connection",
104         .newgateway     = connection_newgateway,
105         .delgateway     = connection_delgateway,
106 };
107
108 static int set_route(struct connman_element *element, const char *gateway)
109 {
110         struct ifreq ifr;
111         struct rtentry rt;
112         struct sockaddr_in *addr;
113         int sk, err;
114
115         DBG("element %p", element);
116
117         sk = socket(PF_INET, SOCK_DGRAM, 0);
118         if (sk < 0)
119                 return -1;
120
121         memset(&ifr, 0, sizeof(ifr));
122         ifr.ifr_ifindex = element->index;
123
124         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
125                 close(sk);
126                 return -1;
127         }
128
129         DBG("ifname %s", ifr.ifr_name);
130
131         memset(&rt, 0, sizeof(rt));
132         rt.rt_flags = RTF_UP | RTF_GATEWAY;
133
134         addr = (struct sockaddr_in *) &rt.rt_dst;
135         addr->sin_family = AF_INET;
136         addr->sin_addr.s_addr = INADDR_ANY;
137
138         addr = (struct sockaddr_in *) &rt.rt_gateway;
139         addr->sin_family = AF_INET;
140         addr->sin_addr.s_addr = inet_addr(gateway);
141
142         addr = (struct sockaddr_in *) &rt.rt_genmask;
143         addr->sin_family = AF_INET;
144         addr->sin_addr.s_addr = INADDR_ANY;
145
146         err = ioctl(sk, SIOCADDRT, &rt);
147         if (err < 0)
148                 DBG("default route setting failed (%s)", strerror(errno));
149
150         close(sk);
151
152         return err;
153 }
154
155 static int del_route(struct connman_element *element, const char *gateway)
156 {
157         struct ifreq ifr;
158         struct rtentry rt;
159         struct sockaddr_in *addr;
160         int sk, err;
161
162         DBG("element %p", element);
163
164         sk = socket(PF_INET, SOCK_DGRAM, 0);
165         if (sk < 0)
166                 return -1;
167
168         memset(&ifr, 0, sizeof(ifr));
169         ifr.ifr_ifindex = element->index;
170
171         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
172                 close(sk);
173                 return -1;
174         }
175
176         DBG("ifname %s", ifr.ifr_name);
177
178         memset(&rt, 0, sizeof(rt));
179         rt.rt_flags = RTF_UP | RTF_GATEWAY;
180
181         addr = (struct sockaddr_in *) &rt.rt_dst;
182         addr->sin_family = AF_INET;
183         addr->sin_addr.s_addr = INADDR_ANY;
184
185         addr = (struct sockaddr_in *) &rt.rt_gateway;
186         addr->sin_family = AF_INET;
187         addr->sin_addr.s_addr = inet_addr(gateway);
188
189         addr = (struct sockaddr_in *) &rt.rt_genmask;
190         addr->sin_family = AF_INET;
191         addr->sin_addr.s_addr = INADDR_ANY;
192
193         err = ioctl(sk, SIOCDELRT, &rt);
194         if (err < 0)
195                 DBG("default route removal failed (%s)", strerror(errno));
196
197         close(sk);
198
199         return err;
200 }
201
202 static DBusMessage *get_properties(DBusConnection *conn,
203                                         DBusMessage *msg, void *data)
204 {
205         struct connman_element *element = data;
206         DBusMessage *reply;
207         DBusMessageIter array, dict;
208         connman_uint8_t strength = 0;
209         const char *device, *network;
210         const char *type = NULL, *method = NULL;
211         const char *address = NULL, *netmask = NULL, *gateway = NULL;
212
213         DBG("conn %p", conn);
214
215         if (__connman_security_check_privilege(msg,
216                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
217                 return __connman_error_permission_denied(msg);
218
219         reply = dbus_message_new_method_return(msg);
220         if (reply == NULL)
221                 return NULL;
222
223         dbus_message_iter_init_append(reply, &array);
224
225         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
226                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
227                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
228                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
229
230         connman_element_get_static_property(element, "Type", &type);
231
232         if (type != NULL)
233                 connman_dbus_dict_append_variant(&dict, "Type",
234                                                 DBUS_TYPE_STRING, &type);
235
236         connman_element_get_static_property(element, "Strength", &strength);
237         if (strength > 0)
238                 connman_dbus_dict_append_variant(&dict, "Strength",
239                                                 DBUS_TYPE_BYTE, &strength);
240
241         if (element->devname != NULL)
242                 connman_dbus_dict_append_variant(&dict, "Interface",
243                                         DBUS_TYPE_STRING, &element->devname);
244
245         connman_dbus_dict_append_variant(&dict, "Default",
246                                         DBUS_TYPE_BOOLEAN, &element->enabled);
247
248         device = __connman_element_get_device(element);
249         if (device != NULL)
250                 connman_dbus_dict_append_variant(&dict, "Device",
251                                         DBUS_TYPE_OBJECT_PATH, &device);
252
253         network = __connman_element_get_network(element);
254         if (network != NULL)
255                 connman_dbus_dict_append_variant(&dict, "Network",
256                                         DBUS_TYPE_OBJECT_PATH, &network);
257
258         connman_element_get_value(element,
259                                 CONNMAN_PROPERTY_ID_IPV4_METHOD, &method);
260
261         connman_element_get_value(element,
262                                 CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address);
263         connman_element_get_value(element,
264                                 CONNMAN_PROPERTY_ID_IPV4_NETMASK, &netmask);
265         connman_element_get_value(element,
266                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
267
268         if (method != NULL)
269                 connman_dbus_dict_append_variant(&dict, "IPv4.Method",
270                                                 DBUS_TYPE_STRING, &method);
271
272         if (address != NULL)
273                 connman_dbus_dict_append_variant(&dict, "IPv4.Address",
274                                                 DBUS_TYPE_STRING, &address);
275
276         if (netmask != NULL)
277                 connman_dbus_dict_append_variant(&dict, "IPv4.Netmask",
278                                                 DBUS_TYPE_STRING, &netmask);
279
280         if (gateway != NULL)
281                 connman_dbus_dict_append_variant(&dict, "IPv4.Gateway",
282                                                 DBUS_TYPE_STRING, &gateway);
283
284         dbus_message_iter_close_container(&array, &dict);
285
286         return reply;
287 }
288
289 static DBusMessage *set_property(DBusConnection *conn,
290                                         DBusMessage *msg, void *data)
291 {
292         DBusMessageIter iter, value;
293         const char *name;
294         int type;
295
296         DBG("conn %p", conn);
297
298         if (dbus_message_iter_init(msg, &iter) == FALSE)
299                 return __connman_error_invalid_arguments(msg);
300
301         dbus_message_iter_get_basic(&iter, &name);
302         dbus_message_iter_next(&iter);
303         dbus_message_iter_recurse(&iter, &value);
304
305         if (__connman_security_check_privilege(msg,
306                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
307                 return __connman_error_permission_denied(msg);
308
309         type = dbus_message_iter_get_arg_type(&value);
310
311         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
312 }
313
314 static GDBusMethodTable connection_methods[] = {
315         { "GetProperties", "",   "a{sv}", get_properties },
316         { "SetProperty",   "sv", "",      set_property   },
317         { },
318 };
319
320 static GDBusSignalTable connection_signals[] = {
321         { "PropertyChanged", "sv" },
322         { },
323 };
324
325 static DBusConnection *connection;
326
327 static void emit_connections_signal(void)
328 {
329 }
330
331 static int register_interface(struct connman_element *element)
332 {
333         DBG("element %p name %s", element, element->name);
334
335         if (g_dbus_register_interface(connection, element->path,
336                                         CONNMAN_CONNECTION_INTERFACE,
337                                         connection_methods, connection_signals,
338                                         NULL, element, NULL) == FALSE) {
339                 connman_error("Failed to register %s connection", element->path);
340                 return -EIO;
341         }
342
343         emit_connections_signal();
344
345         return 0;
346 }
347
348 static void unregister_interface(struct connman_element *element)
349 {
350         DBG("element %p name %s", element, element->name);
351
352         emit_connections_signal();
353
354         g_dbus_unregister_interface(connection, element->path,
355                                                 CONNMAN_CONNECTION_INTERFACE);
356 }
357
358 static int connection_probe(struct connman_element *element)
359 {
360         const char *gateway = NULL;
361
362         DBG("element %p name %s", element, element->name);
363
364         if (element->parent == NULL)
365                 return -ENODEV;
366
367         if (element->parent->type != CONNMAN_ELEMENT_TYPE_IPV4)
368                 return -ENODEV;
369
370         connman_element_get_value(element,
371                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
372
373         DBG("gateway %s", gateway);
374
375         if (register_interface(element) < 0)
376                 return -ENODEV;
377
378         if (gateway == NULL)
379                 return 0;
380
381         if (g_slist_length(gateway_list) > 0) {
382                 DBG("default gateway already present");
383                 return 0;
384         }
385
386         set_route(element, gateway);
387
388         connman_element_set_enabled(element, TRUE);
389
390         return 0;
391 }
392
393 static void connection_remove(struct connman_element *element)
394 {
395         const char *gateway = NULL;
396
397         DBG("element %p name %s", element, element->name);
398
399         unregister_interface(element);
400
401         connman_element_get_value(element,
402                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
403
404         DBG("gateway %s", gateway);
405
406         if (gateway == NULL)
407                 return;
408
409         del_route(element, gateway);
410 }
411
412 static struct connman_driver connection_driver = {
413         .name           = "connection",
414         .type           = CONNMAN_ELEMENT_TYPE_CONNECTION,
415         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
416         .probe          = connection_probe,
417         .remove         = connection_remove,
418 };
419
420 int __connman_connection_init(void)
421 {
422         DBG("");
423
424         connection = connman_dbus_get_connection();
425
426         if (connman_rtnl_register(&connection_rtnl) < 0)
427                 connman_error("Failed to setup RTNL gateway driver");
428
429         connman_rtnl_send_getroute();
430
431         return connman_driver_register(&connection_driver);
432 }
433
434 void __connman_connection_cleanup(void)
435 {
436         GSList *list;
437
438         DBG("");
439
440         connman_driver_unregister(&connection_driver);
441
442         connman_rtnl_unregister(&connection_rtnl);
443
444         for (list = gateway_list; list; list = list->next) {
445                 struct gateway_data *data = list->data;
446
447                 DBG("index %d gateway %s", data->index, data->gateway);
448
449                 g_free(data->gateway);
450                 g_free(data);
451                 list->data = NULL;
452         }
453
454         g_slist_free(gateway_list);
455         gateway_list = NULL;
456
457         dbus_connection_unref(connection);
458 }