Bug 797262 - IPV6 support for webrtc. r=drno
authorByron Campen [:bwc] <docfaraday@gmail.com>
Wed, 22 Apr 2015 15:02:50 -0500
changeset 251133 dfb822545e3446e8d01bb3fb25e4313350c72c0e
parent 251132 2fd98d3d9258915ec9b54b955b6a84794040d67d
child 251134 9ac36249a38bba15b215a74903398e7a65732e02
push id61770
push userryanvm@gmail.com
push dateThu, 02 Jul 2015 14:27:43 +0000
treeherdermozilla-inbound@dfb822545e34 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdrno
bugs797262
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 797262 - IPV6 support for webrtc. r=drno
media/mtransport/gonk_addrs.cpp
media/mtransport/nr_socket_prsock.cpp
media/mtransport/nricectx.cpp
media/mtransport/nricectx.h
media/mtransport/nriceresolver.cpp
media/mtransport/nriceresolverfake.cpp
media/mtransport/nriceresolverfake.h
media/mtransport/nrinterfaceprioritizer.cpp
media/mtransport/stun_udp_socket_filter.cpp
media/mtransport/test/buffered_stun_socket_unittest.cpp
media/mtransport/test/ice_unittest.cpp
media/mtransport/test/multi_tcp_socket_unittest.cpp
media/mtransport/test/proxy_tunnel_socket_unittest.cpp
media/mtransport/test/stunserver.cpp
media/mtransport/test/stunserver.h
media/mtransport/test/test_nr_socket_unittest.cpp
media/mtransport/test/turn_unittest.cpp
media/mtransport/third_party/nICEr/IMPORT_FILES
media/mtransport/third_party/nICEr/nicer.gyp
media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
media/mtransport/third_party/nICEr/src/ice/ice_component.c
media/mtransport/third_party/nICEr/src/ice/ice_component.h
media/mtransport/third_party/nICEr/src/ice/ice_media_stream.c
media/mtransport/third_party/nICEr/src/ice/ice_parser.c
media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c
media/mtransport/third_party/nICEr/src/net/nr_resolver.h
media/mtransport/third_party/nICEr/src/net/transport_addr.c
media/mtransport/third_party/nICEr/src/net/transport_addr.h
media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c
media/mtransport/third_party/nICEr/src/stun/addrs.c
media/mtransport/third_party/nICEr/src/stun/addrs.h
media/mtransport/third_party/nICEr/src/stun/ifaddrs-android.c
media/mtransport/third_party/nICEr/src/stun/ifaddrs-android.h
media/mtransport/third_party/nICEr/src/stun/stun_codec.c
media/mtransport/third_party/nICEr/src/stun/stun_reg.h
media/mtransport/third_party/nICEr/src/stun/stun_util.c
media/mtransport/third_party/nICEr/src/stun/stun_util.h
media/mtransport/third_party/nrappkit/src/util/util.c
media/mtransport/third_party/nrappkit/src/util/util.h
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
media/webrtc/signaling/src/sdp/SdpMediaSection.h
media/webrtc/signaling/test/signaling_unittests.cpp
modules/libpref/init/all.js
--- a/media/mtransport/gonk_addrs.cpp
+++ b/media/mtransport/gonk_addrs.cpp
@@ -114,17 +114,17 @@ GetInterfaces(std::vector<NetworkInterfa
     aInterfaces->push_back(interface);
   }
   return NS_OK;
 }
 } // anonymous namespace
 
 int
 nr_stun_get_addrs(nr_local_addr aAddrs[], int aMaxAddrs,
-                  int aDropLoopback, int* aCount)
+                  int aDropLoopback, int aDropLinkLocal, int* aCount)
 {
   nsresult rv;
   int r;
 
   // Get network interface list.
   std::vector<NetworkInterface> interfaces;
   nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
   mozilla::SyncRunnable::DispatchToThread(
@@ -136,30 +136,29 @@ nr_stun_get_addrs(nr_local_addr aAddrs[]
   }
 
   // Translate to nr_transport_addr.
   int32_t n = 0;
   size_t num_interface = std::min(interfaces.size(), (size_t)aMaxAddrs);
   for (size_t i = 0; i < num_interface; ++i) {
     NetworkInterface &interface = interfaces[i];
     if (nr_sockaddr_to_transport_addr((sockaddr*)&(interface.addr),
-                                      sizeof(struct sockaddr_in),
                                       IPPROTO_UDP, 0, &(aAddrs[n].addr))) {
       r_log(NR_LOG_STUN, LOG_WARNING, "Problem transforming address");
       return R_FAILED;
     }
     strlcpy(aAddrs[n].addr.ifname, interface.name.c_str(),
             sizeof(aAddrs[n].addr.ifname));
     aAddrs[n].interface.type = interface.type;
     aAddrs[n].interface.estimated_speed = 0;
     n++;
   }
 
   *aCount = n;
-  r = nr_stun_remove_duplicate_addrs(aAddrs, aDropLoopback, aCount);
+  r = nr_stun_remove_duplicate_addrs(aAddrs, aDropLoopback, aDropLinkLocal, aCount);
   if (r != 0) {
     return r;
   }
 
   for (int i = 0; i < *aCount; ++i) {
     char typestr[100];
     nr_local_addr_fmt_info_string(aAddrs + i, typestr, sizeof(typestr));
     r_log(NR_LOG_STUN, LOG_DEBUG, "Address %d: %s on %s, type: %s\n",
--- a/media/mtransport/nr_socket_prsock.cpp
+++ b/media/mtransport/nr_socket_prsock.cpp
@@ -332,30 +332,21 @@ static int nr_transport_addr_to_praddr(n
 
     switch(addr->ip_version){
       case NR_IPV4:
         naddr->inet.family = PR_AF_INET;
         naddr->inet.port = addr->u.addr4.sin_port;
         naddr->inet.ip = addr->u.addr4.sin_addr.s_addr;
         break;
       case NR_IPV6:
-#if 0
         naddr->ipv6.family = PR_AF_INET6;
         naddr->ipv6.port = addr->u.addr6.sin6_port;
-#ifdef LINUX
-        memcpy(naddr->ipv6.ip._S6_un._S6_u8,
-               &addr->u.addr6.sin6_addr.__in6_u.__u6_addr8, 16);
-#else
-        memcpy(naddr->ipv6.ip._S6_un._S6_u8,
-               &addr->u.addr6.sin6_addr.__u6_addr.__u6_addr8, 16);
-#endif
-#else
-        // TODO: make IPv6 work
-        ABORT(R_INTERNAL);
-#endif
+        naddr->ipv6.flowinfo = addr->u.addr6.sin6_flowinfo;
+        memcpy(&naddr->ipv6.ip, &addr->u.addr6.sin6_addr, sizeof(in6_addr));
+        naddr->ipv6.scope_id = addr->u.addr6.sin6_scope_id;
         break;
       default:
         ABORT(R_BAD_ARGS);
     }
 
     _status = 0;
   abort:
     return(_status);
@@ -435,35 +426,37 @@ int nr_netaddr_to_transport_addr(const n
 
 int nr_praddr_to_transport_addr(const PRNetAddr *praddr,
                                 nr_transport_addr *addr, int protocol,
                                 int keep)
   {
     int _status;
     int r;
     struct sockaddr_in ip4;
+    struct sockaddr_in6 ip6;
 
     switch(praddr->raw.family) {
       case PR_AF_INET:
         ip4.sin_family = PF_INET;
         ip4.sin_addr.s_addr = praddr->inet.ip;
         ip4.sin_port = praddr->inet.port;
         if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip4,
-                                               sizeof(ip4),
                                                protocol, keep,
                                                addr)))
           ABORT(r);
         break;
       case PR_AF_INET6:
-#if 0
-        r = nr_sockaddr_to_transport_addr((sockaddr *)&praddr->raw,
-          sizeof(struct sockaddr_in6),IPPROTO_UDP,keep,addr);
+        ip6.sin6_family = PF_INET6;
+        ip6.sin6_port = praddr->ipv6.port;
+        ip6.sin6_flowinfo = praddr->ipv6.flowinfo;
+        memcpy(&ip6.sin6_addr, &praddr->ipv6.ip, sizeof(in6_addr));
+        ip6.sin6_scope_id = praddr->ipv6.scope_id;
+        if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip6,protocol,keep,addr)))
+          ABORT(r);
         break;
-#endif
-        ABORT(R_BAD_ARGS);
       default:
         MOZ_ASSERT(false);
         ABORT(R_BAD_ARGS);
     }
 
     _status=0;
  abort:
     return(_status);
@@ -511,24 +504,26 @@ int NrSocket::create(nr_transport_addr *
     ABORT(R_INTERNAL);
   }
 
   if((r=nr_transport_addr_to_praddr(addr, &naddr)))
     ABORT(r);
 
   switch (addr->protocol) {
     case IPPROTO_UDP:
-      if (!(fd_ = PR_NewUDPSocket())) {
-        r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
+      if (!(fd_ = PR_OpenUDPSocket(naddr.raw.family))) {
+        r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create UDP socket, "
+              "family=%d, err=%d", naddr.raw.family, PR_GetError());
         ABORT(R_INTERNAL);
       }
       break;
     case IPPROTO_TCP:
-      if (!(fd_ = PR_NewTCPSocket())) {
-        r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
+      if (!(fd_ = PR_OpenTCPSocket(naddr.raw.family))) {
+        r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create TCP socket, "
+              "family=%d, err=%d", naddr.raw.family, PR_GetError());
         ABORT(R_INTERNAL);
       }
       // Set ReuseAddr for TCP sockets to enable having several
       // sockets bound to same local IP and port
       PRSocketOptionData opt_reuseaddr;
       opt_reuseaddr.option = PR_SockOpt_Reuseaddr;
       opt_reuseaddr.value.reuse_addr = PR_TRUE;
       status = PR_SetSocketOption(fd_, &opt_reuseaddr);
@@ -681,17 +676,18 @@ int NrSocket::sendto(const void *msg, si
   }
 
   // TODO: Convert flags?
   status = PR_SendTo(fd_, msg, len, flags, &naddr, PR_INTERVAL_NO_WAIT);
   if (status < 0 || (size_t)status != len) {
     if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
       ABORT(R_WOULDBLOCK);
 
-    r_log(LOG_GENERIC, LOG_INFO, "Error in sendto: %s", to->as_string);
+    r_log(LOG_GENERIC, LOG_INFO, "Error in sendto %s: %d",
+          to->as_string, PR_GetError());
     ABORT(R_IO_ERROR);
   }
 
   _status=0;
 abort:
   return(_status);
 }
 
--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -375,17 +375,18 @@ void NrIceCtx::trickle_cb(void *arg, nr_
 
   s->SignalCandidate(s, candidate_str);
 }
 
 RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
                                   bool offerer,
                                   bool set_interface_priorities,
                                   bool allow_loopback,
-                                  bool tcp_enabled) {
+                                  bool tcp_enabled,
+                                  bool allow_link_local) {
 
   RefPtr<NrIceCtx> ctx = new NrIceCtx(name, offerer);
 
   // Initialize the crypto callbacks and logging stuff
   if (!initialized) {
     NR_reg_init(NR_REG_MODE_LOCAL);
     RLogRingBuffer::CreateInstance();
     nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
@@ -467,16 +468,20 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const 
     NR_reg_set_int4((char *)NR_ICE_REG_ICE_TCP_LISTEN_BACKLOG,
                      ice_tcp_listen_backlog);
 
     NR_reg_set_char((char *)NR_ICE_REG_ICE_TCP_DISABLE, !tcp_enabled);
 
     if (allow_loopback) {
       NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, 1);
     }
+
+    if (allow_link_local) {
+      NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS, 1);
+    }
   }
 
   // Create the ICE context
   int r;
 
   UINT4 flags = offerer ? NR_ICE_CTX_FLAGS_OFFERER:
       NR_ICE_CTX_FLAGS_ANSWERER;
   flags |= NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION;
--- a/media/mtransport/nricectx.h
+++ b/media/mtransport/nricectx.h
@@ -207,17 +207,18 @@ class NrIceCtx {
   enum Controlling { ICE_CONTROLLING,
                      ICE_CONTROLLED
   };
 
   static RefPtr<NrIceCtx> Create(const std::string& name,
                                  bool offerer,
                                  bool set_interface_priorities = true,
                                  bool allow_loopback = false,
-                                 bool tcp_enabled = true);
+                                 bool tcp_enabled = true,
+                                 bool allow_link_local = false);
 
   // Deinitialize all ICE global state. Used only for testing.
   static void internal_DeinitializeGlobal();
 
 
   nr_ice_ctx *ctx() { return ctx_; }
   nr_ice_peer_ctx *peer() { return peer_; }
 
--- a/media/mtransport/nriceresolver.cpp
+++ b/media/mtransport/nriceresolver.cpp
@@ -145,30 +145,43 @@ int NrIceResolver::resolve(void *obj,
 int NrIceResolver::resolve(nr_resolver_resource *resource,
                            int (*cb)(void *cb_arg, nr_transport_addr *addr),
                            void *cb_arg,
                            void **handle) {
   int _status;
   MOZ_ASSERT(allocated_resolvers_ > 0);
   ASSERT_ON_THREAD(sts_thread_);
   nsRefPtr<PendingResolution> pr;
+  uint32_t resolve_flags = 0;
 
   if (resource->transport_protocol != IPPROTO_UDP &&
       resource->transport_protocol != IPPROTO_TCP) {
     MOZ_MTLOG(ML_ERROR, "Only UDP and TCP are is supported.");
     ABORT(R_NOT_FOUND);
   }
   pr = new PendingResolution(sts_thread_,
                              resource->port? resource->port : 3478,
                              resource->transport_protocol ?
                              resource->transport_protocol :
                              IPPROTO_UDP,
                              cb, cb_arg);
+
+  switch(resource->address_family) {
+    case AF_INET:
+      resolve_flags |= nsIDNSService::RESOLVE_DISABLE_IPV6;
+      break;
+    case AF_INET6:
+      resolve_flags |= nsIDNSService::RESOLVE_DISABLE_IPV4;
+      break;
+    default:
+      ABORT(R_BAD_ARGS);
+  }
+
   if (NS_FAILED(dns_->AsyncResolve(nsAutoCString(resource->domain_name),
-                                   nsIDNSService::RESOLVE_DISABLE_IPV6, pr,
+                                   resolve_flags, pr,
                                    sts_thread_, getter_AddRefs(pr->request_)))) {
     MOZ_MTLOG(ML_ERROR, "AsyncResolve failed.");
     ABORT(R_NOT_FOUND);
   }
   // Because the C API offers no "finished" method to release the handle we
   // return, we cannot return the request we got from AsyncResolve directly.
   //
   // Instead, we return an addref'ed reference to PendingResolution itself,
--- a/media/mtransport/nriceresolverfake.cpp
+++ b/media/mtransport/nriceresolverfake.cpp
@@ -117,16 +117,17 @@ int NrIceResolverFake::resolve(void *obj
 
   PendingResolution *pending =
       new PendingResolution(fake,
                             resource->domain_name,
                             resource->port ? resource->port : 3478,
                             resource->transport_protocol ?
                             resource->transport_protocol :
                             IPPROTO_UDP,
+                            resource->address_family,
                             cb, cb_arg);
 
   if ((r=NR_ASYNC_TIMER_SET(fake->delay_ms_,NrIceResolverFake::resolve_cb,
                             (void *)pending, &pending->timer_handle_))) {
     delete pending;
     ABORT(r);
   }
   *handle = pending;
@@ -135,17 +136,18 @@ int NrIceResolverFake::resolve(void *obj
 abort:
   return(_status);
 }
 
 void NrIceResolverFake::resolve_cb(NR_SOCKET s, int how, void *cb_arg) {
   MOZ_ASSERT(cb_arg);
   PendingResolution *pending = static_cast<PendingResolution *>(cb_arg);
 
-  const PRNetAddr *addr=pending->resolver_->Resolve(pending->hostname_);
+  const PRNetAddr *addr=pending->resolver_->Resolve(pending->hostname_,
+                                                    pending->address_family_);
 
   if (addr) {
     nr_transport_addr transport_addr;
 
     int r = nr_praddr_to_transport_addr(addr, &transport_addr,
                                         pending->transport_, 0);
     MOZ_ASSERT(!r);
     if (r)
--- a/media/mtransport/nriceresolverfake.h
+++ b/media/mtransport/nriceresolverfake.h
@@ -58,17 +58,26 @@ typedef struct nr_resolver_resource_ nr_
 namespace mozilla {
 
 class NrIceResolverFake {
  public:
   NrIceResolverFake();
   ~NrIceResolverFake();
 
   void SetAddr(const std::string& hostname, const PRNetAddr& addr) {
-    addrs_[hostname] = addr;
+    switch (addr.raw.family) {
+      case AF_INET:
+        addrs_[hostname] = addr;
+        break;
+      case AF_INET6:
+        addrs6_[hostname] = addr;
+        break;
+      default:
+        MOZ_CRASH();
+    }
   }
 
   nr_resolver *AllocateResolver();
 
   void DestroyResolver();
 
 private:
   // Implementations of vtbl functions
@@ -78,47 +87,61 @@ private:
                      int (*cb)(void *cb_arg,
                                nr_transport_addr *addr),
                      void *cb_arg,
                      void **handle);
   static void resolve_cb(NR_SOCKET s, int how, void *cb_arg);
   static int cancel(void *obj, void *handle);
 
   // Get an address.
-  const PRNetAddr *Resolve(const std::string& hostname) {
-    if (!addrs_.count(hostname))
-      return nullptr;
+  const PRNetAddr *Resolve(const std::string& hostname, int address_family) {
+    switch (address_family) {
+      case AF_INET:
+        if (!addrs_.count(hostname))
+          return nullptr;
 
-    return &addrs_[hostname];
+        return &addrs_[hostname];
+      case AF_INET6:
+        if (!addrs6_.count(hostname))
+          return nullptr;
+
+        return &addrs6_[hostname];
+      default:
+        MOZ_CRASH();
+    }
   }
 
 
   struct PendingResolution {
     PendingResolution(NrIceResolverFake *resolver,
                       const std::string& hostname,
                       uint16_t port,
                       int transport,
+                      int address_family,
                       int (*cb)(void *cb_arg, nr_transport_addr *addr),
                       void *cb_arg) :
         resolver_(resolver),
         hostname_(hostname),
         port_(port),
         transport_(transport),
+        address_family_(address_family),
         cb_(cb), cb_arg_(cb_arg) {}
 
     NrIceResolverFake *resolver_;
     std::string hostname_;
     uint16_t port_;
     int transport_;
+    int address_family_;
     int (*cb_)(void *cb_arg, nr_transport_addr *addr);
     void *cb_arg_;
     void *timer_handle_;
   };
 
   nr_resolver_vtbl* vtbl_;
   std::map<std::string, PRNetAddr> addrs_;
+  std::map<std::string, PRNetAddr> addrs6_;
   uint32_t delay_ms_;
   int allocated_resolvers_;
 };
 
 }  // End of namespace mozilla
 
 #endif
--- a/media/mtransport/nrinterfaceprioritizer.cpp
+++ b/media/mtransport/nrinterfaceprioritizer.cpp
@@ -13,29 +13,31 @@ MOZ_MTLOG_MODULE("mtransport")
 namespace {
 
 class LocalAddress {
 public:
   LocalAddress()
     : key_(),
       is_vpn_(-1),
       estimated_speed_(-1),
-      type_preference_(-1) {}
+      type_preference_(-1),
+      ip_version_(-1) {}
 
   bool Init(const nr_local_addr& local_addr) {
     char buf[MAXIFNAME + 41];
     int r = nr_transport_addr_fmt_ifname_addr_string(&local_addr.addr, buf, sizeof(buf));
     if (r) {
       MOZ_MTLOG(ML_ERROR, "Error formatting interface address string.");
       return false;
     }
     key_ = buf;
     is_vpn_ = (local_addr.interface.type & NR_INTERFACE_TYPE_VPN) != 0 ? 1 : 0;
     estimated_speed_ = local_addr.interface.estimated_speed;
     type_preference_ = GetNetworkTypePreference(local_addr.interface.type);
+    ip_version_ = local_addr.addr.ip_version;
     return true;
   }
 
   bool operator<(const LocalAddress& rhs) const {
     // Interface that is "less" here is preferred.
     // If type preferences are different, we should simply sort by
     // |type_preference_|.
     if (type_preference_ != rhs.type_preference_) {
@@ -49,16 +51,21 @@ public:
       return is_vpn_ < rhs.is_vpn_;
     }
 
     // Compare estimated speed.
     if (estimated_speed_ != rhs.estimated_speed_) {
       return estimated_speed_ > rhs.estimated_speed_;
     }
 
+    // Prefer IPV6 over IPV4
+    if (ip_version_ != rhs.ip_version_) {
+      return ip_version_ > rhs.ip_version_;
+    }
+
     // All things above are the same, we can at least sort with key.
     return key_ < rhs.key_;
   }
 
   const std::string& GetKey() const {
     return key_;
   }
 
@@ -77,16 +84,17 @@ private:
     }
     return 4;
   }
 
   std::string key_;
   int is_vpn_;
   int estimated_speed_;
   int type_preference_;
+  int ip_version_;
 };
 
 class InterfacePrioritizer {
 public:
   InterfacePrioritizer()
     : local_addrs_(),
       preference_map_(),
       sorted_(false) {}
--- a/media/mtransport/stun_udp_socket_filter.cpp
+++ b/media/mtransport/stun_udp_socket_filter.cpp
@@ -16,52 +16,61 @@ extern "C" {
 #include "nr_socket_prsock.h"
 #if defined(MOZILLA_XPCOMRT_API)
 #include "mozilla/Module.h"
 #include "mozilla/ModuleUtils.h"
 #endif
 
 namespace {
 
-class NetAddressAdapter {
+class NetAddrCompare {
  public:
-  MOZ_IMPLICIT NetAddressAdapter(const mozilla::net::NetAddr& netaddr)
-    : addr_(ntohl(netaddr.inet.ip)),
-      port_(ntohs(netaddr.inet.port)) {
-    MOZ_ASSERT(netaddr.raw.family == AF_INET);
-  }
+   bool operator()(const mozilla::net::NetAddr& lhs,
+                   const mozilla::net::NetAddr& rhs) const {
+     if (lhs.raw.family != rhs.raw.family) {
+       return lhs.raw.family < rhs.raw.family;
+     }
 
-  bool operator<(const NetAddressAdapter& rhs) const {
-    return addr_ != rhs.addr_ ? (addr_ < rhs.addr_) : (port_ < rhs.port_);
-  }
-
-  bool operator!=(const NetAddressAdapter& rhs) const {
-    return (*this < rhs) || (rhs < *this);
-  }
-
- private:
-  const uint32_t addr_;
-  const uint16_t port_;
+     switch (lhs.raw.family) {
+       case AF_INET:
+         if (lhs.inet.port != rhs.inet.port) {
+           return lhs.inet.port < rhs.inet.port;
+         }
+         return lhs.inet.ip < rhs.inet.ip;
+       case AF_INET6:
+         if (lhs.inet6.port != rhs.inet6.port) {
+           return lhs.inet6.port < rhs.inet6.port;
+         }
+         return memcmp(&lhs.inet6.ip, &rhs.inet6.ip, sizeof(lhs.inet6.ip)) < 0;
+       default:
+         MOZ_ASSERT(false);
+     }
+     return false;
+   }
 };
 
 class PendingSTUNRequest {
  public:
-  PendingSTUNRequest(const NetAddressAdapter& netaddr, const UINT12 &id)
+  PendingSTUNRequest(const mozilla::net::NetAddr& netaddr, const UINT12 &id)
     : id_(id),
       net_addr_(netaddr),
       is_id_set_(true) {}
 
-  MOZ_IMPLICIT PendingSTUNRequest(const NetAddressAdapter& netaddr)
+  MOZ_IMPLICIT PendingSTUNRequest(const mozilla::net::NetAddr& netaddr)
     : id_(),
       net_addr_(netaddr),
       is_id_set_(false) {}
 
   bool operator<(const PendingSTUNRequest& rhs) const {
-    if (net_addr_ != rhs.net_addr_) {
-      return net_addr_ < rhs.net_addr_;
+    if (NetAddrCompare()(net_addr_, rhs.net_addr_)) {
+      return true;
+    }
+
+    if (NetAddrCompare()(rhs.net_addr_, net_addr_)) {
+      return false;
     }
 
     if (!is_id_set_ && !rhs.is_id_set_) {
       // PendingSTUNRequest can be stored to set only when it has id,
       // so comparing two PendingSTUNRequst without id is not going
       // to happen.
       MOZ_CRASH();
     }
@@ -71,17 +80,17 @@ class PendingSTUNRequest {
       return false;
     }
 
     return memcmp(id_.octet, rhs.id_.octet, sizeof(id_.octet)) < 0;
   }
 
  private:
   const UINT12 id_;
-  const NetAddressAdapter net_addr_;
+  const mozilla::net::NetAddr net_addr_;
   const bool is_id_set_;
 };
 
 class STUNUDPSocketFilter : public nsIUDPSocketFilter {
  public:
   STUNUDPSocketFilter()
     : white_list_(),
       pending_requests_() {}
@@ -96,35 +105,29 @@ class STUNUDPSocketFilter : public nsIUD
   bool filter_incoming_packet(const mozilla::net::NetAddr *remote_addr,
                               const uint8_t *data,
                               uint32_t len);
 
   bool filter_outgoing_packet(const mozilla::net::NetAddr *remote_addr,
                               const uint8_t *data,
                               uint32_t len);
 
-  std::set<NetAddressAdapter> white_list_;
+  std::set<mozilla::net::NetAddr, NetAddrCompare> white_list_;
   std::set<PendingSTUNRequest> pending_requests_;
   std::set<PendingSTUNRequest> response_allowed_;
 };
 
 NS_IMPL_ISUPPORTS(STUNUDPSocketFilter, nsIUDPSocketFilter)
 
 NS_IMETHODIMP
 STUNUDPSocketFilter::FilterPacket(const mozilla::net::NetAddr *remote_addr,
                                   const uint8_t *data,
                                   uint32_t len,
                                   int32_t direction,
                                   bool *result) {
-  // Allowing IPv4 address only.
-  if (remote_addr->raw.family != AF_INET) {
-    *result = false;
-    return NS_OK;
-  }
-
   switch (direction) {
     case nsIUDPSocketFilter::SF_INCOMING:
       *result = filter_incoming_packet(remote_addr, data, len);
       break;
     case nsIUDPSocketFilter::SF_OUTGOING:
       *result = filter_outgoing_packet(remote_addr, data, len);
       break;
     default:
--- a/media/mtransport/test/buffered_stun_socket_unittest.cpp
+++ b/media/mtransport/test/buffered_stun_socket_unittest.cpp
@@ -59,17 +59,17 @@ class BufferedStunSocketTest : public ::
     int r = nr_socket_buffered_stun_create(
         dummy->get_nr_socket(),
         kStunMessageLen,
         TURN_TCP_FRAMING,
         &test_socket_);
     ASSERT_EQ(0, r);
     dummy_ = dummy.forget();  // Now owned by test_socket_.
 
-    r = nr_ip4_str_port_to_transport_addr(
+    r = nr_str_port_to_transport_addr(
         (char *)"192.0.2.133", 3333, IPPROTO_TCP, &remote_addr_);
     ASSERT_EQ(0, r);
 
     r = nr_socket_connect(test_socket_,
                           &remote_addr_);
     ASSERT_EQ(0, r);
   }
 
@@ -179,17 +179,17 @@ TEST_F(BufferedStunSocketTest, TestSendT
   ASSERT_EQ(R_WOULDBLOCK, r);
 
   dummy_->CheckWriteBuffer(nullptr, 0);
 }
 
 TEST_F(BufferedStunSocketTest, TestSendToWrongAddr) {
   nr_transport_addr addr;
 
-  int r = nr_ip4_str_port_to_transport_addr(
+  int r = nr_str_port_to_transport_addr(
       (char *)"192.0.2.134", 3333, IPPROTO_TCP, &addr);
   ASSERT_EQ(0, r);
 
   r = nr_socket_sendto(test_socket_,
                        kStunMessage,
                        kStunMessageLen,
                        0, &addr);
   ASSERT_EQ(R_BAD_DATA, r);
--- a/media/mtransport/test/ice_unittest.cpp
+++ b/media/mtransport/test/ice_unittest.cpp
@@ -349,18 +349,18 @@ class IceTestPeer : public sigslot::has_
     SetStunServers(stun_servers);
   }
 
   void SetStunServers(const std::vector<NrIceStunServer> &servers) {
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(servers)));
   }
 
   void UseTestStunServer() {
-    SetStunServer(TestStunServer::GetInstance()->addr(),
-                  TestStunServer::GetInstance()->port());
+    SetStunServer(TestStunServer::GetInstance(AF_INET)->addr(),
+                  TestStunServer::GetInstance(AF_INET)->port());
   }
 
   void SetTurnServer(const std::string addr, uint16_t port,
                      const std::string username,
                      const std::string password,
                      const char* transport) {
     std::vector<unsigned char> password_vec(password.begin(), password.end());
     SetTurnServer(addr, port, username, password_vec, transport);
@@ -377,25 +377,25 @@ class IceTestPeer : public sigslot::has_
     turn_servers.push_back(*server);
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetTurnServers(turn_servers)));
   }
 
   void SetTurnServers(const std::vector<NrIceTurnServer> servers) {
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetTurnServers(servers)));
   }
 
-  void SetFakeResolver() {
+  void SetFakeResolver(const std::string& ip = g_stun_server_address,
+                       const std::string& fqdn = g_stun_server_hostname) {
     ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init()));
-    if (!g_stun_server_address.empty() && !g_stun_server_hostname.empty()) {
+    if (!ip.empty() && !fqdn.empty()) {
       PRNetAddr addr;
-      PRStatus status = PR_StringToNetAddr(g_stun_server_address.c_str(),
-                                            &addr);
+      PRStatus status = PR_StringToNetAddr(ip.c_str(), &addr);
       addr.inet.port = kDefaultStunServerPort;
       ASSERT_EQ(PR_SUCCESS, status);
-      fake_resolver_.SetAddr(g_stun_server_hostname, addr);
+      fake_resolver_.SetAddr(fqdn, addr);
     }
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(
         fake_resolver_.AllocateResolver())));
   }
 
   void SetDNSResolver() {
     ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init()));
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(
@@ -1093,19 +1093,26 @@ void SchedulableTrickleCandidate::Trickl
   timer_handle_ = nullptr;
   nsresult res = peer_->TrickleCandidate_s(candidate_, stream_);
   ASSERT_TRUE(NS_SUCCEEDED(res));
 }
 
 class IceGatherTest : public ::testing::Test {
  public:
   void SetUp() {
-    test_utils->sts_target()->Dispatch(WrapRunnable(TestStunServer::GetInstance(),
-                                                    &TestStunServer::Reset),
-                                       NS_DISPATCH_SYNC);
+    test_utils->sts_target()->Dispatch(
+        WrapRunnable(TestStunServer::GetInstance(AF_INET),
+                     &TestStunServer::Reset),
+        NS_DISPATCH_SYNC);
+    if (TestStunServer::GetInstance(AF_INET6)) {
+      test_utils->sts_target()->Dispatch(
+          WrapRunnable(TestStunServer::GetInstance(AF_INET6),
+                       &TestStunServer::Reset),
+          NS_DISPATCH_SYNC);
+    }
   }
 
   void TearDown() {
     peer_ = nullptr;
 
     test_utils->sts_target()->Dispatch(WrapRunnable(this,
                                                     &IceGatherTest::TearDown_s),
                                        NS_DISPATCH_SYNC);
@@ -1130,64 +1137,100 @@ class IceGatherTest : public ::testing::
       WaitForGather(waitTime);
     }
   }
 
   void WaitForGather(unsigned int waitTime = kDefaultTimeout) {
     ASSERT_TRUE_WAIT(peer_->gathering_complete(), waitTime);
   }
 
-  void UseFakeStunUdpServerWithResponse(const std::string& fake_addr,
-                                        uint16_t fake_port) {
-    EnsurePeer();
-    TestStunServer::GetInstance()->SetResponseAddr(fake_addr, fake_port);
-    // Sets an additional stun server
-    peer_->SetStunServer(TestStunServer::GetInstance()->addr(),
-                         TestStunServer::GetInstance()->port(),
-                         kNrIceTransportUdp);
+  void AddStunServerWithResponse(
+      const std::string& fake_addr,
+      uint16_t fake_port,
+      const std::string& fqdn,
+      const std::string& proto,
+      std::vector<NrIceStunServer>* stun_servers) {
+    int family;
+    if (fake_addr.find(':') != std::string::npos) {
+      family = AF_INET6;
+    } else {
+      family = AF_INET;
+    }
+
+    std::string stun_addr;
+    uint16_t stun_port;
+    if (proto == kNrIceTransportUdp) {
+      TestStunServer::GetInstance(family)->SetResponseAddr(fake_addr,
+                                                           fake_port);
+      stun_addr = TestStunServer::GetInstance(family)->addr();
+      stun_port = TestStunServer::GetInstance(family)->port();
+    } else if (proto == kNrIceTransportTcp) {
+      TestStunTcpServer::GetInstance(family)->SetResponseAddr(fake_addr,
+                                                              fake_port);
+      stun_addr = TestStunTcpServer::GetInstance(family)->addr();
+      stun_port = TestStunTcpServer::GetInstance(family)->port();
+    } else {
+      MOZ_CRASH();
+    }
+
+    if (!fqdn.empty()) {
+      peer_->SetFakeResolver(stun_addr, fqdn);
+      stun_addr = fqdn;
+    }
+
+    stun_servers->push_back(*NrIceStunServer::Create(stun_addr,
+                                                     stun_port,
+                                                     proto.c_str()));
   }
 
-  void UseFakeStunTcpServerWithResponse(const std::string& fake_addr,
-                                        uint16_t fake_port) {
-    EnsurePeer();
-    TestStunTcpServer::GetInstance()->SetResponseAddr(fake_addr, fake_port);
-    // Sets an additional stun server
-    peer_->SetStunServer(TestStunTcpServer::GetInstance()->addr(),
-                         TestStunTcpServer::GetInstance()->port(),
-                         kNrIceTransportTcp);
-  }
-
-  void UseFakeStunUdpTcpServersWithResponse(const std::string& fake_udp_addr,
-                                            uint16_t fake_udp_port,
-                                            const std::string& fake_tcp_addr,
-                                            uint16_t fake_tcp_port) {
+  void UseFakeStunUdpServerWithResponse(
+      const std::string& fake_addr,
+      uint16_t fake_port,
+      const std::string& fqdn = std::string()) {
     EnsurePeer();
     std::vector<NrIceStunServer> stun_servers;
-
-    stun_servers.push_back(*NrIceStunServer::Create(
-        TestStunServer::GetInstance()->addr(),
-        TestStunServer::GetInstance()->port(),
-        kNrIceTransportUdp));
-    stun_servers.push_back(*NrIceStunServer::Create(
-        TestStunTcpServer::GetInstance()->addr(),
-        TestStunTcpServer::GetInstance()->port(),
-        kNrIceTransportTcp));
-
-    TestStunServer::GetInstance()->SetResponseAddr(fake_udp_addr,
-                                                   fake_udp_port);
-    TestStunTcpServer::GetInstance()->SetResponseAddr(fake_tcp_addr,
-                                                      fake_tcp_port);
-    // Sets an additional stun server
+    AddStunServerWithResponse(fake_addr, fake_port, fqdn, "udp", &stun_servers);
+    peer_->SetStunServers(stun_servers);
+  }
+
+  void UseFakeStunTcpServerWithResponse(
+      const std::string& fake_addr,
+      uint16_t fake_port,
+      const std::string& fqdn = std::string()) {
+    EnsurePeer();
+    std::vector<NrIceStunServer> stun_servers;
+    AddStunServerWithResponse(fake_addr, fake_port, fqdn, "tcp", &stun_servers);
+    peer_->SetStunServers(stun_servers);
+  }
+
+  void UseFakeStunUdpTcpServersWithResponse(
+      const std::string& fake_udp_addr,
+      uint16_t fake_udp_port,
+      const std::string& fake_tcp_addr,
+      uint16_t fake_tcp_port) {
+    EnsurePeer();
+    std::vector<NrIceStunServer> stun_servers;
+    AddStunServerWithResponse(fake_udp_addr,
+                              fake_udp_port,
+                              "", // no fqdn
+                              "udp",
+                              &stun_servers);
+    AddStunServerWithResponse(fake_tcp_addr,
+                              fake_tcp_port,
+                              "", // no fqdn
+                              "tcp",
+                              &stun_servers);
+
     peer_->SetStunServers(stun_servers);
   }
 
   void UseTestStunServer() {
-    TestStunServer::GetInstance()->Reset();
-    peer_->SetStunServer(TestStunServer::GetInstance()->addr(),
-                         TestStunServer::GetInstance()->port());
+    TestStunServer::GetInstance(AF_INET)->Reset();
+    peer_->SetStunServer(TestStunServer::GetInstance(AF_INET)->addr(),
+                         TestStunServer::GetInstance(AF_INET)->port());
   }
 
   // NB: Only does substring matching, watch out for stuff like "1.2.3.4"
   // matching "21.2.3.47". " 1.2.3.4 " should not have false positives.
   bool StreamHasMatchingCandidate(unsigned int stream,
                                   const std::string& match,
                                   const std::string& match2 = "") {
     std::vector<std::string> candidates = peer_->GetCandidates(stream);
@@ -1309,17 +1352,17 @@ class IceConnectTest : public ::testing:
     mapping_type_ = type;
   }
 
   void BlockUdp() {
     block_udp_ = true;
   }
 
   void UseTestStunServer() {
-    TestStunServer::GetInstance()->Reset();
+    TestStunServer::GetInstance(AF_INET)->Reset();
     p1_->UseTestStunServer();
     p2_->UseTestStunServer();
   }
 
   void SetTurnServer(const std::string addr, uint16_t port,
                      const std::string username,
                      const std::string password,
                      const char* transport = kNrIceTransportUdp) {
@@ -1477,18 +1520,18 @@ class PrioritizerTest : public ::testing
 
   void AddInterface(const std::string& num, int type, int estimated_speed) {
     std::string str_addr = "10.0.0." + num;
     std::string ifname = "eth" + num;
     nr_local_addr local_addr;
     local_addr.interface.type = type;
     local_addr.interface.estimated_speed = estimated_speed;
 
-    int r = nr_ip4_str_port_to_transport_addr(str_addr.c_str(), 0,
-                                              IPPROTO_UDP, &(local_addr.addr));
+    int r = nr_str_port_to_transport_addr(str_addr.c_str(), 0,
+                                          IPPROTO_UDP, &(local_addr.addr));
     ASSERT_EQ(0, r);
     strncpy(local_addr.addr.ifname, ifname.c_str(), MAXIFNAME);
 
     r = nr_interface_prioritizer_add_interface(prioritizer_, &local_addr);
     ASSERT_EQ(0, r);
     r = nr_interface_prioritizer_sort_preference(prioritizer_);
     ASSERT_EQ(0, r);
   }
@@ -1786,63 +1829,109 @@ TEST_F(IceGatherTest, VerifyTestStunServ
 
 TEST_F(IceGatherTest, VerifyTestStunTcpServer) {
   UseFakeStunTcpServerWithResponse("192.0.2.233", 3333);
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.2.233 3333 typ srflx",
     " tcptype "));
 }
 
+TEST_F(IceGatherTest, VerifyTestStunServerV6) {
+  if (!TestStunServer::GetInstance(AF_INET6)) {
+    // No V6 addresses
+    return;
+  }
+  UseFakeStunUdpServerWithResponse("beef::", 3333);
+  Gather();
+  ASSERT_TRUE(StreamHasMatchingCandidate(0, " beef:: 3333 "));
+}
+
+TEST_F(IceGatherTest, VerifyTestStunServerFQDN) {
+  UseFakeStunUdpServerWithResponse("192.0.2.133", 3333, "stun.example.com");
+  Gather();
+  ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.2.133 3333 "));
+}
+
+TEST_F(IceGatherTest, VerifyTestStunServerV6FQDN) {
+  if (!TestStunServer::GetInstance(AF_INET6)) {
+    // No V6 addresses
+    return;
+  }
+  UseFakeStunUdpServerWithResponse("beef::", 3333, "stun.example.com");
+  Gather();
+  ASSERT_TRUE(StreamHasMatchingCandidate(0, " beef:: 3333 "));
+}
+
 TEST_F(IceGatherTest, TestStunServerReturnsWildcardAddr) {
   UseFakeStunUdpServerWithResponse("0.0.0.0", 3333);
   Gather(kDefaultTimeout * 3);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 0.0.0.0 "));
 }
 
+TEST_F(IceGatherTest, TestStunServerReturnsWildcardAddrV6) {
+  if (!TestStunServer::GetInstance(AF_INET6)) {
+    // No V6 addresses
+    return;
+  }
+  UseFakeStunUdpServerWithResponse("::", 3333);
+  Gather(kDefaultTimeout * 3);
+  ASSERT_FALSE(StreamHasMatchingCandidate(0, " :: "));
+}
+
 TEST_F(IceGatherTest, TestStunServerReturnsPort0) {
   UseFakeStunUdpServerWithResponse("192.0.2.133", 0);
   Gather(kDefaultTimeout * 3);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.2.133 0 "));
 }
 
 TEST_F(IceGatherTest, TestStunServerReturnsLoopbackAddr) {
   UseFakeStunUdpServerWithResponse("127.0.0.133", 3333);
   Gather(kDefaultTimeout * 3);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 127.0.0.133 "));
 }
 
+TEST_F(IceGatherTest, TestStunServerReturnsLoopbackAddrV6) {
+  if (!TestStunServer::GetInstance(AF_INET6)) {
+    // No V6 addresses
+    return;
+  }
+  UseFakeStunUdpServerWithResponse("::1", 3333);
+  Gather(kDefaultTimeout * 3);
+  ASSERT_FALSE(StreamHasMatchingCandidate(0, " ::1 "));
+}
+
 TEST_F(IceGatherTest, TestStunServerTrickle) {
   UseFakeStunUdpServerWithResponse("192.0.2.1", 3333);
-  TestStunServer::GetInstance()->SetActive(false);
+  TestStunServer::GetInstance(AF_INET)->SetActive(false);
   Gather(0);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1"));
-  TestStunServer::GetInstance()->SetActive(true);
+  TestStunServer::GetInstance(AF_INET)->SetActive(true);
   WaitForGather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1"));
 }
 
 TEST_F(IceGatherTest, TestStunTcpServerTrickle) {
   UseFakeStunTcpServerWithResponse("192.0.3.1", 3333);
-  TestStunTcpServer::GetInstance()->SetActive(false);
+  TestStunTcpServer::GetInstance(AF_INET)->SetActive(false);
   Gather(0);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
-  TestStunTcpServer::GetInstance()->SetActive(true);
+  TestStunTcpServer::GetInstance(AF_INET)->SetActive(true);
   WaitForGather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
 }
 
 TEST_F(IceGatherTest, TestStunTcpAndUdpServerTrickle) {
   UseFakeStunUdpTcpServersWithResponse("192.0.2.1", 3333, "192.0.3.1", 3333);
-  TestStunServer::GetInstance()->SetActive(false);
-  TestStunTcpServer::GetInstance()->SetActive(false);
+  TestStunServer::GetInstance(AF_INET)->SetActive(false);
+  TestStunTcpServer::GetInstance(AF_INET)->SetActive(false);
   Gather(0);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1", "UDP"));
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
-  TestStunServer::GetInstance()->SetActive(true);
-  TestStunTcpServer::GetInstance()->SetActive(true);
+  TestStunServer::GetInstance(AF_INET)->SetActive(true);
+  TestStunTcpServer::GetInstance(AF_INET)->SetActive(true);
   WaitForGather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1", "UDP"));
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
 }
 
 TEST_F(IceConnectTest, TestGather) {
   AddStream("first", 1);
   ASSERT_TRUE(Gather());
@@ -2858,20 +2947,28 @@ int main(int argc, char **argv)
   ::testing::InitGoogleTest(&argc, argv);
 
   ::testing::TestEventListeners& listeners =
         ::testing::UnitTest::GetInstance()->listeners();
   // Adds a listener to the end.  Google Test takes the ownership.
 
   listeners.Append(new test::RingbufferDumper(test_utils));
   test_utils->sts_target()->Dispatch(
-    WrapRunnableNM(&TestStunServer::GetInstance), NS_DISPATCH_SYNC);
+      WrapRunnableNM(&TestStunServer::GetInstance, AF_INET),
+                     NS_DISPATCH_SYNC);
+  test_utils->sts_target()->Dispatch(
+    WrapRunnableNM(&TestStunServer::GetInstance, AF_INET6),
+                   NS_DISPATCH_SYNC);
 
   test_utils->sts_target()->Dispatch(
-    WrapRunnableNM(&TestStunTcpServer::GetInstance), NS_DISPATCH_SYNC);
+      WrapRunnableNM(&TestStunTcpServer::GetInstance, AF_INET),
+                     NS_DISPATCH_SYNC);
+  test_utils->sts_target()->Dispatch(
+    WrapRunnableNM(&TestStunTcpServer::GetInstance, AF_INET6),
+                   NS_DISPATCH_SYNC);
 
   int rv = RUN_ALL_TESTS();
 
   test_utils->sts_target()->Dispatch(
     WrapRunnableNM(&TestStunServer::ShutdownInstance), NS_DISPATCH_SYNC);
 
   test_utils->sts_target()->Dispatch(
     WrapRunnableNM(&TestStunTcpServer::ShutdownInstance), NS_DISPATCH_SYNC);
--- a/media/mtransport/test/multi_tcp_socket_unittest.cpp
+++ b/media/mtransport/test/multi_tcp_socket_unittest.cpp
@@ -107,17 +107,17 @@ class MultiTcpSocketTest : public ::test
           stun_host, port, kNrIceTransportTcp));
       stun_servers.push_back(*server);
 
       ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(stun_servers)));
     }
 
     r = 1;
     for (int tries=10; tries && r; --tries) {
-      r = nr_ip4_str_port_to_transport_addr(
+      r = nr_str_port_to_transport_addr(
         (char *)"127.0.0.1", EnsureEphemeral(port_s++), IPPROTO_TCP, &local);
       ASSERT_EQ(0, r);
 
       r = nr_socket_multi_tcp_create(ice_ctx_->ctx(),
           &local, tcp_type, 1, use_framing, 2048, sock);
     }
 
     ASSERT_EQ(0, r);
--- a/media/mtransport/test/proxy_tunnel_socket_unittest.cpp
+++ b/media/mtransport/test/proxy_tunnel_socket_unittest.cpp
@@ -79,17 +79,17 @@ class DummyResolver {
 
   static int resolve(void *obj,
                      nr_resolver_resource *resource,
                      int (*cb)(void *cb_arg, nr_transport_addr *addr),
                      void *cb_arg,
                      void **handle) {
     nr_transport_addr addr;
 
-    nr_ip4_str_port_to_transport_addr(
+    nr_str_port_to_transport_addr(
         (char *)kProxyAddr.c_str(), kProxyPort, IPPROTO_TCP, &addr);
 
     cb(cb_arg, &addr);
     return 0;
   }
 
   static int cancel(void *obj, void *handle) {
     return 0;
@@ -115,21 +115,21 @@ class ProxyTunnelSocketTest : public ::t
     nr_proxy_tunnel_config_destroy(&config_);
   }
 
   void SetUp() {
     nsRefPtr<DummySocket> dummy(new DummySocket());
 
     nr_resolver_ = resolver_impl_.get_nr_resolver();
 
-    int r = nr_ip4_str_port_to_transport_addr(
+    int r = nr_str_port_to_transport_addr(
         (char *)kRemoteAddr.c_str(), kRemotePort, IPPROTO_TCP, &remote_addr_);
     ASSERT_EQ(0, r);
 
-    r = nr_ip4_str_port_to_transport_addr(
+    r = nr_str_port_to_transport_addr(
         (char *)kProxyAddr.c_str(), kProxyPort, IPPROTO_TCP, &proxy_addr_);
     ASSERT_EQ(0, r);
 
     nr_proxy_tunnel_config_create(&config_);
     nr_proxy_tunnel_config_set_resolver(config_, nr_resolver_);
     nr_proxy_tunnel_config_set_proxy(config_, kProxyAddr.c_str(), kProxyPort);
 
     r = nr_socket_proxy_tunnel_create(
--- a/media/mtransport/test/stunserver.cpp
+++ b/media/mtransport/test/stunserver.cpp
@@ -183,16 +183,18 @@ int nr_socket_wrapped_create(nr_socket *
 }
 
 
 // Instance static.
 // Note: Calling Create() at static init time is not going to be safe, since
 // we have no reason to expect this will be initted to a nullptr yet.
 TestStunServer* TestStunServer::instance;
 TestStunTcpServer* TestStunTcpServer::instance;
+TestStunServer* TestStunServer::instance6;
+TestStunTcpServer* TestStunTcpServer::instance6;
 uint16_t TestStunServer::instance_port = 3478;
 uint16_t TestStunTcpServer::instance_port = 3478;
 
 TestStunServer::~TestStunServer() {
   // TODO(ekr@rtfm.com): Put this on the right thread.
 
   // Unhook callback from our listen socket.
   if (listen_sock_) {
@@ -238,36 +240,49 @@ int TestStunServer::TryOpenListenSocket(
   if (nr_socket_local_create(nullptr, &addr->addr, &listen_sock_)) {
     MOZ_MTLOG(ML_ERROR, "Couldn't create listen socket");
     return R_ALREADY;
   }
 
   return 0;
 }
 
-int TestStunServer::Initialize() {
-  nr_local_addr addrs[100];
+int TestStunServer::Initialize(int address_family) {
+  static const size_t max_addrs = 100;
+  nr_local_addr addrs[max_addrs];
   int addr_ct;
   int r;
+  int i;
 
-  r = nr_stun_find_local_addresses(addrs, 100, &addr_ct);
+  r = nr_stun_find_local_addresses(addrs, max_addrs, &addr_ct);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't retrieve addresses");
     return R_INTERNAL;
   }
 
   if (addr_ct < 1) {
     MOZ_MTLOG(ML_ERROR, "No local addresses");
     return R_INTERNAL;
   }
 
+  for (i = 0; i < addr_ct; ++i) {
+    if (addrs[i].addr.addr->sa_family == address_family) {
+      break;
+    }
+  }
+
+  if (i == addr_ct) {
+    MOZ_MTLOG(ML_ERROR, "No local addresses of the configured IP version");
+    return R_INTERNAL;
+  }
+
   int tries = 100;
   while (tries--) {
-    // Bind to the first address (arbitrarily) on configured port (default 3478)
-    r = TryOpenListenSocket(&addrs[0], instance_port);
+    // Bind on configured port (default 3478)
+    r = TryOpenListenSocket(&addrs[i], instance_port);
     // We interpret R_ALREADY to mean the addr is probably in use. Try another.
     // Otherwise, it either worked or it didn't, and we check below.
     if (r != R_ALREADY) {
       break;
     }
     ++instance_port;
   }
 
@@ -286,35 +301,35 @@ int TestStunServer::Initialize() {
                                 &stun_server_);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't create STUN server");
     return R_INTERNAL;
   }
 
   // Cache the address and port.
   char addr_string[INET6_ADDRSTRLEN];
-  r = nr_transport_addr_get_addrstring(&addrs[0].addr, addr_string,
+  r = nr_transport_addr_get_addrstring(&addrs[i].addr, addr_string,
                                        sizeof(addr_string));
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Failed to convert listen addr to a string representation");
     return R_INTERNAL;
   }
 
   listen_addr_ = addr_string;
   listen_port_ = instance_port;
 
   return 0;
 }
 
-TestStunServer* TestStunServer::Create() {
+TestStunServer* TestStunServer::Create(int address_family) {
   NR_reg_init(NR_REG_MODE_LOCAL);
 
   ScopedDeletePtr<TestStunServer> server(new TestStunServer());
 
-  if (server->Initialize())
+  if (server->Initialize(address_family))
     return nullptr;
 
   NR_SOCKET fd;
   int r = nr_socket_getfd(server->listen_sock_, &fd);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't get fd");
     return nullptr;
   }
@@ -323,28 +338,39 @@ TestStunServer* TestStunServer::Create()
 
   return server.forget();
 }
 
 void TestStunServer::ConfigurePort(uint16_t port) {
   instance_port = port;
 }
 
-TestStunServer* TestStunServer::GetInstance() {
-  if (!instance)
-    instance = Create();
+TestStunServer* TestStunServer::GetInstance(int address_family) {
+  switch (address_family) {
+    case AF_INET:
+      if (!instance)
+        instance = Create(address_family);
 
-  MOZ_ASSERT(instance);
-  return instance;
+      MOZ_ASSERT(instance);
+      return instance;
+    case AF_INET6:
+      if (!instance6)
+        instance6 = Create(address_family);
+
+      return instance6;
+    default:
+      MOZ_CRASH();
+  }
 }
 
 void TestStunServer::ShutdownInstance() {
   delete instance;
-
   instance = nullptr;
+  delete instance6;
+  instance6 = nullptr;
 }
 
 
 struct DeferredStunOperation {
   DeferredStunOperation(TestStunServer *server,
                         const char *data, size_t len,
                         nr_transport_addr *addr) :
       server_(server),
@@ -448,19 +474,19 @@ nsresult TestStunServer::SetResponseAddr
 
   return NS_OK;
 }
 
 nsresult TestStunServer::SetResponseAddr(const std::string& addr,
                                          uint16_t port) {
   nr_transport_addr addr2;
 
-  int r = nr_ip4_str_port_to_transport_addr(addr.c_str(),
-                                            port, IPPROTO_UDP,
-                                            &addr2);
+  int r = nr_str_port_to_transport_addr(addr.c_str(),
+                                        port, IPPROTO_UDP,
+                                        &addr2);
   if (r)
     return NS_ERROR_FAILURE;
 
   return SetResponseAddr(&addr2);
 }
 
 void TestStunServer::Reset() {
   delay_ms_ = 0;
@@ -474,22 +500,32 @@ void TestStunServer::Reset() {
 
 
 // TestStunTcpServer
 
 void TestStunTcpServer::ConfigurePort(uint16_t port) {
   instance_port = port;
 }
 
-TestStunTcpServer* TestStunTcpServer::GetInstance() {
-  if (!instance)
-    instance = Create();
+TestStunTcpServer* TestStunTcpServer::GetInstance(int address_family) {
+  switch (address_family) {
+    case AF_INET:
+      if (!instance)
+        instance = Create(address_family);
 
-  MOZ_ASSERT(instance);
-  return instance;
+      MOZ_ASSERT(instance);
+      return instance;
+    case AF_INET6:
+      if (!instance6)
+        instance6 = Create(address_family);
+
+      return instance6;
+    default:
+      MOZ_CRASH();
+  }
 }
 
 void TestStunTcpServer::ShutdownInstance() {
   delete instance;
 
   instance = nullptr;
 }
 
@@ -518,22 +554,24 @@ int TestStunTcpServer::TryOpenListenSock
   if(nr_socket_listen(listen_sock_, 10)) {
     MOZ_MTLOG(ML_ERROR, "Couldn't listen on socket");
     return R_ALREADY;
   }
 
   return 0;
 }
 
-TestStunTcpServer* TestStunTcpServer::Create() {
+TestStunTcpServer* TestStunTcpServer::Create(int address_family) {
   NR_reg_init(NR_REG_MODE_LOCAL);
 
   ScopedDeletePtr<TestStunTcpServer> server(new TestStunTcpServer());
 
-  server->Initialize();
+  if (server->Initialize(address_family)) {
+    return nullptr;
+  }
 
   nr_socket_multi_tcp_set_readable_cb(server->listen_sock_,
     &TestStunServer::readable_cb, server.get());
 
   return server.forget();
 }
 
 TestStunTcpServer::~TestStunTcpServer() {
--- a/media/mtransport/test/stunserver.h
+++ b/media/mtransport/test/stunserver.h
@@ -19,22 +19,23 @@ typedef struct nr_socket_ nr_socket;
 typedef struct nr_local_addr_ nr_local_addr;
 
 namespace mozilla {
 
 class TestStunServer {
  public:
   // Generally, you should only call API in this class from the same thread that
   // the initial |GetInstance| call was made from.
-  static TestStunServer *GetInstance();
+  static TestStunServer *GetInstance(int address_family = AF_INET);
   static void ShutdownInstance();
   // |ConfigurePort| will only have an effect if called before the first call
   // to |GetInstance| (possibly following a |ShutdownInstance| call)
   static void ConfigurePort(uint16_t port);
-  static TestStunServer *Create();
+  // AF_INET, AF_INET6
+  static TestStunServer *Create(int address_family);
 
   virtual ~TestStunServer();
 
   void SetActive(bool active);
   void SetDelay(uint32_t delay_ms);
   void SetDropInitialPackets(uint32_t count);
   const std::string& addr() const { return listen_addr_; }
   uint16_t port() const { return listen_port_; }
@@ -54,17 +55,17 @@ class TestStunServer {
         stun_server_(nullptr),
         active_(true),
         delay_ms_(0),
         initial_ct_(0),
         response_addr_(nullptr),
         timer_handle_(nullptr) {}
 
   int SetInternalPort(nr_local_addr* addr, uint16_t port);
-  int Initialize();
+  int Initialize(int address_family);
   static void readable_cb(NR_SOCKET sock, int how, void *cb_arg);
 
  private:
   void Process(const uint8_t *msg, size_t len, nr_transport_addr *addr_in);
   virtual int TryOpenListenSocket(nr_local_addr* addr, uint16_t port);
   static void process_cb(NR_SOCKET sock, int how, void *cb_arg);
 
  protected:
@@ -77,31 +78,33 @@ class TestStunServer {
   bool active_;
   uint32_t delay_ms_;
   uint32_t initial_ct_;
   nr_transport_addr *response_addr_;
   void *timer_handle_;
   std::map<std::string, uint32_t> received_ct_;
 
   static TestStunServer* instance;
+  static TestStunServer* instance6;
   static uint16_t instance_port;
 };
 
 class TestStunTcpServer: public TestStunServer {
  public:
-  static TestStunTcpServer *GetInstance();
+  static TestStunTcpServer *GetInstance(int address_family);
   static void ShutdownInstance();
   static void ConfigurePort(uint16_t port);
   virtual ~TestStunTcpServer();
  protected:
   TestStunTcpServer()
       : ice_ctx_(nullptr) {}
 
   nsRefPtr<NrIceCtx> ice_ctx_;
  private:
   virtual int TryOpenListenSocket(nr_local_addr* addr, uint16_t port);
-  static TestStunTcpServer *Create();
+  static TestStunTcpServer *Create(int address_family);
 
   static TestStunTcpServer* instance;
+  static TestStunTcpServer* instance6;
   static uint16_t instance_port;
 };
 } // End of namespace mozilla
 #endif
--- a/media/mtransport/test/test_nr_socket_unittest.cpp
+++ b/media/mtransport/test/test_nr_socket_unittest.cpp
@@ -62,17 +62,17 @@ class TestNrSocketTest : public ::testin
   }
 
   nsRefPtr<TestNrSocket> CreateTestNrSocket_s(const char *ip_str,
                                               TestNat *nat) {
     // If no nat is supplied, we create a default NAT which is disabled. This
     // is how we simulate a non-natted socket.
     nsRefPtr<TestNrSocket> sock(new TestNrSocket(nat ? nat : new TestNat));
     nr_transport_addr address;
-    nr_ip4_str_port_to_transport_addr(ip_str, 0, IPPROTO_UDP, &address);
+    nr_str_port_to_transport_addr(ip_str, 0, IPPROTO_UDP, &address);
     int r = sock->create(&address);
     if (r) {
       return nullptr;
     }
     return sock;
   }
 
   void CreatePublicAddrs(size_t count, const char *ip_str = "127.0.0.1") {
--- a/media/mtransport/test/turn_unittest.cpp
+++ b/media/mtransport/test/turn_unittest.cpp
@@ -127,17 +127,17 @@ class TurnClient : public ::testing::Tes
           nr_socket_buffered_stun_create(real_socket_, 100000, TURN_TCP_FRAMING,
                                          &buffered_socket_);
       ASSERT_EQ(0, r);
       net_socket_ = buffered_socket_;
     } else {
       net_socket_ = real_socket_;
     }
 
-    r = nr_ip4_str_port_to_transport_addr(turn_server_.c_str(), 3478,
+    r = nr_str_port_to_transport_addr(turn_server_.c_str(), 3478,
       protocol_, &addr);
     ASSERT_EQ(0, r);
 
     std::vector<unsigned char> password_vec(
         g_turn_password.begin(), g_turn_password.end());
     Data password;
     INIT_DATA(password, &password_vec[0], password_vec.size());
     r = nr_turn_client_ctx_create("test", net_socket_,
@@ -232,20 +232,20 @@ class TurnClient : public ::testing::Tes
     ASSERT_EQ(0, target.compare(0, 4, "IP4:"));
 
     size_t offset = target.rfind(':');
     ASSERT_NE(std::string::npos, offset);
 
     std::string host = target.substr(4, offset - 4);
     std::string port = target.substr(offset + 1);
 
-    r = nr_ip4_str_port_to_transport_addr(host.c_str(),
-                                          atoi(port.c_str()),
-                                          IPPROTO_UDP,
-                                          &addr);
+    r = nr_str_port_to_transport_addr(host.c_str(),
+                                      atoi(port.c_str()),
+                                      IPPROTO_UDP,
+                                      &addr);
     ASSERT_EQ(0, r);
 
     r = nr_turn_client_ensure_perm(turn_ctx_, &addr);
     ASSERT_EQ(0, r);
   }
 
   void RequestPermission(const std::string& target) {
     RUN_ON_THREAD(test_utils->sts_target(),
@@ -319,20 +319,20 @@ class TurnClient : public ::testing::Tes
     ASSERT_EQ(0, target.compare(0, 4, "IP4:"));
 
     size_t offset = target.rfind(':');
     ASSERT_NE(std::string::npos, offset);
 
     std::string host = target.substr(4, offset - 4);
     std::string port = target.substr(offset + 1);
 
-    r = nr_ip4_str_port_to_transport_addr(host.c_str(),
-                                          atoi(port.c_str()),
-                                          IPPROTO_UDP,
-                                          &addr);
+    r = nr_str_port_to_transport_addr(host.c_str(),
+                                      atoi(port.c_str()),
+                                      IPPROTO_UDP,
+                                      &addr);
     ASSERT_EQ(0, r);
 
     unsigned char test[100];
     for (size_t i=0; i<sizeof(test); i++) {
       test[i] = i & 0xff;
     }
 
     std::cerr << "Sending test message to " << target << " ..." << std::endl;
@@ -483,33 +483,33 @@ int main(int argc, char **argv)
       g_turn_password.empty()) {
     printf(
         "Set TURN_SERVER_ADDRESS, TURN_SERVER_USER, and TURN_SERVER_PASSWORD\n"
         "environment variables to run this test\n");
     return 0;
   }
   {
     nr_transport_addr addr;
-    if (nr_ip4_str_port_to_transport_addr(g_turn_server.c_str(), 3478,
-                                          IPPROTO_UDP, &addr)) {
+    if (nr_str_port_to_transport_addr(g_turn_server.c_str(), 3478,
+                                      IPPROTO_UDP, &addr)) {
       printf("Invalid TURN_SERVER_ADDRESS \"%s\". Only IP numbers supported.\n",
              g_turn_server.c_str());
       return 0;
     }
   }
   test_utils = new MtransportTestUtils();
   NSS_NoDB_Init(nullptr);
   NSS_SetDomesticPolicy();
 
   // Set up the ICE registry, etc.
   // TODO(ekr@rtfm.com): Clean up
   std::string dummy("dummy");
   RUN_ON_THREAD(test_utils->sts_target(),
                 WrapRunnableNM(&NrIceCtx::Create,
-                               dummy, false, false, false, false),
+                               dummy, false, false, false, false, false),
                 NS_DISPATCH_SYNC);
 
   // Start the tests
   ::testing::InitGoogleTest(&argc, argv);
 
   int rv = RUN_ALL_TESTS();
   delete test_utils;
   return rv;
--- a/media/mtransport/third_party/nICEr/IMPORT_FILES
+++ b/media/mtransport/third_party/nICEr/IMPORT_FILES
@@ -32,16 +32,18 @@
                 ./src/net/transport_addr.c
                 ./src/net/transport_addr.h
                 ./src/net/transport_addr_reg.c
                 ./src/net/transport_addr_reg.h
 
                 # STUN
                 ./src/stun/addrs.c
                 ./src/stun/addrs.h
+                ./src/stun/ifaddrs-android.c
+                ./src/stun/ifaddrs-android.h
                 ./src/stun/nr_socket_turn.c
                 ./src/stun/nr_socket_turn.h
                 ./src/stun/stun.h
                 ./src/stun/stun_build.c
                 ./src/stun/stun_build.h
                 ./src/stun/stun_client_ctx.c
                 ./src/stun/stun_client_ctx.h
                 ./src/stun/stun_codec.c
--- a/media/mtransport/third_party/nICEr/nicer.gyp
+++ b/media/mtransport/third_party/nICEr/nicer.gyp
@@ -83,16 +83,18 @@
                 "./src/net/local_addr.c",
                 "./src/net/local_addr.h",
                 "./src/net/nr_interface_prioritizer.c",
                 "./src/net/nr_interface_prioritizer.h",
 
                 # STUN
                 "./src/stun/addrs.c",
                 "./src/stun/addrs.h",
+                "./src/stun/ifaddrs-android.c",
+                "./src/stun/ifaddrs-android.h",
                 "./src/stun/nr_socket_turn.c",
                 "./src/stun/nr_socket_turn.h",
                 "./src/stun/nr_socket_buffered_stun.c",
                 "./src/stun/nr_socket_buffered_stun.h",
                 "./src/stun/stun.h",
                 "./src/stun/stun_build.c",
                 "./src/stun/stun_build.h",
                 "./src/stun/stun_client_ctx.c",
--- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
@@ -59,17 +59,17 @@ static char *RCSSTRING __UNUSED__="$Id: 
 #include "ice_candidate.h"
 #include "ice_codeword.h"
 #include "ice_reg.h"
 #include "ice_util.h"
 #include "nr_socket_turn.h"
 #include "nr_socket.h"
 #include "nr_socket_multi_tcp.h"
 
-static int next_automatic_preference = 224;
+static int next_automatic_preference = 127;
 
 static int nr_ice_candidate_initialize2(nr_ice_candidate *cand);
 static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand);
 static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand);
 static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg);
 #ifdef USE_TURN
 static int nr_ice_start_relay_turn(nr_ice_candidate *cand);
 static void nr_ice_turn_allocated_cb(NR_SOCKET sock, int how, void *cb_arg);
@@ -465,18 +465,22 @@ int nr_ice_candidate_compute_priority(nr
             r_log(LOG_ICE,LOG_ERR,"Out of preference values. Can't assign one for interface %s",cand->base.ifname);
             ABORT(R_NOT_FOUND);
           }
           r_log(LOG_ICE,LOG_DEBUG,"Automatically assigning preference for interface %s->%d",cand->base.ifname,
             next_automatic_preference);
           if (r=NR_reg_set2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,next_automatic_preference)){
             ABORT(r);
           }
-          interface_preference=next_automatic_preference;
+          interface_preference=next_automatic_preference << 1;
           next_automatic_preference--;
+          if (cand->base.ip_version == NR_IPV6) {
+            /* Prefer IPV6 over IPV4 on the same interface. */
+            interface_preference += 1;
+          }
         }
         else {
           ABORT(r);
         }
       }
     }
     else {
       char key_of_interface[MAXIFNAME + 41];
@@ -545,16 +549,21 @@ int nr_ice_candidate_initialize(nr_ice_c
       case RELAYED:
         protocol=NR_RESOLVE_PROTOCOL_TURN;
         /* Fall through */
 #endif
       case SERVER_REFLEXIVE:
         cand->state=NR_ICE_CAND_STATE_INITIALIZING;
 
         if(cand->stun_server->type == NR_ICE_STUN_SERVER_TYPE_ADDR) {
+          if(cand->base.ip_version != cand->stun_server->u.addr.ip_version) {
+            r_log(LOG_ICE, LOG_INFO, "ICE-CANDIDATE(%s): Skipping srflx/relayed candidate with different IP version (%d) than STUN/TURN server (%d).", cand->label,cand->base.ip_version,cand->stun_server->u.addr.ip_version);
+            ABORT(R_NOT_FOUND); /* Same error code when DNS lookup fails */
+          }
+
           /* Just copy the address */
           if (r=nr_transport_addr_copy(&cand->stun_server_addr,
                                        &cand->stun_server->u.addr)) {
             r_log(LOG_ICE,LOG_ERR,"ICE-CANDIDATE(%s): Could not copy STUN server addr", cand->label);
             ABORT(r);
           }
 
           if(r=nr_ice_candidate_initialize2(cand))
@@ -562,16 +571,27 @@ int nr_ice_candidate_initialize(nr_ice_c
         }
         else {
           nr_resolver_resource resource;
           resource.domain_name=cand->stun_server->u.dnsname.host;
           resource.port=cand->stun_server->u.dnsname.port;
           resource.stun_turn=protocol;
           resource.transport_protocol=cand->stun_server->transport;
 
+          switch (cand->base.ip_version) {
+            case NR_IPV4:
+              resource.address_family=AF_INET;
+              break;
+            case NR_IPV6:
+              resource.address_family=AF_INET6;
+              break;
+            default:
+              ABORT(R_BAD_ARGS);
+          }
+
           /* Try to resolve */
           if(!cand->ctx->resolver) {
             r_log(LOG_ICE, LOG_ERR, "ICE-CANDIDATE(%s): Can't use DNS names without a resolver", cand->label);
             ABORT(R_BAD_ARGS);
           }
 
           if(r=nr_resolver_resolve(cand->ctx->resolver,
                                    &resource,
--- a/media/mtransport/third_party/nICEr/src/ice/ice_component.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.c
@@ -994,16 +994,19 @@ int nr_ice_component_pair_candidate(nr_i
       if (!lcand->tcp_type && pcand->tcp_type)
         continue;
       if (lcand->tcp_type == TCP_TYPE_ACTIVE && pcand->tcp_type != TCP_TYPE_PASSIVE)
         continue;
       if (lcand->tcp_type == TCP_TYPE_SO && pcand->tcp_type != TCP_TYPE_SO)
         continue;
       if (lcand->tcp_type == TCP_TYPE_PASSIVE)
         continue;
+      if(pcand->addr.ip_version != lcand->addr.ip_version)
+        continue;
+
       /*
         Two modes, depending on |pair_all_remote|
 
         1. Pair remote candidates which have not been paired
            (used in initial pairing or in processing the other side's
            trickle candidates).
         2. Pair any remote candidate (used when processing our own
            trickle candidates).
@@ -1329,8 +1332,49 @@ int nr_ice_component_insert_pair(nr_ice_
       }
     }
 
     _status=0;
   abort:
     return(_status);
   }
 
+int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version)
+  {
+    int _status;
+    nr_ice_candidate *cand;
+    nr_ice_candidate *best_cand = NULL;
+
+    /* We have the component. Now find the "best" candidate, making
+       use of the fact that more "reliable" candidate types have
+       higher numbers. So, we sort by type and then priority within
+       type
+    */
+    cand=TAILQ_FIRST(&comp->candidates);
+    while(cand){
+      if (cand->state == NR_ICE_CAND_STATE_INITIALIZED &&
+          cand->addr.ip_version == ip_version) {
+        if (!best_cand) {
+          best_cand = cand;
+        }
+        else if (best_cand->type < cand->type) {
+          best_cand = cand;
+        } else if (best_cand->type == cand->type &&
+                   best_cand->priority < cand->priority) {
+          best_cand = cand;
+        }
+      }
+
+      cand=TAILQ_NEXT(cand,entry_comp);
+    }
+
+    /* No candidates */
+    if (!best_cand)
+      ABORT(R_NOT_FOUND);
+
+    *candp = best_cand;
+
+    _status=0;
+  abort:
+    return(_status);
+
+  }
+
--- a/media/mtransport/third_party/nICEr/src/ice/ice_component.h
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.h
@@ -88,13 +88,14 @@ int nr_ice_component_pair_candidates(nr_
 int nr_ice_component_service_pre_answer_requests(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, char *username, int *serviced);
 int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair);
 int nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair);
 int nr_ice_component_check_if_failed(nr_ice_component *comp);
 int nr_ice_component_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp);
 int nr_ice_component_set_failed(nr_ice_component *comp);
 int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp);
 int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair);
+int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version);
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 #endif
--- a/media/mtransport/third_party/nICEr/src/ice/ice_media_stream.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_media_stream.c
@@ -218,66 +218,39 @@ int nr_ice_media_stream_get_attributes(n
           RFREE(attrs[index]);
         }
         RFREE(attrs);
       }
     }
     return(_status);
   }
 
-
 /* Get a default candidate per 4.1.4 */
 int nr_ice_media_stream_get_default_candidate(nr_ice_media_stream *stream, int component, nr_ice_candidate **candp)
   {
-    int _status;
+    int r,_status;
     nr_ice_component *comp;
-    nr_ice_candidate *cand;
-    nr_ice_candidate *best_cand = NULL;
 
     comp=STAILQ_FIRST(&stream->components);
     while(comp){
       if (comp->component_id == component)
         break;
 
       comp=STAILQ_NEXT(comp,entry);
     }
 
     if (!comp)
       ABORT(R_NOT_FOUND);
 
-    /* We have the component. Now find the "best" candidate, making
-       use of the fact that more "reliable" candidate types have
-       higher numbers. So, we sort by type and then priority within
-       type
-    */
-    cand=TAILQ_FIRST(&comp->candidates);
-    while(cand){
-      if (cand->state == NR_ICE_CAND_STATE_INITIALIZED) {
-        if (!best_cand) {
-          best_cand = cand;
-        }
-        else {
-          if (best_cand->type < cand->type) {
-            best_cand = cand;
-          } else if (best_cand->type == cand->type) {
-            if (best_cand->priority < cand->priority)
-              best_cand = cand;
-          }
-        }
-      }
-
-      cand=TAILQ_NEXT(cand,entry_comp);
+    /* If there aren't any IPV4 candidates, try IPV6 */
+    if((r=nr_ice_component_get_default_candidate(comp, candp, NR_IPV4)) &&
+       (r=nr_ice_component_get_default_candidate(comp, candp, NR_IPV6))) {
+      ABORT(r);
     }
 
-    /* No candidates */
-    if (!best_cand)
-      ABORT(R_NOT_FOUND);
-
-    *candp = best_cand;
-
     _status=0;
   abort:
     return(_status);
   }
 
 
 int nr_ice_media_stream_pair_candidates(nr_ice_peer_ctx *pctx,nr_ice_media_stream *lstream,nr_ice_media_stream *pstream)
   {
--- a/media/mtransport/third_party/nICEr/src/ice/ice_parser.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_parser.c
@@ -115,17 +115,16 @@ abort:
 int
 nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_stream *stream,nr_ice_candidate **candp)
 {
     int r,_status;
     char* str = orig;
     nr_ice_candidate *cand;
     char *connection_address=0;
     unsigned int port;
-    in_addr_t addr;
     int i;
     unsigned int component_id;
     char *rel_addr=0;
     unsigned char transport;
 
     if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
         ABORT(R_NO_MEMORY);
 
@@ -207,32 +206,27 @@ nr_ice_peer_candidate_from_attribute(nr_
 
     /* Peer address/port */
     if ((r=grab_token(&str, &connection_address)))
         ABORT(r);
 
     if (*str == '\0')
         ABORT(R_BAD_DATA);
 
-    addr = inet_addr(connection_address);
-    if (addr == INADDR_NONE)
-        ABORT(R_BAD_DATA);
-
     skip_whitespace(&str);
     if (*str == '\0')
         ABORT(R_BAD_DATA);
 
     if (sscanf(str, "%u", &port) != 1)
         ABORT(R_BAD_DATA);
 
     if (port < 1 || port > 0x0FFFF)
         ABORT(R_BAD_DATA);
 
-    /* Assume v4 for now */
-    if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,transport,&cand->addr))
+    if ((r=nr_str_port_to_transport_addr(connection_address,port,transport,&cand->addr)))
       ABORT(r);
 
     skip_to_past_space(&str);
     if (*str == '\0')
         ABORT(R_BAD_DATA);
 
     /* Type */
     if (strncasecmp("typ", str, 3))
@@ -284,20 +278,16 @@ nr_ice_peer_candidate_from_attribute(nr_
             ABORT(R_BAD_DATA);
 
         if ((r=grab_token(&str, &rel_addr)))
             ABORT(r);
 
         if (*str == '\0')
             ABORT(R_BAD_DATA);
 
-        addr = inet_addr(rel_addr);
-        if (addr == INADDR_NONE)
-            ABORT(R_BAD_DATA);
-
         skip_whitespace(&str);
         if (*str == '\0')
             ABORT(R_BAD_DATA);
 
         if (strncasecmp("rport", str, 5))
               ABORT(R_BAD_DATA);
 
         fast_forward(&str, 5);
@@ -309,18 +299,17 @@ nr_ice_peer_candidate_from_attribute(nr_
             ABORT(R_BAD_DATA);
 
         if (sscanf(str, "%u", &port) != 1)
             ABORT(R_BAD_DATA);
 
         if (port < 1 || port > 0x0FFFF)
             ABORT(R_BAD_DATA);
 
-        /* Assume v4 for now */
-        if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,transport,&cand->base))
+        if ((r=nr_str_port_to_transport_addr(rel_addr,port,transport,&cand->base)))
           ABORT(r);
 
         skip_to_past_space(&str);
         /* it's expected to be at EOD at this point */
 
         break;
     default:
         ABORT(R_INTERNAL);
--- a/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c
+++ b/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c
@@ -251,17 +251,17 @@ int nr_socket_proxy_tunnel_connect(void 
 
   if ((r=nr_transport_addr_copy(&sock->remote_addr, addr))) {
     ABORT(r);
   }
 
   assert(config->proxy_host);
 
   /* Check if the proxy_host is already an IP address */
-  has_addr = !nr_ip4_str_port_to_transport_addr(config->proxy_host,
+  has_addr = !nr_str_port_to_transport_addr(config->proxy_host,
       config->proxy_port, IPPROTO_TCP, &proxy_addr);
 
   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_connect: %s", config->proxy_host);
 
   if (!has_addr && !config->resolver) {
     r_log(LOG_GENERIC,LOG_ERR,"nr_socket_proxy_tunnel_connect name resolver not configured");
     ABORT(R_NOT_FOUND);
   }
--- a/media/mtransport/third_party/nICEr/src/net/nr_resolver.h
+++ b/media/mtransport/third_party/nICEr/src/net/nr_resolver.h
@@ -41,16 +41,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 #define NR_RESOLVE_PROTOCOL_STUN 1
 #define NR_RESOLVE_PROTOCOL_TURN 2
 
 typedef struct nr_resolver_resource_ {
   char *domain_name;
   UINT2 port;
   int stun_turn;
   UCHAR transport_protocol;
+  UCHAR address_family;
 } nr_resolver_resource;
 
 typedef struct nr_resolver_vtbl_ {
   int (*destroy)(void **obj);
   int (*resolve)(void *obj,
                  nr_resolver_resource *resource,
                  int (*cb)(void *cb_arg, nr_transport_addr *addr),
                  void *cb_arg,
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr.c
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.c
@@ -95,54 +95,61 @@ int nr_transport_addr_fmt_ifname_addr_st
     int _status;
     char buffer[40];
 
     switch(addr->ip_version){
       case NR_IPV4:
         if (!inet_ntop(AF_INET, &addr->u.addr4.sin_addr,buffer,sizeof(buffer))) {
            strncpy(buffer, "[error]", len);
         }
-        snprintf(buf,len,"%s:%s",addr->ifname,buffer);
+        break;
+      case NR_IPV6:
+        if (!inet_ntop(AF_INET6, &addr->u.addr6.sin6_addr,buffer,sizeof(buffer))) {
+           strncpy(buffer, "[error]", len);
+        }
         break;
       default:
         ABORT(R_INTERNAL);
     }
+    snprintf(buf,len,"%s:%s",addr->ifname,buffer);
 
     _status=0;
   abort:
     return(_status);
   }
 
-int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int saddr_len, int protocol, int keep, nr_transport_addr *addr)
+int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int protocol, int keep, nr_transport_addr *addr)
   {
     int r,_status;
 
     if(!keep) memset(addr,0,sizeof(nr_transport_addr));
 
-    if(saddr->sa_family==PF_INET){
-      if(saddr_len != sizeof(struct sockaddr_in))
+    switch(protocol){
+      case IPPROTO_TCP:
+      case IPPROTO_UDP:
+        break;
+      default:
         ABORT(R_BAD_ARGS);
+    }
 
-      switch(protocol){
-        case IPPROTO_TCP:
-        case IPPROTO_UDP:
-          break;
-        default:
-          ABORT(R_BAD_ARGS);
-      }
+    addr->protocol=protocol;
+
+    if(saddr->sa_family==AF_INET){
       addr->ip_version=NR_IPV4;
-      addr->protocol=protocol;
 
       memcpy(&addr->u.addr4,saddr,sizeof(struct sockaddr_in));
       addr->addr=(struct sockaddr *)&addr->u.addr4;
-      addr->addr_len=saddr_len;
+      addr->addr_len=sizeof(struct sockaddr_in);
     }
-    else if(saddr->sa_family==PF_INET6){
-      /* Not implemented */
-      ABORT(R_INTERNAL);
+    else if(saddr->sa_family==AF_INET6){
+      addr->ip_version=NR_IPV6;
+
+      memcpy(&addr->u.addr6, saddr, sizeof(struct sockaddr_in6));
+      addr->addr=(struct sockaddr *)&addr->u.addr6;
+      addr->addr_len=sizeof(struct sockaddr_in6);
     }
     else
       ABORT(R_BAD_ARGS);
 
     if(r=nr_transport_addr_fmt_addr_string(addr))
       ABORT(r);
 
     _status=0;
@@ -201,26 +208,52 @@ int nr_ip4_port_to_transport_addr(UINT4 
     if(r=nr_transport_addr_fmt_addr_string(addr))
       ABORT(r);
 
     _status=0;
   abort:
     return(_status);
   }
 
-int nr_ip4_str_port_to_transport_addr(const char *ip4, UINT2 port, int protocol, nr_transport_addr *addr)
+int nr_str_port_to_transport_addr(const char *ip, UINT2 port, int protocol, nr_transport_addr *addr_out)
   {
     int r,_status;
-    in_addr_t ip_addr;
+    struct in_addr addr;
+    struct in6_addr addr6;
+
+    if (inet_pton(AF_INET, ip, &addr) == 1) {
+      if(r=nr_ip4_port_to_transport_addr(ntohl(addr.s_addr),port,protocol,addr_out))
+        ABORT(r);
+    } else if (inet_pton(AF_INET6, ip, &addr6) == 1) {
+      if(r=nr_ip6_port_to_transport_addr(&addr6,port,protocol,addr_out))
+        ABORT(r);
+    } else {
+      ABORT(R_BAD_DATA);
+    }
 
-    ip_addr=inet_addr(ip4);
-    if (ip_addr == INADDR_NONE)
-      ABORT(R_BAD_DATA);
-    /* Assume v4 for now */
-    if(r=nr_ip4_port_to_transport_addr(ntohl(ip_addr),port,protocol,addr))
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ip6_port_to_transport_addr(struct in6_addr* addr6, UINT2 port, int protocol, nr_transport_addr *addr)
+  {
+    int r,_status;
+
+    memset(addr, 0, sizeof(nr_transport_addr));
+
+    addr->ip_version=NR_IPV6;
+    addr->protocol=protocol;
+    addr->u.addr6.sin6_family=PF_INET6;
+    addr->u.addr6.sin6_port=htons(port);
+    memcpy(addr->u.addr6.sin6_addr.s6_addr, addr6->s6_addr, sizeof(addr6->s6_addr));
+    addr->addr=(struct sockaddr *)&addr->u.addr6;
+    addr->addr_len=sizeof(struct sockaddr_in6);
+
+    if(r=nr_transport_addr_fmt_addr_string(addr))
       ABORT(r);
 
     _status=0;
   abort:
     return(_status);
   }
 
 int nr_transport_addr_get_addrstring(nr_transport_addr *addr, char *str, int maxlen)
@@ -286,36 +319,16 @@ int nr_transport_addr_set_port(nr_transp
         ABORT(R_INTERNAL);
     }
 
     _status=0;
   abort:
     return(_status);
   }
 
-int nr_transport_addr_get_ip4(nr_transport_addr *addr, UINT4 *ip4p)
-  {
-    int _status;
-
-    switch(addr->ip_version){
-      case NR_IPV4:
-        *ip4p=ntohl(addr->u.addr4.sin_addr.s_addr);
-        break;
-      case NR_IPV6:
-        ABORT(R_NOT_FOUND);
-        break;
-      default:
-        ABORT(R_INTERNAL);
-    }
-
-    _status=0;
-  abort:
-    return(_status);
-  }
-
 /* memcmp() may not work if, for instance, the string or interface
    haven't been made. Hmmm.. */
 int nr_transport_addr_cmp(nr_transport_addr *addr1,nr_transport_addr *addr2,int mode)
   {
     assert(mode);
 
     if(addr1->ip_version != addr2->ip_version)
       return(1);
@@ -335,17 +348,23 @@ int nr_transport_addr_cmp(nr_transport_a
         if(addr1->u.addr4.sin_addr.s_addr != addr2->u.addr4.sin_addr.s_addr)
           return(1);
         if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ALL)
           return(0);
         if(addr1->u.addr4.sin_port != addr2->u.addr4.sin_port)
           return(1);
         break;
       case NR_IPV6:
-        UNIMPLEMENTED;
+        if(memcmp(addr1->u.addr6.sin6_addr.s6_addr,addr2->u.addr6.sin6_addr.s6_addr,sizeof(struct in6_addr)))
+          return(1);
+        if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ALL)
+          return(0);
+        if(addr1->u.addr6.sin6_port != addr2->u.addr6.sin6_port)
+          return(1);
+        break;
       default:
         abort();
     }
 
     return(0);
   }
 
 int nr_transport_addr_is_loopback(nr_transport_addr *addr)
@@ -358,30 +377,52 @@ int nr_transport_addr_is_loopback(nr_tra
               return 1;
             break;
           default:
             UNIMPLEMENTED;
             break;
         }
         break;
 
+      case NR_IPV6:
+        if(!memcmp(addr->u.addr6.sin6_addr.s6_addr,in6addr_loopback.s6_addr,sizeof(struct in6_addr)))
+          return(1);
+        break;
       default:
         UNIMPLEMENTED;
     }
 
     return(0);
   }
 
+int nr_transport_addr_is_link_local(nr_transport_addr *addr)
+  {
+    if(addr->ip_version == NR_IPV6){
+      UINT4* addrTop = (UINT4*)(addr->u.addr6.sin6_addr.s6_addr);
+      return ((*addrTop & htonl(0xFFC00000)) == htonl(0xFE800000));
+    } else {
+      assert(0);
+    }
+
+    return(0);
+  }
+
 int nr_transport_addr_is_wildcard(nr_transport_addr *addr)
   {
     switch(addr->ip_version){
       case NR_IPV4:
         if(addr->u.addr4.sin_addr.s_addr==INADDR_ANY)
           return(1);
         if(addr->u.addr4.sin_port==0)
           return(1);
         break;
+      case NR_IPV6:
+        if(!memcmp(addr->u.addr6.sin6_addr.s6_addr,in6addr_any.s6_addr,sizeof(struct in6_addr)))
+          return(1);
+        if(addr->u.addr6.sin6_port==0)
+          return(1);
+        break;
       default:
         UNIMPLEMENTED;
     }
 
     return(0);
   }
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr.h
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.h
@@ -66,33 +66,34 @@ typedef struct nr_transport_addr_ {
     struct sockaddr_in6 addr6;
   } u;
   char ifname[MAXIFNAME];
   /* A string version.
      56 = 5 ("IP6:[") + 39 (ipv6 address) + 2 ("]:") + 5 (port) + 4 (/UDP) + 1 (null) */
   char as_string[56];
 } nr_transport_addr;
 
-int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int saddr_len, int protocol, int keep, nr_transport_addr *addr);
+int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int protocol, int keep, nr_transport_addr *addr);
 
 // addresses, ports in local byte order
 int nr_ip4_port_to_transport_addr(UINT4 ip4, UINT2 port, int protocol, nr_transport_addr *addr);
-int nr_ip4_str_port_to_transport_addr(const char *ip4, UINT2 port, int protocol, nr_transport_addr *addr);
+int nr_str_port_to_transport_addr(const char *ip4, UINT2 port, int protocol, nr_transport_addr *addr);
+int nr_ip6_port_to_transport_addr(struct in6_addr* addr6, UINT2 port, int protocol, nr_transport_addr *addr);
 
 int nr_transport_addr_get_addrstring(nr_transport_addr *addr, char *str, int maxlen);
 int nr_transport_addr_get_port(nr_transport_addr *addr, int *port);
-int nr_transport_addr_get_ip4(nr_transport_addr *addr, UINT4 *ip4p);
 int nr_transport_addr_cmp(nr_transport_addr *addr1,nr_transport_addr *addr2,int mode);
 #define NR_TRANSPORT_ADDR_CMP_MODE_VERSION   1
 #define NR_TRANSPORT_ADDR_CMP_MODE_PROTOCOL  2
 #define NR_TRANSPORT_ADDR_CMP_MODE_ADDR      3
 #define NR_TRANSPORT_ADDR_CMP_MODE_ALL       4
 
 int nr_transport_addr_is_wildcard(nr_transport_addr *addr);
 int nr_transport_addr_is_loopback(nr_transport_addr *addr);
+int nr_transport_addr_is_link_local(nr_transport_addr *addr);
 int nr_transport_addr_copy(nr_transport_addr *to, nr_transport_addr *from);
 int nr_transport_addr_copy_keep_ifname(nr_transport_addr *to, nr_transport_addr *from);
 int nr_transport_addr_fmt_addr_string(nr_transport_addr *addr);
 int nr_transport_addr_fmt_ifname_addr_string(const nr_transport_addr *addr, char *buf, int len);
 int nr_transport_addr_set_port(nr_transport_addr *addr, int port);
 
 #endif
 
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c
@@ -48,16 +48,19 @@ static char *RCSSTRING __UNUSED__="$Id: 
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #endif
 #include <assert.h>
 #include "nr_api.h"
 #include "transport_addr.h"
 #include "transport_addr_reg.h"
 
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46 /* Value used by linux/BSD */
+#endif
 
 int
 nr_reg_get_transport_addr(NR_registry prefix, int keep, nr_transport_addr *addr)
 {
     int r,_status;
     unsigned int count;
     char *address = 0;
     UINT2 port = 0;
@@ -102,17 +105,17 @@ nr_reg_get_transport_addr(NR_registry pr
         else if (!strcasecmp("udp", protocol))
             p = IPPROTO_UDP;
         else
             ABORT(R_BAD_DATA);
     }
 
     if (!keep) memset(addr, 0, sizeof(*addr));
 
-    if ((r=nr_ip4_str_port_to_transport_addr(address?address:"0.0.0.0", port, p, addr)))
+    if ((r=nr_str_port_to_transport_addr(address?address:"0.0.0.0", port, p, addr)))
         ABORT(r);
 
     if (ifname)
         strlcpy(addr->ifname, ifname, sizeof(addr->ifname));
 
     _status=0;
   abort:
     RFREE(protocol);
@@ -128,54 +131,69 @@ nr_reg_set_transport_addr(NR_registry pr
 
     if (! keep) {
         if ((r=NR_reg_del(prefix)))
             ABORT(r);
     }
 
     switch (addr->ip_version) {
     case NR_IPV4:
-        if (addr->u.addr4.sin_addr.s_addr != INADDR_ANY) {
+        if (!nr_transport_addr_is_wildcard(addr)) {
             if ((r=NR_reg_set2_string(prefix, "address", inet_ntoa(addr->u.addr4.sin_addr))))
                 ABORT(r);
         }
 
         if (addr->u.addr4.sin_port != 0) {
             if ((r=NR_reg_set2_uint2(prefix, "port", ntohs(addr->u.addr4.sin_port))))
                 ABORT(r);
         }
-
-        switch (addr->protocol) {
-        case IPPROTO_TCP:
-            if ((r=NR_reg_set2_string(prefix, "protocol", "tcp")))
-                ABORT(r);
-            break;
-        case IPPROTO_UDP:
-            if ((r=NR_reg_set2_string(prefix, "protocol", "udp")))
-                ABORT(r);
-            break;
-        default:
-            UNIMPLEMENTED;
-            break;
-        }
-
-        if (strlen(addr->ifname) > 0) {
-            if ((r=NR_reg_set2_string(prefix, "ifname", addr->ifname)))
-                ABORT(r);
-        }
         break;
 
     case NR_IPV6:
-        UNIMPLEMENTED;
+        if (!nr_transport_addr_is_wildcard(addr)) {
+          char address[INET6_ADDRSTRLEN];
+          if(!inet_ntop(AF_INET6, &addr->u.addr6.sin6_addr,address,sizeof(address))) {
+            ABORT(R_BAD_DATA);
+          }
+
+          if ((r=NR_reg_set2_string(prefix, "address", address))) {
+            ABORT(r);
+          }
+        }
+
+        if (addr->u.addr6.sin6_port != 0) {
+            if ((r=NR_reg_set2_uint2(prefix, "port", ntohs(addr->u.addr6.sin6_port))))
+                ABORT(r);
+        }
         break;
     default:
         ABORT(R_INTERNAL);
         break;
     }
 
+    /* We abort if neither NR_IPV4 or NR_IPV6 above */
+    switch (addr->protocol) {
+      case IPPROTO_TCP:
+        if ((r=NR_reg_set2_string(prefix, "protocol", "tcp")))
+          ABORT(r);
+        break;
+      case IPPROTO_UDP:
+        if ((r=NR_reg_set2_string(prefix, "protocol", "udp")))
+          ABORT(r);
+        break;
+      default:
+        UNIMPLEMENTED;
+        break;
+    }
+
+    if (strlen(addr->ifname) > 0) {
+      if ((r=NR_reg_set2_string(prefix, "ifname", addr->ifname)))
+        ABORT(r);
+    }
+
     _status=0;
   abort:
     if (_status)
         NR_reg_del(prefix);
     return _status;
 }
 
 int
--- a/media/mtransport/third_party/nICEr/src/stun/addrs.c
+++ b/media/mtransport/third_party/nICEr/src/stun/addrs.c
@@ -36,277 +36,52 @@ static char *RCSSTRING __UNUSED__="$Id: 
 #include <csi_platform.h>
 #include <assert.h>
 #include <string.h>
 
 #ifdef WIN32
 #include <winsock2.h>
 #include <iphlpapi.h>
 #include <tchar.h>
-#else   /* UNIX */
-#include <sys/param.h>
+#else   /* !WIN32 */
+
 #include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
 #ifndef ANDROID
-#include <sys/syslog.h>
+/* This works on linux and BSD, but not android */
+#include <sys/types.h> /* getifaddrs */
+#include <ifaddrs.h> /* getifaddrs */
 #else
-#include <syslog.h>
+#include "ifaddrs-android.h"
+#define getifaddrs android_getifaddrs
+#define freeifaddrs android_freeifaddrs
+#endif
+
+#ifdef LINUX
+
+#ifdef ANDROID
 /* Work around an Android NDK < r8c bug */
 #undef __unused
-#endif
-#ifndef LINUX
-#include <net/if.h>
-#if !defined(__OpenBSD__) && !defined(__NetBSD__)
-#include <net/if_var.h>
-#endif
-#include <net/if_dl.h>
-#include <net/if_types.h>
-#include <sys/sockio.h>
 #else
-#include <linux/sockios.h>
-#include <linux/if.h>
-#include <linux/kernel.h>
-#include <linux/wireless.h>
-#ifndef ANDROID
-#include <linux/ethtool.h>
-#endif
-#endif
-#include <net/route.h>
+#include <linux/if.h> /* struct ifreq, IFF_POINTTOPOINT */
+#include <linux/wireless.h> /* struct iwreq */
+#include <linux/ethtool.h> /* struct ethtool_cmd */
+#include <linux/sockios.h> /* SIOCETHTOOL */
+#endif /* ANDROID */
 
-/* IP */
-#include <netinet/in.h>
-#ifdef LINUX
-#include "sys/ioctl.h"
-#else
-#include <netinet/in_var.h>
-#endif
-#include <arpa/inet.h>
-#include <netdb.h>
-#endif  /* UNIX */
+#endif /* LINUX */
+
+#endif  /* !WIN32 */
 
 #include "stun.h"
 #include "addrs.h"
 
-
-
-#if defined(BSD) || defined(DARWIN)
-/*
- * Copyright (c) 1983, 1993
- *    The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *[3 Deleted as of 22nd July 1999; see
- *    ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
- *    for details]
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <sys/sysctl.h>
-
-static void stun_rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
-static int stun_grab_addrs(char *name, int addrcount,
-               struct ifa_msghdr *ifam,
-               nr_local_addr addrs[], int maxaddrs, int *count);
-static int
-nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr);
-
-
-/*
- * Expand the compacted form of addresses as returned via the
- * configuration read via sysctl().
- */
-#define ROUNDUP(a) \
-    ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
-
-static void
-stun_rt_xaddrs(cp, cplim, rtinfo)
-    caddr_t cp, cplim;
-    struct rt_addrinfo *rtinfo;
-{
-    struct sockaddr *sa;
-    int i;
-
-    memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
-    for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
-        if ((rtinfo->rti_addrs & (1 << i)) == 0)
-            continue;
-        rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
-        ADVANCE(cp, sa);
-    }
-}
-
-static int
-stun_grab_addrs(char *name, int addrcount, struct ifa_msghdr *ifam, nr_local_addr addrs[], int maxaddrs, int *count)
-{
-    int r,_status;
-    int s = -1;
-    struct ifreq ifr;
-    struct rt_addrinfo info;
-    struct sockaddr_in *sin;
-
-    ifr.ifr_addr.sa_family = AF_INET;
-    strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-
-    if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) {
-      r_log(NR_LOG_STUN, LOG_ERR, "unable to obtain addresses from socket");
-      ABORT(R_FAILED);
-    }
-
-    while (addrcount > 0) {
-        info.rti_addrs = ifam->ifam_addrs;
-
-        /* Expand the compacted addresses */
-        stun_rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info);
-        addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
-        addrs[*count].interface.estimated_speed = 0;
-        /* TODO (Bug 895790) Get interface properties for Darwin */
-
-        switch (info.rti_info[RTAX_IFA]->sa_family) {
-        case AF_INET:
-            sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
-
-            if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sin, sizeof(*sin), IPPROTO_UDP, 0, &(addrs[*count].addr))))
-                ABORT(r);
-
-            strlcpy(addrs[*count].addr.ifname, name, sizeof(addrs[*count].addr.ifname));
-
-            ++*count;
-            break;
-        case AF_INET6:
-            UNIMPLEMENTED;
-            break;
-        }
-
-        addrcount--;
-
-        if (*count >= maxaddrs) {
-            r_log(NR_LOG_STUN, LOG_WARNING, "Address list truncated at %d out of %d entries", maxaddrs, maxaddrs+addrcount);
-            break;
-        }
-
-        ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
-    }
-
-    _status = 0;
-  abort:
-    if (s != -1) close(s);
-    return _status;
-}
-
-static int
-stun_get_mib_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
-{
-    int _status;
-    char name[32];
-    int flags;
-    int addrcount;
-    struct if_msghdr *ifm, *nextifm;
-    struct ifa_msghdr *ifam;
-    struct sockaddr_dl *sdl;
-    char *buf = 0;
-    char *lim;
-    char *next;
-    size_t needed;
-    int mib[6];
-
-    *count = 0;
-
-    mib[0] = CTL_NET;
-    mib[1] = PF_ROUTE;
-    mib[2] = 0;
-    mib[3] = AF_INET;
-    mib[4] = NET_RT_IFLIST;
-    mib[5] = 0;
-
-    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
-        errx(1, "iflist-sysctl-estimate");
-        ABORT(R_INTERNAL);
-    }
-
-    if ((buf = malloc(needed)) == NULL) {
-        errx(1, "malloc");
-        ABORT(R_NO_MEMORY);
-    }
-
-    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
-        errx(1, "actual retrieval of interface table");
-        ABORT(R_INTERNAL);
-    }
-
-    lim = buf + needed;
-
-    next = buf;
-    while (next < lim) {
-        ifm = (struct if_msghdr *)next;
-
-        if (ifm->ifm_type == RTM_IFINFO) {
-            sdl = (struct sockaddr_dl *)(ifm + 1);
-            flags = ifm->ifm_flags;
-        } else {
-            r_log(NR_LOG_STUN, LOG_WARNING, "out of sync parsing NET_RT_IFLIST");
-            r_log(NR_LOG_STUN, LOG_DEBUG, "expected %d, got %d, msglen = %d, buf:%p, next:%p, lim:%p", RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen, buf, next, lim);
-            ABORT(R_FAILED);
-        }
-
-        next += ifm->ifm_msglen;
-        ifam = NULL;
-        addrcount = 0;
-        while (next < lim) {
-
-            nextifm = (struct if_msghdr *)next;
-
-            if (nextifm->ifm_type != RTM_NEWADDR)
-                break;
-
-            if (ifam == NULL)
-                ifam = (struct ifa_msghdr *)nextifm;
-
-            addrcount++;
-            next += nextifm->ifm_msglen;
-        }
-
-        if (sdl->sdl_nlen > sizeof(name) - 1) {
-            ABORT(R_INTERNAL);
-        }
-
-        memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
-        name[sdl->sdl_nlen] = '\0';
-
-        stun_grab_addrs(name, addrcount, ifam, addrs, maxaddrs, count);
-    }
-
-    _status = 0;
-abort:
-    if (buf) free(buf);
-    return _status;
-}
-
-#elif defined(WIN32)
+#if defined(WIN32)
 
 #define WIN32_MAX_NUM_INTERFACES  20
 
 
 #define _NR_MAX_KEY_LENGTH 256
 #define _NR_MAX_NAME_LENGTH 512
 
 #define _ADAPTERS_BASE_REG "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
@@ -363,135 +138,16 @@ static int nr_win32_get_adapter_friendly
 
 abort:
     if (_status) {
       if (my_fn) free(my_fn);
     }
     return(_status);
 }
 
-
-static int
-stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
-{
-    int r,_status;
-    PIP_ADAPTER_INFO pAdapterInfo;
-    PIP_ADAPTER_INFO pAdapter = NULL;
-    PIP_ADDR_STRING pAddrString;
-    ULONG out_buf_len;
-    char *friendly_name=0;
-    char munged_ifname[IFNAMSIZ];
-    int n = 0;
-
-    *count = 0;
-
-    pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(sizeof(IP_ADAPTER_INFO));
-    out_buf_len = sizeof(IP_ADAPTER_INFO);
-
-    /* First call to GetAdaptersInfo is mainly to get length */
-
-    if (GetAdaptersInfo(pAdapterInfo, &out_buf_len) == ERROR_BUFFER_OVERFLOW) {
-      RFREE(pAdapterInfo);
-      pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(out_buf_len);
-      if (pAdapterInfo == NULL) {
-        r_log(NR_LOG_STUN, LOG_ERR, "Error allocating memory for GetAdaptersInfo output");
-        ABORT(R_NO_MEMORY);
-      }
-    }
-    if ((r = GetAdaptersInfo(pAdapterInfo, &out_buf_len)) != NO_ERROR) {
-      r_log(NR_LOG_STUN, LOG_ERR, "Got error from GetAdaptersInfo");
-      ABORT(R_INTERNAL);
-    }
-    r_log(NR_LOG_STUN, LOG_DEBUG, "Got AdaptersInfo");
-
-    pAdapter = pAdapterInfo;
-
-    while (pAdapter) {
-      char *c;
-
-      r_log(NR_LOG_STUN, LOG_DEBUG, "Adapter Name (GUID) = %s", pAdapter->AdapterName);
-      r_log(NR_LOG_STUN, LOG_DEBUG, "Adapter Description = %s", pAdapter->Description);
-
-      if (nr_win32_get_adapter_friendly_name(pAdapter->AdapterName, &friendly_name)) {
-        friendly_name = 0;
-      }
-      if (friendly_name && *friendly_name) {
-        r_log(NR_LOG_STUN, LOG_INFO, "Found adapter with friendly name: %s", friendly_name);
-        snprintf(munged_ifname, IFNAMSIZ, "%s%c", friendly_name, 0);
-        RFREE(friendly_name);
-        friendly_name = 0;
-      } else {
-        // Not all adapters follow the friendly name convention. Windows' PPTP
-        // VPN adapter puts "VPN Connection 2" in the Description field instead.
-        // Windows's renaming-logic appears to enforce uniqueness in spite of this.
-        r_log(NR_LOG_STUN, LOG_INFO, "Found adapter with description: %s", pAdapter->Description);
-        snprintf(munged_ifname, IFNAMSIZ, "%s%c", pAdapter->Description, 0);
-      }
-      /* replace spaces with underscores */
-      c = strchr(munged_ifname, ' ');
-      while (c != NULL) {
-        *c = '_';
-         c = strchr(munged_ifname, ' ');
-      }
-      c = strchr(munged_ifname, '.');
-      while (c != NULL) {
-        *c = '+';
-         c = strchr(munged_ifname, '.');
-      }
-
-      r_log(NR_LOG_STUN, LOG_INFO, "Converted ifname: %s", munged_ifname);
-
-      for (pAddrString = &(pAdapter->IpAddressList); pAddrString != NULL; pAddrString = pAddrString->Next) {
-        unsigned long this_addr = inet_addr(pAddrString->IpAddress.String);
-        nr_transport_addr *addr = &(addrs[n].addr);
-
-        if (this_addr == 0)
-          continue;
-
-        r_log(NR_LOG_STUN, LOG_INFO, "Adapter %s address: %s", munged_ifname, pAddrString->IpAddress.String);
-
-        addr->ip_version=NR_IPV4;
-        addr->protocol = IPPROTO_UDP;
-
-        addr->u.addr4.sin_family=PF_INET;
-        addr->u.addr4.sin_port=0;
-        addr->u.addr4.sin_addr.s_addr=this_addr;
-        addr->addr=(struct sockaddr *)&(addr->u.addr4);
-        addr->addr_len=sizeof(struct sockaddr_in);
-
-        strlcpy(addr->ifname, munged_ifname, sizeof(addr->ifname));
-        snprintf(addr->as_string,40,"IP4:%s:%d",
-                 inet_ntoa(addr->u.addr4.sin_addr),
-                 ntohs(addr->u.addr4.sin_port));
-
-        /* TODO: (Bug 895793) Getting interface properties for Windows */
-        addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
-        addrs[n].interface.estimated_speed = 0;
-
-        if (++n >= maxaddrs)
-          goto done;
-      }
-
-      pAdapter = pAdapter->Next;
-    }
-
-  done:
-    *count = n;
-    _status = 0;
-
-  abort:
-    RFREE(pAdapterInfo);
-    RFREE(friendly_name);
-    return _status;
-}
-
-#ifdef GET_WIN32_ADDRS_NO_WIN2K
-   /* Here's a nice way to get adapter addresses and names, but it
-    * isn't supported on Win2000.
-    */
 static int
 stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
 {
     int r,_status;
     PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL, tmpAddress = NULL;
     ULONG buflen;
     char munged_ifname[IFNAMSIZ];
     int n = 0;
@@ -500,31 +156,31 @@ stun_get_win32_addrs(nr_local_addr addrs
 
     if (maxaddrs <= 0)
       ABORT(R_INTERNAL);
 
     /* Call GetAdaptersAddresses() twice.  First, just to get the buf length */
 
     buflen = 0;
 
-    r = GetAdaptersAddresses(AF_INET, 0, NULL, AdapterAddresses, &buflen);
+    r = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, AdapterAddresses, &buflen);
     if (r != ERROR_BUFFER_OVERFLOW) {
       r_log(NR_LOG_STUN, LOG_ERR, "Error getting buf len from GetAdaptersAddresses()");
       ABORT(R_INTERNAL);
     }
 
     AdapterAddresses = (PIP_ADAPTER_ADDRESSES) RMALLOC(buflen);
     if (AdapterAddresses == NULL) {
       r_log(NR_LOG_STUN, LOG_ERR, "Error allocating buf for GetAdaptersAddresses()");
       ABORT(R_NO_MEMORY);
     }
 
     /* for real, this time */
 
-    r = GetAdaptersAddresses(AF_INET, 0, NULL, AdapterAddresses, &buflen);
+    r = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, AdapterAddresses, &buflen);
     if (r != NO_ERROR) {
       r_log(NR_LOG_STUN, LOG_ERR, "Error getting addresses from GetAdaptersAddresses()");
       ABORT(R_INTERNAL);
     }
 
     /* Loop through the adapters */
 
     for (tmpAddress = AdapterAddresses; tmpAddress != NULL; tmpAddress = tmpAddress->Next) {
@@ -549,17 +205,17 @@ stun_get_win32_addrs(nr_local_addr addrs
       if ((tmpAddress->IfIndex != 0) || (tmpAddress->Ipv6IfIndex != 0)) {
         IP_ADAPTER_UNICAST_ADDRESS *u = 0;
 
         for (u = tmpAddress->FirstUnicastAddress; u != 0; u = u->Next) {
           SOCKET_ADDRESS *sa_addr = &u->Address;
 
           if ((sa_addr->lpSockaddr->sa_family == AF_INET) ||
               (sa_addr->lpSockaddr->sa_family == AF_INET6)) {
-            if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, sizeof(*sa_addr->lpSockaddr), IPPROTO_UDP, 0, &(addrs[n].addr))))
+            if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, IPPROTO_UDP, 0, &(addrs[n].addr))))
                 ABORT(r);
           }
           else {
             r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized sa_family for adapteraddress %s",munged_ifname);
             continue;
           }
 
           strlcpy(addrs[n].addr.ifname, munged_ifname, sizeof(addrs[n].addr.ifname));
@@ -575,141 +231,108 @@ stun_get_win32_addrs(nr_local_addr addrs
    done:
     *count = n;
     _status = 0;
 
   abort:
     RFREE(AdapterAddresses);
     return _status;
 }
-#endif  /* GET_WIN32_ADDRS_NO_WIN2K */
 
-#elif defined(__sparc__)
+#else /* WIN32 */
 
 static int
-stun_get_sparc_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
-{
-    *count = 0;
-    UNIMPLEMENTED; /*TODO !nn! - sparc */
-    return 0;
-}
-
-#else
+nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr);
 
 static int
-stun_get_siocgifconf_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
+stun_getifaddrs(nr_local_addr addrs[], int maxaddrs, int *count)
 {
-   struct ifconf ifc;
-   int _status;
-   int s = socket( AF_INET, SOCK_DGRAM, 0 );
-   int len = 100 * sizeof(struct ifreq);
-   int r;
-   int e;
-   char *ptr;
-   int tl;
-   int n;
-   struct ifreq ifr2;
+  int r,_status;
+  struct ifaddrs* if_addrs_head=NULL;
+  struct ifaddrs* if_addr;
 
-   char buf[ len ];
-
-   ifc.ifc_len = len;
-   ifc.ifc_buf = buf;
-
-   e = ioctl(s,SIOCGIFCONF,&ifc);
+  *count=0;
 
-   if ( e == -1 )
-   {
-      return(R_INTERNAL);
-   }
+  if (getifaddrs(&if_addrs_head) == -1) {
+    r_log(NR_LOG_STUN, LOG_ERR, "getifaddrs error e = %d", errno);
+    ABORT(R_INTERNAL);
+  }
 
-   ptr = buf;
-   tl = ifc.ifc_len;
-   n=0;
+  if_addr = if_addrs_head;
 
-   while ( (tl > 0) && ( n < maxaddrs) )
-   {
-      struct ifreq* ifr = (struct ifreq *)ptr;
-
-#ifdef LINUX
-      int si = sizeof(struct ifreq);
-#ifndef ANDROID
-      struct ethtool_cmd ecmd;
-      struct iwreq wrq;
-#endif
-#else
-      int si = sizeof(ifr->ifr_name) + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr));
-#endif
-      tl -= si;
-      ptr += si;
+  while (if_addr && *count < maxaddrs) {
+    switch (if_addr->ifa_addr->sa_family) {
+      case AF_INET:
+      case AF_INET6:
+        if (r=nr_sockaddr_to_transport_addr(if_addr->ifa_addr, IPPROTO_UDP, 0, &(addrs[*count].addr))) {
+          r_log(NR_LOG_STUN, LOG_ERR, "nr_sockaddr_to_transport_addr error r = %d", r);
+        } else {
+#if defined(LINUX) && !defined(ANDROID)
+          struct ethtool_cmd ecmd;
+          struct ifreq ifr;
+          struct iwreq wrq;
+          int e;
+          int s = socket(AF_INET, SOCK_DGRAM, 0);
 
-      ifr2 = *ifr;
-
-      e = ioctl(s,SIOCGIFADDR,&ifr2);
-      if ( e == -1 )
-      {
-          continue;
-      }
-
-      //r_log(NR_LOG_STUN, LOG_ERR, "ioctl addr e = %d",e);
-
-      if ((r=nr_sockaddr_to_transport_addr(&ifr2.ifr_addr, sizeof(ifr2.ifr_addr), IPPROTO_UDP, 0, &(addrs[n].addr)))) {
-          r_log(NR_LOG_STUN, LOG_WARNING, "Problem transforming address");
-      }
-      else {
-          addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
-          addrs[n].interface.estimated_speed = 0;
-#if defined(LINUX) && !defined(ANDROID)
+          strncpy(ifr.ifr_name, if_addr->ifa_name, sizeof(ifr.ifr_name));
           /* TODO (Bug 896851): interface property for Android */
           /* Getting ethtool for ethernet information. */
           ecmd.cmd = ETHTOOL_GSET;
-          ifr2.ifr_data = (void*)&ecmd;
-          e = ioctl(s, SIOCETHTOOL, &ifr2);
+          /* In/out param */
+          ifr.ifr_data = (void*)&ecmd;
+
+          e = ioctl(s, SIOCETHTOOL, &ifr);
           if (e == 0)
           {
              /* For wireless network, we won't get ethtool, it's a wired
-                connection */
-             addrs[n].interface.type = NR_INTERFACE_TYPE_WIRED;
+              * connection */
+             addrs[*count].interface.type = NR_INTERFACE_TYPE_WIRED;
 #ifdef DONT_HAVE_ETHTOOL_SPEED_HI
-             addrs[n].interface.estimated_speed = ecmd.speed;
+             addrs[*count].interface.estimated_speed = ecmd.speed;
 #else
-             addrs[n].interface.estimated_speed = ((ecmd.speed_hi << 16) | ecmd.speed) * 1000;
+             addrs[*count].interface.estimated_speed = ((ecmd.speed_hi << 16) | ecmd.speed) * 1000;
 #endif
           }
 
-          strncpy(wrq.ifr_name, ifr->ifr_name, sizeof(wrq.ifr_name));
+          strncpy(wrq.ifr_name, if_addr->ifa_name, sizeof(wrq.ifr_name));
           e = ioctl(s, SIOCGIWRATE, &wrq);
           if (e == 0)
           {
-             addrs[n].interface.type = NR_INTERFACE_TYPE_WIFI;
-             addrs[n].interface.estimated_speed = wrq.u.bitrate.value / 1000;
+             addrs[*count].interface.type = NR_INTERFACE_TYPE_WIFI;
+             addrs[*count].interface.estimated_speed = wrq.u.bitrate.value / 1000;
           }
 
-          ifr2 = *ifr;
-          e = ioctl(s, SIOCGIFFLAGS, &ifr2);
-          if (e == 0)
+          if (if_addr->ifa_flags & IFF_POINTOPOINT)
           {
-             if (ifr2.ifr_flags & IFF_POINTOPOINT)
-             {
-                addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN | NR_INTERFACE_TYPE_VPN;
-                /* TODO (Bug 896913): find backend network type of this VPN */
-             }
+             addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN | NR_INTERFACE_TYPE_VPN;
+             /* TODO (Bug 896913): find backend network type of this VPN */
           }
+#else
+          addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
+          addrs[*count].interface.estimated_speed = 0;
 #endif
-          strlcpy(addrs[n].addr.ifname, ifr->ifr_name, sizeof(addrs[n].addr.ifname));
-          ++n;
-      }
-   }
+          strlcpy(addrs[*count].addr.ifname, if_addr->ifa_name, sizeof(addrs[*count].addr.ifname));
+          ++(*count);
+        }
+        break;
+      default:
+        ;
+    }
 
-   close(s);
-
-   *count = n;
+    if_addr = if_addr->ifa_next;
+  }
 
-    _status = 0;
-    return _status;
+  _status=0;
+abort:
+  if (if_addrs_head) {
+    freeifaddrs(if_addrs_head);
+  }
+  return(_status);
 }
+
 #endif
 
 static int
 nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr)
 {
     int i;
     int different;
 
@@ -719,17 +342,17 @@ nr_stun_is_duplicate_addr(nr_local_addr 
         if (!different)
             return 1;  /* duplicate */
     }
 
     return 0;
 }
 
 int
-nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int *count)
+nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int remove_link_local, int *count)
 {
     int r, _status;
     nr_local_addr *tmp = 0;
     int i;
     int n;
 
     tmp = RMALLOC(*count * sizeof(*tmp));
     if (!tmp)
@@ -738,16 +361,21 @@ nr_stun_remove_duplicate_addrs(nr_local_
     n = 0;
     for (i = 0; i < *count; ++i) {
         if (nr_stun_is_duplicate_addr(tmp, n, &addrs[i])) {
             /* skip addrs[i], it's a duplicate */
         }
         else if (remove_loopback && nr_transport_addr_is_loopback(&addrs[i].addr)) {
             /* skip addrs[i], it's a loopback */
         }
+        else if (remove_link_local &&
+                 addrs[i].addr.ip_version == NR_IPV6 &&
+                 nr_transport_addr_is_link_local(&addrs[i].addr)) {
+            /* skip addrs[i], it's a link-local address */
+        }
         else {
             /* otherwise, copy it to the temporary array */
             if ((r=nr_local_addr_copy(&tmp[n], &addrs[i])))
                 ABORT(r);
             ++n;
         }
     }
 
@@ -763,33 +391,29 @@ nr_stun_remove_duplicate_addrs(nr_local_
   abort:
     RFREE(tmp);
     return _status;
 }
 
 #ifndef USE_PLATFORM_NR_STUN_GET_ADDRS
 
 int
-nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int drop_loopback, int *count)
+nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int drop_loopback, int drop_link_local, int *count)
 {
     int _status=0;
     int i;
     char typestr[100];
 
-#if defined(BSD) || defined(DARWIN)
-    _status = stun_get_mib_addrs(addrs, maxaddrs, count);
-#elif defined(WIN32)
+#ifdef WIN32
     _status = stun_get_win32_addrs(addrs, maxaddrs, count);
-#elif defined(__sparc__)
-    _status = stun_get_sparc_addrs(addrs, maxaddrs, count);
 #else
-    _status = stun_get_siocgifconf_addrs(addrs, maxaddrs, count);
+    _status = stun_getifaddrs(addrs, maxaddrs, count);
 #endif
 
-    nr_stun_remove_duplicate_addrs(addrs, drop_loopback, count);
+    nr_stun_remove_duplicate_addrs(addrs, drop_loopback, drop_link_local, count);
 
     for (i = 0; i < *count; ++i) {
     nr_local_addr_fmt_info_string(addrs+i,typestr,sizeof(typestr));
         r_log(NR_LOG_STUN, LOG_DEBUG, "Address %d: %s on %s, type: %s\n",
             i,addrs[i].addr.as_string,addrs[i].addr.ifname,typestr);
     }
 
     return _status;
--- a/media/mtransport/third_party/nICEr/src/stun/addrs.h
+++ b/media/mtransport/third_party/nICEr/src/stun/addrs.h
@@ -32,12 +32,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
 
 #ifndef _addrs_h_
 #define _addrs_h_
 
 #include "transport_addr.h"
 #include "local_addr.h"
 
-int nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int remove_loopback, int *count);
-int nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback,int *count);
+int nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int remove_loopback, int remove_link_local, int *count);
+int nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int remove_link_local, int *count);
 
 #endif
copy from media/webrtc/trunk/webrtc/base/ifaddrs-android.cc
copy to media/mtransport/third_party/nICEr/src/stun/ifaddrs-android.c
--- a/media/webrtc/trunk/webrtc/base/ifaddrs-android.cc
+++ b/media/mtransport/third_party/nICEr/src/stun/ifaddrs-android.c
@@ -1,223 +1,242 @@
 /*
- *  Copyright 2012 The WebRTC Project Authors. All rights reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
+Copyright (c) 2011, The WebRTC project authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
 
-#if defined(WEBRTC_ANDROID)
-#include "webrtc/base/ifaddrs-android.h"
+  * Neither the name of Google nor the names of its contributors may
+    be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if defined(ANDROID)
+#include "ifaddrs-android.h"
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/utsname.h>
 #include <sys/ioctl.h>
 #include <netinet/in.h>
 #include <net/if.h>
 #include <unistd.h>
 #include <errno.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 
-namespace {
-
 struct netlinkrequest {
-  nlmsghdr header;
-  ifaddrmsg msg;
+  struct nlmsghdr header;
+  struct ifaddrmsg msg;
 };
 
-const int kMaxReadSize = 4096;
-
-}  // namespace
+static const int kMaxReadSize = 4096;
 
-namespace rtc {
-
-int set_ifname(struct ifaddrs* ifaddr, int interface) {
+static int set_ifname(struct ifaddrs* ifaddr, int interface) {
   char buf[IFNAMSIZ] = {0};
   char* name = if_indextoname(interface, buf);
   if (name == NULL) {
     return -1;
   }
-  ifaddr->ifa_name = new char[strlen(name) + 1];
+  ifaddr->ifa_name = malloc(strlen(name) + 1);
   strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
   return 0;
 }
 
-int set_flags(struct ifaddrs* ifaddr) {
+static int set_flags(struct ifaddrs* ifaddr) {
   int fd = socket(AF_INET, SOCK_DGRAM, 0);
   if (fd == -1) {
     return -1;
   }
-  ifreq ifr;
+  struct ifreq ifr;
   memset(&ifr, 0, sizeof(ifr));
   strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
   int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
   close(fd);
   if (rc == -1) {
     return -1;
   }
   ifaddr->ifa_flags = ifr.ifr_flags;
   return 0;
 }
 
-int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data,
+static int set_addresses(struct ifaddrs* ifaddr, struct ifaddrmsg* msg, void* data,
                   size_t len) {
   if (msg->ifa_family == AF_INET) {
-    sockaddr_in* sa = new sockaddr_in;
+    struct sockaddr_in* sa = malloc(sizeof(struct sockaddr_in));
+    memset(sa, 0, sizeof(struct sockaddr_in));
     sa->sin_family = AF_INET;
     memcpy(&sa->sin_addr, data, len);
-    ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
+    ifaddr->ifa_addr = (struct sockaddr*)sa;
   } else if (msg->ifa_family == AF_INET6) {
-    sockaddr_in6* sa = new sockaddr_in6;
+    struct sockaddr_in6* sa = malloc(sizeof(struct sockaddr_in6));
+    memset(sa, 0, sizeof(struct sockaddr_in6));
     sa->sin6_family = AF_INET6;
     sa->sin6_scope_id = msg->ifa_index;
     memcpy(&sa->sin6_addr, data, len);
-    ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
+    ifaddr->ifa_addr = (struct sockaddr*)sa;
   } else {
     return -1;
   }
   return 0;
 }
 
-int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
+static int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
   char* prefix = NULL;
   if (family == AF_INET) {
-    sockaddr_in* mask = new sockaddr_in;
+    struct sockaddr_in* mask = malloc(sizeof(struct sockaddr_in));
+    memset(mask, 0, sizeof(struct sockaddr_in));
     mask->sin_family = AF_INET;
-    memset(&mask->sin_addr, 0, sizeof(in_addr));
-    ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
+    memset(&mask->sin_addr, 0, sizeof(struct in_addr));
+    ifaddr->ifa_netmask = (struct sockaddr*)mask;
     if (prefixlen > 32) {
       prefixlen = 32;
     }
-    prefix = reinterpret_cast<char*>(&mask->sin_addr);
+    prefix = (char*)&mask->sin_addr;
   } else if (family == AF_INET6) {
-    sockaddr_in6* mask = new sockaddr_in6;
+    struct sockaddr_in6* mask = malloc(sizeof(struct sockaddr_in6));
+    memset(mask, 0, sizeof(struct sockaddr_in6));
     mask->sin6_family = AF_INET6;
-    memset(&mask->sin6_addr, 0, sizeof(in6_addr));
-    ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
+    memset(&mask->sin6_addr, 0, sizeof(struct in6_addr));
+    ifaddr->ifa_netmask = (struct sockaddr*)mask;
     if (prefixlen > 128) {
       prefixlen = 128;
     }
-    prefix = reinterpret_cast<char*>(&mask->sin6_addr);
+    prefix = (char*)&mask->sin6_addr;
   } else {
     return -1;
   }
   for (int i = 0; i < (prefixlen / 8); i++) {
     *prefix++ = 0xFF;
   }
   char remainder = 0xff;
   remainder <<= (8 - prefixlen % 8);
   *prefix = remainder;
   return 0;
 }
 
-int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes,
+static int populate_ifaddrs(struct ifaddrs* ifaddr, struct ifaddrmsg* msg, void* bytes,
                      size_t len) {
   if (set_ifname(ifaddr, msg->ifa_index) != 0) {
     return -1;
   }
   if (set_flags(ifaddr) != 0) {
     return -1;
   }
   if (set_addresses(ifaddr, msg, bytes, len) != 0) {
     return -1;
   }
   if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) {
     return -1;
   }
   return 0;
 }
 
-int getifaddrs(struct ifaddrs** result) {
+int android_getifaddrs(struct ifaddrs** result) {
   int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
   if (fd < 0) {
     return -1;
   }
 
-  netlinkrequest ifaddr_request;
+  struct netlinkrequest ifaddr_request;
   memset(&ifaddr_request, 0, sizeof(ifaddr_request));
   ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
   ifaddr_request.header.nlmsg_type = RTM_GETADDR;
-  ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg));
+  ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
 
   ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
-  if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) {
+  if ((size_t)count != ifaddr_request.header.nlmsg_len) {
     close(fd);
     return -1;
   }
   struct ifaddrs* start = NULL;
   struct ifaddrs* current = NULL;
   char buf[kMaxReadSize];
   ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
   while (amount_read > 0) {
-    nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]);
-    size_t header_size = static_cast<size_t>(amount_read);
+    struct nlmsghdr* header = (struct nlmsghdr*)&buf[0];
+    size_t header_size = (size_t)amount_read;
     for ( ; NLMSG_OK(header, header_size);
           header = NLMSG_NEXT(header, header_size)) {
       switch (header->nlmsg_type) {
         case NLMSG_DONE:
-          // Success. Return.
+          /* Success. Return. */
           *result = start;
           close(fd);
           return 0;
         case NLMSG_ERROR:
           close(fd);
-          freeifaddrs(start);
+          android_freeifaddrs(start);
           return -1;
         case RTM_NEWADDR: {
-          ifaddrmsg* address_msg =
-              reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
-          rtattr* rta = IFA_RTA(address_msg);
+          struct ifaddrmsg* address_msg =
+              (struct ifaddrmsg*)NLMSG_DATA(header);
+          struct rtattr* rta = IFA_RTA(address_msg);
           ssize_t payload_len = IFA_PAYLOAD(header);
           while (RTA_OK(rta, payload_len)) {
             if (rta->rta_type == IFA_ADDRESS) {
               int family = address_msg->ifa_family;
               if (family == AF_INET || family == AF_INET6) {
-                ifaddrs* newest = new ifaddrs;
-                memset(newest, 0, sizeof(ifaddrs));
+                struct ifaddrs* newest = malloc(sizeof(struct ifaddrs));
+                memset(newest, 0, sizeof(struct ifaddrs));
                 if (current) {
                   current->ifa_next = newest;
                 } else {
                   start = newest;
                 }
                 if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta),
                                      RTA_PAYLOAD(rta)) != 0) {
-                  freeifaddrs(start);
+                  android_freeifaddrs(start);
                   *result = NULL;
                   return -1;
                 }
                 current = newest;
               }
             }
             rta = RTA_NEXT(rta, payload_len);
           }
           break;
         }
       }
     }
     amount_read = recv(fd, &buf, kMaxReadSize, 0);
   }
   close(fd);
-  freeifaddrs(start);
+  android_freeifaddrs(start);
   return -1;
 }
 
-void freeifaddrs(struct ifaddrs* addrs) {
+void android_freeifaddrs(struct ifaddrs* addrs) {
   struct ifaddrs* last = NULL;
   struct ifaddrs* cursor = addrs;
   while (cursor) {
-    delete[] cursor->ifa_name;
-    delete cursor->ifa_addr;
-    delete cursor->ifa_netmask;
+    free(cursor->ifa_name);
+    free(cursor->ifa_addr);
+    free(cursor->ifa_netmask);
     last = cursor;
     cursor = cursor->ifa_next;
-    delete last;
+    free(last);
   }
 }
 
-}  // namespace rtc
-#endif  // defined(WEBRTC_ANDROID)
+#endif  /* defined(ANDROID) */
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/stun/ifaddrs-android.h
@@ -0,0 +1,57 @@
+/*
+Copyright (c) 2011, The WebRTC project authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+  * Neither the name of Google nor the names of its contributors may
+    be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef WEBRTC_BASE_IFADDRS_ANDROID_H_
+#define WEBRTC_BASE_IFADDRS_ANDROID_H_
+
+#include <stdio.h>
+#include <sys/socket.h>
+
+/* Implementation of getifaddrs for Android.
+ * Fills out a list of ifaddr structs (see below) which contain information
+ * about every network interface available on the host.
+ * See 'man getifaddrs' on Linux or OS X (nb: it is not a POSIX function). */
+struct ifaddrs {
+  struct ifaddrs* ifa_next;
+  char* ifa_name;
+  unsigned int ifa_flags;
+  struct sockaddr* ifa_addr;
+  struct sockaddr* ifa_netmask;
+  /* Real ifaddrs has broadcast, point to point and data members.
+   * We don't need them (yet?). */
+};
+
+int android_getifaddrs(struct ifaddrs** result);
+void android_freeifaddrs(struct ifaddrs* addrs);
+
+#endif  /* WEBRTC_BASE_IFADDRS_ANDROID_H_ */
+
--- a/media/mtransport/third_party/nICEr/src/stun/stun_codec.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_codec.c
@@ -441,19 +441,25 @@ nr_stun_attr_codec_addr_encode(nr_stun_a
          || nr_stun_encode(&pad, 1               , buflen, buf, &offset)
          || nr_stun_encode(&family, 1            , buflen, buf, &offset)
          || nr_stun_encode_htons(ntohs(addr->u.addr4.sin_port), buflen, buf, &offset)
          || nr_stun_encode_htonl(ntohl(addr->u.addr4.sin_addr.s_addr), buflen, buf, &offset))
             ABORT(R_FAILED);
         break;
 
     case NR_IPV6:
-        assert(0);
-        ABORT(R_INTERNAL);
+        family = NR_STUN_IPV6_FAMILY;
+        if (nr_stun_encode_htons(20              , buflen, buf, &offset)
+         || nr_stun_encode(&pad, 1               , buflen, buf, &offset)
+         || nr_stun_encode(&family, 1            , buflen, buf, &offset)
+         || nr_stun_encode_htons(ntohs(addr->u.addr6.sin6_port), buflen, buf, &offset)
+         || nr_stun_encode(addr->u.addr6.sin6_addr.s6_addr, 16, buflen, buf, &offset))
+            ABORT(R_FAILED);
         break;
+
     default:
         assert(0);
         ABORT(R_INTERNAL);
         break;
     }
 
     *attrlen = offset - start;
 
@@ -465,16 +471,17 @@ nr_stun_attr_codec_addr_encode(nr_stun_a
 static int
 nr_stun_attr_codec_addr_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
 {
     int _status;
     UCHAR pad;
     UCHAR family;
     UINT2 port;
     UINT4 addr4;
+    struct in6_addr addr6;
     nr_transport_addr *result = data;
 
     if (nr_stun_decode(1, buf, buflen, &offset, &pad)
      || nr_stun_decode(1, buf, buflen, &offset, &family))
         ABORT(R_FAILED);
 
     switch (family) {
     case NR_STUN_IPV4_FAMILY:
@@ -487,27 +494,27 @@ nr_stun_attr_codec_addr_decode(nr_stun_a
          || nr_stun_decode_htonl(buf, buflen, &offset, &addr4))
             ABORT(R_FAILED);
 
         if (nr_ip4_port_to_transport_addr(addr4, port, IPPROTO_UDP, result))
             ABORT(R_FAILED);
         break;
 
     case NR_STUN_IPV6_FAMILY:
-        if (attrlen != 16) {
+        if (attrlen != 20) {
             r_log(NR_LOG_STUN, LOG_WARNING, "Illegal attribute length: %d", attrlen);
             ABORT(R_FAILED);
         }
 
-        r_log(NR_LOG_STUN, LOG_WARNING, "IPv6 not supported");
-#ifdef NDEBUG
-        ABORT(SKIP_ATTRIBUTE_DECODE);
-#else
-        UNIMPLEMENTED;
-#endif /* NDEBUG */
+        if (nr_stun_decode_htons(buf, buflen, &offset, &port)
+         || nr_stun_decode(16, buf, buflen, &offset, addr6.s6_addr))
+            ABORT(R_FAILED);
+
+        if (nr_ip6_port_to_transport_addr(&addr6, port, IPPROTO_UDP, result))
+            ABORT(R_FAILED);
         break;
 
     default:
         r_log(NR_LOG_STUN, LOG_WARNING, "Illegal address family: %d", family);
         ABORT(R_FAILED);
         break;
     }
 
@@ -1089,17 +1096,17 @@ nr_stun_attr_codec_xor_mapped_address_en
     r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
 
     /* this needs to be the magic cookie in the header and not
      * the MAGIC_COOKIE constant because if we're talking to
      * older servers (that don't have a magic cookie) they use
      * message ID for this */
     magic_cookie = ntohl(header->magic_cookie);
 
-    nr_stun_xor_mapped_address(magic_cookie, &xor_mapped_address->unmasked, &xor_mapped_address->masked);
+    nr_stun_xor_mapped_address(magic_cookie, header->id, &xor_mapped_address->unmasked, &xor_mapped_address->masked);
 
     r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
 
     if (nr_stun_attr_codec_addr.encode(attr_info, &xor_mapped_address->masked, offset, buflen, buf, attrlen))
         return R_FAILED;
 
     return 0;
 }
@@ -1118,17 +1125,17 @@ nr_stun_attr_codec_xor_mapped_address_de
     r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
 
     /* this needs to be the magic cookie in the header and not
      * the MAGIC_COOKIE constant because if we're talking to
      * older servers (that don't have a magic cookie) they use
      * message ID for this */
     magic_cookie = ntohl(header->magic_cookie);
 
-    nr_stun_xor_mapped_address(magic_cookie, &xor_mapped_address->masked, &xor_mapped_address->unmasked);
+    nr_stun_xor_mapped_address(magic_cookie, header->id, &xor_mapped_address->masked, &xor_mapped_address->unmasked);
 
     r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
 
     _status = 0;
   abort:
     return _status;
 }
 
--- a/media/mtransport/third_party/nICEr/src/stun/stun_reg.h
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_reg.h
@@ -40,16 +40,17 @@ extern "C" {
 #endif /* __cplusplus */
 
 #define NR_STUN_REG_PREF_CLNT_RETRANSMIT_TIMEOUT    "stun.client.retransmission_timeout"
 #define NR_STUN_REG_PREF_CLNT_RETRANSMIT_BACKOFF    "stun.client.retransmission_backoff_factor"
 #define NR_STUN_REG_PREF_CLNT_MAXIMUM_TRANSMITS     "stun.client.maximum_transmits"
 #define NR_STUN_REG_PREF_CLNT_FINAL_RETRANSMIT_BACKOFF   "stun.client.final_retransmit_backoff"
 
 #define NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS            "stun.allow_loopback"
+#define NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS     "stun.allow_link_local"
 #define NR_STUN_REG_PREF_ADDRESS_PRFX               "stun.address"
 #define NR_STUN_REG_PREF_SERVER_NAME                "stun.server.name"
 #define NR_STUN_REG_PREF_SERVER_NONCE_SIZE          "stun.server.nonce_size"
 #define NR_STUN_REG_PREF_SERVER_REALM               "stun.server.realm"
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
--- a/media/mtransport/third_party/nICEr/src/stun/stun_util.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_util.c
@@ -66,30 +66,48 @@ nr_stun_startup(void)
       ABORT(r);
 
    _status=0;
  abort:
    return _status;
 }
 
 int
-nr_stun_xor_mapped_address(UINT4 magicCookie, nr_transport_addr *from, nr_transport_addr *to)
+nr_stun_xor_mapped_address(UINT4 magicCookie, UINT12 transactionId, nr_transport_addr *from, nr_transport_addr *to)
 {
     int _status;
 
     switch (from->ip_version) {
     case NR_IPV4:
         nr_ip4_port_to_transport_addr(
             (ntohl(from->u.addr4.sin_addr.s_addr) ^ magicCookie),
             (ntohs(from->u.addr4.sin_port) ^ (magicCookie>>16)),
             from->protocol, to);
         break;
     case NR_IPV6:
-        assert(0);
-        ABORT(R_INTERNAL);
+        {
+          union {
+            unsigned char addr[16];
+            UINT4 addr32[4];
+          } maskedAddr;
+
+          maskedAddr.addr32[0] = htonl(magicCookie); /* Passed in host byte order */
+          memcpy(&maskedAddr.addr32[1], transactionId.octet, sizeof(transactionId));
+
+          /* We now have the mask in network byte order */
+          /* Xor the address in network byte order */
+          for (int i = 0; i < sizeof(maskedAddr); ++i) {
+            maskedAddr.addr[i] ^= from->u.addr6.sin6_addr.s6_addr[i];
+          }
+
+          nr_ip6_port_to_transport_addr(
+              (struct in6_addr*)&maskedAddr,
+              (ntohs(from->u.addr6.sin6_port) ^ (magicCookie>>16)),
+              from->protocol, to);
+        }
         break;
     default:
         assert(0);
         ABORT(R_INTERNAL);
         break;
     }
 
     _status = 0;
@@ -106,25 +124,33 @@ nr_stun_find_local_addresses(nr_local_ad
     if ((r=NR_reg_get_child_count(NR_STUN_REG_PREF_ADDRESS_PRFX, (unsigned int*)count)))
         if (r == R_NOT_FOUND)
             *count = 0;
         else
             ABORT(r);
 
     if (*count == 0) {
         char allow_loopback;
+        char allow_link_local;
 
         if ((r=NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, &allow_loopback))) {
             if (r == R_NOT_FOUND)
                 allow_loopback = 0;
             else
                 ABORT(r);
         }
 
-        if ((r=nr_stun_get_addrs(addrs, maxaddrs, !allow_loopback, count)))
+        if ((r=NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS, &allow_link_local))) {
+            if (r == R_NOT_FOUND)
+                allow_link_local = 0;
+            else
+                ABORT(r);
+        }
+
+        if ((r=nr_stun_get_addrs(addrs, maxaddrs, !allow_loopback, !allow_link_local, count)))
             ABORT(r);
 
         goto done;
     }
 
     if (*count >= maxaddrs) {
         r_log(NR_LOG_STUN, LOG_INFO, "Address list truncated from %d to %d", *count, maxaddrs);
        *count = maxaddrs;
--- a/media/mtransport/third_party/nICEr/src/stun/stun_util.h
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_util.h
@@ -37,17 +37,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
 #include "stun.h"
 #include "local_addr.h"
 
 extern int NR_LOG_STUN;
 
 int nr_stun_startup(void);
 
-int nr_stun_xor_mapped_address(UINT4 magicCookie, nr_transport_addr *from, nr_transport_addr *to);
+int nr_stun_xor_mapped_address(UINT4 magicCookie, UINT12 transactionId, nr_transport_addr *from, nr_transport_addr *to);
 
 int nr_stun_find_local_addresses(nr_local_addr addrs[], int maxaddrs, int *count);
 
 int nr_stun_different_transaction(UCHAR *msg, int len, nr_stun_message *req);
 
 char* nr_stun_msg_type(int type);
 
 int nr_random_alphanum(char *alphanum, int size);
--- a/media/mtransport/third_party/nrappkit/src/util/util.c
+++ b/media/mtransport/third_party/nrappkit/src/util/util.c
@@ -719,16 +719,41 @@ inet_ntop6(const unsigned char *src, cha
     errno = ENOSPC;
     return (NULL);
   }
   strlcpy(dst, tmp, size);
   return (dst);
 }
 #endif /* INET6 */
 
+#ifdef WIN32
+/* Not exactly, will forgive stuff like <addr>:<port> */
+int inet_pton(int af, const char *src, void *dst)
+{
+  struct sockaddr_storage ss;
+  int addrlen = sizeof(ss);
+
+  if (af != AF_INET && af != AF_INET6) {
+    return -1;
+  }
+
+  if (!WSAStringToAddressA(src, af, NULL, (struct sockaddr*)&ss, &addrlen)) {
+    if (af == AF_INET) {
+      struct sockaddr_in *in = (struct sockaddr_in*)&ss;
+      memcpy(dst, &in->sin_addr, sizeof(struct in_addr));
+    } else {
+      struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&ss;
+      memcpy(dst, &in6->sin6_addr, sizeof(struct in6_addr));
+    }
+    return 1;
+  }
+  return 0;
+}
+#endif /* WIN32 */
+
 #endif
 
 #ifdef WIN32
 #include <time.h>
 /* this is only millisecond-accurate, but that should be OK */
 
 int gettimeofday(struct timeval *tv, void *tz)
   {
--- a/media/mtransport/third_party/nrappkit/src/util/util.h
+++ b/media/mtransport/third_party/nrappkit/src/util/util.h
@@ -62,12 +62,13 @@ int nr_rm_tree(char *path);
 int nr_write_pid_file(char *pid_filename);
 
 int nr_reg_uint4_fetch_and_check(NR_registry key, UINT4 min, UINT4 max, int log_fac, int die, UINT4 *val);
 int nr_reg_uint8_fetch_and_check(NR_registry key, UINT8 min, UINT8 max, int log_fac, int die, UINT8 *val);
 
 #ifdef WIN32
 int snprintf(char *buffer, size_t n, const char *format, ...);
 const char *inet_ntop(int af, const void *src, char *dst, size_t size);
+int inet_pton(int af, const char *src, void *dst);
 #endif
 
 #endif
 
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -371,16 +371,17 @@ PeerConnectionImpl::PeerConnectionImpl(c
   , mIceConnectionState(PCImplIceConnectionState::New)
   , mIceGatheringState(PCImplIceGatheringState::New)
   , mDtlsConnected(false)
   , mWindow(nullptr)
   , mIdentity(nullptr)
   , mPrivacyRequested(false)
   , mSTSThread(nullptr)
   , mAllowIceLoopback(false)
+  , mAllowIceLinkLocal(false)
   , mMedia(nullptr)
   , mUuidGen(MakeUnique<PCUuidGenerator>())
   , mNumAudioStreams(0)
   , mNumVideoStreams(0)
   , mHaveDataStream(false)
   , mAddCandidateErrorCount(0)
   , mTrickle(true) // TODO(ekr@rtfm.com): Use pref
   , mShouldSuppressNegotiationNeeded(false)
@@ -392,16 +393,18 @@ PeerConnectionImpl::PeerConnectionImpl(c
   }
 #endif
   CSFLogInfo(logTag, "%s: PeerConnectionImpl constructor for %s",
              __FUNCTION__, mHandle.c_str());
   STAMP_TIMECARD(mTimeCard, "Constructor Completed");
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
   mAllowIceLoopback = Preferences::GetBool(
     "media.peerconnection.ice.loopback", false);
+  mAllowIceLinkLocal = Preferences::GetBool(
+    "media.peerconnection.ice.link_local", false);
 #endif
 }
 
 PeerConnectionImpl::~PeerConnectionImpl()
 {
   if (mTimeCard) {
     STAMP_TIMECARD(mTimeCard, "Destructor Invoked");
     print_timecard(mTimeCard);
@@ -727,17 +730,16 @@ PeerConnectionImpl::Initialize(PeerConne
     if (NS_FAILED(res)) {
       CSFLogError(logTag, "%s: Invalid RTCConfiguration", __FUNCTION__);
       return res;
     }
     aConfiguration = &converted;
   }
 
   mMedia = new PeerConnectionMedia(this);
-  mMedia->SetAllowIceLoopback(mAllowIceLoopback);
 
   // Connect ICE slots.
   mMedia->SignalIceGatheringStateChange.connect(
       this,
       &PeerConnectionImpl::IceGatheringStateChange);
   mMedia->SignalEndOfLocalCandidates.connect(
       this,
       &PeerConnectionImpl::EndOfLocalCandidates);
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -282,16 +282,21 @@ public:
   // Get the media object
   const nsRefPtr<PeerConnectionMedia>& media() const {
     PC_AUTO_ENTER_API_CALL_NO_CHECK();
     return mMedia;
   }
 
   // Configure the ability to use localhost.
   void SetAllowIceLoopback(bool val) { mAllowIceLoopback = val; }
+  bool GetAllowIceLoopback() const { return mAllowIceLoopback; }
+
+  // Configure the ability to use IPV6 link-local addresses.
+  void SetAllowIceLinkLocal(bool val) { mAllowIceLinkLocal = val; }
+  bool GetAllowIceLinkLocal() const { return mAllowIceLinkLocal; }
 
   // Handle system to allow weak references to be passed through C code
   virtual const std::string& GetHandle();
 
   // Name suitable for exposing to content
   virtual const std::string& GetName();
 
   // ICE events
@@ -734,16 +739,17 @@ private:
   nsCOMPtr<nsIEventTarget> mSTSThread;
 
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
   // DataConnection that's used to get all the DataChannels
   nsRefPtr<mozilla::DataChannelConnection> mDataConnection;
 #endif
 
   bool mAllowIceLoopback;
+  bool mAllowIceLinkLocal;
   nsRefPtr<PeerConnectionMedia> mMedia;
 
   // The JSEP negotiation session.
   mozilla::UniquePtr<PCUuidGenerator> mUuidGen;
   mozilla::UniquePtr<mozilla::JsepSession> mJsepSession;
 
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
   // Start time of ICE, used for telemetry
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -214,17 +214,16 @@ PeerConnectionMedia::ProtocolProxyQueryH
 
 NS_IMPL_ISUPPORTS(PeerConnectionMedia::ProtocolProxyQueryHandler, nsIProtocolProxyCallback)
 #endif // !defined(MOZILLA_XPCOMRT_API)
 
 PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent)
     : mParent(parent),
       mParentHandle(parent->GetHandle()),
       mParentName(parent->GetName()),
-      mAllowIceLoopback(false),
       mIceCtx(nullptr),
       mDNSResolver(new NrIceResolver()),
       mUuidGen(MakeUnique<PCUuidGenerator>()),
       mMainThread(mParent->GetMainThread()),
       mSTSThread(mParent->GetSTSThread()),
       mProxyResolveCompleted(false) {
 }
 
@@ -306,18 +305,19 @@ nsresult PeerConnectionMedia::Init(const
   bool ice_tcp = false;
 #endif
 
   // TODO(ekr@rtfm.com): need some way to set not offerer later
   // Looks like a bug in the NrIceCtx API.
   mIceCtx = NrIceCtx::Create("PC:" + mParentName,
                              true, // Offerer
                              true, // Explicitly set priorities
-                             mAllowIceLoopback,
-                             ice_tcp);
+                             mParent->GetAllowIceLoopback(),
+                             ice_tcp,
+                             mParent->GetAllowIceLinkLocal());
   if(!mIceCtx) {
     CSFLogError(logTag, "%s: Failed to create Ice Context", __FUNCTION__);
     return NS_ERROR_FAILURE;
   }
 
   if (NS_FAILED(rv = mIceCtx->SetStunServers(stun_servers))) {
     CSFLogError(logTag, "%s: Failed to set stun servers", __FUNCTION__);
     return rv;
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -227,19 +227,16 @@ class PeerConnectionMedia : public sigsl
   explicit PeerConnectionMedia(PeerConnectionImpl *parent);
 
   PeerConnectionImpl* GetPC() { return mParent; }
   nsresult Init(const std::vector<NrIceStunServer>& stun_servers,
                 const std::vector<NrIceTurnServer>& turn_servers);
   // WARNING: This destroys the object!
   void SelfDestruct();
 
-  // Configure the ability to use localhost.
-  void SetAllowIceLoopback(bool val) { mAllowIceLoopback = val; }
-
   RefPtr<NrIceCtx> ice_ctx() const { return mIceCtx; }
 
   RefPtr<NrIceMediaStream> ice_media_stream(size_t i) const {
     return mIceCtx->GetStream(i);
   }
 
   size_t num_ice_media_streams() const {
     return mIceCtx->GetStreamCount();
@@ -486,19 +483,16 @@ class PeerConnectionMedia : public sigsl
   nsTArray<nsRefPtr<LocalSourceStreamInfo> > mLocalSourceStreams;
 
   // A list of streams provided by the other side
   // This is only accessed on the main thread (with one special exception)
   nsTArray<nsRefPtr<RemoteSourceStreamInfo> > mRemoteSourceStreams;
 
   std::map<size_t, std::pair<bool, RefPtr<MediaSessionConduit>>> mConduits;
 
-  // Allow loopback for ICE.
-  bool mAllowIceLoopback;
-
   // ICE objects
   RefPtr<NrIceCtx> mIceCtx;
 
   // DNS
   nsRefPtr<NrIceResolver> mDNSResolver;
 
   // Transport flows: even is RTP, odd is RTCP
   std::map<int, RefPtr<TransportFlow> > mTransportFlows;
--- a/media/webrtc/signaling/src/sdp/SdpMediaSection.h
+++ b/media/webrtc/signaling/src/sdp/SdpMediaSection.h
@@ -281,16 +281,21 @@ public:
   GetAddress() const
   {
     return mAddr;
   }
   void
   SetAddress(const std::string& address)
   {
     mAddr = address;
+    if (mAddr.find(':') != std::string::npos) {
+      mAddrType = sdp::kIPv6;
+    } else {
+      mAddrType = sdp::kIPv4;
+    }
   }
   uint8_t
   GetTtl() const
   {
     return mTtl;
   }
   uint32_t
   GetCount() const
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -908,16 +908,17 @@ class SignalingAgent {
     mRemoteDescriptionSet(false) {
     cfg_.addStunServer(stun_addr, stun_port, kNrIceTransportUdp);
     cfg_.addStunServer(stun_addr, stun_port, kNrIceTransportTcp);
 
     PeerConnectionImpl *pcImpl =
       PeerConnectionImpl::CreatePeerConnection();
     EXPECT_TRUE(pcImpl);
     pcImpl->SetAllowIceLoopback(true);
+    pcImpl->SetAllowIceLinkLocal(true);
     pc = new PCDispatchWrapper(pcImpl);
   }
 
 
   ~SignalingAgent() {
     mozilla::SyncRunnable::DispatchToThread(gMainThread,
       WrapRunnable(this, &SignalingAgent::Close));
   }
@@ -4704,17 +4705,17 @@ int main(int argc, char **argv) {
   NSS_NoDB_Init(nullptr);
   NSS_SetDomesticPolicy();
 
   ::testing::TestEventListeners& listeners =
         ::testing::UnitTest::GetInstance()->listeners();
   // Adds a listener to the end.  Google Test takes the ownership.
   listeners.Append(new test::RingbufferDumper(test_utils));
   test_utils->sts_target()->Dispatch(
-    WrapRunnableNM(&TestStunServer::GetInstance), NS_DISPATCH_SYNC);
+    WrapRunnableNM(&TestStunServer::GetInstance, AF_INET), NS_DISPATCH_SYNC);
 
   // Set the main thread global which is this thread.
   nsIThread *thread;
   NS_GetMainThread(&thread);
   gMainThread = thread;
   MOZ_ASSERT(NS_IsMainThread());
 
   // Now create the GTest thread and run all of the tests on it
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -370,16 +370,17 @@ pref("media.getusermedia.browser.enabled
 pref("media.peerconnection.video.min_bitrate", 200);
 pref("media.peerconnection.video.start_bitrate", 300);
 pref("media.peerconnection.video.max_bitrate", 2000);
 #endif
 pref("media.navigator.permission.disabled", false);
 pref("media.peerconnection.default_iceservers", "[]");
 pref("media.peerconnection.ice.loopback", false); // Set only for testing in offline environments.
 pref("media.peerconnection.ice.tcp", false);
+pref("media.peerconnection.ice.link_local", false); // Set only for testing IPV6 in networks that don't assign IPV6 addresses
 pref("media.peerconnection.use_document_iceservers", true);
 pref("media.peerconnection.identity.enabled", true);
 pref("media.peerconnection.identity.timeout", 10000);
 pref("media.peerconnection.ice.stun_client_maximum_transmits", 7);
 pref("media.peerconnection.ice.trickle_grace_period", 5000);
 // These values (aec, agc, and noice) are from media/webrtc/trunk/webrtc/common_types.h
 // kXxxUnchanged = 0, kXxxDefault = 1, and higher values are specific to each
 // setting (for Xxx = Ec, Agc, or Ns).  Defaults are all set to kXxxDefault here.