Merge tag android-5.1.0_r1 into AOSP_5.1_MERGE

Change-Id: I460c2236ef735ec855c97c74847376ba2681c151
diff --git a/Android.mk b/Android.mk
index a640e06..988d925 100644
--- a/Android.mk
+++ b/Android.mk
@@ -6,7 +6,7 @@
 LOCAL_CFLAGS := -Wall -Werror -Wunused-parameter
 LOCAL_C_INCLUDES := external/libnl/include bionic/libc/dns/include
 LOCAL_STATIC_LIBRARIES := libnl
-LOCAL_SHARED_LIBRARIES := libcutils liblog
+LOCAL_SHARED_LIBRARIES := libcutils liblog libnetutils
 
 # The clat daemon.
 LOCAL_MODULE := clatd
@@ -30,7 +30,7 @@
 
 LOCAL_MODULE := clatd_test
 LOCAL_CFLAGS := -Wall -Werror -Wunused-parameter
-LOCAL_SRC_FILES := clatd_test.cpp dump.c checksum.c translate.c icmp.c ipv4.c ipv6.c logging.c
+LOCAL_SRC_FILES := clatd_test.cpp checksum.c translate.c icmp.c ipv4.c ipv6.c logging.c config.c
 LOCAL_MODULE_TAGS := eng tests
 LOCAL_SHARED_LIBRARIES := liblog
 
diff --git a/checksum.h b/checksum.h
index 6195810..d0af88e 100644
--- a/checksum.h
+++ b/checksum.h
@@ -18,6 +18,10 @@
 #ifndef __CHECKSUM_H__
 #define __CHECKSUM_H__
 
+#include <stdint.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
 uint32_t ip_checksum_add(uint32_t current, const void *data, int len);
 uint16_t ip_checksum_finish(uint32_t temp_sum);
 uint16_t ip_checksum(const void *data, int len);
diff --git a/clatd.c b/clatd.c
index dbf725b..3f0af0b 100644
--- a/clatd.c
+++ b/clatd.c
@@ -51,7 +51,7 @@
 #include "getaddr.h"
 #include "dump.h"
 
-#define DEVICENAME4 "clat4"
+#define DEVICEPREFIX "v4-"
 
 /* 40 bytes IPv6 header - 20 bytes IPv4 header + 8 bytes fragment header */
 #define MTU_DELTA 28
@@ -150,42 +150,6 @@
   return 1;
 }
 
-/* function: interface_poll
- * polls the uplink network interface for address changes
- * tunnel - tun device data
- */
-void interface_poll(const struct tun_data *tunnel) {
-  union anyip *interface_ip;
-
-  interface_ip = getinterface_ip(Global_Clatd_Config.default_pdp_interface, AF_INET6);
-  if(!interface_ip) {
-    logmsg(ANDROID_LOG_WARN,"unable to find an ipv6 ip on interface %s",
-           Global_Clatd_Config.default_pdp_interface);
-    return;
-  }
-
-  config_generate_local_ipv6_subnet(&interface_ip->ip6);
-
-  if(!IN6_ARE_ADDR_EQUAL(&interface_ip->ip6, &Global_Clatd_Config.ipv6_local_subnet)) {
-    char from_addr[INET6_ADDRSTRLEN], to_addr[INET6_ADDRSTRLEN];
-    inet_ntop(AF_INET6, &Global_Clatd_Config.ipv6_local_subnet, from_addr, sizeof(from_addr));
-    inet_ntop(AF_INET6, &interface_ip->ip6, to_addr, sizeof(to_addr));
-    logmsg(ANDROID_LOG_WARN, "clat subnet changed from %s to %s", from_addr, to_addr);
-
-    // Start translating packets to the new prefix.
-    memcpy(&Global_Clatd_Config.ipv6_local_subnet, &interface_ip->ip6, sizeof(struct in6_addr));
-
-    // Update our packet socket filter to reflect the new 464xlat IP address.
-    if (!configure_packet_socket(tunnel->read_fd6)) {
-        // Things aren't going to work. Bail out and hope we have better luck next time.
-        // We don't log an error here because configure_packet_socket has already done so.
-        exit(1);
-    }
-  }
-
-  free(interface_ip);
-}
-
 /* function: configure_tun_ip
  * configures the ipv4 and ipv6 addresses on the tunnel interface
  * tunnel - tun device data
@@ -193,6 +157,22 @@
 void configure_tun_ip(const struct tun_data *tunnel) {
   int status;
 
+  // Pick an IPv4 address to use by finding a free address in the configured prefix. Technically,
+  // there is a race here - if another clatd calls config_select_ipv4_address after we do, but
+  // before we call add_address, it can end up having the same IP address as we do. But the time
+  // window in which this can happen is extremely small, and even if we end up with a duplicate
+  // address, the only damage is that IPv4 TCP connections won't be reset until both interfaces go
+  // down.
+  in_addr_t localaddr = config_select_ipv4_address(&Global_Clatd_Config.ipv4_local_subnet,
+                                                   Global_Clatd_Config.ipv4_local_prefixlen);
+  if (localaddr == INADDR_NONE) {
+    logmsg(ANDROID_LOG_FATAL,"No free IPv4 address in %s/%d",
+           inet_ntoa(Global_Clatd_Config.ipv4_local_subnet),
+           Global_Clatd_Config.ipv4_local_prefixlen);
+    exit(1);
+  }
+  Global_Clatd_Config.ipv4_local_subnet.s_addr = localaddr;
+
   // Configure the interface before bringing it up. As soon as we bring the interface up, the
   // framework will be notified and will assume the interface's configuration has been finalized.
   status = add_address(tunnel->device4, AF_INET, &Global_Clatd_Config.ipv4_local_subnet,
@@ -202,6 +182,10 @@
     exit(1);
   }
 
+  char addrstr[INET_ADDRSTRLEN];
+  inet_ntop(AF_INET, &Global_Clatd_Config.ipv4_local_subnet, addrstr, sizeof(addrstr));
+  logmsg(ANDROID_LOG_INFO, "Using IPv4 address %s on %s", addrstr, tunnel->device4);
+
   if((status = if_up(tunnel->device4, Global_Clatd_Config.ipv4mtu)) < 0) {
     logmsg(ANDROID_LOG_FATAL,"configure_tun_ip/if_up(4) failed: %s",strerror(-status));
     exit(1);
@@ -275,6 +259,60 @@
   tunnel->read_fd6 = packetsock;
 }
 
+/* function: update_clat_ipv6_address
+ * picks the clat IPv6 address and configures packet translation to use it.
+ * tunnel - tun device data
+ * interface - uplink interface name
+ * returns: 1 on success, 0 on failure
+ */
+int update_clat_ipv6_address(const struct tun_data *tunnel, const char *interface) {
+  union anyip *interface_ip;
+  char addrstr[INET6_ADDRSTRLEN];
+
+  // TODO: check that the prefix length is /64.
+  interface_ip = getinterface_ip(interface, AF_INET6);
+  if (!interface_ip) {
+    logmsg(ANDROID_LOG_ERROR, "Unable to find an IPv6 address on interface %s", interface);
+    return 0;
+  }
+
+  // If our prefix hasn't changed, do nothing. (If this is the first time we configure an IPv6
+  // address, Global_Clatd_Config.ipv6_local_subnet will be ::, which won't match our new prefix.)
+  if (ipv6_prefix_equal(&interface_ip->ip6, &Global_Clatd_Config.ipv6_local_subnet)) {
+    free(interface_ip);
+    return 1;
+  }
+
+  // Generate an interface ID.
+  config_generate_local_ipv6_subnet(&interface_ip->ip6);
+  inet_ntop(AF_INET6, &interface_ip->ip6, addrstr, sizeof(addrstr));
+
+  if (IN6_IS_ADDR_UNSPECIFIED(&Global_Clatd_Config.ipv6_local_subnet)) {
+    // Startup.
+    logmsg(ANDROID_LOG_INFO, "Using IPv6 address %s on %s", addrstr, interface);
+  } else {
+    // Prefix change.
+    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.
+  if (!configure_packet_socket(tunnel->read_fd6)) {
+      // Things aren't going to work. Bail out and hope we have better luck next time.
+      // We don't log an error here because configure_packet_socket has already done so.
+      exit(1);
+  }
+
+  return 1;
+}
+
 /* function: configure_interface
  * reads the configuration and applies it to the interface
  * uplink_interface - network interface to use to reach the ipv6 internet
@@ -404,7 +442,7 @@
 
     time_t now = time(NULL);
     if(last_interface_poll < (now - INTERFACE_POLL_FREQUENCY)) {
-      interface_poll(tunnel);
+      update_clat_ipv6_address(tunnel, Global_Clatd_Config.default_pdp_interface);
       last_interface_poll = now;
     }
   }
@@ -441,8 +479,7 @@
   char *uplink_interface = NULL, *plat_prefix = NULL, *net_id_str = NULL, *mark_str = NULL;
   unsigned net_id = NETID_UNSET;
   uint32_t mark = MARK_UNSET;
-
-  strcpy(tunnel.device4, DEVICENAME4);
+  unsigned len;
 
   while((opt = getopt(argc, argv, "i:p:n:m:h")) != -1) {
     switch(opt) {
@@ -482,6 +519,12 @@
     exit(1);
   }
 
+  len = snprintf(tunnel.device4, sizeof(tunnel.device4), "%s%s", DEVICEPREFIX, uplink_interface);
+  if (len >= sizeof(tunnel.device4)) {
+    logmsg(ANDROID_LOG_FATAL, "interface name too long '%s'", tunnel.device4);
+    exit(1);
+  }
+
   logmsg(ANDROID_LOG_INFO, "Starting clat version %s on %s netid=%s mark=%s",
          CLATD_VERSION, uplink_interface,
          net_id_str ? net_id_str : "(none)",
@@ -506,19 +549,18 @@
 
   configure_interface(uplink_interface, plat_prefix, &tunnel, net_id);
 
-  if (!configure_packet_socket(tunnel.read_fd6)) {
-    // We've already logged an error.
-    exit(1);
-  }
+  update_clat_ipv6_address(&tunnel, uplink_interface);
 
   // Loop until someone sends us a signal or brings down the tun interface.
   if(signal(SIGTERM, stop_loop) == SIG_ERR) {
     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;
 }
diff --git a/clatd.conf b/clatd.conf
index 0d4b79e..ff80975 100644
--- a/clatd.conf
+++ b/clatd.conf
@@ -1,12 +1,16 @@
-# host ID to use as the source of CLAT traffic
-# this is a /128 taken out of the /64 routed to the phone
-ipv6_host_id ::464
+# Host IID to use as the source of CLAT traffic.
+# This is a /128 taken out of the /64 on the parent interface.
+# A host IID of :: means to generate a checksum-neutral, random IID.
+ipv6_host_id ::
 
-# ipv4 subnet for the local traffic to use.  This is a /32 host address
+# IPv4 address configuration to use when selecting a host address. The first
+# clat daemon started will use the address specified by ipv4_local_subnet. If
+# more than one daemon is run at the same time, subsequent daemons will use
+# other addresses in the prefix of length ipv4_local prefixlen that contains
+# ipv4_local_subnet. The default is to use the IANA-assigned range 192.0.0.0/29,
+# which allows up to 8 clat daemons (.4, .5, .6, .7, .0, .1, .2, .3).
 ipv4_local_subnet 192.0.0.4
-
-# ipv6 extra link local address for the ip6 iface.
-ipv6_local_address fe80::c000:0004
+ipv4_local_prefixlen 29
 
 # get the plat_subnet from dns lookups (requires DNS64)
 plat_from_dns64 yes
diff --git a/clatd.h b/clatd.h
index ca7369b..e7cef43 100644
--- a/clatd.h
+++ b/clatd.h
@@ -23,7 +23,7 @@
 
 #define MAXMTU 1500
 #define PACKETLEN (MAXMTU+sizeof(struct tun_pi))
-#define CLATD_VERSION "1.3"
+#define CLATD_VERSION "1.4"
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
diff --git a/clatd_test.cpp b/clatd_test.cpp
index b35bf70..fe52c21 100644
--- a/clatd_test.cpp
+++ b/clatd_test.cpp
@@ -20,6 +20,7 @@
 
 #include <stdio.h>
 #include <arpa/inet.h>
+#include <netinet/in6.h>
 #include <sys/uio.h>
 
 #include <gtest/gtest.h>
@@ -370,7 +371,7 @@
   *reassembled_len = total_length;
 }
 
-void check_data_matches(const uint8_t *expected, const uint8_t *actual, size_t len, const char *msg) {
+void check_data_matches(const void *expected, const void *actual, size_t len, const char *msg) {
   if (memcmp(expected, actual, len)) {
     // Hex dump, 20 bytes per line, one space between bytes (1 byte = 3 chars), indented by 4.
     int hexdump_len = len * 3 + (len / 20 + 1) * 5;
@@ -382,11 +383,11 @@
         sprintf(actual_hexdump + pos, "\n   ");
         pos += 4;
       }
-      sprintf(expected_hexdump + pos, " %02x", expected[i]);
-      sprintf(actual_hexdump + pos, " %02x", actual[i]);
+      sprintf(expected_hexdump + pos, " %02x", ((uint8_t *) expected)[i]);
+      sprintf(actual_hexdump + pos, " %02x", ((uint8_t *) actual)[i]);
       pos += 3;
     }
-    FAIL() << msg << ": Translated packet doesn't match"
+    FAIL() << msg << ": Data doesn't match"
            << "\n  Expected:" << (char *) expected_hexdump
            << "\n  Actual:" << (char *) actual_hexdump << "\n";
   }
@@ -460,6 +461,7 @@
 
   translate_packet(write_fd, (version == 4), original, original_len);
 
+  snprintf(foo, sizeof(foo), "%s: Invalid translated packet", msg);
   if (version == 6) {
     // Translating to IPv4. Expect a tun header.
     struct tun_pi new_tun_header;
@@ -472,13 +474,15 @@
       ASSERT_LT((size_t) len, *outlen) << msg << ": Translated packet buffer too small\n";
       EXPECT_EQ(expected_proto, new_tun_header.proto) << msg << "Unexpected tun proto\n";
       *outlen = len - sizeof(new_tun_header);
+      check_packet(out, *outlen, msg);
     } else {
-      FAIL() << msg << ": Packet was not translated";
+      FAIL() << msg << ": Packet was not translated: len=" << len;
       *outlen = 0;
     }
   } else {
     // Translating to IPv6. Expect raw packet.
     *outlen = read(read_fd, out, *outlen);
+    check_packet(out, *outlen, msg);
   }
 }
 
@@ -514,6 +518,44 @@
   check_packet(translated, translated_len, msg);
 }
 
+int get_transport_checksum(const uint8_t *packet) {
+  struct iphdr *ip;
+  struct ip6_hdr *ip6;
+  uint8_t protocol;
+  const void *payload;
+
+  int version = ip_version(packet);
+  switch (version) {
+    case 4:
+      ip = (struct iphdr *) packet;
+      if (is_ipv4_fragment(ip)) {
+          return -1;
+      }
+      protocol = ip->protocol;
+      payload = ip + 1;
+      break;
+    case 6:
+      ip6 = (struct ip6_hdr *) packet;
+      protocol = ip6->ip6_nxt;
+      payload = ip6 + 1;
+      break;
+    default:
+      return -1;
+  }
+
+  switch (protocol) {
+    case IPPROTO_UDP:
+      return ((struct udphdr *) payload)->check;
+
+    case IPPROTO_TCP:
+      return ((struct tcphdr *) payload)->check;
+
+    case IPPROTO_FRAGMENT:
+    default:
+      return -1;
+  }
+}
+
 struct clat_config Global_Clatd_Config;
 
 class ClatdTest : public ::testing::Test {
@@ -522,10 +564,185 @@
     inet_pton(AF_INET, kIPv4LocalAddr, &Global_Clatd_Config.ipv4_local_subnet);
     inet_pton(AF_INET6, kIPv6PlatSubnet, &Global_Clatd_Config.plat_subnet);
     inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet);
+    Global_Clatd_Config.ipv6_host_id = in6addr_any;
+    Global_Clatd_Config.use_dynamic_iid = 1;
   }
 };
 
-TEST_F(ClatdTest, Sanitycheck) {
+void expect_ipv6_addr_equal(struct in6_addr *expected, struct in6_addr *actual) {
+  if (!IN6_ARE_ADDR_EQUAL(expected, actual)) {
+    char expected_str[INET6_ADDRSTRLEN], actual_str[INET6_ADDRSTRLEN];
+    inet_ntop(AF_INET6, expected, expected_str, sizeof(expected_str));
+    inet_ntop(AF_INET6, actual, actual_str, sizeof(actual_str));
+    FAIL()
+        << "Unexpected IPv6 address:: "
+        << "\n  Expected: " << expected_str
+        << "\n  Actual:   " << actual_str
+        << "\n";
+  }
+}
+
+TEST_F(ClatdTest, TestIPv6PrefixEqual) {
+  EXPECT_TRUE(ipv6_prefix_equal(&Global_Clatd_Config.plat_subnet,
+                                &Global_Clatd_Config.plat_subnet));
+  EXPECT_FALSE(ipv6_prefix_equal(&Global_Clatd_Config.plat_subnet,
+                                 &Global_Clatd_Config.ipv6_local_subnet));
+
+  struct in6_addr subnet2 = Global_Clatd_Config.ipv6_local_subnet;
+  EXPECT_TRUE(ipv6_prefix_equal(&Global_Clatd_Config.ipv6_local_subnet, &subnet2));
+  EXPECT_TRUE(ipv6_prefix_equal(&subnet2, &Global_Clatd_Config.ipv6_local_subnet));
+
+  subnet2.s6_addr[6] = 0xff;
+  EXPECT_FALSE(ipv6_prefix_equal(&Global_Clatd_Config.ipv6_local_subnet, &subnet2));
+  EXPECT_FALSE(ipv6_prefix_equal(&subnet2, &Global_Clatd_Config.ipv6_local_subnet));
+}
+
+int count_onebits(const void *data, size_t size) {
+  int onebits = 0;
+  for (size_t pos = 0; pos < size; pos++) {
+    uint8_t *byte = ((uint8_t*) data) + pos;
+    for (int shift = 0; shift < 8; shift++) {
+      onebits += (*byte >> shift) & 1;
+    }
+  }
+  return onebits;
+}
+
+TEST_F(ClatdTest, TestCountOnebits) {
+  uint64_t i;
+  i = 1;
+  ASSERT_EQ(1, count_onebits(&i, sizeof(i)));
+  i <<= 61;
+  ASSERT_EQ(1, count_onebits(&i, sizeof(i)));
+  i |= ((uint64_t) 1 << 33);
+  ASSERT_EQ(2, count_onebits(&i, sizeof(i)));
+  i = 0xf1000202020000f0;
+  ASSERT_EQ(5 + 1 + 1 + 1 + 4, count_onebits(&i, sizeof(i)));
+}
+
+TEST_F(ClatdTest, TestGenIIDConfigured) {
+  struct in6_addr myaddr, expected;
+  Global_Clatd_Config.use_dynamic_iid = 0;
+  ASSERT_TRUE(inet_pton(AF_INET6, "::bad:ace:d00d", &Global_Clatd_Config.ipv6_host_id));
+  ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:0:bad:ace:d00d", &expected));
+  ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:f076:ae99:124e:aa54", &myaddr));
+  config_generate_local_ipv6_subnet(&myaddr);
+  expect_ipv6_addr_equal(&expected, &myaddr);
+
+  Global_Clatd_Config.use_dynamic_iid = 1;
+  config_generate_local_ipv6_subnet(&myaddr);
+  EXPECT_FALSE(IN6_ARE_ADDR_EQUAL(&expected, &myaddr));
+}
+
+TEST_F(ClatdTest, TestGenIIDRandom) {
+  struct in6_addr interface_ipv6;
+  ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:f076:ae99:124e:aa54", &interface_ipv6));
+  Global_Clatd_Config.ipv6_host_id = in6addr_any;
+
+  // Generate a boatload of random IIDs.
+  int onebits = 0;
+  uint64_t prev_iid = 0;
+  for (int i = 0; i < 100000; i++) {
+    struct in6_addr myaddr =  interface_ipv6;
+
+    config_generate_local_ipv6_subnet(&myaddr);
+
+    // Check the generated IP address is in the same prefix as the interface IPv6 address.
+    EXPECT_TRUE(ipv6_prefix_equal(&interface_ipv6, &myaddr));
+
+    // Check that consecutive IIDs are not the same.
+    uint64_t iid = * (uint64_t*) (&myaddr.s6_addr[8]);
+    ASSERT_TRUE(iid != prev_iid)
+        << "Two consecutive random IIDs are the same: "
+        << std::showbase << std::hex
+        << iid << "\n";
+    prev_iid = iid;
+
+    // Check that the IID is checksum-neutral with the NAT64 prefix and the
+    // local prefix.
+    struct in_addr *ipv4addr = &Global_Clatd_Config.ipv4_local_subnet;
+    struct in6_addr *plat_subnet = &Global_Clatd_Config.plat_subnet;
+
+    uint16_t c1 = ip_checksum_finish(ip_checksum_add(0, ipv4addr, sizeof(*ipv4addr)));
+    uint16_t c2 = ip_checksum_finish(ip_checksum_add(0, plat_subnet, sizeof(*plat_subnet)) +
+                                     ip_checksum_add(0, &myaddr, sizeof(myaddr)));
+
+    if (c1 != c2) {
+      char myaddr_str[INET6_ADDRSTRLEN], plat_str[INET6_ADDRSTRLEN], ipv4_str[INET6_ADDRSTRLEN];
+      inet_ntop(AF_INET6, &myaddr, myaddr_str, sizeof(myaddr_str));
+      inet_ntop(AF_INET6, plat_subnet, plat_str, sizeof(plat_str));
+      inet_ntop(AF_INET, ipv4addr, ipv4_str, sizeof(ipv4_str));
+      FAIL()
+          << "Bad IID: " << myaddr_str
+          << " not checksum-neutral with " << ipv4_str << " and " << plat_str
+          << std::showbase << std::hex
+          << "\n  IPv4 checksum: " << c1
+          << "\n  IPv6 checksum: " << c2
+          << "\n";
+    }
+
+    // Check that IIDs are roughly random and use all the bits by counting the
+    // total number of bits set to 1 in a random sample of 100000 generated IIDs.
+    onebits += count_onebits(&iid, sizeof(iid));
+  }
+  EXPECT_LE(3190000, onebits);
+  EXPECT_GE(3210000, onebits);
+}
+
+extern "C" addr_free_func config_is_ipv4_address_free;
+int never_free(in_addr_t /* addr */) { return 0; }
+int always_free(in_addr_t /* addr */) { return 1; }
+int only2_free(in_addr_t addr) { return (ntohl(addr) & 0xff) == 2; }
+int over6_free(in_addr_t addr) { return (ntohl(addr) & 0xff) >= 6; }
+int only10_free(in_addr_t addr) { return (ntohl(addr) & 0xff) == 10; }
+
+TEST_F(ClatdTest, SelectIPv4Address) {
+  struct in_addr addr;
+
+  inet_pton(AF_INET, kIPv4LocalAddr, &addr);
+
+  addr_free_func orig_config_is_ipv4_address_free = config_is_ipv4_address_free;
+
+  // If no addresses are free, return INADDR_NONE.
+  config_is_ipv4_address_free = never_free;
+  EXPECT_EQ(INADDR_NONE, config_select_ipv4_address(&addr, 29));
+  EXPECT_EQ(INADDR_NONE, config_select_ipv4_address(&addr, 16));
+
+  // If the configured address is free, pick that. But a prefix that's too big is invalid.
+  config_is_ipv4_address_free = always_free;
+  EXPECT_EQ(inet_addr(kIPv4LocalAddr), config_select_ipv4_address(&addr, 29));
+  EXPECT_EQ(inet_addr(kIPv4LocalAddr), config_select_ipv4_address(&addr, 20));
+  EXPECT_EQ(INADDR_NONE, config_select_ipv4_address(&addr, 15));
+
+  // A prefix length of 32 works, but anything above it is invalid.
+  EXPECT_EQ(inet_addr(kIPv4LocalAddr), config_select_ipv4_address(&addr, 32));
+  EXPECT_EQ(INADDR_NONE, config_select_ipv4_address(&addr, 33));
+
+  // If another address is free, pick it.
+  config_is_ipv4_address_free = over6_free;
+  EXPECT_EQ(inet_addr("192.0.0.6"), config_select_ipv4_address(&addr, 29));
+
+  // Check that we wrap around to addresses that are lower than the first address.
+  config_is_ipv4_address_free = only2_free;
+  EXPECT_EQ(inet_addr("192.0.0.2"), config_select_ipv4_address(&addr, 29));
+  EXPECT_EQ(INADDR_NONE, config_select_ipv4_address(&addr, 30));
+
+  // If a free address exists outside the prefix, we don't pick it.
+  config_is_ipv4_address_free = only10_free;
+  EXPECT_EQ(INADDR_NONE, config_select_ipv4_address(&addr, 29));
+  EXPECT_EQ(inet_addr("192.0.0.10"), config_select_ipv4_address(&addr, 24));
+
+  // Now try using the real function which sees if IP addresses are free using bind().
+  // Assume that the machine running the test has the address 127.0.0.1, but not 8.8.8.8.
+  config_is_ipv4_address_free = orig_config_is_ipv4_address_free;
+  addr.s_addr = inet_addr("8.8.8.8");
+  EXPECT_EQ(inet_addr("8.8.8.8"), config_select_ipv4_address(&addr, 29));
+
+  addr.s_addr = inet_addr("127.0.0.1");
+  EXPECT_EQ(inet_addr("127.0.0.2"), config_select_ipv4_address(&addr, 29));
+}
+
+TEST_F(ClatdTest, DataSanitycheck) {
   // Sanity checks the data.
   uint8_t v4_header[] = { IPV4_UDP_HEADER };
   ASSERT_EQ(sizeof(struct iphdr), sizeof(v4_header)) << "Test IPv4 header: incorrect length\n";
@@ -681,3 +898,43 @@
                              kIPv4Fragments, kIPv4FragLengths,
                              ARRAYSIZE(kIPv6Fragments), "IPv6->IPv4 fragment translation");
 }
+
+void check_translate_checksum_neutral(const uint8_t *original, size_t original_len,
+                                      size_t expected_len, const char *msg) {
+  uint8_t translated[MAXMTU];
+  size_t translated_len = sizeof(translated);
+  do_translate_packet(original, original_len, translated, &translated_len, msg);
+  EXPECT_EQ(expected_len, translated_len) << msg << ": Translated packet length incorrect\n";
+  // do_translate_packet already checks packets for validity and verifies the checksum.
+  int original_check = get_transport_checksum(original);
+  int translated_check = get_transport_checksum(translated);
+  ASSERT_NE(-1, original_check);
+  ASSERT_NE(-1, translated_check);
+  ASSERT_EQ(original_check, translated_check)
+      << "Not checksum neutral: original and translated checksums differ\n";
+}
+
+TEST_F(ClatdTest, TranslateChecksumNeutral) {
+  // Generate a random clat IPv6 address and check that translation is checksum-neutral.
+  Global_Clatd_Config.ipv6_host_id = in6addr_any;
+  ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:f076:ae99:124e:aa54",
+                        &Global_Clatd_Config.ipv6_local_subnet));
+  config_generate_local_ipv6_subnet(&Global_Clatd_Config.ipv6_local_subnet);
+  ASSERT_NE((uint32_t) 0x00000464, Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]);
+  ASSERT_NE((uint32_t) 0, Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]);
+
+  // Check that translating UDP packets is checksum-neutral. First, IPv4.
+  uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
+  fix_udp_checksum(udp_ipv4);
+  check_translate_checksum_neutral(udp_ipv4, sizeof(udp_ipv4), sizeof(udp_ipv4) + 20,
+                                   "UDP/IPv4 -> UDP/IPv6 checksum neutral");
+
+  // Now try IPv6.
+  uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
+  // The test packet uses the static IID, not the random IID. Fix up the source address.
+  struct ip6_hdr *ip6 = (struct ip6_hdr *) udp_ipv6;
+  memcpy(&ip6->ip6_src, &Global_Clatd_Config.ipv6_local_subnet, sizeof(ip6->ip6_src));
+  fix_udp_checksum(udp_ipv6);
+  check_translate_checksum_neutral(udp_ipv4, sizeof(udp_ipv4), sizeof(udp_ipv4) + 20,
+                                   "UDP/IPv4 -> UDP/IPv6 checksum neutral");
+}
diff --git a/config.c b/config.c
index 13889a0..b147868 100644
--- a/config.c
+++ b/config.c
@@ -25,12 +25,14 @@
 #include <unistd.h>
 
 #include <cutils/config_utils.h>
+#include <netutils/ifc.h>
 
 #include "config.h"
 #include "dns64.h"
 #include "logging.h"
 #include "getaddr.h"
 #include "clatd.h"
+#include "checksum.h"
 
 struct clat_config Global_Clatd_Config;
 
@@ -149,6 +151,16 @@
   }
 }
 
+/* function: ipv6_prefix_equal
+ * compares the prefixes two ipv6 addresses. assumes the prefix lengths are both /64.
+ * a1 - first address
+ * a2 - second address
+ * returns: 0 if the subnets are different, 1 if they are the same.
+ */
+int ipv6_prefix_equal(struct in6_addr *a1, struct in6_addr *a2) {
+    return !memcmp(a1, a2, 8);
+}
+
 /* function: dns64_detection
  * does dns lookups to set the plat subnet or exits on failure, waits forever for a dns response with a query backoff timer
  * net_id - (optional) netId to use, NETID_UNSET indicates use of default network
@@ -174,6 +186,88 @@
   }
 }
 
+/* function: gen_random_iid
+ * picks a random interface ID that is checksum neutral with the IPv4 address and the NAT64 prefix
+ * myaddr            - IPv6 address to write to
+ * ipv4_local_subnet - clat IPv4 address
+ * plat_subnet       - NAT64 prefix
+ */
+void gen_random_iid(struct in6_addr *myaddr, struct in_addr *ipv4_local_subnet,
+                    struct in6_addr *plat_subnet) {
+  // Fill last 8 bytes of IPv6 address with random bits.
+  arc4random_buf(&myaddr->s6_addr[8], 8);
+
+  // Make the IID checksum-neutral. That is, make it so that:
+  //   checksum(Local IPv4 | Remote IPv4) = checksum(Local IPv6 | Remote IPv6)
+  // in other words (because remote IPv6 = NAT64 prefix | Remote IPv4):
+  //   checksum(Local IPv4) = checksum(Local IPv6 | NAT64 prefix)
+  // Do this by adjusting the two bytes in the middle of the IID.
+
+  uint16_t middlebytes = (myaddr->s6_addr[11] << 8) + myaddr->s6_addr[12];
+
+  uint32_t c1 = ip_checksum_add(0, ipv4_local_subnet, sizeof(*ipv4_local_subnet));
+  uint32_t c2 = ip_checksum_add(0, plat_subnet, sizeof(*plat_subnet)) +
+                ip_checksum_add(0, myaddr, sizeof(*myaddr));
+
+  uint16_t delta = ip_checksum_adjust(middlebytes, c1, c2);
+  myaddr->s6_addr[11] = delta >> 8;
+  myaddr->s6_addr[12] = delta & 0xff;
+}
+
+// Factored out to a separate function for testability.
+int connect_is_ipv4_address_free(in_addr_t addr) {
+  int s = socket(AF_INET, SOCK_DGRAM, 0);
+  if (s == -1) {
+    return 0;
+  }
+
+  // Attempt to connect to the address. If the connection succeeds and getsockname returns the same
+  // the address then the address is already assigned to the system and we can't use it.
+  struct sockaddr_in sin = { .sin_family = AF_INET, .sin_addr = { addr }, .sin_port = 53 };
+  socklen_t len = sizeof(sin);
+  int inuse = connect(s, (struct sockaddr *) &sin, sizeof(sin)) == 0 &&
+              getsockname(s, (struct sockaddr *) &sin, &len) == 0 &&
+              (size_t) len >= sizeof(sin) &&
+              sin.sin_addr.s_addr == addr;
+
+  close(s);
+  return !inuse;
+}
+
+addr_free_func config_is_ipv4_address_free = connect_is_ipv4_address_free;
+
+/* function: config_select_ipv4_address
+ * picks a free IPv4 address, starting from ip and trying all addresses in the prefix in order
+ * ip        - the IP address from the configuration file
+ * prefixlen - the length of the prefix from which addresses may be selected.
+ * returns: the IPv4 address, or INADDR_NONE if no addresses were available
+ */
+in_addr_t config_select_ipv4_address(const struct in_addr *ip, int16_t prefixlen) {
+  in_addr_t chosen = INADDR_NONE;
+
+  // Don't accept prefixes that are too large because we scan addresses one by one.
+  if (prefixlen < 16 || prefixlen > 32) {
+      return chosen;
+  }
+
+  // All these are in host byte order.
+  in_addr_t mask = 0xffffffff >> (32 - prefixlen) << (32 - prefixlen);
+  in_addr_t ipv4 = ntohl(ip->s_addr);
+  in_addr_t first_ipv4 = ipv4;
+  in_addr_t prefix = ipv4 & mask;
+
+  // Pick the first IPv4 address in the pool, wrapping around if necessary.
+  // So, for example, 192.0.0.4 -> 192.0.0.5 -> 192.0.0.6 -> 192.0.0.7 -> 192.0.0.0.
+  do {
+     if (config_is_ipv4_address_free(htonl(ipv4))) {
+       chosen = htonl(ipv4);
+       break;
+     }
+     ipv4 = prefix | ((ipv4 + 1) & ~mask);
+  } while (ipv4 != first_ipv4);
+
+  return chosen;
+}
 
 /* function: config_generate_local_ipv6_subnet
  * generates the local ipv6 subnet when given the interface ip
@@ -183,36 +277,19 @@
 void config_generate_local_ipv6_subnet(struct in6_addr *interface_ip) {
   int i;
 
-  for(i = 2; i < 4; i++) {
-    interface_ip->s6_addr32[i] = Global_Clatd_Config.ipv6_host_id.s6_addr32[i];
+  if (Global_Clatd_Config.use_dynamic_iid) {
+    /* Generate a random interface ID. */
+    gen_random_iid(interface_ip,
+                   &Global_Clatd_Config.ipv4_local_subnet,
+                   &Global_Clatd_Config.plat_subnet);
+  } else {
+    /* Use the specified interface ID. */
+    for(i = 2; i < 4; i++) {
+      interface_ip->s6_addr32[i] = Global_Clatd_Config.ipv6_host_id.s6_addr32[i];
+    }
   }
 }
 
-/* function: subnet_from_interface
- * finds the ipv6 subnet configured on the specified interface
- * root      - parsed configuration
- * interface - network interface name
- */
-int subnet_from_interface(cnode *root, const char *interface) {
-  union anyip *interface_ip;
-
-  if(!config_item_ip6(root, "ipv6_host_id", "::200:5E10:0:0", &Global_Clatd_Config.ipv6_host_id))
-    return 0;
-
-  interface_ip = getinterface_ip(interface, AF_INET6);
-  if(!interface_ip) {
-    logmsg(ANDROID_LOG_FATAL,"unable to find an ipv6 ip on interface %s",interface);
-    return 0;
-  }
-
-  memcpy(&Global_Clatd_Config.ipv6_local_subnet, &interface_ip->ip6, sizeof(struct in6_addr));
-  free(interface_ip);
-
-  config_generate_local_ipv6_subnet(&Global_Clatd_Config.ipv6_local_subnet);
-
-  return 1;
-}
-
 /* function: read_config
  * reads the config file and parses it into the global variable Global_Clatd_Config. returns 0 on failure, 1 on success
  * file             - filename to parse
@@ -224,6 +301,7 @@
         unsigned net_id) {
   cnode *root = config_node("", "");
   void *tmp_ptr = NULL;
+  unsigned flags;
 
   if(!root) {
     logmsg(ANDROID_LOG_FATAL,"out of memory");
@@ -238,9 +316,8 @@
     goto failed;
   }
 
-  strncpy(Global_Clatd_Config.default_pdp_interface, uplink_interface, sizeof(Global_Clatd_Config.default_pdp_interface));
-
-  if(!subnet_from_interface(root,Global_Clatd_Config.default_pdp_interface))
+  Global_Clatd_Config.default_pdp_interface = strdup(uplink_interface);
+  if (!Global_Clatd_Config.default_pdp_interface)
     goto failed;
 
   if(!config_item_int16_t(root, "mtu", "-1", &Global_Clatd_Config.mtu))
@@ -249,10 +326,12 @@
   if(!config_item_int16_t(root, "ipv4mtu", "-1", &Global_Clatd_Config.ipv4mtu))
     goto failed;
 
-  if(!config_item_ip(root, "ipv4_local_subnet", DEFAULT_IPV4_LOCAL_SUBNET, &Global_Clatd_Config.ipv4_local_subnet))
+  if(!config_item_ip(root, "ipv4_local_subnet", DEFAULT_IPV4_LOCAL_SUBNET,
+                     &Global_Clatd_Config.ipv4_local_subnet))
     goto failed;
 
-  if(!config_item_ip6(root, "ipv6_local_address", DEFAULT_IPV6_LOCAL_ADDRESS, &Global_Clatd_Config.ipv6_local_address))
+  if(!config_item_int16_t(root, "ipv4_local_prefixlen", DEFAULT_IPV4_LOCAL_PREFIXLEN,
+                          &Global_Clatd_Config.ipv4_local_prefixlen))
     goto failed;
 
   if(plat_prefix) { // plat subnet is coming from the command line
@@ -278,6 +357,19 @@
     }
   }
 
+  if (!config_item_ip6(root, "ipv6_host_id", "::", &Global_Clatd_Config.ipv6_host_id))
+    goto failed;
+
+  /* In order to prevent multiple devices attempting to use the same clat address, never use a
+     statically-configured interface ID on a broadcast interface such as wifi. */
+  if (!IN6_IS_ADDR_UNSPECIFIED(&Global_Clatd_Config.ipv6_host_id)) {
+    ifc_init();
+    ifc_get_info(Global_Clatd_Config.default_pdp_interface, NULL, NULL, &flags);
+    ifc_close();
+    Global_Clatd_Config.use_dynamic_iid = (flags & IFF_BROADCAST) != 0;
+  } else {
+    Global_Clatd_Config.use_dynamic_iid = 1;
+  }
 
   return 1;
 
@@ -295,9 +387,9 @@
 
   logmsg(ANDROID_LOG_DEBUG,"mtu = %d",Global_Clatd_Config.mtu);
   logmsg(ANDROID_LOG_DEBUG,"ipv4mtu = %d",Global_Clatd_Config.ipv4mtu);
-  logmsg(ANDROID_LOG_DEBUG,"ipv6_local_address = %s",inet_ntop(AF_INET6, &Global_Clatd_Config.ipv6_local_address, charbuffer, sizeof(charbuffer)));
   logmsg(ANDROID_LOG_DEBUG,"ipv6_local_subnet = %s",inet_ntop(AF_INET6, &Global_Clatd_Config.ipv6_local_subnet, charbuffer, sizeof(charbuffer)));
   logmsg(ANDROID_LOG_DEBUG,"ipv4_local_subnet = %s",inet_ntop(AF_INET, &Global_Clatd_Config.ipv4_local_subnet, charbuffer, sizeof(charbuffer)));
+  logmsg(ANDROID_LOG_DEBUG,"ipv4_local_prefixlen = %d", Global_Clatd_Config.ipv4_local_prefixlen);
   logmsg(ANDROID_LOG_DEBUG,"plat_subnet = %s",inet_ntop(AF_INET6, &Global_Clatd_Config.plat_subnet, charbuffer, sizeof(charbuffer)));
   logmsg(ANDROID_LOG_DEBUG,"default_pdp_interface = %s",Global_Clatd_Config.default_pdp_interface);
 }
diff --git a/config.h b/config.h
index fa47152..b6d9ae1 100644
--- a/config.h
+++ b/config.h
@@ -19,22 +19,21 @@
 #define __CONFIG_H__
 
 #include <netinet/in.h>
-#include <sys/system_properties.h>
 
-#define DEFAULT_IPV4_LOCAL_SUBNET "192.168.255.1"
-#define DEFAULT_IPV6_LOCAL_ADDRESS "fe80::c000:0004"
-
-#define DEFAULT_DNS64_DETECTION_HOSTNAME "ipv4.google.com"
+#define DEFAULT_IPV4_LOCAL_SUBNET "192.0.0.4"
+#define DEFAULT_IPV4_LOCAL_PREFIXLEN "29"
+#define DEFAULT_DNS64_DETECTION_HOSTNAME "ipv4only.arpa"
 
 struct clat_config {
   int16_t mtu, ipv4mtu;
-  struct in6_addr ipv6_local_address;
   struct in6_addr ipv6_local_subnet;
   struct in6_addr ipv6_host_id;
   struct in_addr ipv4_local_subnet;
+  int16_t ipv4_local_prefixlen;
   struct in6_addr plat_subnet;
-  char default_pdp_interface[PROP_VALUE_MAX];
+  char *default_pdp_interface;
   char *plat_from_dns64_hostname;
+  int use_dynamic_iid;
 };
 
 extern struct clat_config Global_Clatd_Config;
@@ -42,5 +41,9 @@
 int read_config(const char *file, const char *uplink_interface, const char *plat_prefix,
         unsigned net_id);
 void config_generate_local_ipv6_subnet(struct in6_addr *interface_ip);
+in_addr_t config_select_ipv4_address(const struct in_addr *ip, int16_t prefixlen);
+int ipv6_prefix_equal(struct in6_addr *a1, struct in6_addr *a2);
+
+typedef int (*addr_free_func)(in_addr_t addr);
 
 #endif /* __CONFIG_H__ */
diff --git a/setif.c b/setif.c
index 5ee00bc..359ed24 100644
--- a/setif.c
+++ b/setif.c
@@ -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 @@
 
   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);
+}
diff --git a/setif.h b/setif.h
index 7f83f73..d31eed5 100644
--- a/setif.h
+++ b/setif.h
@@ -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