Remove unused connection interface
[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         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         memset(&addr, 0, sizeof(addr));
96         addr.sin_family = AF_INET;
97         addr.sin_addr.s_addr = inet_addr(gateway);
98         memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
99
100         memset(&addr, 0, sizeof(addr));
101         addr.sin_family = AF_INET;
102         addr.sin_addr.s_addr = INADDR_ANY;
103         memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
104
105         memset(&addr, 0, sizeof(addr));
106         addr.sin_family = AF_INET;
107         addr.sin_addr.s_addr = INADDR_ANY;
108         memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
109
110         rt.rt_dev = ifr.ifr_name;
111
112         err = ioctl(sk, SIOCADDRT, &rt);
113         if (err < 0)
114                 connman_error("Setting host gateway route failed (%s)",
115                                                         strerror(errno));
116
117         memset(&rt, 0, sizeof(rt));
118         rt.rt_flags = RTF_UP | RTF_GATEWAY;
119
120         memset(&addr, 0, sizeof(addr));
121         addr.sin_family = AF_INET;
122         addr.sin_addr.s_addr = INADDR_ANY;
123         memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
124
125         memset(&addr, 0, sizeof(addr));
126         addr.sin_family = AF_INET;
127         addr.sin_addr.s_addr = inet_addr(gateway);
128         memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
129
130         memset(&addr, 0, sizeof(addr));
131         addr.sin_family = AF_INET;
132         addr.sin_addr.s_addr = INADDR_ANY;
133         memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
134
135         err = ioctl(sk, SIOCADDRT, &rt);
136         if (err < 0)
137                 connman_error("Setting default route failed (%s)",
138                                                         strerror(errno));
139
140         close(sk);
141
142         return err;
143 }
144
145 static int del_route(struct connman_element *element, const char *gateway)
146 {
147         struct ifreq ifr;
148         struct rtentry rt;
149         struct sockaddr_in addr;
150         int sk, err;
151
152         DBG("element %p", element);
153
154         sk = socket(PF_INET, SOCK_DGRAM, 0);
155         if (sk < 0)
156                 return -1;
157
158         memset(&ifr, 0, sizeof(ifr));
159         ifr.ifr_ifindex = element->index;
160
161         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
162                 close(sk);
163                 return -1;
164         }
165
166         DBG("ifname %s", ifr.ifr_name);
167
168         memset(&rt, 0, sizeof(rt));
169         rt.rt_flags = RTF_UP | RTF_GATEWAY;
170
171         memset(&addr, 0, sizeof(addr));
172         addr.sin_family = AF_INET;
173         addr.sin_addr.s_addr = INADDR_ANY;
174         memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
175
176         memset(&addr, 0, sizeof(addr));
177         addr.sin_family = AF_INET;
178         addr.sin_addr.s_addr = inet_addr(gateway);
179         memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
180
181         memset(&addr, 0, sizeof(addr));
182         addr.sin_family = AF_INET;
183         addr.sin_addr.s_addr = INADDR_ANY;
184         memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
185
186         err = ioctl(sk, SIOCDELRT, &rt);
187         if (err < 0)
188                 connman_error("Removing default route failed (%s)",
189                                                         strerror(errno));
190
191         close(sk);
192
193         return err;
194 }
195
196 static void find_element(struct connman_element *element, gpointer user_data)
197 {
198         struct gateway_data *data = user_data;
199
200         DBG("element %p name %s", element, element->name);
201
202         if (data->element != NULL)
203                 return;
204
205         if (element->index != data->index)
206                 return;
207
208         data->element = element;
209 }
210
211 static struct gateway_data *add_gateway(int index, const char *gateway)
212 {
213         struct gateway_data *data;
214         struct connman_service *service;
215
216         data = g_try_new0(struct gateway_data, 1);
217         if (data == NULL)
218                 return NULL;
219
220         data->index = index;
221         data->gateway = g_strdup(gateway);
222         data->active = FALSE;
223         data->element = NULL;
224
225         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION,
226                                                         find_element, data);
227
228         service = __connman_element_get_service(data->element);
229         data->order = __connman_service_get_order(service);
230
231         gateway_list = g_slist_append(gateway_list, data);
232
233         return data;
234 }
235
236 static void connection_newgateway(int index, const char *gateway)
237 {
238         struct gateway_data *data;
239
240         DBG("index %d gateway %s", index, gateway);
241
242         data = find_gateway(index, gateway);
243         if (data == NULL)
244                 return;
245
246         data->active = TRUE;
247 }
248
249 static void set_default_gateway(struct gateway_data *data)
250 {
251         struct connman_element *element = data->element;
252         struct connman_service *service = NULL;
253
254         DBG("gateway %s", data->gateway);
255
256         if (set_route(element, data->gateway) < 0)
257                 return;
258
259         service = __connman_element_get_service(element);
260         __connman_service_indicate_default(service);
261 }
262
263 static struct gateway_data *find_default_gateway(void)
264 {
265         struct gateway_data *found = NULL;
266         unsigned int order = 0;
267         GSList *list;
268
269         for (list = gateway_list; list; list = list->next) {
270                 struct gateway_data *data = list->data;
271
272                 if (found == NULL || data->order > order) {
273                         found = data;
274                         order = data->order;
275                 }
276         }
277
278         return found;
279 }
280
281 static void remove_gateway(struct gateway_data *data)
282 {
283         DBG("gateway %s", data->gateway);
284
285         gateway_list = g_slist_remove(gateway_list, data);
286
287         if (data->active == TRUE)
288                 del_route(data->element, data->gateway);
289
290         g_free(data->gateway);
291         g_free(data);
292 }
293
294 static void connection_delgateway(int index, const char *gateway)
295 {
296         struct gateway_data *data;
297
298         DBG("index %d gateway %s", index, gateway);
299
300         data = find_gateway(index, gateway);
301         if (data != NULL)
302                 data->active = FALSE;
303
304         data = find_default_gateway();
305         if (data != NULL)
306                 set_default_gateway(data);
307 }
308
309 static struct connman_rtnl connection_rtnl = {
310         .name           = "connection",
311         .newgateway     = connection_newgateway,
312         .delgateway     = connection_delgateway,
313 };
314
315 static struct gateway_data *find_active_gateway(void)
316 {
317         GSList *list;
318
319         DBG("");
320
321         for (list = gateway_list; list; list = list->next) {
322                 struct gateway_data *data = list->data;
323                 if (data->active == TRUE)
324                         return data;
325         }
326
327         return NULL;
328 }
329
330 static int connection_probe(struct connman_element *element)
331 {
332         struct connman_service *service = NULL;
333         const char *gateway = NULL;
334         struct gateway_data *active_gateway = NULL;
335         struct gateway_data *new_gateway = NULL;
336
337         DBG("element %p name %s", element, element->name);
338
339         if (element->parent == NULL)
340                 return -ENODEV;
341
342         if (element->parent->type != CONNMAN_ELEMENT_TYPE_IPV4)
343                 return -ENODEV;
344
345         connman_element_get_value(element,
346                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
347
348         DBG("gateway %s", gateway);
349
350         service = __connman_element_get_service(element);
351         __connman_service_indicate_state(service,
352                                         CONNMAN_SERVICE_STATE_READY);
353
354         connman_element_set_enabled(element, TRUE);
355
356         if (gateway == NULL)
357                 return 0;
358
359         active_gateway = find_active_gateway();
360         new_gateway = add_gateway(element->index, gateway);
361
362         if (active_gateway == NULL) {
363                 set_default_gateway(new_gateway);
364                 return 0;
365         }
366
367         if (new_gateway->order >= active_gateway->order) {
368                 del_route(active_gateway->element, active_gateway->gateway);
369                 return 0;
370         }
371
372         return 0;
373 }
374
375 static void connection_remove(struct connman_element *element)
376 {
377         struct connman_service *service;
378         const char *gateway = NULL;
379         struct gateway_data *data = NULL;
380
381         DBG("element %p name %s", element, element->name);
382
383         service = __connman_element_get_service(element);
384         __connman_service_indicate_state(service,
385                                         CONNMAN_SERVICE_STATE_DISCONNECT);
386
387         connman_element_set_enabled(element, FALSE);
388
389         connman_element_get_value(element,
390                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
391
392         DBG("gateway %s", gateway);
393
394         if (gateway == NULL)
395                 return;
396
397         data = find_gateway(element->index, gateway);
398         if (data == NULL)
399                 return;
400
401         remove_gateway(data);
402 }
403
404 static struct connman_driver connection_driver = {
405         .name           = "connection",
406         .type           = CONNMAN_ELEMENT_TYPE_CONNECTION,
407         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
408         .probe          = connection_probe,
409         .remove         = connection_remove,
410 };
411
412 int __connman_connection_init(void)
413 {
414         DBG("");
415
416         if (connman_rtnl_register(&connection_rtnl) < 0)
417                 connman_error("Failed to setup RTNL gateway driver");
418
419         return connman_driver_register(&connection_driver);
420 }
421
422 void __connman_connection_cleanup(void)
423 {
424         GSList *list;
425
426         DBG("");
427
428         connman_driver_unregister(&connection_driver);
429
430         connman_rtnl_unregister(&connection_rtnl);
431
432         for (list = gateway_list; list; list = list->next) {
433                 struct gateway_data *data = list->data;
434
435                 DBG("index %d gateway %s", data->index, data->gateway);
436
437                 g_free(data->gateway);
438                 g_free(data);
439                 list->data = NULL;
440         }
441
442         g_slist_free(gateway_list);
443         gateway_list = NULL;
444 }
445
446 static void update_order(void)
447 {
448         GSList *list = NULL;
449
450         for (list = gateway_list; list; list = list->next) {
451                 struct gateway_data *data = list->data;
452                 struct connman_service *service;
453
454                 service = __connman_element_get_service(data->element);
455                 data->order = __connman_service_get_order(service);
456         }
457 }
458
459 gboolean __connman_connection_update_gateway(void)
460 {
461         struct gateway_data *active_gateway, *default_gateway;
462         gboolean updated = FALSE;
463
464         update_order();
465
466         active_gateway = find_active_gateway();
467         default_gateway = find_default_gateway();
468
469         if (active_gateway && active_gateway != default_gateway) {
470                 del_route(active_gateway->element, active_gateway->gateway);
471                 updated = TRUE;
472         }
473
474         return updated;
475 }