git: be7586fe468f - stable/14 - sctp: improve sending of packets containing an INIT ACK chunk

From: Michael Tuexen <tuexen_at_FreeBSD.org>
Date: Wed, 17 Apr 2024 13:47:41 UTC
The branch stable/14 has been updated by tuexen:

URL: https://cgit.FreeBSD.org/src/commit/?id=be7586fe468f5c3afbe8fc413e160bb9626d0497

commit be7586fe468f5c3afbe8fc413e160bb9626d0497
Author:     Michael Tuexen <tuexen@FreeBSD.org>
AuthorDate: 2024-02-24 18:16:36 +0000
Commit:     Michael Tuexen <tuexen@FreeBSD.org>
CommitDate: 2024-04-17 13:47:17 +0000

    sctp: improve sending of packets containing an INIT ACK chunk
    
    If the peer announced support of zero checksums, do so when sending
    packets containing an INIT ACK chunk.
    
    (cherry picked from commit 644cffe67f61ad5b36b60d621d1c630ff2a50412)
---
 sys/netinet/sctp_input.c  |  2 +-
 sys/netinet/sctp_output.c | 36 ++++++++++++++++++++++++++++++++----
 sys/netinet/sctp_output.h |  4 +++-
 3 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 6937f8a2a43f..a55ef5ac1eab 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -406,7 +406,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
 	op_err = sctp_arethere_unrecognized_parameters(m,
 	    (offset + sizeof(struct sctp_init_chunk)),
 	    &abort_flag, (struct sctp_chunkhdr *)cp,
-	    &nat_friendly, &cookie_found);
+	    &nat_friendly, &cookie_found, NULL);
 	if (abort_flag) {
 		/* Send an abort and notify peer */
 		sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index c988a8426fe8..a8facff6b917 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -4918,7 +4918,8 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
     int param_offset, int *abort_processing,
     struct sctp_chunkhdr *cp,
     int *nat_friendly,
-    int *cookie_found)
+    int *cookie_found,
+    uint32_t *edmid)
 {
 	/*
 	 * Given a mbuf containing an INIT or INIT-ACK with the param_offset
@@ -4934,8 +4935,8 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
 	 * hoped that this routine may be reused in the future by new
 	 * features.
 	 */
+	struct sctp_zero_checksum_acceptable zero_chksum, *zero_chksum_p;
 	struct sctp_paramhdr *phdr, params;
-
 	struct mbuf *mat, *m_tmp, *op_err, *op_err_last;
 	int at, limit, pad_needed;
 	uint16_t ptype, plen, padded_size;
@@ -4944,6 +4945,9 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
 	if (cookie_found != NULL) {
 		*cookie_found = 0;
 	}
+	if (edmid != NULL) {
+		*edmid = SCTP_EDMID_NONE;
+	}
 	mat = in_initpkt;
 	limit = ntohs(cp->chunk_length) - sizeof(struct sctp_init_chunk);
 	at = param_offset;
@@ -4999,6 +5003,22 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
 			}
 			at += padded_size;
 			break;
+		case SCTP_ZERO_CHECKSUM_ACCEPTABLE:
+			if (padded_size != sizeof(struct sctp_zero_checksum_acceptable)) {
+				SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error checksum acceptable %d\n", plen);
+				goto invalid_size;
+			}
+			if (edmid != NULL) {
+				phdr = sctp_get_next_param(mat, at,
+				    (struct sctp_paramhdr *)&zero_chksum,
+				    sizeof(struct sctp_zero_checksum_acceptable));
+				if (phdr != NULL) {
+					zero_chksum_p = (struct sctp_zero_checksum_acceptable *)phdr;
+					*edmid = ntohl(zero_chksum_p->edmid);
+				}
+			}
+			at += padded_size;
+			break;
 		case SCTP_RANDOM:
 			if (padded_size > (sizeof(struct sctp_auth_random) + SCTP_RANDOM_MAX_SIZE)) {
 				SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error random %d\n", plen);
@@ -5513,7 +5533,9 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
 	int nat_friendly = 0;
 	int error;
 	struct socket *so;
+	uint32_t edmid;
 	uint16_t num_ext, chunk_len, padding_len, parameter_len;
+	bool use_zero_crc;
 
 	if (stcb) {
 		asoc = &stcb->asoc;
@@ -5554,7 +5576,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
 	    (offset + sizeof(struct sctp_init_chunk)),
 	    &abort_flag,
 	    (struct sctp_chunkhdr *)init_chk,
-	    &nat_friendly, NULL);
+	    &nat_friendly, NULL, &edmid);
 	if (abort_flag) {
 do_a_abort:
 		if (op_err == NULL) {
@@ -6155,12 +6177,18 @@ do_a_abort:
 		over_addr = NULL;
 	}
 
+	if (asoc != NULL) {
+		use_zero_crc = (asoc->rcv_edmid != SCTP_EDMID_NONE) && (asoc->rcv_edmid == edmid);
+	} else {
+		use_zero_crc = (inp->rcv_edmid != SCTP_EDMID_NONE) && (inp->rcv_edmid == edmid);
+	}
+
 	if ((error = sctp_lowlevel_chunk_output(inp, NULL, NULL, to, m, 0, NULL, 0, 0,
 	    0, 0,
 	    inp->sctp_lport, sh->src_port, init_chk->init.initiate_tag,
 	    port, over_addr,
 	    mflowtype, mflowid,
-	    false,		/* XXXMT: Improve this! */
+	    use_zero_crc,
 	    SCTP_SO_NOT_LOCKED))) {
 		SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak send error %d\n", error);
 		if (error == ENOBUFS) {
diff --git a/sys/netinet/sctp_output.h b/sys/netinet/sctp_output.h
index 1a1d17221b02..88c12367346a 100644
--- a/sys/netinet/sctp_output.h
+++ b/sys/netinet/sctp_output.h
@@ -80,7 +80,9 @@ sctp_send_initiate_ack(struct sctp_inpcb *, struct sctp_tcb *,
 
 struct mbuf *
 sctp_arethere_unrecognized_parameters(struct mbuf *, int, int *,
-    struct sctp_chunkhdr *, int *, int *);
+    struct sctp_chunkhdr *, int *, int *,
+    uint32_t *);
+
 void sctp_queue_op_err(struct sctp_tcb *, struct mbuf *);
 
 int