sctp: initial implementation of draft-tuexen-tsvwg-sctp-zero-checksum
This commit is contained in:
parent
626d1e4a82
commit
4a2b92d99f
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user