diff --git a/lib/libc/net/sctp_sys_calls.c b/lib/libc/net/sctp_sys_calls.c index a7da95c51271..b2451d701968 100644 --- a/lib/libc/net/sctp_sys_calls.c +++ b/lib/libc/net/sctp_sys_calls.c @@ -350,6 +350,9 @@ sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size) case SCTP_REMOTE_UDP_ENCAPS_PORT: ((struct sctp_udpencaps *)arg)->sue_assoc_id = id; break; + case SCTP_ECN_SUPPORTED: + ((struct sctp_assoc_value *)arg)->assoc_id = id; + break; case SCTP_MAX_BURST: ((struct sctp_assoc_value *)arg)->assoc_id = id; break; diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h index 4c5c03dcb433..d36b4a59343b 100644 --- a/sys/netinet/sctp.h +++ b/sys/netinet/sctp.h @@ -121,6 +121,7 @@ struct sctp_paramhdr { #define SCTP_DEFAULT_PRINFO 0x00000022 #define SCTP_PEER_ADDR_THLDS 0x00000023 #define SCTP_REMOTE_UDP_ENCAPS_PORT 0x00000024 +#define SCTP_ECN_SUPPORTED 0x00000025 /* * read-only options diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index dd10e4cd8a8b..5f96435897e9 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -2785,7 +2785,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, inp->sctp_socket = so; inp->sctp_frag_point = (*inp_p)->sctp_frag_point; inp->sctp_cmt_on_off = (*inp_p)->sctp_cmt_on_off; - inp->sctp_ecn_enable = (*inp_p)->sctp_ecn_enable; + inp->ecn_supported = (*inp_p)->ecn_supported; inp->partial_delivery_point = (*inp_p)->partial_delivery_point; inp->sctp_context = (*inp_p)->sctp_context; inp->local_strreset_support = (*inp_p)->local_strreset_support; @@ -5898,7 +5898,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt } /* take care of ecn */ if ((data_processed == 1) && - (stcb->asoc.ecn_allowed == 1) && + (stcb->asoc.ecn_supported == 1) && ((ecn_bits & SCTP_CE_BITS) == SCTP_CE_BITS)) { /* Yep, we need to add a ECNE */ sctp_send_ecn_echo(stcb, net, high_tsn); diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 6e3c01688c9f..a1663525d0c4 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3914,7 +3914,7 @@ sctp_add_cookie(struct mbuf *init, int init_offset, static uint8_t sctp_get_ect(struct sctp_tcb *stcb) { - if ((stcb != NULL) && (stcb->asoc.ecn_allowed == 1)) { + if ((stcb != NULL) && (stcb->asoc.ecn_supported == 1)) { return (SCTP_ECT0_BIT); } else { return (0); @@ -4785,7 +4785,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked chunk_len += parameter_len; } /* ECN parameter */ - if (stcb->asoc.ecn_allowed == 1) { + if (stcb->asoc.ecn_supported == 1) { parameter_len = (uint16_t) sizeof(struct sctp_paramhdr); ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len); ph->param_type = htons(SCTP_ECN_CAPABLE); @@ -5882,8 +5882,8 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, chunk_len += parameter_len; } /* ECN parameter */ - if (((asoc != NULL) && (asoc->ecn_allowed == 1)) || - ((asoc == NULL) && (inp->sctp_ecn_enable == 1))) { + if (((asoc != NULL) && (asoc->ecn_supported == 1)) || + ((asoc == NULL) && (inp->ecn_supported == 1))) { parameter_len = (uint16_t) sizeof(struct sctp_paramhdr); ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len); ph->param_type = htons(SCTP_ECN_CAPABLE); diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index ef103cd186ba..07ab20e6edae 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -2483,7 +2483,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) inp->partial_delivery_point = SCTP_SB_LIMIT_RCV(so) >> SCTP_PARTIAL_DELIVERY_SHIFT; inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; inp->sctp_cmt_on_off = SCTP_BASE_SYSCTL(sctp_cmt_on_off); - inp->sctp_ecn_enable = SCTP_BASE_SYSCTL(sctp_ecn_enable); + inp->ecn_supported = (uint8_t) SCTP_BASE_SYSCTL(sctp_ecn_enable); /* init the small hash table we use to track asocid <-> tcb */ inp->sctp_asocidhash = SCTP_HASH_INIT(SCTP_STACK_VTAG_HASH_SIZE, &inp->hashasocidmark); if (inp->sctp_asocidhash == NULL) { @@ -6081,7 +6081,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, sctp_key_t *new_key; uint32_t keylen; int got_random = 0, got_hmacs = 0, got_chklist = 0; - uint8_t ecn_allowed; + uint8_t ecn_supported; #ifdef INET struct sockaddr_in sin; @@ -6111,7 +6111,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, sa = src; } /* Turn off ECN until we get through all params */ - ecn_allowed = 0; + ecn_supported = 0; TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { /* mark all addresses that we have currently on the list */ net->dest_state |= SCTP_ADDR_NOT_IN_ASSOC; @@ -6360,7 +6360,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } else #endif if (ptype == SCTP_ECN_CAPABLE) { - ecn_allowed = 1; + ecn_supported = 1; } else if (ptype == SCTP_ULP_ADAPTATION) { if (stcb->asoc.state != SCTP_STATE_OPEN) { struct sctp_adaptation_layer_indication ai, @@ -6612,9 +6612,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } } } - if (ecn_allowed == 0) { - stcb->asoc.ecn_allowed = 0; - } + stcb->asoc.ecn_supported &= ecn_supported; /* validate authentication required parameters */ if (got_random && got_hmacs) { stcb->asoc.peer_supports_auth = 1; diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h index 8045765c4c5e..9fa1c1abf293 100644 --- a/sys/netinet/sctp_pcb.h +++ b/sys/netinet/sctp_pcb.h @@ -406,7 +406,7 @@ struct sctp_inpcb { uint32_t sctp_context; uint8_t local_strreset_support; uint32_t sctp_cmt_on_off; - uint32_t sctp_ecn_enable; + uint8_t ecn_supported; struct sctp_nonpad_sndrcvinfo def_send; /*- * These three are here for the sosend_dgram diff --git a/sys/netinet/sctp_peeloff.c b/sys/netinet/sctp_peeloff.c index fd8c93c54763..2373445ed1ce 100644 --- a/sys/netinet/sctp_peeloff.c +++ b/sys/netinet/sctp_peeloff.c @@ -118,7 +118,7 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id) n_inp->sctp_mobility_features = inp->sctp_mobility_features; n_inp->sctp_frag_point = inp->sctp_frag_point; n_inp->sctp_cmt_on_off = inp->sctp_cmt_on_off; - n_inp->sctp_ecn_enable = inp->sctp_ecn_enable; + n_inp->ecn_supported = inp->ecn_supported; n_inp->partial_delivery_point = inp->partial_delivery_point; n_inp->sctp_context = inp->sctp_context; n_inp->local_strreset_support = inp->local_strreset_support; diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h index a8b86c620400..701dc8aa4e56 100644 --- a/sys/netinet/sctp_structs.h +++ b/sys/netinet/sctp_structs.h @@ -1151,7 +1151,7 @@ struct sctp_association { */ /* Flag to tell if ECN is allowed */ - uint8_t ecn_allowed; + uint8_t ecn_supported; /* Did the peer make the stream config (add out) request */ uint8_t peer_req_out; diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 595aca3483bd..89df3c40682e 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -3294,6 +3294,33 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, } break; } + case SCTP_ECN_SUPPORTED: + { + struct sctp_assoc_value *av; + + SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); + SCTP_FIND_STCB(inp, stcb, av->assoc_id); + + if (stcb) { + av->assoc_value = stcb->asoc.ecn_supported; + SCTP_TCB_UNLOCK(stcb); + } else { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { + SCTP_INP_RLOCK(inp); + av->assoc_value = inp->ecn_supported; + SCTP_INP_RUNLOCK(inp); + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } + } + if (error == 0) { + *optsize = sizeof(struct sctp_assoc_value); + } + break; + } case SCTP_ENABLE_STREAM_RESET: { struct sctp_assoc_value *av; @@ -5857,6 +5884,35 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } break; } + case SCTP_ECN_SUPPORTED: + { + struct sctp_assoc_value *av; + + SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); + SCTP_FIND_STCB(inp, stcb, av->assoc_id); + + if (stcb) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + SCTP_TCB_UNLOCK(stcb); + } else { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { + SCTP_INP_WLOCK(inp); + if (av->assoc_value == 0) { + inp->ecn_supported = 0; + } else { + inp->ecn_supported = 0; + } + SCTP_INP_WUNLOCK(inp); + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } + } + break; + } default: SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); error = ENOPROTOOPT; diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 380b49f588a4..0c2c06e9b702 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -904,7 +904,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, asoc->heart_beat_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); asoc->cookie_life = inp->sctp_ep.def_cookie_life; asoc->sctp_cmt_on_off = inp->sctp_cmt_on_off; - asoc->ecn_allowed = inp->sctp_ecn_enable; + asoc->ecn_supported = inp->ecn_supported; asoc->sctp_nr_sack_on_off = (uint8_t) SCTP_BASE_SYSCTL(sctp_nr_sack_on_off); asoc->sctp_cmt_pf = (uint8_t) 0; asoc->sctp_frag_point = inp->sctp_frag_point;