@@ -149,22 +149,19 @@ lws_quic_client_probe_preferred_address(struct lws *nwsi,
149149 if (qn -> is_server )
150150 return 1 ;
151151
152- /* Save the migration parameters */
153- qn -> prefaddr_original_sa46 = nwsi -> udp -> sa46 ;
154- qn -> prefaddr_original_rem_cid = qn -> rem_cid ;
152+ /* Save the migration parameters for later */
155153 qn -> probing_sa46 = * pref_sa46 ;
156- qn -> probing_sa46_valid = 1 ;
157154 if (pref_cid ) {
158155 qn -> prefaddr_rem_cid = * pref_cid ;
159156 if (pref_token )
160157 memcpy (qn -> prefaddr_rem_token , pref_token , 16 );
161158 }
162159
163160 /*
164- * Defer the actual socket swap + DCID change until the handshake is
165- * complete: the preferred_address TP arrives during the handshake, and
166- * swapping before both sides have APP keys strands the migration (the
167- * server can't decrypt APP-level packets from the new source port) .
161+ * Defer the actual socket swap + DCID change until the server confirms
162+ * handshake completion via HANDSHAKE_DONE. The preferred_address TP
163+ * arrives during the handshake; swapping before both sides have APP
164+ * keys strands the migration .
168165 */
169166 if (!qn -> handshake_done ) {
170167 qn -> prefaddr_pending = 1 ;
@@ -1272,7 +1269,9 @@ rops_handle_POLLIN_quic(struct lws_context_per_thread *pt, struct lws *wsi,
12721269
12731270 /* F-57: Validate short header DCID */
12741271 if (!(p [0 ] & 0x80 ) && nwsi && nwsi -> quic .qn && nwsi -> quic .qn -> loc_cid .len ) {
1275- if (local_dcid_len > (size_t )n - 1 || memcmp (& p [1 ], nwsi -> quic .qn -> loc_cid .id , local_dcid_len )) {
1272+ if (local_dcid_len > (size_t )n - 1 ||
1273+ (memcmp (& p [1 ], nwsi -> quic .qn -> loc_cid .id , local_dcid_len ) &&
1274+ memcmp (& p [1 ], nwsi -> quic .qn -> prefaddr_rem_cid .id , local_dcid_len ))) {
12761275 lwsl_wsi_notice (wsi , "QUIC RX: Short header DCID mismatch" );
12771276 /* Drop packet */
12781277 p += packet_size ;
@@ -1501,19 +1500,6 @@ rops_handle_POLLIN_quic(struct lws_context_per_thread *pt, struct lws *wsi,
15011500 nwsi -> quic .qn -> probing_sa46 = migration_sa46 ;
15021501 nwsi -> quic .qn -> probing_sa46_valid = 1 ;
15031502
1504- {
1505- int _li ;
1506- for (_li = 0 ; _li <= LWS_QUIC_LEVEL_HANDSHAKE ; _li ++ ) {
1507- lws_start_foreach_dll_safe (struct lws_dll2 * , _d , _d1 ,
1508- nwsi -> quic .qn -> pending_tx [_li ].head ) {
1509- struct lws_quic_tx_frame * _f = lws_container_of (_d ,
1510- struct lws_quic_tx_frame , list );
1511- lws_dll2_remove (& _f -> list );
1512- lws_free (_f );
1513- } lws_end_foreach_dll_safe (_d , _d1 );
1514- }
1515- }
1516-
15171503 if (!nwsi -> quic .qn -> path_challenge_pending ) {
15181504 struct lws_quic_tx_frame * f_pc =
15191505 lws_zalloc (sizeof (* f_pc ) + 8 ,
@@ -1609,19 +1595,37 @@ rops_handle_POLLIN_quic(struct lws_context_per_thread *pt, struct lws *wsi,
16091595 }
16101596
16111597 int parse_res = lws_quic_parse_frames (nwsi , pn_space , & p [pn_offset + (size_t )pn_len ], (size_t )dec_len , & sa46 );
1612-
1598+
16131599 /* ALPN negotiation might have migrated the network WSI! */
16141600 if (nwsi && !nwsi -> quic .qn ) {
16151601 nwsi = lws_get_quic_network_wsi (nwsi );
16161602 }
16171603
1604+ /*
1605+ * After frame parsing may have generated Handshake-level
1606+ * ACKs, discard any pending Initial/Handshake TX so those
1607+ * ACKs don't race ahead of PATH_CHALLENGE to the new path.
1608+ * The handshake is done; only APP-level frames (including
1609+ * PATH_CHALLENGE) should reach the new client port.
1610+ */
1611+ if (nwsi && nwsi -> quic .qn && nwsi -> quic .qn -> probing_sa46_valid &&
1612+ nwsi -> quic .qn -> handshake_done ) {
1613+ int _li ;
1614+ for (_li = 0 ; _li <= LWS_QUIC_LEVEL_HANDSHAKE ; _li ++ ) {
1615+ lws_start_foreach_dll_safe (struct lws_dll2 * , _d , _d1 ,
1616+ nwsi -> quic .qn -> pending_tx [_li ].head ) {
1617+ struct lws_quic_tx_frame * _f = lws_container_of (_d ,
1618+ struct lws_quic_tx_frame , list );
1619+ lws_dll2_remove (& _f -> list );
1620+ lws_free (_f );
1621+ } lws_end_foreach_dll_safe (_d , _d1 );
1622+ }
1623+ }
1624+
16181625 /*
16191626 * The server commits the new path ONLY on PATH_RESPONSE
16201627 * validation (handled in parse-quic.c). Do NOT commit
1621- * here on non-probing packets: doing so would make the
1622- * first server datagram to the new client port be a
1623- * regular ACK/STREAM frame instead of the PATH_CHALLENGE
1624- * that QIR connectionmigration requires.
1628+ * here on non-probing packets.
16251629 */
16261630
16271631 if (nwsi ) {
0 commit comments