diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2014-10-21 12:37:48 +0900 |
---|---|---|
committer | Lorenzo Colitti <lorenzo@google.com> | 2014-10-29 11:53:05 +0900 |
commit | 8a41a5d140b3cf56a54bdeef234e89ee12cba0dc (patch) | |
tree | 0c9d8647d776b79d18cc169425a347aed38a5d87 | |
parent | 1352a3a26c4d7c32b38b7fadb837799a23014aa6 (diff) | |
download | android_external_android-clat-8a41a5d140b3cf56a54bdeef234e89ee12cba0dc.tar.gz android_external_android-clat-8a41a5d140b3cf56a54bdeef234e89ee12cba0dc.tar.bz2 android_external_android-clat-8a41a5d140b3cf56a54bdeef234e89ee12cba0dc.zip |
Support 464xlat on broadcast interfaces such as wifi.
This works by generating a random IID and then using the
IPV6_JOIN_ANYCAST socket option on the write-only raw socket to
configure an address on the interface.
Change-Id: Ieb885b7c54454988e2e4254a14b4213cba3bd791
-rw-r--r-- | clatd.c | 4 | ||||
-rw-r--r-- | setif.c | 51 | ||||
-rw-r--r-- | setif.h | 3 |
3 files changed, 58 insertions, 0 deletions
@@ -275,10 +275,12 @@ int update_clat_ipv6_address(const struct tun_data *tunnel, const char *interfac char from_addr[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &Global_Clatd_Config.ipv6_local_subnet, from_addr, sizeof(from_addr)); logmsg(ANDROID_LOG_INFO, "clat IPv6 address changed from %s to %s", from_addr, addrstr); + del_anycast_address(tunnel->write_fd6, &Global_Clatd_Config.ipv6_local_subnet); } // Start translating packets to the new prefix. Global_Clatd_Config.ipv6_local_subnet = interface_ip->ip6; + add_anycast_address(tunnel->write_fd6, &Global_Clatd_Config.ipv6_local_subnet, interface); free(interface_ip); // Update our packet socket filter to reflect the new 464xlat IP address. @@ -534,9 +536,11 @@ int main(int argc, char **argv) { logmsg(ANDROID_LOG_FATAL, "sigterm handler failed: %s", strerror(errno)); exit(1); } + event_loop(&tunnel); logmsg(ANDROID_LOG_INFO,"Shutting down clat on %s", uplink_interface); + del_anycast_address(tunnel.write_fd6, &Global_Clatd_Config.ipv6_local_subnet); return 0; } @@ -23,8 +23,11 @@ #include <netlink/handlers.h> #include <netlink/msg.h> +#include "logging.h" #include "netlink_msg.h" +#define DEBUG_OPTNAME(a) case (a): { optname = #a; break; } + /* function: add_address * adds an IP address to/from an interface, returns 0 on success and <0 on failure * ifname - name of interface to change @@ -127,3 +130,51 @@ cleanup: return retval; } + +static int do_anycast_setsockopt(int sock, int what, struct in6_addr *addr, int ifindex) { + struct ipv6_mreq mreq = { *addr, ifindex }; + char *optname; + int ret; + + switch (what) { + DEBUG_OPTNAME(IPV6_JOIN_ANYCAST) + DEBUG_OPTNAME(IPV6_LEAVE_ANYCAST) + default: + optname = "???"; + break; + } + + ret = setsockopt(sock, SOL_IPV6, what, &mreq, sizeof(mreq)); + if (ret) { + logmsg(ANDROID_LOG_ERROR, "%s: setsockopt(%s): %s", __func__, optname, strerror(errno)); + } + + return ret; +} + +/* function: add_anycast_address + * adds an anycast IPv6 address to an interface, returns 0 on success and <0 on failure + * sock - the socket to add the address to + * addr - the IP address to add + * ifname - name of interface to add the address to + */ +int add_anycast_address(int sock, struct in6_addr *addr, const char *ifname) { + int ifindex, s, ret; + + ifindex = if_nametoindex(ifname); + if (!ifindex) { + logmsg(ANDROID_LOG_ERROR, "%s: unknown ifindex for interface %s", __func__, ifname); + return -ENODEV; + } + + return do_anycast_setsockopt(sock, IPV6_JOIN_ANYCAST, addr, ifindex); +} + +/* function: del_anycast_address + * removes an anycast IPv6 address from the system, returns 0 on success and <0 on failure + * sock - the socket to remove from, must have had the address added via add_anycast_address + * addr - the IP address to remove + */ +int del_anycast_address(int sock, struct in6_addr *addr) { + return do_anycast_setsockopt(sock, IPV6_LEAVE_ANYCAST, addr, 0); +} @@ -21,4 +21,7 @@ int add_address(const char *ifname, int family, const void *address, int cidr, const void *broadcast); int if_up(const char *ifname, int mtu); +int add_anycast_address(int sock, const struct in6_addr *addr, const char *interface); +int del_anycast_address(int sock, const struct in6_addr *addr); + #endif |