5 * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
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.
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.
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
27 #include <net/if_arp.h>
30 #define IFF_LOWER_UP 0x10000
37 struct connman_ipconfig {
41 struct connman_ipconfig *origin;
43 const struct connman_ipconfig_ops *ops;
46 enum connman_ipconfig_method method;
47 struct connman_ipaddress *address;
50 struct connman_ipdevice {
59 struct connman_ipconfig *config;
61 struct connman_ipconfig_driver *driver;
62 struct connman_ipconfig *driver_config;
65 static GHashTable *ipdevice_hash = NULL;
66 static GList *ipconfig_list = NULL;
68 struct connman_ipaddress *connman_ipaddress_alloc(void)
70 struct connman_ipaddress *ipaddress;
72 ipaddress = g_try_new0(struct connman_ipaddress, 1);
73 if (ipaddress == NULL)
79 void connman_ipaddress_free(struct connman_ipaddress *ipaddress)
81 if (ipaddress == NULL)
84 g_free(ipaddress->broadcast);
85 g_free(ipaddress->peer);
86 g_free(ipaddress->local);
90 void connman_ipaddress_copy(struct connman_ipaddress *ipaddress,
91 struct connman_ipaddress *source)
93 if (ipaddress == NULL || source == NULL)
96 ipaddress->prefixlen = source->prefixlen;
98 g_free(ipaddress->local);
99 ipaddress->local = g_strdup(source->local);
101 g_free(ipaddress->peer);
102 ipaddress->peer = g_strdup(source->peer);
104 g_free(ipaddress->broadcast);
105 ipaddress->broadcast = g_strdup(source->broadcast);
108 static void free_address_list(struct connman_ipdevice *ipdevice)
112 for (list = ipdevice->address_list; list; list = list->next) {
113 struct connman_ipaddress *ipaddress = list->data;
115 connman_ipaddress_free(ipaddress);
119 g_slist_free(ipdevice->address_list);
120 ipdevice->address_list = NULL;
123 static struct connman_ipaddress *find_ipaddress(struct connman_ipdevice *ipdevice,
124 unsigned char prefixlen, const char *local)
128 for (list = ipdevice->address_list; list; list = list->next) {
129 struct connman_ipaddress *ipaddress = list->data;
131 if (g_strcmp0(ipaddress->local, local) == 0 &&
132 ipaddress->prefixlen == prefixlen)
139 static const char *type2str(unsigned short type)
144 case ARPHRD_LOOPBACK:
157 static const char *scope2str(unsigned char scope)
169 static void free_ipdevice(gpointer data)
171 struct connman_ipdevice *ipdevice = data;
173 connman_info("%s {remove} index %d", ipdevice->ifname,
176 if (ipdevice->config != NULL)
177 connman_ipconfig_unref(ipdevice->config);
179 free_address_list(ipdevice);
180 g_free(ipdevice->gateway);
182 g_free(ipdevice->ifname);
186 static GSList *driver_list = NULL;
188 static gint compare_priority(gconstpointer a, gconstpointer b)
190 const struct connman_ipconfig_driver *driver1 = a;
191 const struct connman_ipconfig_driver *driver2 = b;
193 return driver2->priority - driver1->priority;
197 * connman_ipconfig_driver_register:
198 * @driver: IP configuration driver
200 * Register a new IP configuration driver
202 * Returns: %0 on success
204 int connman_ipconfig_driver_register(struct connman_ipconfig_driver *driver)
206 DBG("driver %p name %s", driver, driver->name);
208 driver_list = g_slist_insert_sorted(driver_list, driver,
215 * connman_ipconfig_driver_unregister:
216 * @driver: IP configuration driver
218 * Remove a previously registered IP configuration driver.
220 void connman_ipconfig_driver_unregister(struct connman_ipconfig_driver *driver)
222 DBG("driver %p name %s", driver, driver->name);
224 driver_list = g_slist_remove(driver_list, driver);
227 static void __connman_ipconfig_lower_up(struct connman_ipdevice *ipdevice)
231 DBG("ipconfig %p", ipdevice->config);
233 if (ipdevice->config == NULL)
236 switch (ipdevice->config->method) {
237 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
238 case CONNMAN_IPCONFIG_METHOD_IGNORE:
239 case CONNMAN_IPCONFIG_METHOD_STATIC:
241 case CONNMAN_IPCONFIG_METHOD_DHCP:
245 if (ipdevice->driver != NULL)
248 ipdevice->driver_config = connman_ipconfig_clone(ipdevice->config);
249 if (ipdevice->driver_config == NULL)
252 for (list = driver_list; list; list = list->next) {
253 struct connman_ipconfig_driver *driver = list->data;
255 if (driver->request(ipdevice->driver_config) == 0) {
256 ipdevice->driver = driver;
261 if (ipdevice->driver == NULL) {
262 connman_ipconfig_unref(ipdevice->driver_config);
263 ipdevice->driver_config = NULL;
267 static void __connman_ipconfig_lower_down(struct connman_ipdevice *ipdevice)
269 DBG("ipconfig %p", ipdevice->config);
271 if (ipdevice->config == NULL)
274 if (ipdevice->driver == NULL)
277 ipdevice->driver->release(ipdevice->driver_config);
279 ipdevice->driver = NULL;
281 connman_ipconfig_unref(ipdevice->driver_config);
282 ipdevice->driver_config = NULL;
284 connman_inet_clear_address(ipdevice->index);
287 void __connman_ipconfig_newlink(int index, unsigned short type,
290 struct connman_ipdevice *ipdevice;
293 gboolean up = FALSE, down = FALSE;
294 gboolean lower_up = FALSE, lower_down = FALSE;
297 DBG("index %d", index);
299 if (type == ARPHRD_LOOPBACK)
302 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
303 if (ipdevice != NULL)
306 ifname = connman_inet_ifname(index);
307 if (__connman_element_device_isfiltered(ifname) == TRUE) {
308 connman_info("Ignoring network interface %s (filtered)",
314 ipdevice = g_try_new0(struct connman_ipdevice, 1);
315 if (ipdevice == NULL) {
320 ipdevice->index = index;
321 ipdevice->ifname = ifname;
322 ipdevice->type = type;
324 g_hash_table_insert(ipdevice_hash, GINT_TO_POINTER(index), ipdevice);
326 connman_info("%s {create} index %d type %d <%s>", ipdevice->ifname,
327 index, type, type2str(type));
330 if (flags == ipdevice->flags)
333 if ((ipdevice->flags & IFF_UP) != (flags & IFF_UP)) {
340 if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) !=
341 (flags & (IFF_RUNNING | IFF_LOWER_UP))) {
342 if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) ==
343 (IFF_RUNNING | IFF_LOWER_UP))
345 else if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) == 0)
349 connman_inet_clear_address(index);
351 ipdevice->flags = flags;
353 str = g_string_new(NULL);
358 g_string_append(str, "UP");
360 g_string_append(str, "DOWN");
362 if (flags & IFF_RUNNING)
363 g_string_append(str, ",RUNNING");
365 if (flags & IFF_LOWER_UP)
366 g_string_append(str, ",LOWER_UP");
368 connman_info("%s {update} flags %u <%s>", ipdevice->ifname,
371 g_string_free(str, TRUE);
373 for (list = g_list_first(ipconfig_list); list;
374 list = g_list_next(list)) {
375 struct connman_ipconfig *ipconfig = list->data;
377 if (index != ipconfig->index)
380 if (up == TRUE && ipconfig->ops->up)
381 ipconfig->ops->up(ipconfig);
382 if (lower_up == TRUE && ipconfig->ops->lower_up)
383 ipconfig->ops->lower_up(ipconfig);
385 if (lower_down == TRUE && ipconfig->ops->lower_down)
386 ipconfig->ops->lower_down(ipconfig);
387 if (down == TRUE && ipconfig->ops->down)
388 ipconfig->ops->down(ipconfig);
392 __connman_ipconfig_lower_up(ipdevice);
394 __connman_ipconfig_lower_down(ipdevice);
397 void __connman_ipconfig_dellink(int index)
399 struct connman_ipdevice *ipdevice;
402 DBG("index %d", index);
404 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
405 if (ipdevice == NULL)
408 for (list = g_list_first(ipconfig_list); list;
409 list = g_list_next(list)) {
410 struct connman_ipconfig *ipconfig = list->data;
412 if (index != ipconfig->index)
415 ipconfig->index = -1;
417 if (ipconfig->ops->lower_down)
418 ipconfig->ops->lower_down(ipconfig);
419 if (ipconfig->ops->down)
420 ipconfig->ops->down(ipconfig);
423 __connman_ipconfig_lower_down(ipdevice);
425 g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
428 void __connman_ipconfig_newaddr(int index, const char *label,
429 unsigned char prefixlen, const char *address)
431 struct connman_ipdevice *ipdevice;
432 struct connman_ipaddress *ipaddress;
435 DBG("index %d", index);
437 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
438 if (ipdevice == NULL)
441 ipaddress = connman_ipaddress_alloc();
442 if (ipaddress == NULL)
445 ipaddress->prefixlen = prefixlen;
446 ipaddress->local = g_strdup(address);
448 ipdevice->address_list = g_slist_append(ipdevice->address_list,
451 connman_info("%s {add} address %s/%u label %s", ipdevice->ifname,
452 address, prefixlen, label);
454 if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
457 if (g_slist_length(ipdevice->address_list) > 1)
460 for (list = g_list_first(ipconfig_list); list;
461 list = g_list_next(list)) {
462 struct connman_ipconfig *ipconfig = list->data;
464 if (index != ipconfig->index)
467 if (ipconfig->ops->ip_bound)
468 ipconfig->ops->ip_bound(ipconfig);
472 void __connman_ipconfig_deladdr(int index, const char *label,
473 unsigned char prefixlen, const char *address)
475 struct connman_ipdevice *ipdevice;
476 struct connman_ipaddress *ipaddress;
479 DBG("index %d", index);
481 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
482 if (ipdevice == NULL)
485 ipaddress = find_ipaddress(ipdevice, prefixlen, address);
486 if (ipaddress == NULL)
489 ipdevice->address_list = g_slist_remove(ipdevice->address_list,
492 connman_ipaddress_free(ipaddress);
494 connman_info("%s {del} address %s/%u label %s", ipdevice->ifname,
495 address, prefixlen, label);
497 if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
500 if (g_slist_length(ipdevice->address_list) > 0)
503 for (list = g_list_first(ipconfig_list); list;
504 list = g_list_next(list)) {
505 struct connman_ipconfig *ipconfig = list->data;
507 if (index != ipconfig->index)
510 if (ipconfig->ops->ip_release)
511 ipconfig->ops->ip_release(ipconfig);
515 void __connman_ipconfig_newroute(int index, unsigned char scope,
516 const char *dst, const char *gateway)
518 struct connman_ipdevice *ipdevice;
520 DBG("index %d", index);
522 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
523 if (ipdevice == NULL)
526 if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
527 g_free(ipdevice->gateway);
528 ipdevice->gateway = g_strdup(gateway);
531 connman_info("%s {add} route %s gw %s scope %u <%s>",
532 ipdevice->ifname, dst, gateway,
533 scope, scope2str(scope));
536 void __connman_ipconfig_delroute(int index, unsigned char scope,
537 const char *dst, const char *gateway)
539 struct connman_ipdevice *ipdevice;
541 DBG("index %d", index);
543 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
544 if (ipdevice == NULL)
547 if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
548 g_free(ipdevice->gateway);
549 ipdevice->gateway = NULL;
552 connman_info("%s {del} route %s gw %s scope %u <%s>",
553 ipdevice->ifname, dst, gateway,
554 scope, scope2str(scope));
557 void __connman_ipconfig_foreach(void (*function) (int index, void *user_data),
562 keys = g_hash_table_get_keys(ipdevice_hash);
566 for (list = g_list_first(keys); list; list = g_list_next(list)) {
567 int index = GPOINTER_TO_INT(list->data);
569 function(index, user_data);
575 unsigned short __connman_ipconfig_get_type(int index)
577 struct connman_ipdevice *ipdevice;
579 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
580 if (ipdevice == NULL)
583 return ipdevice->type;
586 unsigned int __connman_ipconfig_get_flags(int index)
588 struct connman_ipdevice *ipdevice;
590 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
591 if (ipdevice == NULL)
594 return ipdevice->flags;
597 const char *__connman_ipconfig_get_gateway(int index)
599 struct connman_ipdevice *ipdevice;
601 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
602 if (ipdevice == NULL)
605 return ipdevice->gateway;
609 * connman_ipconfig_create:
611 * Allocate a new ipconfig structure.
613 * Returns: a newly-allocated #connman_ipconfig structure
615 struct connman_ipconfig *connman_ipconfig_create(int index)
617 struct connman_ipconfig *ipconfig;
619 DBG("index %d", index);
621 ipconfig = g_try_new0(struct connman_ipconfig, 1);
622 if (ipconfig == NULL)
625 ipconfig->refcount = 1;
627 ipconfig->index = index;
629 ipconfig->address = connman_ipaddress_alloc();
630 if (ipconfig->address == NULL) {
635 DBG("ipconfig %p", ipconfig);
641 * connman_ipconfig_clone:
643 * Clone an ipconfig structure and create new reference.
645 * Returns: a newly-allocated #connman_ipconfig structure
647 struct connman_ipconfig *connman_ipconfig_clone(struct connman_ipconfig *ipconfig)
649 struct connman_ipconfig *ipconfig_clone;
651 DBG("ipconfig %p", ipconfig);
653 ipconfig_clone = g_try_new0(struct connman_ipconfig, 1);
654 if (ipconfig_clone == NULL)
657 ipconfig_clone->refcount = 1;
659 ipconfig_clone->origin = connman_ipconfig_ref(ipconfig);
661 ipconfig_clone->index = -1;
663 return ipconfig_clone;
667 * connman_ipconfig_ref:
668 * @ipconfig: ipconfig structure
670 * Increase reference counter of ipconfig
672 struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig)
674 g_atomic_int_inc(&ipconfig->refcount);
680 * connman_ipconfig_unref:
681 * @ipconfig: ipconfig structure
683 * Decrease reference counter of ipconfig
685 void connman_ipconfig_unref(struct connman_ipconfig *ipconfig)
687 if (g_atomic_int_dec_and_test(&ipconfig->refcount) == TRUE) {
688 connman_ipconfig_set_ops(ipconfig, NULL);
690 if (ipconfig->origin != NULL) {
691 connman_ipconfig_unref(ipconfig->origin);
692 ipconfig->origin = NULL;
695 connman_ipaddress_free(ipconfig->address);
701 * connman_ipconfig_get_data:
702 * @ipconfig: ipconfig structure
704 * Get private data pointer
706 void *connman_ipconfig_get_data(struct connman_ipconfig *ipconfig)
708 return ipconfig->ops_data;
712 * connman_ipconfig_set_data:
713 * @ipconfig: ipconfig structure
714 * @data: data pointer
716 * Set private data pointer
718 void connman_ipconfig_set_data(struct connman_ipconfig *ipconfig, void *data)
720 ipconfig->ops_data = data;
724 * connman_ipconfig_get_index:
725 * @ipconfig: ipconfig structure
727 * Get interface index
729 int connman_ipconfig_get_index(struct connman_ipconfig *ipconfig)
731 if (ipconfig->origin != NULL)
732 return ipconfig->origin->index;
734 return ipconfig->index;
738 * connman_ipconfig_get_ifname:
739 * @ipconfig: ipconfig structure
743 const char *connman_ipconfig_get_ifname(struct connman_ipconfig *ipconfig)
745 struct connman_ipdevice *ipdevice;
747 if (ipconfig->index < 0)
750 ipdevice = g_hash_table_lookup(ipdevice_hash,
751 GINT_TO_POINTER(ipconfig->index));
752 if (ipdevice == NULL)
755 return ipdevice->ifname;
759 * connman_ipconfig_set_ops:
760 * @ipconfig: ipconfig structure
761 * @ops: operation callbacks
763 * Set the operation callbacks
765 void connman_ipconfig_set_ops(struct connman_ipconfig *ipconfig,
766 const struct connman_ipconfig_ops *ops)
768 if (ipconfig->ops != NULL)
769 ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
774 ipconfig_list = g_list_append(ipconfig_list, ipconfig);
778 * connman_ipconfig_set_method:
779 * @ipconfig: ipconfig structure
780 * @method: configuration method
782 * Set the configuration method
784 int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
785 enum connman_ipconfig_method method)
787 ipconfig->method = method;
793 * connman_ipconfig_bind:
794 * @ipconfig: ipconfig structure
795 * @ipaddress: ipaddress structure
797 * Bind IP address details to configuration
799 void connman_ipconfig_bind(struct connman_ipconfig *ipconfig,
800 struct connman_ipaddress *ipaddress)
802 struct connman_ipconfig *origin;
804 origin = ipconfig->origin ? ipconfig->origin : ipconfig;
806 connman_ipaddress_copy(origin->address, ipaddress);
808 connman_inet_set_address(origin->index, origin->address);
811 int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
813 struct connman_ipdevice *ipdevice;
815 DBG("ipconfig %p", ipconfig);
817 if (ipconfig == NULL || ipconfig->index < 0)
820 ipdevice = g_hash_table_lookup(ipdevice_hash,
821 GINT_TO_POINTER(ipconfig->index));
822 if (ipdevice == NULL)
825 if (ipdevice->config != NULL)
826 connman_ipconfig_unref(ipdevice->config);
828 ipdevice->config = connman_ipconfig_ref(ipconfig);
833 int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
835 struct connman_ipdevice *ipdevice;
837 DBG("ipconfig %p", ipconfig);
839 if (ipconfig == NULL || ipconfig->index < 0)
842 ipdevice = g_hash_table_lookup(ipdevice_hash,
843 GINT_TO_POINTER(ipconfig->index));
844 if (ipdevice == NULL)
847 if (ipdevice->config == NULL || ipdevice->config != ipconfig)
850 connman_ipconfig_unref(ipdevice->config);
851 ipdevice->config = NULL;
856 const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method)
859 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
861 case CONNMAN_IPCONFIG_METHOD_IGNORE:
863 case CONNMAN_IPCONFIG_METHOD_STATIC:
865 case CONNMAN_IPCONFIG_METHOD_DHCP:
872 enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method)
874 if (g_strcmp0(method, "ignore") == 0)
875 return CONNMAN_IPCONFIG_METHOD_IGNORE;
876 else if (g_strcmp0(method, "static") == 0)
877 return CONNMAN_IPCONFIG_METHOD_STATIC;
878 else if (g_strcmp0(method, "dhcp") == 0)
879 return CONNMAN_IPCONFIG_METHOD_DHCP;
881 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
884 static void append_variant(DBusMessageIter *iter, const char *prefix,
885 const char *key, int type, void *val)
889 if (prefix == NULL) {
890 connman_dbus_dict_append_variant(iter, key, type, val);
894 str = g_strdup_printf("%s%s", prefix, key);
896 connman_dbus_dict_append_variant(iter, str, type, val);
901 void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
902 DBusMessageIter *iter, const char *prefix)
906 str = __connman_ipconfig_method2string(ipconfig->method);
910 append_variant(iter, prefix, "Method", DBUS_TYPE_STRING, &str);
913 int __connman_ipconfig_set_ipv4(struct connman_ipconfig *ipconfig,
914 const char *key, DBusMessageIter *value)
916 int type = dbus_message_iter_get_arg_type(value);
918 DBG("ipconfig %p key %s type %d", ipconfig, key, type);
920 if (g_strcmp0(key, "Method") == 0) {
923 if (type != DBUS_TYPE_STRING)
926 dbus_message_iter_get_basic(value, &method);
928 ipconfig->method = __connman_ipconfig_string2method(method);
935 int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
936 GKeyFile *keyfile, const char *identifier, const char *prefix)
938 DBG("ipconfig %p identifier %s", ipconfig, identifier);
943 int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
944 GKeyFile *keyfile, const char *identifier, const char *prefix)
946 DBG("ipconfig %p identifier %s", ipconfig, identifier);
951 int __connman_ipconfig_init(void)
955 ipdevice_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
956 NULL, free_ipdevice);
961 void __connman_ipconfig_cleanup(void)
965 g_hash_table_destroy(ipdevice_hash);
966 ipdevice_hash = NULL;