| Index: webrtc/p2p/base/jseptransport.cc
 | 
| diff --git a/webrtc/p2p/base/jseptransport.cc b/webrtc/p2p/base/jseptransport.cc
 | 
| index 4bc24fd07bc3951eec878a23f226ef992c336ec6..301ae24003b8bf61eda8b09fdbd9d06dc99163bc 100644
 | 
| --- a/webrtc/p2p/base/jseptransport.cc
 | 
| +++ b/webrtc/p2p/base/jseptransport.cc
 | 
| @@ -278,9 +278,8 @@ bool JsepTransport::NeedsIceRestart() const {
 | 
|    return needs_ice_restart_;
 | 
|  }
 | 
|  
 | 
| -void JsepTransport::GetSslRole(rtc::SSLRole* ssl_role) const {
 | 
| -  RTC_DCHECK(ssl_role);
 | 
| -  *ssl_role = secure_role_;
 | 
| +rtc::Optional<rtc::SSLRole> JsepTransport::GetSslRole() const {
 | 
| +  return ssl_role_;
 | 
|  }
 | 
|  
 | 
|  bool JsepTransport::GetStats(TransportStats* stats) {
 | 
| @@ -342,11 +341,6 @@ bool JsepTransport::ApplyLocalTransportDescription(
 | 
|  bool JsepTransport::ApplyRemoteTransportDescription(
 | 
|      DtlsTransportInternal* dtls_transport,
 | 
|      std::string* error_desc) {
 | 
| -  // Currently, all ICE-related calls still go through this DTLS channel. But
 | 
| -  // that will change once we get rid of TransportChannelImpl, and the DTLS
 | 
| -  // channel interface no longer includes ICE-specific methods. Then this class
 | 
| -  // will need to call dtls->ice()->SetIceRole(), for example, assuming the Dtls
 | 
| -  // interface will expose its inner ICE channel.
 | 
|    dtls_transport->ice_transport()->SetRemoteIceParameters(
 | 
|        remote_description_->GetIceParameters());
 | 
|    dtls_transport->ice_transport()->SetRemoteIceMode(
 | 
| @@ -359,7 +353,7 @@ bool JsepTransport::ApplyNegotiatedTransportDescription(
 | 
|      std::string* error_desc) {
 | 
|    // Set SSL role. Role must be set before fingerprint is applied, which
 | 
|    // initiates DTLS setup.
 | 
| -  if (!dtls_transport->SetSslRole(secure_role_)) {
 | 
| +  if (ssl_role_ && !dtls_transport->SetSslRole(*ssl_role_)) {
 | 
|      return BadTransportDescription("Failed to set SSL role for the channel.",
 | 
|                                     error_desc);
 | 
|    }
 | 
| @@ -374,8 +368,9 @@ bool JsepTransport::ApplyNegotiatedTransportDescription(
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
| -bool JsepTransport::NegotiateTransportDescription(ContentAction local_role,
 | 
| -                                                  std::string* error_desc) {
 | 
| +bool JsepTransport::NegotiateTransportDescription(
 | 
| +    ContentAction local_description_type,
 | 
| +    std::string* error_desc) {
 | 
|    if (!local_description_ || !remote_description_) {
 | 
|      const std::string msg =
 | 
|          "Applying an answer transport description "
 | 
| @@ -388,10 +383,10 @@ bool JsepTransport::NegotiateTransportDescription(ContentAction local_role,
 | 
|        remote_description_->identity_fingerprint.get();
 | 
|    if (remote_fp && local_fp) {
 | 
|      remote_fingerprint_.reset(new rtc::SSLFingerprint(*remote_fp));
 | 
| -    if (!NegotiateRole(local_role, &secure_role_, error_desc)) {
 | 
| +    if (!NegotiateRole(local_description_type, error_desc)) {
 | 
|        return false;
 | 
|      }
 | 
| -  } else if (local_fp && (local_role == CA_ANSWER)) {
 | 
| +  } else if (local_fp && (local_description_type == CA_ANSWER)) {
 | 
|      return BadTransportDescription(
 | 
|          "Local fingerprint supplied when caller didn't offer DTLS.",
 | 
|          error_desc);
 | 
| @@ -412,10 +407,8 @@ bool JsepTransport::NegotiateTransportDescription(ContentAction local_role,
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
| -bool JsepTransport::NegotiateRole(ContentAction local_role,
 | 
| -                                  rtc::SSLRole* ssl_role,
 | 
| -                                  std::string* error_desc) const {
 | 
| -  RTC_DCHECK(ssl_role);
 | 
| +bool JsepTransport::NegotiateRole(ContentAction local_description_type,
 | 
| +                                  std::string* error_desc) {
 | 
|    if (!local_description_ || !remote_description_) {
 | 
|      const std::string msg =
 | 
|          "Local and Remote description must be set before "
 | 
| @@ -450,7 +443,7 @@ bool JsepTransport::NegotiateRole(ContentAction local_role,
 | 
|    ConnectionRole remote_connection_role = remote_description_->connection_role;
 | 
|  
 | 
|    bool is_remote_server = false;
 | 
| -  if (local_role == CA_OFFER) {
 | 
| +  if (local_description_type == CA_OFFER) {
 | 
|      if (local_connection_role != CONNECTIONROLE_ACTPASS) {
 | 
|        return BadTransportDescription(
 | 
|            "Offerer must use actpass value for setup attribute.", error_desc);
 | 
| @@ -470,8 +463,23 @@ bool JsepTransport::NegotiateRole(ContentAction local_role,
 | 
|    } else {
 | 
|      if (remote_connection_role != CONNECTIONROLE_ACTPASS &&
 | 
|          remote_connection_role != CONNECTIONROLE_NONE) {
 | 
| -      return BadTransportDescription(
 | 
| -          "Offerer must use actpass value for setup attribute.", error_desc);
 | 
| +      // Accept a remote role attribute that's not "actpass", but matches the
 | 
| +      // current negotiated role. This is allowed by dtls-sdp, though our
 | 
| +      // implementation will never generate such an offer as it's not
 | 
| +      // recommended.
 | 
| +      //
 | 
| +      // See https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-dtls-sdp,
 | 
| +      // section 5.5.
 | 
| +      if (!ssl_role_ ||
 | 
| +          (*ssl_role_ == rtc::SSL_CLIENT &&
 | 
| +           remote_connection_role == CONNECTIONROLE_ACTIVE) ||
 | 
| +          (*ssl_role_ == rtc::SSL_SERVER &&
 | 
| +           remote_connection_role == CONNECTIONROLE_PASSIVE)) {
 | 
| +        return BadTransportDescription(
 | 
| +            "Offerer must use actpass value or current negotiated role for "
 | 
| +            "setup attribute.",
 | 
| +            error_desc);
 | 
| +      }
 | 
|      }
 | 
|  
 | 
|      if (local_connection_role == CONNECTIONROLE_ACTIVE ||
 | 
| @@ -487,7 +495,7 @@ bool JsepTransport::NegotiateRole(ContentAction local_role,
 | 
|      // If local is passive, local will act as server.
 | 
|    }
 | 
|  
 | 
| -  *ssl_role = is_remote_server ? rtc::SSL_CLIENT : rtc::SSL_SERVER;
 | 
| +  ssl_role_.emplace(is_remote_server ? rtc::SSL_CLIENT : rtc::SSL_SERVER);
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
| 
 |