013a14f05db40a8cdc1a2fb0fd5efefacea3268f
[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         char *gateway;
50 };
51
52 static void free_address_list(struct connman_ipconfig *ipconfig)
53 {
54         GSList *list;
55
56         for (list = ipconfig->address_list; list; list = list->next) {
57                 struct connman_ipaddress *ipaddress = list->data;
58
59                 g_free(ipaddress->address);
60                 g_free(ipaddress);
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                 g_free(ipconfig->gateway);
140
141                 free_address_list(ipconfig);
142
143                 g_free(ipconfig->interface);
144                 g_free(ipconfig);
145         }
146 }
147
148 /**
149  * connman_ipconfig_set_method:
150  * @ipconfig: ipconfig structure
151  * @method: configuration method
152  *
153  * Set the configuration method
154  */
155 int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
156                                         enum connman_ipconfig_method method)
157 {
158         ipconfig->method = method;
159
160         return 0;
161 }
162
163 int __connman_ipconfig_get_index(struct connman_ipconfig *ipconfig)
164 {
165         return ipconfig->index;
166 }
167
168 unsigned short __connman_ipconfig_get_type(struct connman_ipconfig *ipconfig)
169 {
170         return ipconfig->type;
171 }
172
173 unsigned int __connman_ipconfig_get_flags(struct connman_ipconfig *ipconfig)
174 {
175         return ipconfig->flags;
176 }
177
178 const char *__connman_ipconfig_get_gateway(struct connman_ipconfig *ipconfig)
179 {
180         return ipconfig->gateway;
181 }
182
183 void __connman_ipconfig_update_link(struct connman_ipconfig *ipconfig,
184                                         unsigned flags, unsigned change)
185 {
186         GString *str;
187
188         if (flags == ipconfig->flags)
189                 return;
190
191         ipconfig->flags = flags;
192
193         str = g_string_new(NULL);
194         if (str == NULL)
195                 return;
196
197         if (flags & IFF_UP)
198                 g_string_append(str, "UP");
199         else
200                 g_string_append(str, "DOWN");
201
202         if (flags & IFF_RUNNING)
203                 g_string_append(str, ",RUNNING");
204
205         if (flags & IFF_LOWER_UP)
206                 g_string_append(str, ",LOWER_UP");
207
208         connman_info("%s {update} flags %u change %u <%s>",
209                                 ipconfig->interface, flags, change, str->str);
210
211         g_string_free(str, TRUE);
212 }
213
214 void __connman_ipconfig_add_address(struct connman_ipconfig *ipconfig,
215                                 const char *label, unsigned char prefixlen,
216                                 const char *address, const char *broadcast)
217 {
218         struct connman_ipaddress *ipaddress;
219
220         ipaddress = g_try_new0(struct connman_ipaddress, 1);
221         if (ipaddress == NULL)
222                 return;
223
224         ipaddress->prefixlen = prefixlen;
225         ipaddress->address = g_strdup(address);
226
227         ipconfig->address_list = g_slist_append(ipconfig->address_list,
228                                                                 ipaddress);
229
230         connman_info("%s {add} address %s/%u label %s", ipconfig->interface,
231                                                 address, prefixlen, label);
232 }
233
234 void __connman_ipconfig_del_address(struct connman_ipconfig *ipconfig,
235                                 const char *label, unsigned char prefixlen,
236                                 const char *address, const char *broadcast)
237 {
238         struct connman_ipaddress *ipaddress;
239
240         ipaddress = find_ipaddress(ipconfig, prefixlen, address);
241         if (ipaddress == NULL)
242                 return;
243
244         ipconfig->address_list = g_slist_remove(ipconfig->address_list,
245                                                                 ipaddress);
246
247         g_free(ipaddress->address);
248         g_free(ipaddress);
249
250         connman_info("%s {del} address %s/%u label %s", ipconfig->interface,
251                                                 address, prefixlen, label);
252 }
253
254 static const char *scope2str(unsigned char scope)
255 {
256         switch (scope) {
257         case 0:
258                 return "UNIVERSE";
259         case 253:
260                 return "LINK";
261         }
262
263         return "";
264 }
265
266 void __connman_ipconfig_add_route(struct connman_ipconfig *ipconfig,
267                                 unsigned char scope, const char *destination,
268                                                         const char *gateway)
269 {
270         if (scope == 0 && g_strcmp0(destination, "0.0.0.0") == 0) {
271                 g_free(ipconfig->gateway);
272                 ipconfig->gateway = g_strdup(gateway);
273         }
274
275         connman_info("%s {add} route %s gw %s scope %u <%s>",
276                                         ipconfig->interface, destination,
277                                         gateway, scope, scope2str(scope));
278 }
279
280 void __connman_ipconfig_del_route(struct connman_ipconfig *ipconfig,
281                                 unsigned char scope, const char *destination,
282                                                         const char *gateway)
283 {
284         if (scope == 0 && g_strcmp0(destination, "0.0.0.0") == 0) {
285                 g_free(ipconfig->gateway);
286                 ipconfig->gateway = NULL;
287         }
288
289         connman_info("%s {del} route %s gw %s scope %u <%s>",
290                                         ipconfig->interface, destination,
291                                         gateway, scope, scope2str(scope));
292 }
293
294 const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method)
295 {
296         switch (method) {
297         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
298                 break;
299         case CONNMAN_IPCONFIG_METHOD_OFF:
300                 return "off";
301         case CONNMAN_IPCONFIG_METHOD_STATIC:
302                 return "static";
303         case CONNMAN_IPCONFIG_METHOD_DHCP:
304                 return "dhcp";
305         }
306
307         return NULL;
308 }
309
310 enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method)
311 {
312         if (g_strcmp0(method, "off") == 0)
313                 return CONNMAN_IPCONFIG_METHOD_OFF;
314         else if (g_strcmp0(method, "static") == 0)
315                 return CONNMAN_IPCONFIG_METHOD_STATIC;
316         else if (g_strcmp0(method, "dhcp") == 0)
317                 return CONNMAN_IPCONFIG_METHOD_DHCP;
318         else
319                 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
320 }
321
322 static void append_variant(DBusMessageIter *iter, const char *prefix,
323                                         const char *key, int type, void *val)
324 {
325         char *str;
326
327         if (prefix == NULL) {
328                 connman_dbus_dict_append_variant(iter, key, type, val);
329                 return;
330         }
331
332         str = g_strdup_printf("%s%s", prefix, key);
333         if (str != NULL)
334                 connman_dbus_dict_append_variant(iter, str, type, val);
335
336         g_free(str);
337 }
338
339 void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
340                                 DBusMessageIter *iter, const char *prefix)
341 {
342         const char *str;
343
344         str = __connman_ipconfig_method2string(ipconfig->method);
345         if (str == NULL)
346                 return;
347
348         append_variant(iter, prefix, "Method", DBUS_TYPE_STRING, &str);
349 }
350
351 int __connman_ipconfig_set_ipv4(struct connman_ipconfig *ipconfig,
352                                 const char *key, DBusMessageIter *value)
353 {
354         int type = dbus_message_iter_get_arg_type(value);
355
356         DBG("ipconfig %p key %s type %d", ipconfig, key, type);
357
358         if (g_strcmp0(key, "Method") == 0) {
359                 const char *method;
360
361                 if (type != DBUS_TYPE_STRING)
362                         return -EINVAL;
363
364                 dbus_message_iter_get_basic(value, &method);
365
366                 ipconfig->method = __connman_ipconfig_string2method(method);
367         } else
368                 return -EINVAL;
369
370         return 0;
371 }
372
373 int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
374                 GKeyFile *keyfile, const char *identifier, const char *prefix)
375 {
376         DBG("ipconfig %p identifier %s", ipconfig, identifier);
377
378         return 0;
379 }
380
381 int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
382                 GKeyFile *keyfile, const char *identifier, const char *prefix)
383 {
384         DBG("ipconfig %p identifier %s", ipconfig, identifier);
385
386         return 0;
387 }
388
389 static GSList *driver_list = NULL;
390
391 static gint compare_priority(gconstpointer a, gconstpointer b)
392 {
393         const struct connman_ipconfig_driver *driver1 = a;
394         const struct connman_ipconfig_driver *driver2 = b;
395
396         return driver2->priority - driver1->priority;
397 }
398
399 /**
400  * connman_ipconfig_driver_register:
401  * @driver: IP configuration driver
402  *
403  * Register a new IP configuration driver
404  *
405  * Returns: %0 on success
406  */
407 int connman_ipconfig_driver_register(struct connman_ipconfig_driver *driver)
408 {
409         DBG("driver %p name %s", driver, driver->name);
410
411         driver_list = g_slist_insert_sorted(driver_list, driver,
412                                                         compare_priority);
413
414         return 0;
415 }
416
417 /**
418  * connman_ipconfig_driver_unregister:
419  * @driver: IP configuration driver
420  *
421  * Remove a previously registered IP configuration driver.
422  */
423 void connman_ipconfig_driver_unregister(struct connman_ipconfig_driver *driver)
424 {
425         DBG("driver %p name %s", driver, driver->name);
426
427         driver_list = g_slist_remove(driver_list, driver);
428 }