Integrate RTNL deeper into IP configuration tracking
[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_ipconfig {
37         gint refcount;
38         int index;
39         char *interface;
40         unsigned short type;
41         unsigned int flags;
42         enum connman_ipconfig_method method;
43 };
44
45 /**
46  * connman_ipconfig_create:
47  *
48  * Allocate a new ipconfig structure.
49  *
50  * Returns: a newly-allocated #connman_ipconfig structure
51  */
52 struct connman_ipconfig *connman_ipconfig_create(int index)
53 {
54         struct connman_ipconfig *ipconfig;
55
56         DBG("");
57
58         ipconfig = g_try_new0(struct connman_ipconfig, 1);
59         if (ipconfig == NULL)
60                 return NULL;
61
62         ipconfig->refcount = 1;
63
64         ipconfig->index = index;
65         ipconfig->interface = connman_inet_ifname(index);
66
67         DBG("ipconfig %p", ipconfig);
68
69         connman_info("%s {create} index %d", ipconfig->interface,
70                                                         ipconfig->index);
71
72         return ipconfig;
73 }
74
75 /**
76  * connman_ipconfig_ref:
77  * @ipconfig: ipconfig structure
78  *
79  * Increase reference counter of ipconfig
80  */
81 struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig)
82 {
83         g_atomic_int_inc(&ipconfig->refcount);
84
85         return ipconfig;
86 }
87
88 /**
89  * connman_ipconfig_unref:
90  * @ipconfig: ipconfig structure
91  *
92  * Decrease reference counter of ipconfig
93  */
94 void connman_ipconfig_unref(struct connman_ipconfig *ipconfig)
95 {
96         if (g_atomic_int_dec_and_test(&ipconfig->refcount) == TRUE) {
97                 connman_info("%s {remove} index %d", ipconfig->interface,
98                                                         ipconfig->index);
99
100                 g_free(ipconfig->interface);
101                 g_free(ipconfig);
102         }
103 }
104
105 /**
106  * connman_ipconfig_set_method:
107  * @ipconfig: ipconfig structure
108  * @method: configuration method
109  *
110  * Set the configuration method
111  */
112 int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
113                                         enum connman_ipconfig_method method)
114 {
115         ipconfig->method = method;
116
117         return 0;
118 }
119
120 int __connman_ipconfig_get_index(struct connman_ipconfig *ipconfig)
121 {
122         return ipconfig->index;
123 }
124
125 unsigned short __connman_ipconfig_get_type(struct connman_ipconfig *ipconfig)
126 {
127         return ipconfig->type;
128 }
129
130 unsigned int __connman_ipconfig_get_flags(struct connman_ipconfig *ipconfig)
131 {
132         return ipconfig->flags;
133 }
134
135 void __connman_ipconfig_update_link(struct connman_ipconfig *ipconfig,
136                                         unsigned flags, unsigned change)
137 {
138         GString *str;
139
140         if (flags == ipconfig->flags)
141                 return;
142
143         ipconfig->flags = flags;
144
145         str = g_string_new(NULL);
146         if (str == NULL)
147                 return;
148
149         if (flags & IFF_UP)
150                 g_string_append(str, "UP");
151         else
152                 g_string_append(str, "DOWN");
153
154         if (flags & IFF_RUNNING)
155                 g_string_append(str, ",RUNNING");
156
157         if (flags & IFF_LOWER_UP)
158                 g_string_append(str, ",LOWER_UP");
159
160         connman_info("%s {update} flags %u change %u <%s>",
161                                 ipconfig->interface, flags, change, str->str);
162
163         g_string_free(str, TRUE);
164 }
165
166 void __connman_ipconfig_add_address(struct connman_ipconfig *ipconfig,
167                                 const char *label, unsigned char prefixlen,
168                                 const char *address, const char *broadcast)
169 {
170         connman_info("%s {add} address %s/%u label %s", ipconfig->interface,
171                                                 address, prefixlen, label);
172 }
173
174 void __connman_ipconfig_del_address(struct connman_ipconfig *ipconfig,
175                                 const char *label, unsigned char prefixlen,
176                                 const char *address, const char *broadcast)
177 {
178         connman_info("%s {del} address %s/%u label %s", ipconfig->interface,
179                                                 address, prefixlen, label);
180 }
181
182 const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method)
183 {
184         switch (method) {
185         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
186                 break;
187         case CONNMAN_IPCONFIG_METHOD_OFF:
188                 return "off";
189         case CONNMAN_IPCONFIG_METHOD_STATIC:
190                 return "static";
191         case CONNMAN_IPCONFIG_METHOD_DHCP:
192                 return "dhcp";
193         }
194
195         return NULL;
196 }
197
198 enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method)
199 {
200         if (g_strcmp0(method, "off") == 0)
201                 return CONNMAN_IPCONFIG_METHOD_OFF;
202         else if (g_strcmp0(method, "static") == 0)
203                 return CONNMAN_IPCONFIG_METHOD_STATIC;
204         else if (g_strcmp0(method, "dhcp") == 0)
205                 return CONNMAN_IPCONFIG_METHOD_DHCP;
206         else
207                 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
208 }
209
210 static void append_variant(DBusMessageIter *iter, const char *prefix,
211                                         const char *key, int type, void *val)
212 {
213         char *str;
214
215         if (prefix == NULL) {
216                 connman_dbus_dict_append_variant(iter, key, type, val);
217                 return;
218         }
219
220         str = g_strdup_printf("%s%s", prefix, key);
221         if (str != NULL)
222                 connman_dbus_dict_append_variant(iter, str, type, val);
223
224         g_free(str);
225 }
226
227 void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
228                                 DBusMessageIter *iter, const char *prefix)
229 {
230         const char *str;
231
232         str = __connman_ipconfig_method2string(ipconfig->method);
233         if (str == NULL)
234                 return;
235
236         append_variant(iter, prefix, "Method", DBUS_TYPE_STRING, &str);
237 }
238
239 int __connman_ipconfig_set_ipv4(struct connman_ipconfig *ipconfig,
240                                 const char *key, DBusMessageIter *value)
241 {
242         int type = dbus_message_iter_get_arg_type(value);
243
244         DBG("ipconfig %p key %s type %d", ipconfig, key, type);
245
246         if (g_strcmp0(key, "Method") == 0) {
247                 const char *method;
248
249                 if (type != DBUS_TYPE_STRING)
250                         return -EINVAL;
251
252                 dbus_message_iter_get_basic(value, &method);
253
254                 ipconfig->method = __connman_ipconfig_string2method(method);
255         } else
256                 return -EINVAL;
257
258         return 0;
259 }
260
261 int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
262                 GKeyFile *keyfile, const char *identifier, const char *prefix)
263 {
264         DBG("ipconfig %p identifier %s", ipconfig, identifier);
265
266         return 0;
267 }
268
269 int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
270                 GKeyFile *keyfile, const char *identifier, const char *prefix)
271 {
272         DBG("ipconfig %p identifier %s", ipconfig, identifier);
273
274         return 0;
275 }
276
277 static GSList *driver_list = NULL;
278
279 static gint compare_priority(gconstpointer a, gconstpointer b)
280 {
281         const struct connman_ipconfig_driver *driver1 = a;
282         const struct connman_ipconfig_driver *driver2 = b;
283
284         return driver2->priority - driver1->priority;
285 }
286
287 /**
288  * connman_ipconfig_driver_register:
289  * @driver: IP configuration driver
290  *
291  * Register a new IP configuration driver
292  *
293  * Returns: %0 on success
294  */
295 int connman_ipconfig_driver_register(struct connman_ipconfig_driver *driver)
296 {
297         DBG("driver %p name %s", driver, driver->name);
298
299         driver_list = g_slist_insert_sorted(driver_list, driver,
300                                                         compare_priority);
301
302         return 0;
303 }
304
305 /**
306  * connman_ipconfig_driver_unregister:
307  * @driver: IP configuration driver
308  *
309  * Remove a previously registered IP configuration driver.
310  */
311 void connman_ipconfig_driver_unregister(struct connman_ipconfig_driver *driver)
312 {
313         DBG("driver %p name %s", driver, driver->name);
314
315         driver_list = g_slist_remove(driver_list, driver);
316 }