aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMichael Tuexen <tuexen@FreeBSD.org>2023-03-10 00:45:46 +0000
committerMichael Tuexen <tuexen@FreeBSD.org>2023-03-10 00:45:46 +0000
commit4a2b92d99fee987e87a5c3789e0892ab6e680018 (patch)
tree1efa3b8c1eb3e4bd109fba7c8b73c07993633ec3 /sys
parent626d1e4a82e25d274cdadfebfd81a28e968efb5b (diff)
downloadsrc-4a2b92d99fee987e87a5c3789e0892ab6e680018.tar.gz
src-4a2b92d99fee987e87a5c3789e0892ab6e680018.zip
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/sctp.h1
-rw-r--r--sys/netinet/sctp_constants.h2
-rw-r--r--sys/netinet/sctp_input.c157
-rw-r--r--sys/netinet/sctp_output.c71
-rw-r--r--sys/netinet/sctp_pcb.c9
-rw-r--r--sys/netinet/sctp_pcb.h1
-rw-r--r--sys/netinet/sctp_structs.h6
-rw-r--r--sys/netinet/sctp_sysctl.c5
-rw-r--r--sys/netinet/sctp_sysctl.h8
-rw-r--r--sys/netinet/sctp_uio.h6
-rw-r--r--sys/netinet/sctp_usrreq.c23
-rw-r--r--sys/netinet/sctputil.c1
12 files changed, 232 insertions, 58 deletions
diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h
index d67b33acd8ad..95dd85c5d8c0 100644
--- a/sys/netinet/sctp.h
+++ b/sys/netinet/sctp.h
@@ -129,6 +129,7 @@ struct sctp_paramhdr {
#define SCTP_NRSACK_SUPPORTED 0x00000030
#define SCTP_PKTDROP_SUPPORTED 0x00000031
#define SCTP_MAX_CWND 0x00000032
+#define SCTP_ACCEPT_ZERO_CHECKSUM 0x00000033
/*
* read-only options
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h
index 3df6ad6db2aa..3772a933bf85 100644
--- a/sys/netinet/sctp_constants.h
+++ b/sys/netinet/sctp_constants.h
@@ -410,7 +410,7 @@ __FBSDID("$FreeBSD$");
/*************0x8000 series*************/
#define SCTP_ECN_CAPABLE 0x8000
-
+#define SCTP_ZERO_CHECKSUM_ACCEPTABLE 0x8001
/* RFC 4895 */
#define SCTP_RANDOM 0x8002
#define SCTP_CHUNK_LIST 0x8003
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 3f5046811258..dfc74e1e84f3 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -5263,73 +5263,138 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
uint32_t vrf_id, uint16_t port)
{
- uint32_t high_tsn;
- int fwd_tsn_seen = 0, data_processed = 0;
- struct mbuf *m = *mm, *op_err;
char msg[SCTP_DIAG_INFO_LEN];
- int un_sent;
- int cnt_ctrl_ready = 0;
+ struct mbuf *m = *mm, *op_err;
struct sctp_inpcb *inp = NULL, *inp_decr = NULL;
struct sctp_tcb *stcb = NULL;
struct sctp_nets *net = NULL;
+ uint32_t high_tsn;
+ uint32_t cksum_in_hdr;
+ int un_sent;
+ int cnt_ctrl_ready = 0;
+ int fwd_tsn_seen = 0, data_processed = 0;
+ bool cksum_validated, stcb_looked_up;
SCTP_STAT_INCR(sctps_recvdatagrams);
#ifdef SCTP_AUDITING_ENABLED
sctp_audit_log(0xE0, 1);
sctp_auditing(0, inp, stcb, net);
#endif
+
+ stcb_looked_up = false;
if (compute_crc != 0) {
- uint32_t check, calc_check;
-
- check = sh->checksum;
- sh->checksum = 0;
- calc_check = sctp_calculate_cksum(m, iphlen);
- sh->checksum = check;
- if (calc_check != check) {
- SCTPDBG(SCTP_DEBUG_INPUT1, "Bad CSUM on SCTP packet calc_check:%x check:%x m:%p mlen:%d iphlen:%d\n",
- calc_check, check, (void *)m, length, iphlen);
- stcb = sctp_findassociation_addr(m, offset, src, dst,
- sh, ch, &inp, &net, vrf_id);
+ cksum_validated = false;
+ cksum_in_hdr = sh->checksum;
+ if (cksum_in_hdr != htonl(0)) {
+ uint32_t cksum_calculated;
+
+ validate_cksum:
+ sh->checksum = 0;
+ cksum_calculated = sctp_calculate_cksum(m, iphlen);
+ sh->checksum = cksum_in_hdr;
+ if (cksum_calculated != cksum_in_hdr) {
+ if (stcb_looked_up) {
+ /*
+ * The packet has a zero checksum,
+ * which is not the correct CRC, no
+ * stcb has been found or an stcb
+ * has been found but an incorrect
+ * zero checksum is not acceptable.
+ */
+ KASSERT(cksum_in_hdr == htonl(0),
+ ("cksum in header not zero: %x",
+ ntohl(cksum_in_hdr)));
+ if ((inp == NULL) &&
+ (SCTP_BASE_SYSCTL(sctp_ootb_with_zero_cksum) == 1)) {
+ /*
+ * This is an OOTB packet,
+ * depending on the sysctl
+ * variable, pretend that
+ * the checksum is
+ * acceptable, to allow an
+ * appropriate response
+ * (ABORT, for examlpe) to
+ * be sent.
+ */
+ KASSERT(stcb == NULL,
+ ("stcb is %p", stcb));
+ SCTP_STAT_INCR(sctps_recvzerocrc);
+ goto cksum_validated;
+ }
+ } else {
+ stcb = sctp_findassociation_addr(m, offset, src, dst,
+ sh, ch, &inp, &net, vrf_id);
+ }
+ SCTPDBG(SCTP_DEBUG_INPUT1, "Bad cksum in SCTP packet:%x calculated:%x m:%p mlen:%d iphlen:%d\n",
+ ntohl(cksum_in_hdr), ntohl(cksum_calculated), (void *)m, length, iphlen);
#if defined(INET) || defined(INET6)
- if ((ch->chunk_type != SCTP_INITIATION) &&
- (net != NULL) && (net->port != port)) {
- if (net->port == 0) {
- /* UDP encapsulation turned on. */
- net->mtu -= sizeof(struct udphdr);
- if (stcb->asoc.smallest_mtu > net->mtu) {
- sctp_pathmtu_adjustment(stcb, net->mtu, true);
+ if ((ch->chunk_type != SCTP_INITIATION) &&
+ (net != NULL) && (net->port != port)) {
+ if (net->port == 0) {
+ /*
+ * UDP encapsulation turned
+ * on.
+ */
+ net->mtu -= sizeof(struct udphdr);
+ if (stcb->asoc.smallest_mtu > net->mtu) {
+ sctp_pathmtu_adjustment(stcb, net->mtu, true);
+ }
+ } else if (port == 0) {
+ /*
+ * UDP encapsulation turned
+ * off.
+ */
+ net->mtu += sizeof(struct udphdr);
+ /* XXX Update smallest_mtu */
}
- } else if (port == 0) {
- /* UDP encapsulation turned off. */
- net->mtu += sizeof(struct udphdr);
- /* XXX Update smallest_mtu */
+ net->port = port;
}
- net->port = port;
- }
#endif
- if (net != NULL) {
- net->flowtype = mflowtype;
- net->flowid = mflowid;
+ if (net != NULL) {
+ net->flowtype = mflowtype;
+ net->flowid = mflowid;
+ }
+ SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh);
+ if ((inp != NULL) && (stcb != NULL)) {
+ if (stcb->asoc.pktdrop_supported) {
+ sctp_send_packet_dropped(stcb, net, m, length, iphlen, 1);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED);
+ }
+ } else if ((inp != NULL) && (stcb == NULL)) {
+ inp_decr = inp;
+ }
+ SCTP_STAT_INCR(sctps_badsum);
+ SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors);
+ goto out;
+ } else {
+ cksum_validated = true;
}
- SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh);
- if ((inp != NULL) && (stcb != NULL)) {
- sctp_send_packet_dropped(stcb, net, m, length, iphlen, 1);
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED);
- } else if ((inp != NULL) && (stcb == NULL)) {
- inp_decr = inp;
- }
- SCTP_STAT_INCR(sctps_badsum);
- SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors);
- goto out;
+ }
+ KASSERT(cksum_validated || cksum_in_hdr == htonl(0),
+ ("cksum 0x%08x not zero and not validated", ntohl(cksum_in_hdr)));
+ if (!cksum_validated) {
+ stcb = sctp_findassociation_addr(m, offset, src, dst,
+ sh, ch, &inp, &net, vrf_id);
+ stcb_looked_up = true;
+ if ((stcb == NULL) || (stcb->asoc.zero_checksum == 0)) {
+ goto validate_cksum;
+ }
+ SCTP_STAT_INCR(sctps_recvzerocrc);
}
}
+cksum_validated:
/* Destination port of 0 is illegal, based on RFC4960. */
- if (sh->dest_port == 0) {
+ if (sh->dest_port == htons(0)) {
SCTP_STAT_INCR(sctps_hdrops);
+ if ((stcb == NULL) && (inp != NULL)) {
+ inp_decr = inp;
+ }
goto out;
}
- stcb = sctp_findassociation_addr(m, offset, src, dst,
- sh, ch, &inp, &net, vrf_id);
+ if (!stcb_looked_up) {
+ stcb = sctp_findassociation_addr(m, offset, src, dst,
+ sh, ch, &inp, &net, vrf_id);
+ }
#if defined(INET) || defined(INET6)
if ((ch->chunk_type != SCTP_INITIATION) &&
(net != NULL) && (net->port != port)) {
@@ -5352,8 +5417,8 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
net->flowid = mflowid;
}
if (inp == NULL) {
- SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh);
SCTP_STAT_INCR(sctps_noport);
+ SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh);
if (badport_bandlim(BANDLIM_SCTP_OOTB) < 0) {
goto out;
}
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index feb3fc31561d..97e89cb1396c 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -3969,6 +3969,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
uint16_t port,
union sctp_sockstore *over_addr,
uint8_t mflowtype, uint32_t mflowid,
+ bool use_zero_crc,
int so_locked)
{
/* nofragment_flag to tell if IP_DF should be set (IPv4 only) */
@@ -4203,15 +4204,23 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
}
SCTP_ATTACH_CHAIN(o_pak, m, packet_length);
if (port) {
- sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip) + sizeof(struct udphdr));
- SCTP_STAT_INCR(sctps_sendswcrc);
+ if (use_zero_crc) {
+ SCTP_STAT_INCR(sctps_sendzerocrc);
+ } else {
+ sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip) + sizeof(struct udphdr));
+ SCTP_STAT_INCR(sctps_sendswcrc);
+ }
if (V_udp_cksum) {
SCTP_ENABLE_UDP_CSUM(o_pak);
}
} else {
- m->m_pkthdr.csum_flags = CSUM_SCTP;
- m->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum);
- SCTP_STAT_INCR(sctps_sendhwcrc);
+ if (use_zero_crc) {
+ SCTP_STAT_INCR(sctps_sendzerocrc);
+ } else {
+ m->m_pkthdr.csum_flags = CSUM_SCTP;
+ m->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum);
+ SCTP_STAT_INCR(sctps_sendhwcrc);
+ }
}
#ifdef SCTP_PACKET_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING)
@@ -4710,6 +4719,15 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked)
chunk_len += parameter_len;
}
+ /* Zero checksum acceptable parameter */
+ if (stcb->asoc.zero_checksum > 0) {
+ parameter_len = (uint16_t)sizeof(struct sctp_paramhdr);
+ ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
+ ph->param_type = htons(SCTP_ZERO_CHECKSUM_ACCEPTABLE);
+ ph->param_length = htons(parameter_len);
+ chunk_len += parameter_len;
+ }
+
/* Add NAT friendly parameter. */
if (SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly)) {
parameter_len = (uint16_t)sizeof(struct sctp_paramhdr);
@@ -4883,7 +4901,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked)
inp->sctp_lport, stcb->rport, htonl(0),
net->port, NULL,
0, 0,
- so_locked))) {
+ false, so_locked))) {
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak send error %d\n", error);
if (error == ENOBUFS) {
stcb->asoc.ifp_had_enobuf = 1;
@@ -5909,6 +5927,16 @@ do_a_abort:
chunk_len += parameter_len;
}
+ /* Zero checksum acceptable parameter */
+ if (((asoc != NULL) && (asoc->zero_checksum > 0)) ||
+ ((asoc == NULL) && (inp->zero_checksum == 1))) {
+ parameter_len = (uint16_t)sizeof(struct sctp_paramhdr);
+ ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
+ ph->param_type = htons(SCTP_ZERO_CHECKSUM_ACCEPTABLE);
+ ph->param_length = htons(parameter_len);
+ chunk_len += parameter_len;
+ }
+
/* Add NAT friendly parameter */
if (nat_friendly) {
parameter_len = (uint16_t)sizeof(struct sctp_paramhdr);
@@ -6117,6 +6145,7 @@ do_a_abort:
inp->sctp_lport, sh->src_port, init_chk->init.initiate_tag,
port, over_addr,
mflowtype, mflowid,
+ false, /* XXXMT: Improve this! */
SCTP_SO_NOT_LOCKED))) {
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak send error %d\n", error);
if (error == ENOBUFS) {
@@ -7784,6 +7813,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
* destination.
*/
int quit_now = 0;
+ bool use_zero_crc;
*num_out = 0;
*reason_code = 0;
@@ -8145,7 +8175,7 @@ again_one_more_time:
htonl(stcb->asoc.peer_vtag),
net->port, NULL,
0, 0,
- so_locked))) {
+ false, so_locked))) {
/*
* error, we could not
* output
@@ -8167,6 +8197,7 @@ again_one_more_time:
*/
sctp_move_chunks_from_net(stcb, net);
}
+ asconf = 0;
*reason_code = 7;
break;
} else {
@@ -8180,6 +8211,7 @@ again_one_more_time:
outchain = endoutchain = NULL;
auth = NULL;
auth_offset = 0;
+ asconf = 0;
if (!no_out_cnt)
*num_out += ctl_cnt;
/* recalc a clean slate and setup */
@@ -8391,8 +8423,10 @@ again_one_more_time:
* flight size since this little guy
* is a control only packet.
*/
+ use_zero_crc = asoc->zero_checksum = 2;
if (asconf) {
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, net);
+ use_zero_crc = false;
/*
* do NOT clear the asconf
* flag as it is used to do
@@ -8402,6 +8436,7 @@ again_one_more_time:
}
if (cookie) {
sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net);
+ use_zero_crc = false;
cookie = 0;
}
/* Only HB or ASCONF advances time */
@@ -8423,7 +8458,7 @@ again_one_more_time:
htonl(stcb->asoc.peer_vtag),
net->port, NULL,
0, 0,
- so_locked))) {
+ use_zero_crc, so_locked))) {
/*
* error, we could not
* output
@@ -8444,6 +8479,7 @@ again_one_more_time:
*/
sctp_move_chunks_from_net(stcb, net);
}
+ asconf = 0;
*reason_code = 7;
break;
} else {
@@ -8457,6 +8493,7 @@ again_one_more_time:
outchain = endoutchain = NULL;
auth = NULL;
auth_offset = 0;
+ asconf = 0;
if (!no_out_cnt)
*num_out += ctl_cnt;
/* recalc a clean slate and setup */
@@ -8719,9 +8756,11 @@ no_data_fill:
/* Is there something to send for this destination? */
if (outchain) {
/* We may need to start a control timer or two */
+ use_zero_crc = asoc->zero_checksum == 2;
if (asconf) {
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
stcb, net);
+ use_zero_crc = false;
/*
* do NOT clear the asconf flag as it is
* used to do appropriate source address
@@ -8730,6 +8769,7 @@ no_data_fill:
}
if (cookie) {
sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net);
+ use_zero_crc = false;
cookie = 0;
}
/* must start a send timer if data is being sent */
@@ -8764,6 +8804,7 @@ no_data_fill:
htonl(stcb->asoc.peer_vtag),
net->port, NULL,
0, 0,
+ use_zero_crc,
so_locked))) {
/* error, we could not output */
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
@@ -8781,6 +8822,7 @@ no_data_fill:
*/
sctp_move_chunks_from_net(stcb, net);
}
+ asconf = 0;
*reason_code = 6;
/*-
* I add this line to be paranoid. As far as
@@ -8797,6 +8839,7 @@ no_data_fill:
endoutchain = NULL;
auth = NULL;
auth_offset = 0;
+ asconf = 0;
if (!no_out_cnt) {
*num_out += (ctl_cnt + bundle_at);
}
@@ -9385,6 +9428,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
int override_ok = 1;
int data_auth_reqd = 0;
uint32_t dmtu = 0;
+ bool use_zero_crc;
SCTP_TCB_LOCK_ASSERT(stcb);
tmr_started = ctl_cnt = 0;
@@ -9448,10 +9492,15 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
/* do we have control chunks to retransmit? */
if (m != NULL) {
/* Start a timer no matter if we succeed or fail */
+ use_zero_crc = asoc->zero_checksum == 2;
if (chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) {
sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, chk->whoTo);
- } else if (chk->rec.chunk_id.id == SCTP_ASCONF)
+ use_zero_crc = false;
+ } else if (chk->rec.chunk_id.id == SCTP_ASCONF) {
+ /* XXXMT: Can this happen? */
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, chk->whoTo);
+ use_zero_crc = false;
+ }
chk->snd_count++; /* update our count */
if ((error = sctp_lowlevel_chunk_output(inp, stcb, chk->whoTo,
(struct sockaddr *)&chk->whoTo->ro._l_addr, m,
@@ -9460,6 +9509,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
inp->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag),
chk->whoTo->port, NULL,
0, 0,
+ use_zero_crc,
so_locked))) {
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
if (error == ENOBUFS) {
@@ -9737,6 +9787,7 @@ one_chunk_around:
inp->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag),
net->port, NULL,
0, 0,
+ asoc->zero_checksum == 2,
so_locked))) {
/* error, we could not output */
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
@@ -10897,6 +10948,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked)
stcb->sctp_ep->sctp_lport, stcb->rport, htonl(vtag),
stcb->asoc.primary_destination->port, NULL,
0, 0,
+ stcb->asoc.zero_checksum == 2,
so_locked))) {
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
if (error == ENOBUFS) {
@@ -10945,6 +10997,7 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb,
htonl(vtag),
net->port, NULL,
0, 0,
+ stcb->asoc.zero_checksum == 2,
SCTP_SO_NOT_LOCKED))) {
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
if (error == ENOBUFS) {
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index fa6ad102f864..7567764bfd72 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -2433,6 +2433,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
inp->nrsack_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_nrsack_enable);
inp->pktdrop_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_pktdrop_enable);
inp->idata_supported = 0;
+ inp->zero_checksum = 0;
inp->fibnum = so->so_fibnum;
/* init the small hash table we use to track asocid <-> tcb */
@@ -6402,6 +6403,14 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
} else if (ptype == SCTP_PRSCTP_SUPPORTED) {
/* Peer supports pr-sctp */
peer_supports_prsctp = 1;
+ } else if (ptype == SCTP_ZERO_CHECKSUM_ACCEPTABLE) {
+ /*
+ * Only send zero checksums if the upper layer has
+ * also enabled the support for this.
+ */
+ if (stcb->asoc.zero_checksum == 1) {
+ stcb->asoc.zero_checksum = 2;
+ }
} else if (ptype == SCTP_SUPPORTED_CHUNK_EXT) {
/* A supported extension chunk */
struct sctp_supported_chunk_types_param *pr_supported;
diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h
index fd8115a8101a..39d8b4e7013e 100644
--- a/sys/netinet/sctp_pcb.h
+++ b/sys/netinet/sctp_pcb.h
@@ -409,6 +409,7 @@ struct sctp_inpcb {
uint8_t reconfig_supported;
uint8_t nrsack_supported;
uint8_t pktdrop_supported;
+ uint8_t zero_checksum;
struct sctp_nonpad_sndrcvinfo def_send;
/*-
* These three are here for the sosend_dgram
diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h
index e28c2265589d..504e9ad79fe3 100644
--- a/sys/netinet/sctp_structs.h
+++ b/sys/netinet/sctp_structs.h
@@ -1185,6 +1185,12 @@ struct sctp_association {
uint8_t pktdrop_supported;
uint8_t idata_supported;
+ /*
+ * Zero checksum supported information: 0: disabled 1: enabled for
+ * rcv 2: enabled for snd/rcv
+ */
+ uint8_t zero_checksum;
+
/* Did the peer make the stream config (add out) request */
uint8_t peer_req_out;
diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c
index fcc02f315a1b..b48aedf0b950 100644
--- a/sys/netinet/sctp_sysctl.c
+++ b/sys/netinet/sctp_sysctl.c
@@ -121,6 +121,7 @@ sctp_init_sysctls(void)
SCTP_BASE_SYSCTL(sctp_blackhole) = SCTPCTL_BLACKHOLE_DEFAULT;
SCTP_BASE_SYSCTL(sctp_sendall_limit) = SCTPCTL_SENDALL_LIMIT_DEFAULT;
SCTP_BASE_SYSCTL(sctp_diag_info_code) = SCTPCTL_DIAG_INFO_CODE_DEFAULT;
+ SCTP_BASE_SYSCTL(sctp_ootb_with_zero_cksum) = SCTPCTL_OOTB_WITH_ZERO_CKSUM_DEFAULT;
#if defined(SCTP_LOCAL_TRACE_BUF)
memset(&SCTP_BASE_SYSCTL(sctp_log), 0, sizeof(struct sctp_log));
#endif
@@ -828,6 +829,9 @@ sctp_sysctl_handle_stats(SYSCTL_HANDLER_ARGS)
sb.sctps_send_burst_avoid += sarry->sctps_send_burst_avoid;
sb.sctps_send_cwnd_avoid += sarry->sctps_send_cwnd_avoid;
sb.sctps_fwdtsn_map_over += sarry->sctps_fwdtsn_map_over;
+ sb.sctps_queue_upd_ecne += sarry->sctps_queue_upd_ecne;
+ sb.sctps_recvzerocrc += sarry->sctps_recvzerocrc;
+ sb.sctps_sendzerocrc += sarry->sctps_sendzerocrc;
if (req->newptr != NULL) {
memcpy(sarry, &sb_temp, sizeof(struct sctpstat));
}
@@ -970,6 +974,7 @@ SCTP_UINT_SYSCTL(use_dcccecn, sctp_use_dccc_ecn, SCTPCTL_RTTVAR_DCCCECN)
SCTP_UINT_SYSCTL(blackhole, sctp_blackhole, SCTPCTL_BLACKHOLE)
SCTP_UINT_SYSCTL(sendall_limit, sctp_sendall_limit, SCTPCTL_SENDALL_LIMIT)
SCTP_UINT_SYSCTL(diag_info_code, sctp_diag_info_code, SCTPCTL_DIAG_INFO_CODE)
+SCTP_UINT_SYSCTL(ootb_with_zero_cksum, sctp_ootb_with_zero_cksum, SCTPCTL_OOTB_WITH_ZERO_CKSUM)
#ifdef SCTP_DEBUG
SCTP_UINT_SYSCTL(debug, sctp_debug_on, SCTPCTL_DEBUG)
#endif
diff --git a/sys/netinet/sctp_sysctl.h b/sys/netinet/sctp_sysctl.h
index 695cd743403b..12a7c5200b40 100644
--- a/sys/netinet/sctp_sysctl.h
+++ b/sys/netinet/sctp_sysctl.h
@@ -106,7 +106,6 @@ struct sctp_sysctl {
uint32_t sctp_rttvar_eqret;
uint32_t sctp_steady_step;
uint32_t sctp_use_dccc_ecn;
- uint32_t sctp_diag_info_code;
#if defined(SCTP_LOCAL_TRACE_BUF)
struct sctp_log sctp_log;
#endif
@@ -117,6 +116,8 @@ struct sctp_sysctl {
uint32_t sctp_initial_cwnd;
uint32_t sctp_blackhole;
uint32_t sctp_sendall_limit;
+ uint32_t sctp_diag_info_code;
+ uint32_t sctp_ootb_with_zero_cksum;
#if defined(SCTP_DEBUG)
uint32_t sctp_debug_on;
#endif
@@ -546,6 +547,11 @@ struct sctp_sysctl {
#define SCTPCTL_DIAG_INFO_CODE_MAX 65535
#define SCTPCTL_DIAG_INFO_CODE_DEFAULT 0
+#define SCTPCTL_OOTB_WITH_ZERO_CKSUM_DESC "Accept OOTB packets with zero checksum"
+#define SCTPCTL_OOTB_WITH_ZERO_CKSUM_MIN 0
+#define SCTPCTL_OOTB_WITH_ZERO_CKSUM_MAX 1
+#define SCTPCTL_OOTB_WITH_ZERO_CKSUM_DEFAULT 0
+
#if defined(SCTP_DEBUG)
/* debug: Configure debug output */
#define SCTPCTL_DEBUG_DESC "Configure debug output"
diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h
index 330a4529b039..e833b0ab33ae 100644
--- a/sys/netinet/sctp_uio.h
+++ b/sys/netinet/sctp_uio.h
@@ -1120,7 +1120,11 @@ struct sctpstat {
* fwd-tsn's */
uint32_t sctps_queue_upd_ecne; /* Number of times we queued or
* updated an ECN chunk on send queue */
- uint32_t sctps_reserved[31]; /* Future ABI compat - remove int's
+ uint32_t sctps_recvzerocrc; /* Number of accepted packets with
+ * zero CRC */
+ uint32_t sctps_sendzerocrc; /* Number of packets sent with zero
+ * CRC */
+ uint32_t sctps_reserved[29]; /* Future ABI compat - remove int's
* from here when adding new */
};
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index d308b75aa90d..57d5abdebd30 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -6834,6 +6834,29 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
break;
}
+ case SCTP_ACCEPT_ZERO_CHECKSUM:
+ {
+ uint32_t *value;
+
+ SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
+ SCTP_INP_WLOCK(inp);
+ if (*value == 0) {
+ /*
+ * Do not allow turning zero checksum
+ * acceptance off again, since this could
+ * result in inconsistent behaviour for
+ * listeners.
+ */
+ if (inp->zero_checksum > 0) {
+ error = EINVAL;
+ }
+ } else {
+ inp->zero_checksum = 1;
+ }
+ SCTP_INP_WUNLOCK(inp);
+ break;
+ }
+
default:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = ENOPROTOOPT;
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index f4b6ca8c0836..8bb0f7446b68 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -1149,6 +1149,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
asoc->nrsack_supported = inp->nrsack_supported;
asoc->pktdrop_supported = inp->pktdrop_supported;
asoc->idata_supported = inp->idata_supported;
+ asoc->zero_checksum = inp->zero_checksum;
asoc->sctp_cmt_pf = (uint8_t)0;
asoc->sctp_frag_point = inp->sctp_frag_point;
asoc->sctp_features = inp->sctp_features;