patch cl/351272707 without adding frame timings.
diff --git a/cpp/core/internal/bwu_manager.cc b/cpp/core/internal/bwu_manager.cc
index f7b38fe..d198a36 100644
--- a/cpp/core/internal/bwu_manager.cc
+++ b/cpp/core/internal/bwu_manager.cc
@@ -301,6 +301,13 @@
       return;
     }
 
+    if (!WriteClientIntroductionAckFrame(channel)) {
+      // This was never a fully EstablishedConnection, no need to provide a
+      // closure reason.
+      channel->Close();
+      return;
+    }
+
     const std::string& endpoint_id = introduction.endpoint_id();
     auto item = in_progress_upgrades_.extract(endpoint_id);
     if (item.empty()) return;
@@ -424,6 +431,22 @@
     return {};
   }
 
+  if (upgrade_path_info.supports_client_introduction_ack()) {
+    if (!ReadClientIntroductionAckFrame(channel.get())) {
+      // This was never a fully EstablishedConnection, no need to provide a
+      // closure reason.
+      channel->Close();
+
+      NEARBY_LOG(
+          ERROR,
+          "Failed to read BWU_NEGOTIATION.CLIENT_INTRODUCTION_ACK OfflineFrame "
+          "to newly-created EndpointChannel %s, aborting upgrade.",
+          channel->GetName().c_str());
+
+      return {};
+    }
+  }
+
   NEARBY_LOG(
       INFO,
       "Successfully wrote  BWU_NEGOTIATION.CLIENT_INTRODUCTION OfflineFrame to "
@@ -480,12 +503,33 @@
   OfflineFrame frame = transfer.result();
   if (!frame.has_v1() || !frame.v1().has_bandwidth_upgrade_negotiation())
     return false;
+  if (frame.v1().bandwidth_upgrade_negotiation().event_type() !=
+      BandwidthUpgradeNegotiationFrame::CLIENT_INTRODUCTION)
+    return false;
   const auto& frame_intro =
       frame.v1().bandwidth_upgrade_negotiation().client_introduction();
   introduction = frame_intro;
   return true;
 }
 
+bool BwuManager::ReadClientIntroductionAckFrame(EndpointChannel* channel) {
+  auto data = channel->Read();
+  if (!data.ok()) return false;
+  auto transfer(parser::FromBytes(data.result()));
+  if (!transfer.ok()) return false;
+  OfflineFrame frame = transfer.result();
+  if (!frame.has_v1() || !frame.v1().has_bandwidth_upgrade_negotiation())
+    return false;
+  if (frame.v1().bandwidth_upgrade_negotiation().event_type() !=
+      BandwidthUpgradeNegotiationFrame::CLIENT_INTRODUCTION_ACK)
+    return false;
+  return true;
+}
+
+bool BwuManager::WriteClientIntroductionAckFrame(EndpointChannel* channel) {
+  return channel->Write(parser::ForBwuIntroductionAck()).Ok();
+}
+
 void BwuManager::ProcessLastWriteToPriorChannelEvent(
     ClientProxy* client, const std::string& endpoint_id) {
   // By this point in the upgrade protocol, there is the guarantee that both
diff --git a/cpp/core/internal/bwu_manager.h b/cpp/core/internal/bwu_manager.h
index 9422313..45baa93 100644
--- a/cpp/core/internal/bwu_manager.h
+++ b/cpp/core/internal/bwu_manager.h
@@ -143,6 +143,8 @@
                                            const std::string& endpoint_id);
   bool ReadClientIntroductionFrame(EndpointChannel* endpoint_channel,
                                    ClientIntroduction& introduction);
+  bool ReadClientIntroductionAckFrame(EndpointChannel* endpoint_channel);
+  bool WriteClientIntroductionAckFrame(EndpointChannel* endpoint_channel);
   void ProcessEndpointDisconnection(ClientProxy* client,
                                     const std::string& endpoint_id,
                                     CountDownLatch* barrier);
diff --git a/cpp/core/internal/offline_frames.cc b/cpp/core/internal/offline_frames.cc
index 0064dcd..af83a03 100644
--- a/cpp/core/internal/offline_frames.cc
+++ b/cpp/core/internal/offline_frames.cc
@@ -160,6 +160,7 @@
       BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
   auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info();
   upgrade_path_info->set_medium(UpgradePathInfo::WIFI_HOTSPOT);
+  upgrade_path_info->set_supports_client_introduction_ack(true);
   upgrade_path_info->set_supports_disabling_encryption(
       supports_disabling_encryption);
   auto* wifi_hotspot_credentials =
@@ -184,6 +185,7 @@
       BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
   auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info();
   upgrade_path_info->set_medium(UpgradePathInfo::WIFI_LAN);
+  upgrade_path_info->set_supports_client_introduction_ack(true);
   auto* wifi_lan_socket = upgrade_path_info->mutable_wifi_lan_socket();
   wifi_lan_socket->set_ip_address(ip_address);
   wifi_lan_socket->set_wifi_port(port);
@@ -205,6 +207,7 @@
       BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
   auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info();
   upgrade_path_info->set_medium(UpgradePathInfo::WIFI_AWARE);
+  upgrade_path_info->set_supports_client_introduction_ack(true);
   upgrade_path_info->set_supports_disabling_encryption(
       supports_disabling_encryption);
   auto* wifi_aware_credentials =
@@ -231,6 +234,7 @@
       BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
   auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info();
   upgrade_path_info->set_medium(UpgradePathInfo::WIFI_DIRECT);
+  upgrade_path_info->set_supports_client_introduction_ack(true);
   upgrade_path_info->set_supports_disabling_encryption(
       supports_disabling_encryption);
   auto* wifi_direct_credentials =
@@ -255,6 +259,7 @@
       BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
   auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info();
   upgrade_path_info->set_medium(UpgradePathInfo::BLUETOOTH);
+  upgrade_path_info->set_supports_client_introduction_ack(true);
   auto* bluetooth_credentials =
       upgrade_path_info->mutable_bluetooth_credentials();
   bluetooth_credentials->set_mac_address(mac_address);
@@ -275,6 +280,7 @@
       BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
   auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info();
   upgrade_path_info->set_medium(UpgradePathInfo::WEB_RTC);
+  upgrade_path_info->set_supports_client_introduction_ack(true);
   auto* webrtc_credentials = upgrade_path_info->mutable_web_rtc_credentials();
   webrtc_credentials->set_peer_id(peer_id);
   auto* local_location_hint = webrtc_credentials->mutable_location_hint();
@@ -324,6 +330,19 @@
   return ToBytes(std::move(frame));
 }
 
+ByteArray ForBwuIntroductionAck() {
+  OfflineFrame frame;
+
+  frame.set_version(OfflineFrame::V1);
+  auto* v1_frame = frame.mutable_v1();
+  v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION);
+  auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation();
+  sub_frame->set_event_type(
+      BandwidthUpgradeNegotiationFrame::CLIENT_INTRODUCTION_ACK);
+
+  return ToBytes(std::move(frame));
+}
+
 ByteArray ForBwuFailure(const UpgradePathInfo& info) {
   OfflineFrame frame;
 
diff --git a/cpp/core/internal/offline_frames.h b/cpp/core/internal/offline_frames.h
index 0c5eb21..b8694d7 100644
--- a/cpp/core/internal/offline_frames.h
+++ b/cpp/core/internal/offline_frames.h
@@ -60,6 +60,7 @@
 
 // Builds Bandwidth Upgrade [BWU] messages.
 ByteArray ForBwuIntroduction(const std::string& endpoint_id);
+ByteArray ForBwuIntroductionAck();
 ByteArray ForBwuWifiHotspotPathAvailable(const std::string& ssid,
                                          const std::string& password,
                                          std::int32_t port,
diff --git a/cpp/core/internal/offline_frames_test.cc b/cpp/core/internal/offline_frames_test.cc
index bdc526a..a64355d 100644
--- a/cpp/core/internal/offline_frames_test.cc
+++ b/cpp/core/internal/offline_frames_test.cc
@@ -203,6 +203,7 @@
             gateway: "0.0.0.0"
           >
           supports_disabling_encryption: false
+          supports_client_introduction_ack: true
         >
       >
     >)pb";
@@ -225,6 +226,7 @@
         upgrade_path_info: <
           medium: WIFI_LAN
           wifi_lan_socket: < ip_address: "\x01\x02\x03\x04" wifi_port: 1234 >
+          supports_client_introduction_ack: true
         >
       >
     >)pb";
@@ -251,6 +253,7 @@
             password: "password"
           >
           supports_disabling_encryption: false
+          supports_client_introduction_ack: true
         >
       >
     >)pb";
@@ -279,6 +282,7 @@
             frequency: 1000
           >
           supports_disabling_encryption: false
+          supports_client_introduction_ack: true
         >
       >
     >)pb";
@@ -304,6 +308,7 @@
             service_name: "service"
             mac_address: "\x11\x22\x33\x44\x55\x66"
           >
+          supports_client_introduction_ack: true
         >
       >
     >)pb";