git: 644cffe67f61 - main - sctp: improve sending of packets containing an INIT ACK chunk

From: Michael Tuexen <tuexen_at_FreeBSD.org>
Date: Sat, 24 Feb 2024 18:20:03 UTC
The branch main has been updated by tuexen:

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

commit 644cffe67f61ad5b36b60d621d1c630ff2a50412
Author:     Michael Tuexen <tuexen@FreeBSD.org>
AuthorDate: 2024-02-24 18:16:36 +0000
Commit:     Michael Tuexen <tuexen@FreeBSD.org>
CommitDate: 2024-02-24 18:16:36 +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.
    
    MFC after:      1 week
---
 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