summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Tuexen <tuexen@fh-muenster.de>2023-03-10 01:58:47 +0100
committerMichael Tuexen <tuexen@fh-muenster.de>2023-03-10 01:58:47 +0100
commitca70d3af67059294eea4a4276ae17acdcff7c090 (patch)
treeae024be31e8456d585d04188bdff7d96b908bea6
parentc1d6cb3bf4344e01e7d0b3157f4e7103d55b0fbf (diff)
Initial support of draft-tuexen-tsvwg-sctp-zero-checksum
-rwxr-xr-xusrsctplib/netinet/sctp.h1
-rwxr-xr-xusrsctplib/netinet/sctp_constants.h2
-rwxr-xr-xusrsctplib/netinet/sctp_input.c152
-rwxr-xr-xusrsctplib/netinet/sctp_output.c87
-rwxr-xr-xusrsctplib/netinet/sctp_pcb.c9
-rwxr-xr-xusrsctplib/netinet/sctp_pcb.h1
-rwxr-xr-xusrsctplib/netinet/sctp_structs.h7
-rwxr-xr-xusrsctplib/netinet/sctp_sysctl.c10
-rwxr-xr-xusrsctplib/netinet/sctp_sysctl.h8
-rwxr-xr-xusrsctplib/netinet/sctp_uio.h6
-rwxr-xr-xusrsctplib/netinet/sctp_usrreq.c22
-rwxr-xr-xusrsctplib/netinet/sctputil.c1
-rw-r--r--usrsctplib/usrsctp.h5
13 files changed, 241 insertions, 70 deletions
diff --git a/usrsctplib/netinet/sctp.h b/usrsctplib/netinet/sctp.h
index 2722511..203f6f1 100755
--- a/usrsctplib/netinet/sctp.h
+++ b/usrsctplib/netinet/sctp.h
@@ -139,6 +139,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/usrsctplib/netinet/sctp_constants.h b/usrsctplib/netinet/sctp_constants.h
index 3037627..ca2ed70 100755
--- a/usrsctplib/netinet/sctp_constants.h
+++ b/usrsctplib/netinet/sctp_constants.h
@@ -419,7 +419,7 @@ extern void getwintimeofday(struct timeval *tv);
/*************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/usrsctplib/netinet/sctp_input.c b/usrsctplib/netinet/sctp_input.c
index 4c58763..78cf07e 100755
--- a/usrsctplib/netinet/sctp_input.c
+++ b/usrsctplib/netinet/sctp_input.c
@@ -5746,78 +5746,136 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
#endif
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;
#if defined(__Userspace__)
struct socket *upcall_socket = NULL;
#endif
+ 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 defined(__FreeBSD__) && !defined(__Userspace__)
- if (net != NULL) {
- net->flowtype = mflowtype;
- net->flowid = mflowid;
- }
- SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh);
+ if (net != NULL) {
+ net->flowtype = mflowtype;
+ net->flowid = mflowid;
+ }
+ SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh);
#endif
- 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;
+ 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_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)) {
@@ -5842,11 +5900,9 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
}
#endif
if (inp == NULL) {
-#if defined(__FreeBSD__) && !defined(__Userspace__)
- SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh);
-#endif
SCTP_STAT_INCR(sctps_noport);
#if defined(__FreeBSD__) && !defined(__Userspace__)
+ SCTP_PROBE5(receive, NULL, stcb, m, stcb, sh);
if (badport_bandlim(BANDLIM_SCTP_OOTB) < 0) {
goto out;
}
diff --git a/usrsctplib/netinet/sctp_output.c b/usrsctplib/netinet/sctp_output.c
index 2619197..7f79600 100755
--- a/usrsctplib/netinet/sctp_output.c
+++ b/usrsctplib/netinet/sctp_output.c
@@ -4090,7 +4090,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
#if defined(__FreeBSD__) && !defined(__Userspace__)
uint8_t mflowtype, uint32_t mflowid,
#endif
-int so_locked)
+ bool use_zero_crc,
+ int so_locked)
/* nofragment_flag to tell if IP_DF should be set (IPv4 only) */
{
/**
@@ -4390,8 +4391,12 @@ int so_locked)
}
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 !defined(__Userspace__)
#if defined(__FreeBSD__)
if (V_udp_cksum) {
@@ -4402,19 +4407,23 @@ int so_locked)
#endif
#endif
} else {
-#if defined(__FreeBSD__) && !defined(__Userspace__)
- m->m_pkthdr.csum_flags = CSUM_SCTP;
- m->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum);
- SCTP_STAT_INCR(sctps_sendhwcrc);
-#else
- if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
- (stcb) && (stcb->asoc.scope.loopback_scope))) {
- sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip));
- SCTP_STAT_INCR(sctps_sendswcrc);
+ if (use_zero_crc) {
+ SCTP_STAT_INCR(sctps_sendzerocrc);
} else {
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ m->m_pkthdr.csum_flags = CSUM_SCTP;
+ m->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum);
SCTP_STAT_INCR(sctps_sendhwcrc);
- }
+#else
+ if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
+ (stcb) && (stcb->asoc.scope.loopback_scope))) {
+ sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip));
+ SCTP_STAT_INCR(sctps_sendswcrc);
+ } else {
+ SCTP_STAT_INCR(sctps_sendhwcrc);
+ }
#endif
+ }
}
#ifdef SCTP_PACKET_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING)
@@ -5160,6 +5169,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);
@@ -5335,7 +5353,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked)
#if defined(__FreeBSD__) && !defined(__Userspace__)
0, 0,
#endif
- so_locked))) {
+ false, so_locked))) {
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak send error %d\n", error);
if (error == ENOBUFS) {
stcb->asoc.ifp_had_enobuf = 1;
@@ -6453,6 +6471,16 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
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);
@@ -6685,6 +6713,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
+ false, /* XXXMT: Improve this! */
SCTP_SO_NOT_LOCKED))) {
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak send error %d\n", error);
if (error == ENOBUFS) {
@@ -8370,6 +8399,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
/* JRS 5/14/07 - Add flag for whether a heartbeat is sent to
the destination. */
int quit_now = 0;
+ bool use_zero_crc;
#if defined(__APPLE__) && !defined(__Userspace__)
if (so_locked) {
@@ -8746,7 +8776,7 @@ again_one_more_time:
#if defined(__FreeBSD__) && !defined(__Userspace__)
0, 0,
#endif
- so_locked))) {
+ false, so_locked))) {
/* error, we could not output */
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
if (from_where == 0) {
@@ -8765,6 +8795,7 @@ again_one_more_time:
*/
sctp_move_chunks_from_net(stcb, net);
}
+ asconf = 0;
*reason_code = 7;
break;
} else {
@@ -8778,6 +8809,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 */
@@ -8983,8 +9015,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
@@ -8994,6 +9028,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 */
@@ -9017,7 +9052,7 @@ again_one_more_time:
#if defined(__FreeBSD__) && !defined(__Userspace__)
0, 0,
#endif
- so_locked))) {
+ use_zero_crc, so_locked))) {
/* error, we could not output */
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
if (from_where == 0) {
@@ -9035,6 +9070,7 @@ again_one_more_time:
*/
sctp_move_chunks_from_net(stcb, net);
}
+ asconf = 0;
*reason_code = 7;
break;
} else {
@@ -9048,6 +9084,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 */
@@ -9313,9 +9350,11 @@ again_one_more_time:
/* 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 selection.
@@ -9323,6 +9362,7 @@ again_one_more_time:
}
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 */
@@ -9359,6 +9399,7 @@ again_one_more_time:
#if defined(__FreeBSD__) && !defined(__Userspace__)
0, 0,
#endif
+ use_zero_crc,
so_locked))) {
/* error, we could not output */
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
@@ -9376,6 +9417,7 @@ again_one_more_time:
*/
sctp_move_chunks_from_net(stcb, net);
}
+ asconf = 0;
*reason_code = 6;
/*-
* I add this line to be paranoid. As far as
@@ -9391,6 +9433,7 @@ again_one_more_time:
endoutchain = NULL;
auth = NULL;
auth_offset = 0;
+ asconf = 0;
if (!no_out_cnt) {
*num_out += (ctl_cnt + bundle_at);
}
@@ -9979,6 +10022,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;
#if defined(__APPLE__) && !defined(__Userspace__)
if (so_locked) {
@@ -10049,10 +10093,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,
@@ -10063,6 +10112,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
#if defined(__FreeBSD__) && !defined(__Userspace__)
0, 0,
#endif
+ use_zero_crc,
so_locked))) {
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
if (error == ENOBUFS) {
@@ -10344,6 +10394,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
#if defined(__FreeBSD__) && !defined(__Userspace__)
0, 0,
#endif
+ asoc->zero_checksum == 2,
so_locked))) {
/* error, we could not output */
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
@@ -11524,6 +11575,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked)
#if defined(__FreeBSD__) && !defined(__Userspace__)
0, 0,
#endif
+ stcb->asoc.zero_checksum == 2,
so_locked))) {
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
if (error == ENOBUFS) {
@@ -11574,6 +11626,7 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb,
#if defined(__FreeBSD__) && !defined(__Userspace__)
0, 0,
#endif
+ 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/usrsctplib/netinet/sctp_pcb.c b/usrsctplib/netinet/sctp_pcb.c
index 23875ec..233ba5d 100755
--- a/usrsctplib/netinet/sctp_pcb.c
+++ b/usrsctplib/netinet/sctp_pcb.c
@@ -2797,6 +2797,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;
#if defined(__FreeBSD__) && !defined(__Userspace__)
inp->fibnum = so->so_fibnum;
@@ -7411,6 +7412,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/usrsctplib/netinet/sctp_pcb.h b/usrsctplib/netinet/sctp_pcb.h
index 76efc58..71c2188 100755
--- a/usrsctplib/netinet/sctp_pcb.h
+++ b/usrsctplib/netinet/sctp_pcb.h
@@ -496,6 +496,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/usrsctplib/netinet/sctp_structs.h b/usrsctplib/netinet/sctp_structs.h
index 62b9baf..e96c2c0 100755
--- a/usrsctplib/netinet/sctp_structs.h
+++ b/usrsctplib/netinet/sctp_structs.h
@@ -1234,6 +1234,13 @@ 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/usrsctplib/netinet/sctp_sysctl.c b/usrsctplib/netinet/sctp_sysctl.c
index 243153c..ffbe49e 100755
--- a/usrsctplib/netinet/sctp_sysctl.c
+++ b/usrsctplib/netinet/sctp_sysctl.c
@@ -151,6 +151,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)
#if defined(_WIN32) && !defined(__Userspace__)
/* On Windows, the resource for global variables is limited. */
@@ -1033,6 +1034,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));
}
@@ -1242,6 +1246,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
@@ -1341,6 +1346,7 @@ sctp_sysctl_handle_int(SYSCTL_HANDLER_ARGS)
RANGECHK(SCTP_BASE_SYSCTL(sctp_blackhole), SCTPCTL_BLACKHOLE_MIN, SCTPCTL_BLACKHOLE_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_sendall_limit), SCTPCTL_SENDALL_LIMIT_MIN, SCTPCTL_SENDALL_LIMIT_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_diag_info_code), SCTPCTL_DIAG_INFO_CODE_MIN, SCTPCTL_DIAG_INFO_CODE_MAX);
+ RANGECHK(SCTP_BASE_SYSCTL(sctp_ootb_with_zero_cksum), SCTPCTL_OOTB_WITH_ZERO_CKSUM_MIN, SCTPCTL_OOTB_WITH_ZERO_CKSUM_MAX);
#ifdef SCTP_DEBUG
RANGECHK(SCTP_BASE_SYSCTL(sctp_debug_on), SCTPCTL_DEBUG_MIN, SCTPCTL_DEBUG_MAX);
#endif
@@ -1641,6 +1647,10 @@ sysctl_setup_sctp(void)
&SCTP_BASE_SYSCTL(sctp_diag_info_code), 0, sctp_sysctl_handle_int,
SCTPCTL_DIAG_INFO_CODE_DESC);
+ sysctl_add_oid(&sysctl_oid_top, "ootb_with_zero_cksum", CTLTYPE_INT|CTLFLAG_RW,
+ &SCTP_BASE_SYSCTL(sctp_ootb_with_zero_cksum), 0, sctp_sysctl_handle_int,
+ SCTPCTL_OOTB_WITH_ZERO_CKSUM_DESC);
+
#ifdef SCTP_DEBUG
sysctl_add_oid(&sysctl_oid_top, "debug", CTLTYPE_INT|CTLFLAG_RW,
&SCTP_BASE_SYSCTL(sctp_debug_on), 0, sctp_sysctl_handle_int,
diff --git a/usrsctplib/netinet/sctp_sysctl.h b/usrsctplib/netinet/sctp_sysctl.h
index 5268e8c..9dc40c8 100755
--- a/usrsctplib/netinet/sctp_sysctl.h
+++ b/usrsctplib/netinet/sctp_sysctl.h
@@ -111,7 +111,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)
#if defined(_WIN32) && !defined(__Userspace__)
struct sctp_log *sctp_log;
@@ -126,6 +125,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
@@ -576,6 +577,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/usrsctplib/netinet/sctp_uio.h b/usrsctplib/netinet/sctp_uio.h
index 9daf847..eee2d64 100755
--- a/usrsctplib/netinet/sctp_uio.h
+++ b/usrsctplib/netinet/sctp_uio.h
@@ -1104,8 +1104,10 @@ struct sctpstat {
uint32_t sctps_send_burst_avoid; /* Unused */
uint32_t sctps_send_cwnd_avoid; /* Send cwnd full avoidance, already max burst inflight to net */
uint32_t sctps_fwdtsn_map_over; /* number of map array over-runs via 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 from here when adding new */
+ uint32_t sctps_queue_upd_ecne; /* Number of times we queued or updated an ECN chunk on send queue */
+ 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 */
};
#define SCTP_STAT_INCR(_x) SCTP_STAT_INCR_BY(_x,1)
diff --git a/usrsctplib/netinet/sctp_usrreq.c b/usrsctplib/netinet/sctp_usrreq.c
index c5c3d7d..b686158 100755
--- a/usrsctplib/netinet/sctp_usrreq.c
+++ b/usrsctplib/netinet/sctp_usrreq.c
@@ -7795,6 +7795,28 @@ 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/usrsctplib/netinet/sctputil.c b/usrsctplib/netinet/sctputil.c
index eb8e006..7c9e2ed 100755
--- a/usrsctplib/netinet/sctputil.c
+++ b/usrsctplib/netinet/sctputil.c
@@ -1178,6 +1178,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;
diff --git a/usrsctplib/usrsctp.h b/usrsctplib/usrsctp.h
index e0c17c3..4c135a1 100644
--- a/usrsctplib/usrsctp.h
+++ b/usrsctplib/usrsctp.h
@@ -1146,6 +1146,7 @@ USRSCTP_SYSCTL_DECL(sctp_steady_step)
USRSCTP_SYSCTL_DECL(sctp_use_dccc_ecn)
USRSCTP_SYSCTL_DECL(sctp_buffer_splitting)
USRSCTP_SYSCTL_DECL(sctp_initial_cwnd)
+USRSCTP_SYSCTL_DECL(sctp_ootb_with_zero_cksum)
#ifdef SCTP_DEBUG
USRSCTP_SYSCTL_DECL(sctp_debug_on)
/* More specific values can be found in sctp_constants, but
@@ -1304,7 +1305,9 @@ struct sctpstat {
uint32_t sctps_send_cwnd_avoid; /* Send cwnd full avoidance, already max burst inflight to net */
uint32_t sctps_fwdtsn_map_over; /* number of map array over-runs via 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 from here when adding new */
+ 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 */
};
void