summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJukka Rissanen <jukka.rissanen@linux.intel.com>2013-04-04 14:44:49 +0300
committerPatrik Flykt <patrik.flykt@linux.intel.com>2013-04-05 14:37:15 +0300
commitbb147fc28a6c2bb3b81a9677af518c8e3bf6cc4e (patch)
treebe0f0e97bd06c8f8aefabf791522e8e5a1eb272f
parent5b128587ec25d575a683b9a37e6ac33ce17bd760 (diff)
downloadconnman-bb147fc28a6c2bb3b81a9677af518c8e3bf6cc4e.tar.gz
connman-bb147fc28a6c2bb3b81a9677af518c8e3bf6cc4e.tar.bz2
connman-bb147fc28a6c2bb3b81a9677af518c8e3bf6cc4e.zip
inet: Get an address from a given interface and address family
The returned address is used when we need to have a listening socket tied to specific interface and address, and do not want to bind to any address.
-rw-r--r--src/connman.h1
-rw-r--r--src/inet.c55
2 files changed, 56 insertions, 0 deletions
diff --git a/src/connman.h b/src/connman.h
index e9c774e7..b63e6582 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -133,6 +133,7 @@ int __connman_inet_modify_address(int cmd, int flags, int index, int family,
const char *peer,
unsigned char prefixlen,
const char *broadcast);
+int __connman_inet_get_interface_address(int index, int family, void *address);
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
diff --git a/src/inet.c b/src/inet.c
index 0027fe6f..51965760 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -45,6 +45,7 @@
#include <fcntl.h>
#include <linux/if_tun.h>
#include <ctype.h>
+#include <ifaddrs.h>
#include "connman.h"
@@ -2376,3 +2377,57 @@ connman_bool_t connman_inet_is_ipv6_supported()
close(sk);
return TRUE;
}
+
+int __connman_inet_get_interface_address(int index, int family, void *address)
+{
+ struct ifaddrs *ifaddr, *ifa;
+ int err = -ENOENT;
+ char name[IF_NAMESIZE];
+
+ if (if_indextoname(index, name) == NULL)
+ return -EINVAL;
+
+ DBG("index %d interface %s", index, name);
+
+ if (getifaddrs(&ifaddr) < 0) {
+ err = -errno;
+ DBG("Cannot get addresses err %d/%s", err, strerror(-err));
+ return err;
+ }
+
+ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL)
+ continue;
+
+ if (strncmp(ifa->ifa_name, name, IF_NAMESIZE) == 0 &&
+ ifa->ifa_addr->sa_family == family) {
+ if (family == AF_INET) {
+ struct sockaddr_in *in4 = (struct sockaddr_in *)
+ ifa->ifa_addr;
+ if (in4->sin_addr.s_addr == INADDR_ANY)
+ continue;
+ memcpy(address, &in4->sin_addr,
+ sizeof(struct in_addr));
+ } else if (family == AF_INET6) {
+ struct sockaddr_in6 *in6 =
+ (struct sockaddr_in6 *)ifa->ifa_addr;
+ if (memcmp(&in6->sin6_addr, &in6addr_any,
+ sizeof(struct in6_addr)) == 0)
+ continue;
+ memcpy(address, &in6->sin6_addr,
+ sizeof(struct in6_addr));
+
+ } else {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = 0;
+ break;
+ }
+ }
+
+out:
+ freeifaddrs(ifaddr);
+ return err;
+}