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;
53 struct connman_ipdevice {
62 struct connman_ipconfig *config;
64 struct connman_ipconfig_driver *driver;
65 struct connman_ipconfig *driver_config;
68 static GHashTable *ipdevice_hash = NULL;
69 static GList *ipconfig_list = NULL;
71 struct connman_ipaddress *connman_ipaddress_alloc(void)
73 struct connman_ipaddress *ipaddress;
75 ipaddress = g_try_new0(struct connman_ipaddress, 1);
76 if (ipaddress == NULL)
82 void connman_ipaddress_free(struct connman_ipaddress *ipaddress)
84 if (ipaddress == NULL)
87 g_free(ipaddress->broadcast);
88 g_free(ipaddress->peer);
89 g_free(ipaddress->local);
93 void connman_ipaddress_copy(struct connman_ipaddress *ipaddress,
94 struct connman_ipaddress *source)
96 if (ipaddress == NULL || source == NULL)
99 ipaddress->prefixlen = source->prefixlen;
101 g_free(ipaddress->local);
102 ipaddress->local = g_strdup(source->local);
104 g_free(ipaddress->peer);
105 ipaddress->peer = g_strdup(source->peer);
107 g_free(ipaddress->broadcast);
108 ipaddress->broadcast = g_strdup(source->broadcast);
111 static void free_address_list(struct connman_ipdevice *ipdevice)
115 for (list = ipdevice->address_list; list; list = list->next) {
116 struct connman_ipaddress *ipaddress = list->data;
118 connman_ipaddress_free(ipaddress);
122 g_slist_free(ipdevice->address_list);
123 ipdevice->address_list = NULL;
126 static struct connman_ipaddress *find_ipaddress(struct connman_ipdevice *ipdevice,
127 unsigned char prefixlen, const char *local)
131 for (list = ipdevice->address_list; list; list = list->next) {
132 struct connman_ipaddress *ipaddress = list->data;
134 if (g_strcmp0(ipaddress->local, local) == 0 &&
135 ipaddress->prefixlen == prefixlen)
142 static const char *type2str(unsigned short type)
147 case ARPHRD_LOOPBACK:
160 static const char *scope2str(unsigned char scope)
172 static void free_ipdevice(gpointer data)
174 struct connman_ipdevice *ipdevice = data;
176 connman_info("%s {remove} index %d", ipdevice->ifname,
179 if (ipdevice->config != NULL)
180 connman_ipconfig_unref(ipdevice->config);
182 free_address_list(ipdevice);
183 g_free(ipdevice->gateway);
185 g_free(ipdevice->ifname);
189 static GSList *driver_list = NULL;
191 static gint compare_priority(gconstpointer a, gconstpointer b)
193 const struct connman_ipconfig_driver *driver1 = a;
194 const struct connman_ipconfig_driver *driver2 = b;
196 return driver2->priority - driver1->priority;
200 * connman_ipconfig_driver_register:
201 * @driver: IP configuration driver
203 * Register a new IP configuration driver
205 * Returns: %0 on success
207 int connman_ipconfig_driver_register(struct connman_ipconfig_driver *driver)
209 DBG("driver %p name %s", driver, driver->name);
211 driver_list = g_slist_insert_sorted(driver_list, driver,
218 * connman_ipconfig_driver_unregister:
219 * @driver: IP configuration driver
221 * Remove a previously registered IP configuration driver.
223 void connman_ipconfig_driver_unregister(struct connman_ipconfig_driver *driver)
225 DBG("driver %p name %s", driver, driver->name);
227 driver_list = g_slist_remove(driver_list, driver);
230 static void __connman_ipconfig_lower_up(struct connman_ipdevice *ipdevice)
234 DBG("ipconfig %p", ipdevice->config);
236 if (ipdevice->config == NULL)
239 switch (ipdevice->config->method) {
240 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
241 case CONNMAN_IPCONFIG_METHOD_IGNORE:
242 case CONNMAN_IPCONFIG_METHOD_STATIC:
244 case CONNMAN_IPCONFIG_METHOD_DHCP:
248 if (ipdevice->driver != NULL)
251 ipdevice->driver_config = connman_ipconfig_clone(ipdevice->config);
252 if (ipdevice->driver_config == NULL)
255 for (list = driver_list; list; list = list->next) {
256 struct connman_ipconfig_driver *driver = list->data;
258 if (driver->request(ipdevice->driver_config) == 0) {
259 ipdevice->driver = driver;
264 if (ipdevice->driver == NULL) {
265 connman_ipconfig_unref(ipdevice->driver_config);
266 ipdevice->driver_config = NULL;
270 static void __connman_ipconfig_lower_down(struct connman_ipdevice *ipdevice)
272 DBG("ipconfig %p", ipdevice->config);
274 if (ipdevice->config == NULL)
277 if (ipdevice->driver == NULL)
280 ipdevice->driver->release(ipdevice->driver_config);
282 ipdevice->driver = NULL;
284 connman_ipconfig_unref(ipdevice->driver_config);
285 ipdevice->driver_config = NULL;
287 connman_inet_clear_address(ipdevice->index);
290 void __connman_ipconfig_newlink(int index, unsigned short type,
291 unsigned int flags, const char *address,
294 struct connman_ipdevice *ipdevice;
297 gboolean up = FALSE, down = FALSE;
298 gboolean lower_up = FALSE, lower_down = FALSE;
301 DBG("index %d", index);
303 if (type == ARPHRD_LOOPBACK)
306 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
307 if (ipdevice != NULL)
310 ifname = connman_inet_ifname(index);
312 if (__connman_element_device_isfiltered(ifname) == TRUE) {
313 connman_info("Ignoring interface %s (filtered)", ifname);
318 ipdevice = g_try_new0(struct connman_ipdevice, 1);
319 if (ipdevice == NULL) {
324 ipdevice->index = index;
325 ipdevice->ifname = ifname;
326 ipdevice->type = type;
328 g_hash_table_insert(ipdevice_hash, GINT_TO_POINTER(index), ipdevice);
330 connman_info("%s {create} index %d type %d <%s>", ipdevice->ifname,
331 index, type, type2str(type));
334 if (ipdevice->config != NULL) {
335 g_free(ipdevice->config->eth);
336 ipdevice->config->eth = g_strdup(address);
337 ipdevice->config->mtu = mtu;
340 if (flags == ipdevice->flags)
343 if ((ipdevice->flags & IFF_UP) != (flags & IFF_UP)) {
350 if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) !=
351 (flags & (IFF_RUNNING | IFF_LOWER_UP))) {
352 if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) ==
353 (IFF_RUNNING | IFF_LOWER_UP))
355 else if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) == 0)
359 ipdevice->flags = flags;
361 str = g_string_new(NULL);
366 g_string_append(str, "UP");
368 g_string_append(str, "DOWN");
370 if (flags & IFF_RUNNING)
371 g_string_append(str, ",RUNNING");
373 if (flags & IFF_LOWER_UP)
374 g_string_append(str, ",LOWER_UP");
376 connman_info("%s {update} flags %u <%s>", ipdevice->ifname,
379 g_string_free(str, TRUE);
381 for (list = g_list_first(ipconfig_list); list;
382 list = g_list_next(list)) {
383 struct connman_ipconfig *ipconfig = list->data;
385 if (index != ipconfig->index)
388 if (up == TRUE && ipconfig->ops->up)
389 ipconfig->ops->up(ipconfig);
390 if (lower_up == TRUE && ipconfig->ops->lower_up)
391 ipconfig->ops->lower_up(ipconfig);
393 if (lower_down == TRUE && ipconfig->ops->lower_down)
394 ipconfig->ops->lower_down(ipconfig);
395 if (down == TRUE && ipconfig->ops->down)
396 ipconfig->ops->down(ipconfig);
400 __connman_ipconfig_lower_up(ipdevice);
402 __connman_ipconfig_lower_down(ipdevice);
405 void __connman_ipconfig_dellink(int index)
407 struct connman_ipdevice *ipdevice;
410 DBG("index %d", index);
412 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
413 if (ipdevice == NULL)
416 for (list = g_list_first(ipconfig_list); list;
417 list = g_list_next(list)) {
418 struct connman_ipconfig *ipconfig = list->data;
420 if (index != ipconfig->index)
423 ipconfig->index = -1;
425 if (ipconfig->ops->lower_down)
426 ipconfig->ops->lower_down(ipconfig);
427 if (ipconfig->ops->down)
428 ipconfig->ops->down(ipconfig);
431 __connman_ipconfig_lower_down(ipdevice);
433 g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
436 void __connman_ipconfig_newaddr(int index, const char *label,
437 unsigned char prefixlen, const char *address)
439 struct connman_ipdevice *ipdevice;
440 struct connman_ipaddress *ipaddress;
443 DBG("index %d", index);
445 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
446 if (ipdevice == NULL)
449 ipaddress = connman_ipaddress_alloc();
450 if (ipaddress == NULL)
453 ipaddress->prefixlen = prefixlen;
454 ipaddress->local = g_strdup(address);
456 ipdevice->address_list = g_slist_append(ipdevice->address_list,
459 connman_info("%s {add} address %s/%u label %s", ipdevice->ifname,
460 address, prefixlen, label);
462 if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
465 if (g_slist_length(ipdevice->address_list) > 1)
468 for (list = g_list_first(ipconfig_list); list;
469 list = g_list_next(list)) {
470 struct connman_ipconfig *ipconfig = list->data;
472 if (index != ipconfig->index)
475 if (ipconfig->ops->ip_bound)
476 ipconfig->ops->ip_bound(ipconfig);
480 void __connman_ipconfig_deladdr(int index, const char *label,
481 unsigned char prefixlen, const char *address)
483 struct connman_ipdevice *ipdevice;
484 struct connman_ipaddress *ipaddress;
487 DBG("index %d", index);
489 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
490 if (ipdevice == NULL)
493 ipaddress = find_ipaddress(ipdevice, prefixlen, address);
494 if (ipaddress == NULL)
497 ipdevice->address_list = g_slist_remove(ipdevice->address_list,
500 connman_ipaddress_free(ipaddress);
502 connman_info("%s {del} address %s/%u label %s", ipdevice->ifname,
503 address, prefixlen, label);
505 if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
508 if (g_slist_length(ipdevice->address_list) > 0)
511 for (list = g_list_first(ipconfig_list); list;
512 list = g_list_next(list)) {
513 struct connman_ipconfig *ipconfig = list->data;
515 if (index != ipconfig->index)
518 if (ipconfig->ops->ip_release)
519 ipconfig->ops->ip_release(ipconfig);
523 void __connman_ipconfig_newroute(int index, unsigned char scope,
524 const char *dst, const char *gateway)
526 struct connman_ipdevice *ipdevice;
528 DBG("index %d", index);
530 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
531 if (ipdevice == NULL)
534 if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
535 g_free(ipdevice->gateway);
536 ipdevice->gateway = g_strdup(gateway);
539 connman_info("%s {add} route %s gw %s scope %u <%s>",
540 ipdevice->ifname, dst, gateway,
541 scope, scope2str(scope));
544 void __connman_ipconfig_delroute(int index, unsigned char scope,
545 const char *dst, const char *gateway)
547 struct connman_ipdevice *ipdevice;
549 DBG("index %d", index);
551 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
552 if (ipdevice == NULL)
555 if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
556 g_free(ipdevice->gateway);
557 ipdevice->gateway = NULL;
560 connman_info("%s {del} route %s gw %s scope %u <%s>",
561 ipdevice->ifname, dst, gateway,
562 scope, scope2str(scope));
565 void __connman_ipconfig_foreach(void (*function) (int index, void *user_data),
570 keys = g_hash_table_get_keys(ipdevice_hash);
574 for (list = g_list_first(keys); list; list = g_list_next(list)) {
575 int index = GPOINTER_TO_INT(list->data);
577 function(index, user_data);
583 unsigned short __connman_ipconfig_get_type(int index)
585 struct connman_ipdevice *ipdevice;
587 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
588 if (ipdevice == NULL)
591 return ipdevice->type;
594 unsigned int __connman_ipconfig_get_flags(int index)
596 struct connman_ipdevice *ipdevice;
598 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
599 if (ipdevice == NULL)
602 return ipdevice->flags;
605 const char *__connman_ipconfig_get_gateway(int index)
607 struct connman_ipdevice *ipdevice;
609 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
610 if (ipdevice == NULL)
613 return ipdevice->gateway;
617 * connman_ipconfig_create:
619 * Allocate a new ipconfig structure.
621 * Returns: a newly-allocated #connman_ipconfig structure
623 struct connman_ipconfig *connman_ipconfig_create(int index)
625 struct connman_ipconfig *ipconfig;
627 DBG("index %d", index);
629 ipconfig = g_try_new0(struct connman_ipconfig, 1);
630 if (ipconfig == NULL)
633 ipconfig->refcount = 1;
635 ipconfig->index = index;
637 ipconfig->address = connman_ipaddress_alloc();
638 if (ipconfig->address == NULL) {
643 DBG("ipconfig %p", ipconfig);
649 * connman_ipconfig_clone:
651 * Clone an ipconfig structure and create new reference.
653 * Returns: a newly-allocated #connman_ipconfig structure
655 struct connman_ipconfig *connman_ipconfig_clone(struct connman_ipconfig *ipconfig)
657 struct connman_ipconfig *ipconfig_clone;
659 DBG("ipconfig %p", ipconfig);
661 ipconfig_clone = g_try_new0(struct connman_ipconfig, 1);
662 if (ipconfig_clone == NULL)
665 ipconfig_clone->refcount = 1;
667 ipconfig_clone->origin = connman_ipconfig_ref(ipconfig);
669 ipconfig_clone->index = -1;
671 return ipconfig_clone;
675 * connman_ipconfig_ref:
676 * @ipconfig: ipconfig structure
678 * Increase reference counter of ipconfig
680 struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig)
682 g_atomic_int_inc(&ipconfig->refcount);
688 * connman_ipconfig_unref:
689 * @ipconfig: ipconfig structure
691 * Decrease reference counter of ipconfig
693 void connman_ipconfig_unref(struct connman_ipconfig *ipconfig)
695 if (g_atomic_int_dec_and_test(&ipconfig->refcount) == TRUE) {
696 connman_ipconfig_set_ops(ipconfig, NULL);
698 if (ipconfig->origin != NULL) {
699 connman_ipconfig_unref(ipconfig->origin);
700 ipconfig->origin = NULL;
703 connman_ipaddress_free(ipconfig->address);
704 g_free(ipconfig->eth);
710 * connman_ipconfig_get_data:
711 * @ipconfig: ipconfig structure
713 * Get private data pointer
715 void *connman_ipconfig_get_data(struct connman_ipconfig *ipconfig)
717 return ipconfig->ops_data;
721 * connman_ipconfig_set_data:
722 * @ipconfig: ipconfig structure
723 * @data: data pointer
725 * Set private data pointer
727 void connman_ipconfig_set_data(struct connman_ipconfig *ipconfig, void *data)
729 ipconfig->ops_data = data;
733 * connman_ipconfig_get_index:
734 * @ipconfig: ipconfig structure
736 * Get interface index
738 int connman_ipconfig_get_index(struct connman_ipconfig *ipconfig)
740 if (ipconfig->origin != NULL)
741 return ipconfig->origin->index;
743 return ipconfig->index;
747 * connman_ipconfig_get_ifname:
748 * @ipconfig: ipconfig structure
752 const char *connman_ipconfig_get_ifname(struct connman_ipconfig *ipconfig)
754 struct connman_ipdevice *ipdevice;
756 if (ipconfig->index < 0)
759 ipdevice = g_hash_table_lookup(ipdevice_hash,
760 GINT_TO_POINTER(ipconfig->index));
761 if (ipdevice == NULL)
764 return ipdevice->ifname;
768 * connman_ipconfig_set_ops:
769 * @ipconfig: ipconfig structure
770 * @ops: operation callbacks
772 * Set the operation callbacks
774 void connman_ipconfig_set_ops(struct connman_ipconfig *ipconfig,
775 const struct connman_ipconfig_ops *ops)
777 if (ipconfig->ops != NULL)
778 ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
783 ipconfig_list = g_list_append(ipconfig_list, ipconfig);
787 * connman_ipconfig_set_method:
788 * @ipconfig: ipconfig structure
789 * @method: configuration method
791 * Set the configuration method
793 int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
794 enum connman_ipconfig_method method)
796 ipconfig->method = method;
802 * connman_ipconfig_bind:
803 * @ipconfig: ipconfig structure
804 * @ipaddress: ipaddress structure
806 * Bind IP address details to configuration
808 void connman_ipconfig_bind(struct connman_ipconfig *ipconfig,
809 struct connman_ipaddress *ipaddress)
811 struct connman_ipconfig *origin;
813 origin = ipconfig->origin ? ipconfig->origin : ipconfig;
815 connman_ipaddress_copy(origin->address, ipaddress);
817 connman_inet_set_address(origin->index, origin->address);
820 int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
822 struct connman_ipdevice *ipdevice;
824 DBG("ipconfig %p", ipconfig);
826 if (ipconfig == NULL || ipconfig->index < 0)
829 ipdevice = g_hash_table_lookup(ipdevice_hash,
830 GINT_TO_POINTER(ipconfig->index));
831 if (ipdevice == NULL)
834 if (ipdevice->config != NULL)
835 connman_ipconfig_unref(ipdevice->config);
837 ipdevice->config = connman_ipconfig_ref(ipconfig);
842 int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
844 struct connman_ipdevice *ipdevice;
846 DBG("ipconfig %p", ipconfig);
848 if (ipconfig == NULL || ipconfig->index < 0)
851 ipdevice = g_hash_table_lookup(ipdevice_hash,
852 GINT_TO_POINTER(ipconfig->index));
853 if (ipdevice == NULL)
856 if (ipdevice->config == NULL || ipdevice->config != ipconfig)
859 connman_ipconfig_unref(ipdevice->config);
860 ipdevice->config = NULL;
865 const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method)
868 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
870 case CONNMAN_IPCONFIG_METHOD_IGNORE:
872 case CONNMAN_IPCONFIG_METHOD_STATIC:
874 case CONNMAN_IPCONFIG_METHOD_DHCP:
881 enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method)
883 if (g_strcmp0(method, "ignore") == 0)
884 return CONNMAN_IPCONFIG_METHOD_IGNORE;
885 else if (g_strcmp0(method, "static") == 0)
886 return CONNMAN_IPCONFIG_METHOD_STATIC;
887 else if (g_strcmp0(method, "dhcp") == 0)
888 return CONNMAN_IPCONFIG_METHOD_DHCP;
890 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
893 void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
894 DBusMessageIter *iter)
898 str = __connman_ipconfig_method2string(ipconfig->method);
902 connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
904 if (ipconfig->address == NULL)
907 if (ipconfig->address->local != NULL) {
908 struct in_addr netmask;
911 connman_dbus_dict_append_basic(iter, "Address",
912 DBUS_TYPE_STRING, &ipconfig->address->local);
914 netmask.s_addr = ~0 << (32 - ipconfig->address->prefixlen);
915 mask = inet_ntoa(netmask);
916 connman_dbus_dict_append_basic(iter, "Netmask",
917 DBUS_TYPE_STRING, &mask);
921 int __connman_ipconfig_set_ipv4(struct connman_ipconfig *ipconfig,
922 const char *key, DBusMessageIter *value)
924 int type = dbus_message_iter_get_arg_type(value);
926 DBG("ipconfig %p key %s type %d", ipconfig, key, type);
928 if (g_strcmp0(key, "Method") == 0) {
931 if (type != DBUS_TYPE_STRING)
934 dbus_message_iter_get_basic(value, &method);
936 ipconfig->method = __connman_ipconfig_string2method(method);
943 int __connman_ipconfig_append_ethernet(struct connman_ipconfig *ipconfig,
944 DBusMessageIter *iter)
946 const char *method = "auto";
948 connman_dbus_dict_append_basic(iter, "Method",
949 DBUS_TYPE_STRING, &method);
951 if (ipconfig->eth != NULL)
952 connman_dbus_dict_append_basic(iter, "Address",
953 DBUS_TYPE_STRING, &ipconfig->eth);
955 if (ipconfig->mtu > 0)
956 connman_dbus_dict_append_basic(iter, "MTU",
957 DBUS_TYPE_UINT16, &ipconfig->mtu);
962 int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
963 GKeyFile *keyfile, const char *identifier, const char *prefix)
965 DBG("ipconfig %p identifier %s", ipconfig, identifier);
970 int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
971 GKeyFile *keyfile, const char *identifier, const char *prefix)
973 DBG("ipconfig %p identifier %s", ipconfig, identifier);
978 int __connman_ipconfig_init(void)
982 ipdevice_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
983 NULL, free_ipdevice);
988 void __connman_ipconfig_cleanup(void)
992 g_hash_table_destroy(ipdevice_hash);
993 ipdevice_hash = NULL;