Use ignore method for unconfigured IP devices
[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 #include <net/if_arp.h>
28
29 #ifndef IFF_LOWER_UP
30 #define IFF_LOWER_UP    0x10000
31 #endif
32
33 #include <gdbus.h>
34
35 #include "connman.h"
36
37 struct connman_ipaddress {
38         unsigned char prefixlen;
39         char *address;
40 };
41
42 struct connman_ipdevice {
43         int index;
44         char *ifname;
45         unsigned short type;
46         unsigned int flags;
47
48         GSList *address_list;
49         char *gateway;
50 };
51
52 struct connman_ipconfig {
53         gint refcount;
54         int index;
55
56         const struct connman_ipconfig_ops *ops;
57         void *ops_data;
58
59         enum connman_ipconfig_method method;
60 };
61
62 static GHashTable *ipdevice_hash = NULL;
63 static GList *ipconfig_list = NULL;
64
65 static void free_address_list(struct connman_ipdevice *ipdevice)
66 {
67         GSList *list;
68
69         for (list = ipdevice->address_list; list; list = list->next) {
70                 struct connman_ipaddress *ipaddress = list->data;
71
72                 g_free(ipaddress->address);
73                 g_free(ipaddress);
74                 list->data = NULL;
75         }
76
77         g_slist_free(ipdevice->address_list);
78         ipdevice->address_list = NULL;
79 }
80
81 static struct connman_ipaddress *find_ipaddress(struct connman_ipdevice *ipdevice,
82                                 unsigned char prefixlen, const char *address)
83 {
84         GSList *list;
85
86         for (list = ipdevice->address_list; list; list = list->next) {
87                 struct connman_ipaddress *ipaddress = list->data;
88
89                 if (g_strcmp0(ipaddress->address, address) == 0 &&
90                                         ipaddress->prefixlen == prefixlen)
91                         return ipaddress;
92         }
93
94         return NULL;
95 }
96
97 static const char *type2str(unsigned short type)
98 {
99         switch (type) {
100         case ARPHRD_ETHER:
101                 return "ETHER";
102         case ARPHRD_LOOPBACK:
103                 return "LOOPBACK";
104         case ARPHRD_PPP:
105                 return "PPP";
106         case ARPHRD_NONE:
107                 return "NONE";
108         case ARPHRD_VOID:
109                 return "VOID";
110         }
111
112         return "";
113 }
114
115 static const char *scope2str(unsigned char scope)
116 {
117         switch (scope) {
118         case 0:
119                 return "UNIVERSE";
120         case 253:
121                 return "LINK";
122         }
123
124         return "";
125 }
126
127 static void free_ipdevice(gpointer data)
128 {
129         struct connman_ipdevice *ipdevice = data;
130
131         connman_info("%s {remove} index %d", ipdevice->ifname,
132                                                         ipdevice->index);
133
134         free_address_list(ipdevice);
135         g_free(ipdevice->gateway);
136
137         g_free(ipdevice->ifname);
138         g_free(ipdevice);
139 }
140
141 void __connman_ipconfig_newlink(int index, unsigned short type,
142                                                         unsigned int flags)
143 {
144         struct connman_ipdevice *ipdevice;
145         GList *list;
146         GString *str;
147         gboolean up = FALSE, down = FALSE;
148         gboolean lower_up = FALSE, lower_down = FALSE;
149
150         DBG("index %d", index);
151
152         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
153         if (ipdevice != NULL)
154                 goto update;
155
156         ipdevice = g_try_new0(struct connman_ipdevice, 1);
157         if (ipdevice == NULL)
158                 return;
159
160         ipdevice->index = index;
161         ipdevice->ifname = connman_inet_ifname(index);
162         ipdevice->type = type;
163
164         g_hash_table_insert(ipdevice_hash, GINT_TO_POINTER(index), ipdevice);
165
166         connman_info("%s {create} index %d type %d <%s>", ipdevice->ifname,
167                                                 index, type, type2str(type));
168
169 update:
170         if (flags == ipdevice->flags)
171                 return;
172
173         if ((ipdevice->flags & IFF_UP) != (flags & IFF_UP)) {
174                 if (flags & IFF_UP)
175                         up = TRUE;
176                 else
177                         down = TRUE;
178         }
179
180         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) !=
181                                 (flags & (IFF_RUNNING | IFF_LOWER_UP))) {
182                 if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) ==
183                                         (IFF_RUNNING | IFF_LOWER_UP))
184                         lower_up = TRUE;
185                 else if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) == 0)
186                         lower_down = TRUE;
187         }
188
189         ipdevice->flags = flags;
190
191         str = g_string_new(NULL);
192         if (str == NULL)
193                 return;
194
195         if (flags & IFF_UP)
196                 g_string_append(str, "UP");
197         else
198                 g_string_append(str, "DOWN");
199
200         if (flags & IFF_RUNNING)
201                 g_string_append(str, ",RUNNING");
202
203         if (flags & IFF_LOWER_UP)
204                 g_string_append(str, ",LOWER_UP");
205
206         connman_info("%s {update} flags %u <%s>", ipdevice->ifname,
207                                                         flags, str->str);
208
209         g_string_free(str, TRUE);
210
211         for (list = g_list_first(ipconfig_list); list;
212                                                 list = g_list_next(list)) {
213                 struct connman_ipconfig *ipconfig = list->data;
214
215                 if (index != ipconfig->index)
216                         continue;
217
218                 if (ipconfig->ops) {
219                         if (up == TRUE && ipconfig->ops->up)
220                                 ipconfig->ops->up(ipconfig);
221                         if (lower_up == TRUE && ipconfig->ops->lower_up)
222                                 ipconfig->ops->lower_up(ipconfig);
223
224                         if (lower_down == TRUE && ipconfig->ops->lower_down)
225                                 ipconfig->ops->lower_down(ipconfig);
226                         if (down == TRUE && ipconfig->ops->down)
227                                 ipconfig->ops->down(ipconfig);
228                 }
229         }
230 }
231
232 void __connman_ipconfig_dellink(int index)
233 {
234         GList *list;
235
236         DBG("index %d", index);
237
238         for (list = g_list_first(ipconfig_list); list;
239                                                 list = g_list_next(list)) {
240                 struct connman_ipconfig *ipconfig = list->data;
241
242                 if (index != ipconfig->index)
243                         continue;
244
245                 ipconfig->index = -1;
246
247                 if (ipconfig->ops && ipconfig->ops->lower_down)
248                         ipconfig->ops->lower_down(ipconfig);
249                 if (ipconfig->ops && ipconfig->ops->down)
250                         ipconfig->ops->down(ipconfig);
251         }
252
253         g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
254 }
255
256 void __connman_ipconfig_newaddr(int index, const char *label,
257                                 unsigned char prefixlen, const char *address)
258 {
259         struct connman_ipdevice *ipdevice;
260         struct connman_ipaddress *ipaddress;
261
262         DBG("index %d", index);
263
264         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
265         if (ipdevice == NULL)
266                 return;
267
268         ipaddress = g_try_new0(struct connman_ipaddress, 1);
269         if (ipaddress == NULL)
270                 return;
271
272         ipaddress->prefixlen = prefixlen;
273         ipaddress->address = g_strdup(address);
274
275         ipdevice->address_list = g_slist_append(ipdevice->address_list,
276                                                                 ipaddress);
277
278         connman_info("%s {add} address %s/%u label %s", ipdevice->ifname,
279                                                 address, prefixlen, label);
280 }
281
282 void __connman_ipconfig_deladdr(int index, const char *label,
283                                 unsigned char prefixlen, const char *address)
284 {
285         struct connman_ipdevice *ipdevice;
286         struct connman_ipaddress *ipaddress;
287
288         DBG("index %d", index);
289
290         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
291         if (ipdevice == NULL)
292                 return;
293
294         ipaddress = find_ipaddress(ipdevice, prefixlen, address);
295         if (ipaddress == NULL)
296                 return;
297
298         ipdevice->address_list = g_slist_remove(ipdevice->address_list,
299                                                                 ipaddress);
300
301         g_free(ipaddress->address);
302         g_free(ipaddress);
303
304         connman_info("%s {del} address %s/%u label %s", ipdevice->ifname,
305                                                 address, prefixlen, label);
306 }
307
308 void __connman_ipconfig_newroute(int index, unsigned char scope,
309                                         const char *dst, const char *gateway)
310 {
311         struct connman_ipdevice *ipdevice;
312
313         DBG("index %d", index);
314
315         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
316         if (ipdevice == NULL)
317                 return;
318
319         if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
320                 g_free(ipdevice->gateway);
321                 ipdevice->gateway = g_strdup(gateway);
322         }
323
324         connman_info("%s {add} route %s gw %s scope %u <%s>",
325                                         ipdevice->ifname, dst, gateway,
326                                                 scope, scope2str(scope));
327 }
328
329 void __connman_ipconfig_delroute(int index, unsigned char scope,
330                                         const char *dst, const char *gateway)
331 {
332         struct connman_ipdevice *ipdevice;
333
334         DBG("index %d", index);
335
336         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
337         if (ipdevice == NULL)
338                 return;
339
340         if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
341                 g_free(ipdevice->gateway);
342                 ipdevice->gateway = NULL;
343         }
344
345         connman_info("%s {del} route %s gw %s scope %u <%s>",
346                                         ipdevice->ifname, dst, gateway,
347                                                 scope, scope2str(scope));
348 }
349
350 void __connman_ipconfig_foreach(void (*function) (int index, void *user_data),
351                                                         void *user_data)
352 {
353         GList *list, *keys;
354
355         keys = g_hash_table_get_keys(ipdevice_hash);
356         if (keys == NULL)
357                 return;
358
359         for (list = g_list_first(keys); list; list = g_list_next(list)) {
360                 int index = GPOINTER_TO_INT(list->data);
361
362                 function(index, user_data);
363         }
364
365         g_list_free(keys);
366 }
367
368 unsigned short __connman_ipconfig_get_type(int index)
369 {
370         struct connman_ipdevice *ipdevice;
371
372         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
373         if (ipdevice == NULL)
374                 return ARPHRD_VOID;
375
376         return ipdevice->type;
377 }
378
379 unsigned int __connman_ipconfig_get_flags(int index)
380 {
381         struct connman_ipdevice *ipdevice;
382
383         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
384         if (ipdevice == NULL)
385                 return 0;
386
387         return ipdevice->flags;
388 }
389
390 const char *__connman_ipconfig_get_gateway(int index)
391 {
392         struct connman_ipdevice *ipdevice;
393
394         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
395         if (ipdevice == NULL)
396                 return NULL;
397
398         return ipdevice->gateway;
399 }
400
401 /**
402  * connman_ipconfig_create:
403  *
404  * Allocate a new ipconfig structure.
405  *
406  * Returns: a newly-allocated #connman_ipconfig structure
407  */
408 struct connman_ipconfig *connman_ipconfig_create(int index)
409 {
410         struct connman_ipconfig *ipconfig;
411
412         DBG("index %d", index);
413
414         ipconfig = g_try_new0(struct connman_ipconfig, 1);
415         if (ipconfig == NULL)
416                 return NULL;
417
418         ipconfig->refcount = 1;
419
420         ipconfig->index = index;
421
422         DBG("ipconfig %p", ipconfig);
423
424         ipconfig_list = g_list_append(ipconfig_list, ipconfig);
425
426         return ipconfig;
427 }
428
429 /**
430  * connman_ipconfig_ref:
431  * @ipconfig: ipconfig structure
432  *
433  * Increase reference counter of ipconfig
434  */
435 struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig)
436 {
437         g_atomic_int_inc(&ipconfig->refcount);
438
439         return ipconfig;
440 }
441
442 /**
443  * connman_ipconfig_unref:
444  * @ipconfig: ipconfig structure
445  *
446  * Decrease reference counter of ipconfig
447  */
448 void connman_ipconfig_unref(struct connman_ipconfig *ipconfig)
449 {
450         if (g_atomic_int_dec_and_test(&ipconfig->refcount) == TRUE) {
451                 ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
452
453                 g_free(ipconfig);
454         }
455 }
456
457 /**
458  * connman_ipconfig_get_data:
459  * @ipconfig: ipconfig structure
460  *
461  * Get private data pointer
462  */
463 void *connman_ipconfig_get_data(struct connman_ipconfig *ipconfig)
464 {
465         return ipconfig->ops_data;
466 }
467
468 /**
469  * connman_ipconfig_set_data:
470  * @ipconfig: ipconfig structure
471  * @data: data pointer
472  *
473  * Set private data pointer
474  */
475 void connman_ipconfig_set_data(struct connman_ipconfig *ipconfig, void *data)
476 {
477         ipconfig->ops_data = data;
478 }
479
480 /**
481  * connman_ipconfig_get_index:
482  * @ipconfig: ipconfig structure
483  *
484  * Get interface index
485  */
486 int connman_ipconfig_get_index(struct connman_ipconfig *ipconfig)
487 {
488         return ipconfig->index;
489 }
490
491 /**
492  * connman_ipconfig_get_ifname:
493  * @ipconfig: ipconfig structure
494  *
495  * Get interface name
496  */
497 const char *connman_ipconfig_get_ifname(struct connman_ipconfig *ipconfig)
498 {
499         struct connman_ipdevice *ipdevice;
500
501         if (ipconfig->index < 0)
502                 return NULL;
503
504         ipdevice = g_hash_table_lookup(ipdevice_hash,
505                                         GINT_TO_POINTER(ipconfig->index));
506         if (ipdevice == NULL)
507                 return NULL;
508
509         return ipdevice->ifname;
510 }
511
512 /**
513  * connman_ipconfig_set_ops:
514  * @ipconfig: ipconfig structure
515  * @ops: operation callbacks
516  *
517  * Set the operation callbacks
518  */
519 void connman_ipconfig_set_ops(struct connman_ipconfig *ipconfig,
520                                 const struct connman_ipconfig_ops *ops)
521 {
522         ipconfig->ops = ops;
523 }
524
525 /**
526  * connman_ipconfig_set_method:
527  * @ipconfig: ipconfig structure
528  * @method: configuration method
529  *
530  * Set the configuration method
531  */
532 int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
533                                         enum connman_ipconfig_method method)
534 {
535         ipconfig->method = method;
536
537         return 0;
538 }
539
540 const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method)
541 {
542         switch (method) {
543         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
544                 break;
545         case CONNMAN_IPCONFIG_METHOD_IGNORE:
546                 return "ignore";
547         case CONNMAN_IPCONFIG_METHOD_STATIC:
548                 return "static";
549         case CONNMAN_IPCONFIG_METHOD_DHCP:
550                 return "dhcp";
551         }
552
553         return NULL;
554 }
555
556 enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method)
557 {
558         if (g_strcmp0(method, "ignore") == 0)
559                 return CONNMAN_IPCONFIG_METHOD_IGNORE;
560         else if (g_strcmp0(method, "static") == 0)
561                 return CONNMAN_IPCONFIG_METHOD_STATIC;
562         else if (g_strcmp0(method, "dhcp") == 0)
563                 return CONNMAN_IPCONFIG_METHOD_DHCP;
564         else
565                 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
566 }
567
568 static void append_variant(DBusMessageIter *iter, const char *prefix,
569                                         const char *key, int type, void *val)
570 {
571         char *str;
572
573         if (prefix == NULL) {
574                 connman_dbus_dict_append_variant(iter, key, type, val);
575                 return;
576         }
577
578         str = g_strdup_printf("%s%s", prefix, key);
579         if (str != NULL)
580                 connman_dbus_dict_append_variant(iter, str, type, val);
581
582         g_free(str);
583 }
584
585 void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
586                                 DBusMessageIter *iter, const char *prefix)
587 {
588         const char *str;
589
590         str = __connman_ipconfig_method2string(ipconfig->method);
591         if (str == NULL)
592                 return;
593
594         append_variant(iter, prefix, "Method", DBUS_TYPE_STRING, &str);
595 }
596
597 int __connman_ipconfig_set_ipv4(struct connman_ipconfig *ipconfig,
598                                 const char *key, DBusMessageIter *value)
599 {
600         int type = dbus_message_iter_get_arg_type(value);
601
602         DBG("ipconfig %p key %s type %d", ipconfig, key, type);
603
604         if (g_strcmp0(key, "Method") == 0) {
605                 const char *method;
606
607                 if (type != DBUS_TYPE_STRING)
608                         return -EINVAL;
609
610                 dbus_message_iter_get_basic(value, &method);
611
612                 ipconfig->method = __connman_ipconfig_string2method(method);
613         } else
614                 return -EINVAL;
615
616         return 0;
617 }
618
619 int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
620                 GKeyFile *keyfile, const char *identifier, const char *prefix)
621 {
622         DBG("ipconfig %p identifier %s", ipconfig, identifier);
623
624         return 0;
625 }
626
627 int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
628                 GKeyFile *keyfile, const char *identifier, const char *prefix)
629 {
630         DBG("ipconfig %p identifier %s", ipconfig, identifier);
631
632         return 0;
633 }
634
635 static GSList *driver_list = NULL;
636
637 static gint compare_priority(gconstpointer a, gconstpointer b)
638 {
639         const struct connman_ipconfig_driver *driver1 = a;
640         const struct connman_ipconfig_driver *driver2 = b;
641
642         return driver2->priority - driver1->priority;
643 }
644
645 /**
646  * connman_ipconfig_driver_register:
647  * @driver: IP configuration driver
648  *
649  * Register a new IP configuration driver
650  *
651  * Returns: %0 on success
652  */
653 int connman_ipconfig_driver_register(struct connman_ipconfig_driver *driver)
654 {
655         DBG("driver %p name %s", driver, driver->name);
656
657         driver_list = g_slist_insert_sorted(driver_list, driver,
658                                                         compare_priority);
659
660         return 0;
661 }
662
663 /**
664  * connman_ipconfig_driver_unregister:
665  * @driver: IP configuration driver
666  *
667  * Remove a previously registered IP configuration driver.
668  */
669 void connman_ipconfig_driver_unregister(struct connman_ipconfig_driver *driver)
670 {
671         DBG("driver %p name %s", driver, driver->name);
672
673         driver_list = g_slist_remove(driver_list, driver);
674 }
675
676 int __connman_ipconfig_init(void)
677 {
678         DBG("");
679
680         ipdevice_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
681                                                         NULL, free_ipdevice);
682
683         return 0;
684 }
685
686 void __connman_ipconfig_cleanup(void)
687 {
688         DBG("");
689
690         g_hash_table_destroy(ipdevice_hash);
691         ipdevice_hash = NULL;
692 }