sctp: initial implementation of draft-tuexen-tsvwg-sctp-zero-checksum

This commit is contained in:
Michael Tuexen 2023-03-10 01:45:46 +01:00
parent 626d1e4a82
commit 4a2b92d99f
12 changed files with 234 additions and 60 deletions

View File

@ -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

View File

@ -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

View File

@ -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
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_looked_up = false;
if (compute_crc != 0) {
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);
}
} else if (port == 0) {
/*
* UDP encapsulation turned
* off.
*/
net->mtu += sizeof(struct udphdr);
/* XXX Update smallest_mtu */
}
net->port = port;
}
#endif
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;
}
}
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);
#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);
}
} else if (port == 0) {
/* UDP encapsulation turned off. */
net->mtu += sizeof(struct udphdr);
/* XXX Update smallest_mtu */
}
net->port = port;
stcb_looked_up = true;
if ((stcb == NULL) || (stcb->asoc.zero_checksum == 0)) {
goto validate_cksum;
}
#endif
if (net != NULL) {
net->flowtype = mflowtype;
net->flowid = mflowid;
}
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;
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;
}

View File

@ -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 @@ 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);
@ -6117,6 +6145,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
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 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
htonl(stcb->asoc.peer_vtag),
net->port, NULL,
0, 0,
so_locked))) {
false, so_locked))) {
/*
* error, we could not
* output
@ -8167,6 +8197,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
*/
sctp_move_chunks_from_net(stcb, net);
}
asconf = 0;
*reason_code = 7;
break;
} else {
@ -8180,6 +8211,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
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 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
* 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 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
}
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 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
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 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
*/
sctp_move_chunks_from_net(stcb, net);
}
asconf = 0;
*reason_code = 7;
break;
} else {
@ -8457,6 +8493,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
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 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
/* 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 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
}
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 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
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 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
*/
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 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
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 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
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) {

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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"

View File

@ -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 */
};

View File

@ -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;

View File

@ -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;