diff options
| author | Michael Tuexen <tuexen@fh-muenster.de> | 2023-03-10 01:58:47 +0100 |
|---|---|---|
| committer | Michael Tuexen <tuexen@fh-muenster.de> | 2023-03-10 01:58:47 +0100 |
| commit | ca70d3af67059294eea4a4276ae17acdcff7c090 (patch) | |
| tree | ae024be31e8456d585d04188bdff7d96b908bea6 | |
| parent | c1d6cb3bf4344e01e7d0b3157f4e7103d55b0fbf (diff) | |
Initial support of draft-tuexen-tsvwg-sctp-zero-checksum
| -rwxr-xr-x | usrsctplib/netinet/sctp.h | 1 | ||||
| -rwxr-xr-x | usrsctplib/netinet/sctp_constants.h | 2 | ||||
| -rwxr-xr-x | usrsctplib/netinet/sctp_input.c | 152 | ||||
| -rwxr-xr-x | usrsctplib/netinet/sctp_output.c | 87 | ||||
| -rwxr-xr-x | usrsctplib/netinet/sctp_pcb.c | 9 | ||||
| -rwxr-xr-x | usrsctplib/netinet/sctp_pcb.h | 1 | ||||
| -rwxr-xr-x | usrsctplib/netinet/sctp_structs.h | 7 | ||||
| -rwxr-xr-x | usrsctplib/netinet/sctp_sysctl.c | 10 | ||||
| -rwxr-xr-x | usrsctplib/netinet/sctp_sysctl.h | 8 | ||||
| -rwxr-xr-x | usrsctplib/netinet/sctp_uio.h | 6 | ||||
| -rwxr-xr-x | usrsctplib/netinet/sctp_usrreq.c | 22 | ||||
| -rwxr-xr-x | usrsctplib/netinet/sctputil.c | 1 | ||||
| -rw-r--r-- | usrsctplib/usrsctp.h | 5 |
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 |
