c149cc61dbcd4422604455d93da973dd4942d79a
[platform/upstream/connman.git] / src / ipconfig.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 <net/if.h>
27
28 #ifndef IFF_LOWER_UP
29 #define IFF_LOWER_UP    0x10000
30 #endif
31
32 #include <gdbus.h>
33
34 #include "connman.h"
35
36 struct connman_ipaddress {
37         unsigned char prefixlen;
38         char *address;
39 };
40
41 struct connman_ipconfig {
42         gint refcount;
43         int index;
44         char *interface;
45         unsigned short type;
46         unsigned int flags;
47         enum connman_ipconfig_method method;
48         GSList *address_list;
49 };
50
51 static void free_address_list(struct connman_ipconfig *ipconfig)
52 {
53         GSList *list;
54
55         for (list = ipconfig->address_list; list; list = list->next) {
56                 struct connman_ipaddress *ipaddress = list->data;
57
58                 g_free(ipaddress->address);
59                 g_free(ipaddress);
60
61                 list->data = NULL;
62         }
63
64         g_slist_free(ipconfig->address_list);
65         ipconfig->address_list = NULL;
66 }
67
68 static struct connman_ipaddress *find_ipaddress(struct connman_ipconfig *ipconfig,
69                                 unsigned char prefixlen, const char *address)
70 {
71         GSList *list;
72
73         for (list = ipconfig->address_list; list; list = list->next) {
74                 struct connman_ipaddress *ipaddress = list->data;
75
76                 if (g_strcmp0(ipaddress->address, address) == 0 &&
77                                         ipaddress->prefixlen == prefixlen)
78                         return ipaddress;
79         }
80
81         return NULL;
82 }
83
84 /**
85  * connman_ipconfig_create:
86  *
87  * Allocate a new ipconfig structure.
88  *
89  * Returns: a newly-allocated #connman_ipconfig structure
90  */
91 struct connman_ipconfig *connman_ipconfig_create(int index)
92 {
93         struct connman_ipconfig *ipconfig;
94
95         DBG("");
96
97         ipconfig = g_try_new0(struct connman_ipconfig, 1);
98         if (ipconfig == NULL)
99                 return NULL;
100
101         ipconfig->refcount = 1;
102
103         ipconfig->index = index;
104         ipconfig->interface = connman_inet_ifname(index);
105
106         DBG("ipconfig %p", ipconfig);
107
108         connman_info("%s {create} index %d", ipconfig->interface,
109                                                         ipconfig->index);
110
111         return ipconfig;
112 }
113
114 /**
115  * connman_ipconfig_ref:
116  * @ipconfig: ipconfig structure
117  *
118  * Increase reference counter of ipconfig
119  */
120 struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig)
121 {
122         g_atomic_int_inc(&ipconfig->refcount);
123
124         return ipconfig;
125 }
126
127 /**
128  * connman_ipconfig_unref:
129  * @ipconfig: ipconfig structure
130  *
131  * Decrease reference counter of ipconfig
132  */
133 void connman_ipconfig_unref(struct connman_ipconfig *ipconfig)
134 {
135         if (g_atomic_int_dec_and_test(&ipconfig->refcount) == TRUE) {
136                 connman_info("%s {remove} index %d", ipconfig->interface,
137                                                         ipconfig->index);
138
139                 free_address_list(ipconfig);
140
141                 g_free(ipconfig->interface);
142                 g_free(ipconfig);
143         }
144 }
145
146 /**
147  * connman_ipconfig_set_method:
148  * @ipconfig: ipconfig structure
149  * @method: configuration method
150  *
151  * Set the configuration method
152  */
153 int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
154                                         enum connman_ipconfig_method method)
155 {
156         ipconfig->method = method;
157
158         return 0;
159 }
160
161 int __connman_ipconfig_get_index(struct connman_ipconfig *ipconfig)
162 {
163         return ipconfig->index;
164 }
165
166 unsigned short __connman_ipconfig_get_type(struct connman_ipconfig *ipconfig)
167 {
168         return ipconfig->type;
169 }
170
171 unsigned int __connman_ipconfig_get_flags(struct connman_ipconfig *ipconfig)
172 {
173         return ipconfig->flags;
174 }
175
176 void __connman_ipconfig_update_link(struct connman_ipconfig *ipconfig,
177                                         unsigned flags, unsigned change)
178 {
179         GString *str;
180
181         if (flags == ipconfig->flags)
182                 return;
183
184         ipconfig->flags = flags;
185
186         str = g_string_new(NULL);
187         if (str == NULL)
188                 return;
189
190         if (flags & IFF_UP)
191                 g_string_append(str, "UP");
192         else
193                 g_string_append(str, "DOWN");
194
195         if (flags & IFF_RUNNING)
196                 g_string_append(str, ",RUNNING");
197
198         if (flags & IFF_LOWER_UP)
199                 g_string_append(str, ",LOWER_UP");
200
201         connman_info("%s {update} flags %u change %u <%s>",
202                                 ipconfig->interface, flags, change, str->str);
203
204         g_string_free(str, TRUE);
205 }
206
207 void __connman_ipconfig_add_address(struct connman_ipconfig *ipconfig,
208                                 const char *label, unsigned char prefixlen,
209                                 const char *address, const char *broadcast)
210 {
211         struct connman_ipaddress *ipaddress;
212
213         ipaddress = g_try_new0(struct connman_ipaddress, 1);
214         if (ipaddress == NULL)
215                 return;
216
217         ipaddress->prefixlen = prefixlen;
218         ipaddress->address = g_strdup(address);
219
220         ipconfig->address_list = g_slist_append(ipconfig->address_list,
221                                                                 ipaddress);
222
223         connman_info("%s {add} address %s/%u label %s", ipconfig->interface,
224                                                 address, prefixlen, label);
225 }
226
227 void __connman_ipconfig_del_address(struct connman_ipconfig *ipconfig,
228                                 const char *label, unsigned char prefixlen,
229                                 const char *address, const char *broadcast)
230 {
231         struct connman_ipaddress *ipaddress;
232
233         ipaddress = find_ipaddress(ipconfig, prefixlen, address);
234         if (ipaddress == NULL)
235                 return;
236
237         ipconfig->address_list = g_slist_remove(ipconfig->address_list,
238                                                                 ipaddress);
239
240         g_free(ipaddress->address);
241         g_free(ipaddress);
242
243         connman_info("%s {del} address %s/%u label %s", ipconfig->interface,
244                                                 address, prefixlen, label);
245 }
246
247 static const char *scope2str(unsigned char scope)
248 {
249         switch (scope) {
250         case 0:
251                 return "UNIVERSE";
252         case 253:
253                 return "LINK";
254         }
255
256         return "";
257 }
258
259 void __connman_ipconfig_add_route(struct connman_ipconfig *ipconfig,
260                                 unsigned char scope, const char *destination,
261                                                         const char *gateway)
262 {
263         connman_info("%s {add} route %s gw %s scope %u <%s>",
264                                         ipconfig->interface, destination,
265                                         gateway, scope, scope2str(scope));
266 }
267
268 void __connman_ipconfig_del_route(struct connman_ipconfig *ipconfig,
269                                 unsigned char scope, const char *destination,
270                                                         const char *gateway)
271 {
272         connman_info("%s {del} route %s gw %s scope %u <%s>",
273                                         ipconfig->interface, destination,
274                                         gateway, scope, scope2str(scope));
275 }
276
277 const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method)
278 {
279         switch (method) {
280         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
281                 break;
282         case CONNMAN_IPCONFIG_METHOD_OFF:
283                 return "off";
284         case CONNMAN_IPCONFIG_METHOD_STATIC:
285                 return "static";
286         case CONNMAN_IPCONFIG_METHOD_DHCP:
287                 return "dhcp";
288         }
289
290         return NULL;
291 }
292
293 enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method)
294 {
295         if (g_strcmp0(method, "off") == 0)
296                 return CONNMAN_IPCONFIG_METHOD_OFF;
297         else if (g_strcmp0(method, "static") == 0)
298                 return CONNMAN_IPCONFIG_METHOD_STATIC;
299         else if (g_strcmp0(method, "dhcp") == 0)
300                 return CONNMAN_IPCONFIG_METHOD_DHCP;
301         else
302                 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
303 }
304
305 static void append_variant(DBusMessageIter *iter, const char *prefix,
306                                         const char *key, int type, void *val)
307 {
308         char *str;
309
310         if (prefix == NULL) {
311                 connman_dbus_dict_append_variant(iter, key, type, val);
312                 return;
313         }
314
315         str = g_strdup_printf("%s%s", prefix, key);
316         if (str != NULL)
317                 connman_dbus_dict_append_variant(iter, str, type, val);
318
319         g_free(str);
320 }
321
322 void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
323                                 DBusMessageIter *iter, const char *prefix)
324 {
325         const char *str;
326
327         str = __connman_ipconfig_method2string(ipconfig->method);
328         if (str == NULL)
329                 return;
330
331         append_variant(iter, prefix, "Method", DBUS_TYPE_STRING, &str);
332 }
333
334 int __connman_ipconfig_set_ipv4(struct connman_ipconfig *ipconfig,
335                                 const char *key, DBusMessageIter *value)
336 {
337         int type = dbus_message_iter_get_arg_type(value);
338
339         DBG("ipconfig %p key %s type %d", ipconfig, key, type);
340
341         if (g_strcmp0(key, "Method") == 0) {
342                 const char *method;
343
344                 if (type != DBUS_TYPE_STRING)
345                         return -EINVAL;
346
347                 dbus_message_iter_get_basic(value, &method);
348
349                 ipconfig->method = __connman_ipconfig_string2method(method);
350         } else
351                 return -EINVAL;
352
353         return 0;
354 }
355
356 int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
357                 GKeyFile *keyfile, const char *identifier, const char *prefix)
358 {
359         DBG("ipconfig %p identifier %s", ipconfig, identifier);
360
361         return 0;
362 }
363
364 int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
365                 GKeyFile *keyfile, const char *identifier, const char *prefix)
366 {
367         DBG("ipconfig %p identifier %s", ipconfig, identifier);
368
369         return 0;
370 }
371
372 static GSList *driver_list = NULL;
373
374 static gint compare_priority(gconstpointer a, gconstpointer b)
375 {
376         const struct connman_ipconfig_driver *driver1 = a;
377         const struct connman_ipconfig_driver *driver2 = b;
378
379         return driver2->priority - driver1->priority;
380 }
381
382 /**
383  * connman_ipconfig_driver_register:
384  * @driver: IP configuration driver
385  *
386  * Register a new IP configuration driver
387  *
388  * Returns: %0 on success
389  */
390 int connman_ipconfig_driver_register(struct connman_ipconfig_driver *driver)
391 {
392         DBG("driver %p name %s", driver, driver->name);
393
394         driver_list = g_slist_insert_sorted(driver_list, driver,
395                                                         compare_priority);
396
397         return 0;
398 }
399
400 /**
401  * connman_ipconfig_driver_unregister:
402  * @driver: IP configuration driver
403  *
404  * Remove a previously registered IP configuration driver.
405  */
406 void connman_ipconfig_driver_unregister(struct connman_ipconfig_driver *driver)
407 {
408         DBG("driver %p name %s", driver, driver->name);
409
410         driver_list = g_slist_remove(driver_list, driver);
411 }