diff --git a/src/core/connection.c b/src/core/connection.c index adb3f66697..b58e816c26 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -2263,7 +2263,8 @@ QuicConnGenerateLocalTransportParameters( QUIC_TP_FLAG_MAX_UDP_PAYLOAD_SIZE | QUIC_TP_FLAG_MAX_ACK_DELAY | QUIC_TP_FLAG_MIN_ACK_DELAY | - QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT; + QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT | + QUIC_TP_FLAG_OBSERVED_ADDRESS; if (Connection->Settings.IdleTimeoutMs != 0) { LocalTP->Flags |= QUIC_TP_FLAG_IDLE_TIMEOUT; @@ -2891,6 +2892,13 @@ QuicConnProcessPeerTransportParameters( Connection->SourceCidLimit = QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_DEFAULT; } + if (Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_OBSERVED_ADDRESS) { + Connection->State.ObservedAddressNegotiated = TRUE; + QuicSendSetSendFlag( + &Connection->Send, + QUIC_CONN_SEND_FLAG_OBSERVED_ADDRESS); + } + if (!FromResumptionTicket) { if (Connection->Settings.VersionNegotiationExtEnabled && Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_VERSION_NEGOTIATION) { @@ -5284,6 +5292,23 @@ QuicConnRecvFrames( break; } + case QUIC_FRAME_OBSERVED_ADDRESS_V4: + case QUIC_FRAME_OBSERVED_ADDRESS_V6: { // Always accept the frame, because we always enable support. + QUIC_OBSERVED_ADDRESS_EX Frame; + if (!QuicObservedAddressFrameDecode(FrameType, PayloadLength, Payload, &Offset, &Frame)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Decoding OBSERVED_ADDRESS frame"); + QuicConnTransportError(Connection, QUIC_ERROR_FRAME_ENCODING_ERROR); + return FALSE; + } + + // TODO - Do something with this. + break; + } + default: // // No default case necessary, as we have already validated the frame @@ -7342,6 +7367,13 @@ QuicConnApplyNewSettings( QuicConnIndicateEvent(Connection, &Event); } + if (QuicConnIsServer(Connection) && Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_OBSERVED_ADDRESS) { + Connection->State.ObservedAddressNegotiated = TRUE; + QuicSendSetSendFlag( + &Connection->Send, + QUIC_CONN_SEND_FLAG_OBSERVED_ADDRESS); + } + if (Connection->Settings.EcnEnabled) { QUIC_PATH* Path = &Connection->Paths[0]; Path->EcnValidationState = ECN_VALIDATION_TESTING; diff --git a/src/core/connection.h b/src/core/connection.h index bfff21972a..b9aa4aa82a 100644 --- a/src/core/connection.h +++ b/src/core/connection.h @@ -194,6 +194,11 @@ typedef union QUIC_CONNECTION_STATE { // BOOLEAN TimestampRecvNegotiated : 1; + // + // Indicates that the peer supports the Observed Address feature. + // + BOOLEAN ObservedAddressNegotiated : 1; + // // Indicates we received APPLICATION_ERROR transport error and are checking also // later packets in case they contain CONNECTION_CLOSE frame with application-layer error. @@ -467,6 +472,11 @@ typedef struct QUIC_CONNECTION { // QUIC_VAR_INT NextSourceCidSequenceNumber; + // + // The sequence number to use for sending a new observed address. + // + QUIC_VAR_INT ObservedAddressSequenceNumber; + // // The most recent Retire Prior To field received in a NEW_CONNECTION_ID // frame. diff --git a/src/core/crypto.c b/src/core/crypto.c index 7633f9b32f..513ee350f3 100644 --- a/src/core/crypto.c +++ b/src/core/crypto.c @@ -2181,7 +2181,8 @@ QuicCryptoEncodeServerTicket( QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_REMOTE | QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_UNI | QUIC_TP_FLAG_INITIAL_MAX_STRMS_BIDI | - QUIC_TP_FLAG_INITIAL_MAX_STRMS_UNI); + QUIC_TP_FLAG_INITIAL_MAX_STRMS_UNI | + QUIC_TP_FLAG_OBSERVED_ADDRESS); EncodedHSTP = QuicCryptoTlsEncodeTransportParameters( diff --git a/src/core/crypto_tls.c b/src/core/crypto_tls.c index da1b459030..67e4c12283 100644 --- a/src/core/crypto_tls.c +++ b/src/core/crypto_tls.c @@ -68,6 +68,7 @@ typedef enum eSniNameType { #define QUIC_TP_ID_GREASE_QUIC_BIT 0x2AB2 // N/A #define QUIC_TP_ID_RELIABLE_RESET_ENABLED 0x17f7586d2cb570 // varint #define QUIC_TP_ID_ENABLE_TIMESTAMP 0x7158 // varint +#define QUIC_TP_ID_OBSERVED_ADDRESS 0x9f81a176 // varint BOOLEAN QuicTpIdIsReserved( @@ -904,6 +905,12 @@ QuicCryptoTlsEncodeTransportParameters( QUIC_TP_ID_ENABLE_TIMESTAMP, QuicVarIntSize(value)); } + if (TransportParams->Flags & QUIC_TP_FLAG_OBSERVED_ADDRESS) { + RequiredTPLen += + TlsTransportParamLength( + QUIC_TP_ID_OBSERVED_ADDRESS, + QuicVarIntSize(2)); // Hardcode for now + } if (TestParam != NULL) { RequiredTPLen += TlsTransportParamLength( @@ -1246,6 +1253,18 @@ QuicCryptoTlsEncodeTransportParameters( "TP: Timestamp (%u)", value); } + if (TransportParams->Flags & QUIC_TP_FLAG_OBSERVED_ADDRESS) { + TPBuf = + TlsWriteTransportParamVarInt( + QUIC_TP_ID_OBSERVED_ADDRESS, + 2, + TPBuf); + QuicTraceLogConnVerbose( + EncodeTPObservedAddress, + Connection, + "TP: Observed Address (%u)", + 2); + } if (TestParam != NULL) { TPBuf = TlsWriteTransportParam( @@ -1953,6 +1972,34 @@ QuicCryptoTlsDecodeTransportParameters( // NOLINT(readability-function-size, goo break; } + case QUIC_TP_ID_OBSERVED_ADDRESS: { + QUIC_VAR_INT value = 0; + if (!TRY_READ_VAR_INT(value)) { + QuicTraceEvent( + ConnErrorStatus, + "[conn][%p] ERROR, %u, %s.", + Connection, + Length, + "Invalid length of QUIC_TP_ID_OBSERVED_ADDRESS"); + goto Exit; + } + if (value > 2) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Invalid value of QUIC_TP_ID_OBSERVED_ADDRESS"); + goto Exit; + } + QuicTraceLogConnVerbose( + DecodeTPObservedAddress, + Connection, + "TP: Observed Address (%u)", + (uint32_t)value); + TransportParams->Flags |= QUIC_TP_FLAG_OBSERVED_ADDRESS; // TODO - Pass value? + break; + } + default: if (QuicTpIdIsReserved(Id)) { QuicTraceLogConnWarning( diff --git a/src/core/frame.c b/src/core/frame.c index 7e1a923e11..2cf729a803 100644 --- a/src/core/frame.c +++ b/src/core/frame.c @@ -1349,6 +1349,101 @@ QuicTimestampFrameDecode( return TRUE; } +_Success_(return != FALSE) +BOOLEAN +QuicObservedAddressFrameEncode( + _In_ const QUIC_OBSERVED_ADDRESS_EX * const Frame, + _Inout_ uint16_t* Offset, + _In_ uint16_t BufferLength, + _Out_writes_to_(BufferLength, *Offset) + uint8_t* Buffer + ) +{ + if (QuicAddrGetFamily(&Frame->Address) == QUIC_ADDRESS_FAMILY_INET) { + const uint16_t RequiredLength = + QuicVarIntSize(QUIC_FRAME_OBSERVED_ADDRESS_V4) + + QuicVarIntSize(Frame->SequenceNumber) + + sizeof(Frame->Address.Ipv4.sin_addr) + + sizeof(Frame->Address.Ipv4.sin_port); + + if (BufferLength < *Offset + RequiredLength) { + return FALSE; + } + + Buffer = Buffer + *Offset; + Buffer = QuicVarIntEncode(QUIC_FRAME_OBSERVED_ADDRESS_V4, Buffer); + Buffer = QuicVarIntEncode(Frame->SequenceNumber, Buffer); + CxPlatCopyMemory(Buffer, &Frame->Address.Ipv4.sin_addr, sizeof(Frame->Address.Ipv4.sin_addr)); + Buffer += sizeof(Frame->Address.Ipv4.sin_addr); + CxPlatCopyMemory(Buffer, &Frame->Address.Ipv4.sin_port, sizeof(Frame->Address.Ipv4.sin_port)); + Buffer += sizeof(Frame->Address.Ipv4.sin_port); + *Offset += RequiredLength; + + } else { + const uint16_t RequiredLength = + QuicVarIntSize(QUIC_FRAME_OBSERVED_ADDRESS_V4) + + QuicVarIntSize(Frame->SequenceNumber) + + sizeof(Frame->Address.Ipv6.sin6_addr) + + sizeof(Frame->Address.Ipv6.sin6_port); + + if (BufferLength < *Offset + RequiredLength) { + return FALSE; + } + + Buffer = Buffer + *Offset; + Buffer = QuicVarIntEncode(QUIC_FRAME_OBSERVED_ADDRESS_V6, Buffer); + Buffer = QuicVarIntEncode(Frame->SequenceNumber, Buffer); + CxPlatCopyMemory(Buffer, &Frame->Address.Ipv6.sin6_addr, sizeof(Frame->Address.Ipv6.sin6_addr)); + Buffer += sizeof(Frame->Address.Ipv6.sin6_addr); + CxPlatCopyMemory(Buffer, &Frame->Address.Ipv6.sin6_port, sizeof(Frame->Address.Ipv6.sin6_port)); + Buffer += sizeof(Frame->Address.Ipv6.sin6_port); + *Offset += RequiredLength; + } + + return TRUE; +} + +_Success_(return != FALSE) +BOOLEAN +QuicObservedAddressFrameDecode( + _In_ QUIC_FRAME_TYPE FrameType, + _In_ uint16_t BufferLength, + _In_reads_bytes_(BufferLength) + const uint8_t * const Buffer, + _Inout_ uint16_t* Offset, + _Out_ QUIC_OBSERVED_ADDRESS_EX* Frame + ) +{ + if (!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->SequenceNumber)) { + return FALSE; + } + + if (FrameType == QUIC_FRAME_OBSERVED_ADDRESS_V4) { + if (BufferLength < *Offset + sizeof(Frame->Address.Ipv4)) { + return FALSE; + } + CxPlatZeroMemory(&Frame->Address.Ipv4, sizeof(Frame->Address.Ipv4)); + Frame->Address.Ipv4.sin_family = QUIC_ADDRESS_FAMILY_INET6; + CxPlatCopyMemory(&Frame->Address.Ipv4.sin_addr, Buffer + *Offset, sizeof(Frame->Address.Ipv4.sin_addr)); + *Offset += sizeof(Frame->Address.Ipv4.sin_addr); + CxPlatCopyMemory(&Frame->Address.Ipv4.sin_port, Buffer + *Offset, sizeof(Frame->Address.Ipv4.sin_port)); + *Offset += sizeof(Frame->Address.Ipv4.sin_port); + + } else { + if (BufferLength < *Offset + sizeof(Frame->Address.Ipv6)) { + return FALSE; + } + CxPlatZeroMemory(&Frame->Address.Ipv6, sizeof(Frame->Address.Ipv6)); + Frame->Address.Ipv6.sin6_family = QUIC_ADDRESS_FAMILY_INET6; + CxPlatCopyMemory(&Frame->Address.Ipv6.sin6_addr, Buffer + *Offset, sizeof(Frame->Address.Ipv6.sin6_addr)); + *Offset += sizeof(Frame->Address.Ipv6.sin6_addr); + CxPlatCopyMemory(&Frame->Address.Ipv6.sin6_port, Buffer + *Offset, sizeof(Frame->Address.Ipv6.sin6_port)); + *Offset += sizeof(Frame->Address.Ipv6.sin6_port); + } + + return TRUE; +} + _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN QuicFrameLog( @@ -1927,6 +2022,31 @@ QuicFrameLog( break; } + case QUIC_FRAME_RELIABLE_RESET_STREAM: { + QUIC_RELIABLE_RESET_STREAM_EX Frame; + if (!QuicReliableResetFrameDecode(PacketLength, Packet, Offset, &Frame)) { + QuicTraceLogVerbose( + FrameLogReliableResetStreamInvalid, + "[%c][%cX][%llu] RELIABLE_RESET_STREAM [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); + return FALSE; + } + + QuicTraceLogVerbose( + FrameLogReliableResetStream, + "[%c][%cX][%llu] RELIABLE_RESET_STREAM ID:%llu ErrorCode:0x%llX FinalSize:%llu ReliableSize:%llu", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.StreamID, + Frame.ErrorCode, + Frame.FinalSize, + Frame.ReliableSize); + break; + } + case QUIC_FRAME_DATAGRAM: case QUIC_FRAME_DATAGRAM_1: { QUIC_DATAGRAM_EX Frame; @@ -2006,13 +2126,14 @@ QuicFrameLog( Frame.Timestamp); break; } - - case QUIC_FRAME_RELIABLE_RESET_STREAM: { - QUIC_RELIABLE_RESET_STREAM_EX Frame; - if (!QuicReliableResetFrameDecode(PacketLength, Packet, Offset, &Frame)) { + + case QUIC_FRAME_OBSERVED_ADDRESS_V4: + case QUIC_FRAME_OBSERVED_ADDRESS_V6: { + QUIC_OBSERVED_ADDRESS_EX Frame; + if (!QuicObservedAddressFrameDecode(FrameType, PacketLength, Packet, Offset, &Frame)) { QuicTraceLogVerbose( - FrameLogReliableResetStreamInvalid, - "[%c][%cX][%llu] RELIABLE_RESET_STREAM [Invalid]", + FrameLogObservedAddressInvalid, + "[%c][%cX][%llu] OBSERVED_ADDRESS [Invalid]", PtkConnPre(Connection), PktRxPre(Rx), PacketNumber); @@ -2020,15 +2141,12 @@ QuicFrameLog( } QuicTraceLogVerbose( - FrameLogReliableResetStream, - "[%c][%cX][%llu] RELIABLE_RESET_STREAM ID:%llu ErrorCode:0x%llX FinalSize:%llu ReliableSize:%llu", + FrameLogObservedAddress, + "[%c][%cX][%llu] OBSERVED_ADDRESS %llu", // TODO - Address PtkConnPre(Connection), PktRxPre(Rx), PacketNumber, - Frame.StreamID, - Frame.ErrorCode, - Frame.FinalSize, - Frame.ReliableSize); + Frame.SequenceNumber); break; } diff --git a/src/core/frame.h b/src/core/frame.h index 277177cbe9..86346aabce 100644 --- a/src/core/frame.h +++ b/src/core/frame.h @@ -159,21 +159,21 @@ typedef enum QUIC_FRAME_TYPE { QUIC_FRAME_IMMEDIATE_ACK = 0xacULL, /* 0xaf to 0x2f4 are unused currently */ QUIC_FRAME_TIMESTAMP = 0x2f5ULL, + /* 0x2f6 to 0x9f80 are unused currently */ + QUIC_FRAME_OBSERVED_ADDRESS_V4 = 0x9f81ULL, // 0x9f81a6ULL, + QUIC_FRAME_OBSERVED_ADDRESS_V6 = 0x9f82ULL, // 0x9f81a7ULL, QUIC_FRAME_MAX_SUPPORTED } QUIC_FRAME_TYPE; -CXPLAT_STATIC_ASSERT( - QUIC_FRAME_MAX_SUPPORTED <= (uint64_t)UINT32_MAX, - "Logging assumes frames types fit in 32-bits"); - #define QUIC_FRAME_IS_KNOWN(X) \ (X <= QUIC_FRAME_HANDSHAKE_DONE || \ (X >= QUIC_FRAME_DATAGRAM && X <= QUIC_FRAME_DATAGRAM_1) || \ X == QUIC_FRAME_ACK_FREQUENCY || X == QUIC_FRAME_IMMEDIATE_ACK || \ X == QUIC_FRAME_RELIABLE_RESET_STREAM || \ - X == QUIC_FRAME_TIMESTAMP \ + X == QUIC_FRAME_TIMESTAMP || \ + X == QUIC_FRAME_OBSERVED_ADDRESS_V4 || X == QUIC_FRAME_OBSERVED_ADDRESS_V6 \ ) // @@ -901,6 +901,38 @@ QuicTimestampFrameDecode( _Out_ QUIC_TIMESTAMP_EX* Frame ); +// +// QUIC_OBSERVED_ADDRESS Encoding/Decoding +// + +typedef struct QUIC_OBSERVED_ADDRESS_EX { + + QUIC_VAR_INT SequenceNumber; + QUIC_ADDR Address; + +} QUIC_OBSERVED_ADDRESS_EX; + +_Success_(return != FALSE) +BOOLEAN +QuicObservedAddressFrameEncode( + _In_ const QUIC_OBSERVED_ADDRESS_EX * const Frame, + _Inout_ uint16_t* Offset, + _In_ uint16_t BufferLength, + _Out_writes_to_(BufferLength, *Offset) + uint8_t* Buffer + ); + +_Success_(return != FALSE) +BOOLEAN +QuicObservedAddressFrameDecode( + _In_ QUIC_FRAME_TYPE FrameType, + _In_ uint16_t BufferLength, + _In_reads_bytes_(BufferLength) + const uint8_t * const Buffer, + _Inout_ uint16_t* Offset, + _Out_ QUIC_OBSERVED_ADDRESS_EX* Frame + ); + // // Helper functions // diff --git a/src/core/loss_detection.c b/src/core/loss_detection.c index 9598c56676..6b027e132b 100644 --- a/src/core/loss_detection.c +++ b/src/core/loss_detection.c @@ -877,6 +877,16 @@ QuicLossDetectionRetransmitFrames( QUIC_CONN_SEND_FLAG_ACK_FREQUENCY); } break; + + case QUIC_FRAME_OBSERVED_ADDRESS_V4: + case QUIC_FRAME_OBSERVED_ADDRESS_V6: + if (Packet->Frames[i].OBSERVED_ADDRESS.Sequence == Connection->ObservedAddressSequenceNumber) { + NewDataQueued |= + QuicSendSetSendFlag( + &Connection->Send, + QUIC_CONN_SEND_FLAG_ACK_FREQUENCY); + } + break; } } diff --git a/src/core/path.c b/src/core/path.c index 91a545c54e..f30d92c826 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -28,6 +28,7 @@ QuicPathInitialize( CxPlatZeroMemory(Path, sizeof(QUIC_PATH)); Path->ID = Connection->NextPathId++; // TODO - Check for duplicates after wrap around? Path->InUse = TRUE; + Path->SendObservedAddress = TRUE; Path->MinRtt = UINT32_MAX; Path->Mtu = Connection->Settings.MinimumMtu; Path->SmoothedRtt = MS_TO_US(Connection->Settings.InitialRttMs); @@ -291,6 +292,19 @@ QuicPathSetActive( *Path = PrevActivePath; } + // + // When changing path, we need to increment the sequence number for observed + // address. + // + if (Path->SendObservedAddress) { + Connection->ObservedAddressSequenceNumber++; + if (Connection->State.ObservedAddressNegotiated) { + QuicSendSetSendFlag( + &Connection->Send, + QUIC_CONN_SEND_FLAG_OBSERVED_ADDRESS); + } + } + QuicTraceLogConnInfo( PathActive, Connection, diff --git a/src/core/path.h b/src/core/path.h index 4fdc2d78d8..44e85d66f0 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -116,6 +116,11 @@ typedef struct QUIC_PATH { // BOOLEAN EncryptionOffloading : 1; + // + // Indicates whether this path needs to send an observed address. + // + BOOLEAN SendObservedAddress : 1; + // // The ending time of ECN validation testing state in microseconds. // diff --git a/src/core/quicdef.h b/src/core/quicdef.h index 07956b50fb..e4eb584ea8 100644 --- a/src/core/quicdef.h +++ b/src/core/quicdef.h @@ -589,6 +589,7 @@ CXPLAT_STATIC_ASSERT( #define QUIC_TP_FLAG_TIMESTAMP_RECV_ENABLED 0x01000000 #define QUIC_TP_FLAG_TIMESTAMP_SEND_ENABLED 0x02000000 #define QUIC_TP_FLAG_TIMESTAMP_SHIFT 24 +#define QUIC_TP_FLAG_OBSERVED_ADDRESS 0x04000000 #define QUIC_TP_MAX_PACKET_SIZE_DEFAULT 65527 #define QUIC_TP_MAX_UDP_PAYLOAD_SIZE_MIN 1200 diff --git a/src/core/send.c b/src/core/send.c index bbd1d0493b..ffff20c3cd 100644 --- a/src/core/send.c +++ b/src/core/send.c @@ -644,6 +644,37 @@ QuicSendWriteFrames( } } + if (Send->SendFlags & QUIC_CONN_SEND_FLAG_OBSERVED_ADDRESS) { + // TODO - Support sending on more than just active path + CXPLAT_DBG_ASSERT(Connection->Paths[0].SendObservedAddress); + + QUIC_OBSERVED_ADDRESS_EX Frame; + Frame.SequenceNumber = Connection->ObservedAddressSequenceNumber; + Frame.Address = Connection->Paths[0].Route.RemoteAddress; + + if (QuicObservedAddressFrameEncode( + &Frame, + &Builder->DatagramLength, + AvailableBufferLength, + Builder->Datagram->Buffer)) { + + Connection->Paths[0].SendObservedAddress = FALSE; + Send->SendFlags &= ~QUIC_CONN_SEND_FLAG_OBSERVED_ADDRESS; + Builder->Metadata->Frames[ + Builder->Metadata->FrameCount].OBSERVED_ADDRESS.Sequence = + Connection->ObservedAddressSequenceNumber++; + if (QuicPacketBuilderAddFrame( + Builder, + QuicAddressGetFamily(&Connection->Paths[0].Route.RemoteAddress) == QUIC_ADDRESS_FAMILY_INET ? + QUIC_FRAME_OBSERVED_ADDRESS_V4 : QUIC_FRAME_OBSERVED_ADDRESS_V6, + TRUE)) { + return TRUE; + } + } else { + RanOutOfRoom = TRUE; + } + } + if (Send->SendFlags & QUIC_CONN_SEND_FLAG_DATA_BLOCKED) { QUIC_DATA_BLOCKED_EX Frame = { Send->OrderedStreamBytesSent }; diff --git a/src/core/send.h b/src/core/send.h index 92ac65502c..a34bef4761 100644 --- a/src/core/send.h +++ b/src/core/send.h @@ -145,6 +145,7 @@ QuicPacketTypeToEncryptLevelV2( #define QUIC_CONN_SEND_FLAG_ACK_FREQUENCY 0x00008000U #define QUIC_CONN_SEND_FLAG_BIDI_STREAMS_BLOCKED 0x00010000U #define QUIC_CONN_SEND_FLAG_UNI_STREAMS_BLOCKED 0x00020000U +#define QUIC_CONN_SEND_FLAG_OBSERVED_ADDRESS 0x00040000U #define QUIC_CONN_SEND_FLAG_DPLPMTUD 0x80000000U // @@ -176,7 +177,8 @@ QuicPacketTypeToEncryptLevelV2( QUIC_CONN_SEND_FLAG_ACK_FREQUENCY | \ QUIC_CONN_SEND_FLAG_DPLPMTUD | \ QUIC_CONN_SEND_FLAG_BIDI_STREAMS_BLOCKED | \ - QUIC_CONN_SEND_FLAG_UNI_STREAMS_BLOCKED \ + QUIC_CONN_SEND_FLAG_UNI_STREAMS_BLOCKED | \ + QUIC_CONN_SEND_FLAG_OBSERVED_ADDRESS \ ) // diff --git a/src/core/sent_packet_metadata.h b/src/core/sent_packet_metadata.h index d18359fc62..aa972935ff 100644 --- a/src/core/sent_packet_metadata.h +++ b/src/core/sent_packet_metadata.h @@ -64,6 +64,9 @@ typedef struct QUIC_SENT_FRAME_METADATA { struct { QUIC_VAR_INT Sequence; } ACK_FREQUENCY; + struct { + QUIC_VAR_INT Sequence; + } OBSERVED_ADDRESS; }; // // The following to fields are for STREAM. However, if they were in stream diff --git a/src/core/unittest/SpinFrame.cpp b/src/core/unittest/SpinFrame.cpp index 0c114bd70e..fdeb81270d 100644 --- a/src/core/unittest/SpinFrame.cpp +++ b/src/core/unittest/SpinFrame.cpp @@ -35,6 +35,7 @@ union QuicV1Frames { QUIC_ACK_FREQUENCY_EX AckFrequencyFrame; QUIC_RELIABLE_RESET_STREAM_EX ReliableResetStreamFrame; QUIC_TIMESTAMP_EX TimestampFrame; + QUIC_OBSERVED_ADDRESS_EX ObservedAddressFrame; }; TEST(SpinFrame, SpinFrame1000000) @@ -49,11 +50,7 @@ TEST(SpinFrame, SpinFrame1000000) BOOLEAN InvalidFrame; uint8_t Buffer[255]; uint8_t BufferLength = 0; - - uint16_t FrameType; - CXPLAT_STATIC_ASSERT( - QUIC_FRAME_MAX_SUPPORTED <= (uint64_t)UINT16_MAX, - "Tests below assumes frames fit in 16-bits"); + uint64_t FrameType; QuicRangeInitialize(QUIC_MAX_RANGE_DECODE_ACKS, &AckBlocks); @@ -241,6 +238,14 @@ TEST(SpinFrame, SpinFrame1000000) FailedDecodes++; } break; + case QUIC_FRAME_OBSERVED_ADDRESS_V4: + case QUIC_FRAME_OBSERVED_ADDRESS_V6: + if (QuicObservedAddressFrameDecode((QUIC_FRAME_TYPE) FrameType, BufferLength, Buffer, &Offset, &DecodedFrame.ObservedAddressFrame)) { + SuccessfulDecodes++; + } else { + FailedDecodes++; + } + break; default: ASSERT_TRUE(FALSE) << "You have a test bug. FrameType: " << (QUIC_FRAME_TYPE) FrameType << " doesn't have a matching case."; break; diff --git a/src/core/unittest/TransportParamTest.cpp b/src/core/unittest/TransportParamTest.cpp index d5ad1e7f79..ef0fc32a1d 100644 --- a/src/core/unittest/TransportParamTest.cpp +++ b/src/core/unittest/TransportParamTest.cpp @@ -270,3 +270,12 @@ TEST(TransportParamTest, ReliableResetEnabled) EncodeDecodeAndCompare(&OriginalTP); EncodeDecodeAndCompare(&OriginalTP, true); } + +TEST(TransportParamTest, ObservedAddress) +{ + QUIC_TRANSPORT_PARAMETERS OriginalTP; + CxPlatZeroMemory(&OriginalTP, sizeof(OriginalTP)); + OriginalTP.Flags = QUIC_TP_FLAG_OBSERVED_ADDRESS; + EncodeDecodeAndCompare(&OriginalTP); + EncodeDecodeAndCompare(&OriginalTP, true); +} diff --git a/src/plugins/dbg/quictypes.h b/src/plugins/dbg/quictypes.h index 03ce0cebe3..a516a43337 100644 --- a/src/plugins/dbg/quictypes.h +++ b/src/plugins/dbg/quictypes.h @@ -813,6 +813,12 @@ typedef enum QUIC_FRAME_TYPE { QUIC_FRAME_DATAGRAM_1 = 0x31ULL, /* 0x32 to 0xad are unused currently */ QUIC_FRAME_ACK_FREQUENCY = 0xafULL, + QUIC_FRAME_IMMEDIATE_ACK = 0xacULL, + /* 0xaf to 0x2f4 are unused currently */ + QUIC_FRAME_TIMESTAMP = 0x2f5ULL, + /* 0x2f6 to 0x9f81a5 are unused currently */ + QUIC_FRAME_OBSERVED_ADDRESS_V4 = 0x9f81a6ULL, + QUIC_FRAME_OBSERVED_ADDRESS_V6 = 0x9f81a7ULL, QUIC_FRAME_MAX_SUPPORTED @@ -888,6 +894,13 @@ struct SentFrameMetadata : Struct { return "DATAGRAM"; case QUIC_FRAME_ACK_FREQUENCY: return "ACK_FREQUENCY"; + case QUIC_FRAME_IMMEDIATE_ACK: + return "IMMEDIATE_ACK"; + case QUIC_FRAME_TIMESTAMP: + return "TIMESTAMP"; + case QUIC_FRAME_OBSERVED_ADDRESS_V4: + case QUIC_FRAME_OBSERVED_ADDRESS_V6: + return "OBSERVED_ADDRESS"; default: return "INVALID FRAME"; }