The result of a joint work between rrs@ and myself at the IETF:

* Decouple the path supervision using a separate HB timer per path.
* Add support for potentially failed state.
* Bring back RTO.min to 1 second.
* Accept packets on IP-addresses already announced via an ASCONF
* While there: do some cleanups.

Approved by: re@
MFC after: 2 months.
This commit is contained in:
Michael Tuexen 2011-08-03 20:21:00 +00:00
parent f36e5acfc1
commit ca85e9482a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=224641
22 changed files with 1095 additions and 1442 deletions

View File

@ -410,6 +410,9 @@ sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size)
case SCTP_DEFAULT_PRINFO:
((struct sctp_default_prinfo *)arg)->pr_assoc_id = id;
break;
case SCTP_PEER_ADDR_THLDS:
((struct sctp_paddrthlds *)arg)->spt_assoc_id = id;
break;
case SCTP_MAX_BURST:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;

View File

@ -119,6 +119,7 @@ struct sctp_paramhdr {
#define SCTP_RECVNXTINFO 0x00000020
#define SCTP_DEFAULT_SNDINFO 0x00000021
#define SCTP_DEFAULT_PRINFO 0x00000022
#define SCTP_PEER_ADDR_THLDS 0x00000023
/*
* read-only options
@ -564,7 +565,6 @@ struct sctp_error_unrecognized_chunk {
#define SCTP_BLK_LOGGING_ENABLE 0x00000001
#define SCTP_CWND_MONITOR_ENABLE 0x00000002
#define SCTP_CWND_LOGGING_ENABLE 0x00000004
#define SCTP_EARLYFR_LOGGING_ENABLE 0x00000010
#define SCTP_FLIGHT_LOGGING_ENABLE 0x00000020
#define SCTP_FR_LOGGING_ENABLE 0x00000040
#define SCTP_LOCK_LOGGING_ENABLE 0x00000080
@ -572,23 +572,23 @@ struct sctp_error_unrecognized_chunk {
#define SCTP_MBCNT_LOGGING_ENABLE 0x00000200
#define SCTP_MBUF_LOGGING_ENABLE 0x00000400
#define SCTP_NAGLE_LOGGING_ENABLE 0x00000800
#define SCTP_RECV_RWND_LOGGING_ENABLE 0x00001000
#define SCTP_RECV_RWND_LOGGING_ENABLE 0x00001000
#define SCTP_RTTVAR_LOGGING_ENABLE 0x00002000
#define SCTP_SACK_LOGGING_ENABLE 0x00004000
#define SCTP_SACK_RWND_LOGGING_ENABLE 0x00008000
#define SCTP_SACK_RWND_LOGGING_ENABLE 0x00008000
#define SCTP_SB_LOGGING_ENABLE 0x00010000
#define SCTP_STR_LOGGING_ENABLE 0x00020000
#define SCTP_WAKE_LOGGING_ENABLE 0x00040000
#define SCTP_LOG_MAXBURST_ENABLE 0x00080000
#define SCTP_LOG_RWND_ENABLE 0x00100000
#define SCTP_LOG_SACK_ARRIVALS_ENABLE 0x00200000
#define SCTP_LTRACE_CHUNK_ENABLE 0x00400000
#define SCTP_LTRACE_ERROR_ENABLE 0x00800000
#define SCTP_LAST_PACKET_TRACING 0x01000000
#define SCTP_THRESHOLD_LOGGING 0x02000000
#define SCTP_LOG_AT_SEND_2_SCTP 0x04000000
#define SCTP_LOG_AT_SEND_2_OUTQ 0x08000000
#define SCTP_LOG_TRY_ADVANCE 0x10000000
#define SCTP_LOG_SACK_ARRIVALS_ENABLE 0x00200000
#define SCTP_LTRACE_CHUNK_ENABLE 0x00400000
#define SCTP_LTRACE_ERROR_ENABLE 0x00800000
#define SCTP_LAST_PACKET_TRACING 0x01000000
#define SCTP_THRESHOLD_LOGGING 0x02000000
#define SCTP_LOG_AT_SEND_2_SCTP 0x04000000
#define SCTP_LOG_AT_SEND_2_OUTQ 0x08000000
#define SCTP_LOG_TRY_ADVANCE 0x10000000
#undef SCTP_PACKED

View File

@ -198,8 +198,9 @@ sctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t * error_tlv,
static struct mbuf *
sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
struct sctp_tcb *stcb, int response_required)
struct sctp_tcb *stcb, int send_hb, int response_required)
{
struct sctp_nets *net;
struct mbuf *m_reply = NULL;
struct sockaddr_storage sa_source, sa_store;
struct sctp_paramhdr *ph;
@ -284,7 +285,7 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
}
/* add the address */
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE,
if (sctp_add_remote_addr(stcb, sa, &net, SCTP_DONOT_SETSCOPE,
SCTP_ADDR_DYNAMIC_ADDED) != 0) {
SCTPDBG(SCTP_DEBUG_ASCONF1,
"process_asconf_add_ip: error adding address\n");
@ -298,10 +299,12 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
m_reply =
sctp_asconf_success_response(aph->correlation_id);
}
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb,
NULL, SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1);
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep,
stcb, NULL);
stcb, net);
if (send_hb) {
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
}
}
return m_reply;
}
@ -554,7 +557,12 @@ sctp_process_asconf_set_primary(struct mbuf *m,
"process_asconf_set_primary: primary address set\n");
/* notify upper layer */
sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
if ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_REACHABLE) &&
(!(stcb->asoc.primary_destination->dest_state & SCTP_ADDR_PF)) &&
(stcb->asoc.alternate)) {
sctp_free_remote_addr(stcb->asoc.alternate);
stcb->asoc.alternate = NULL;
}
if (response_required) {
m_reply = sctp_asconf_success_response(aph->correlation_id);
}
@ -622,7 +630,7 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
struct sctp_asconf_ack_chunk *ack_cp;
struct sctp_asconf_paramhdr *aph, *ack_aph;
struct sctp_ipv6addr_param *p_addr;
unsigned int asconf_limit;
unsigned int asconf_limit, cnt;
int error = 0; /* did an error occur? */
/* asconf param buffer */
@ -717,6 +725,7 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
goto send_reply;
}
/* process through all parameters */
cnt = 0;
while (aph != NULL) {
unsigned int param_length, param_type;
@ -749,7 +758,8 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
case SCTP_ADD_IP_ADDRESS:
asoc->peer_supports_asconf = 1;
m_result = sctp_process_asconf_add_ip(m, aph, stcb,
error);
(cnt < SCTP_BASE_SYSCTL(sctp_hb_maxburst)), error);
cnt++;
break;
case SCTP_DEL_IP_ADDRESS:
asoc->peer_supports_asconf = 1;
@ -1959,7 +1969,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
int status;
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 &&
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 ||
sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
/* subset bound, no ASCONF allowed case, so ignore */
return;
@ -2075,8 +2085,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
stcb, stcb->asoc.primary_destination);
#else
sctp_send_asconf(stcb, stcb->asoc.primary_destination,
addr_locked);
sctp_send_asconf(stcb, NULL, addr_locked);
#endif
}
}
@ -2328,8 +2337,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
* If we have queued params in the open state, send out an ASCONF.
*/
if (num_queued > 0) {
sctp_send_asconf(stcb, stcb->asoc.primary_destination,
SCTP_ADDR_NOT_LOCKED);
sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
}
}
@ -2384,8 +2392,7 @@ sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
stcb->sctp_ep, stcb,
stcb->asoc.primary_destination);
#else
sctp_send_asconf(stcb, stcb->asoc.primary_destination,
SCTP_ADDR_NOT_LOCKED);
sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
#endif
}
} else {
@ -2421,8 +2428,7 @@ sctp_set_primary_ip_address(struct sctp_ifa *ifa)
stcb->sctp_ep, stcb,
stcb->asoc.primary_destination);
#else
sctp_send_asconf(stcb, stcb->asoc.primary_destination,
SCTP_ADDR_NOT_LOCKED);
sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
#endif
}
}
@ -2965,8 +2971,7 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
stcb->sctp_ep, stcb,
stcb->asoc.primary_destination);
#else
sctp_send_asconf(stcb, stcb->asoc.primary_destination,
SCTP_ADDR_NOT_LOCKED);
sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
#endif
}
}
@ -3540,5 +3545,5 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
}
skip_rest:
/* Now we must send the asconf into the queue */
sctp_send_asconf(stcb, net, 0);
sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED);
}

View File

@ -728,40 +728,6 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
}
}
#endif
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
/*
* So, first of all do we need to have a Early FR
* timer running?
*/
if ((!TAILQ_EMPTY(&asoc->sent_queue) &&
(net->ref_count > 1) &&
(net->flight_size < net->cwnd)) ||
(reneged_all)) {
/*
* yes, so in this case stop it if its
* running, and then restart it. Reneging
* all is a special case where we want to
* run the Early FR timer and then force the
* last few unacked to be sent, causing us
* to illicit a sack with gaps to force out
* the others.
*/
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck2);
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
}
SCTP_STAT_INCR(sctps_earlyfrstrid);
sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
} else {
/* No, stop it if its running */
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck3);
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_21);
}
}
}
/* if nothing was acked on this destination skip it */
if (net->net_ack == 0) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
@ -769,51 +735,6 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
}
continue;
}
if (net->net_ack2 > 0) {
/*
* Karn's rule applies to clearing error count, this
* is optional.
*/
net->error_count = 0;
if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
SCTP_ADDR_NOT_REACHABLE) {
/* addr came good */
net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
/* now was it the primary? if so restore */
if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
}
}
/*
* JRS 5/14/07 - If CMT PF is on and the destination
* is in PF state, set the destination to active
* state and set the cwnd to one or two MTU's based
* on whether PF1 or PF2 is being used.
*
* Should we stop any running T3 timer here?
*/
if ((asoc->sctp_cmt_on_off > 0) &&
(asoc->sctp_cmt_pf > 0) &&
((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
net->dest_state &= ~SCTP_ADDR_PF;
old_cwnd = net->cwnd;
net->cwnd = net->mtu * asoc->sctp_cmt_pf;
SDT_PROBE(sctp, cwnd, net, ack,
stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
old_cwnd, net->cwnd);
SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
net, net->cwnd);
/*
* Since the cwnd value is explicitly set,
* skip the code that updates the cwnd
* value.
*/
goto skip_cwnd_update;
}
}
#ifdef JANA_CMT_FAST_RECOVERY
/*
* CMT fast recovery code
@ -833,7 +754,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
* If we are in loss recovery we skip any cwnd
* update
*/
goto skip_cwnd_update;
return;
}
/*
* Did any measurements go on for this network?
@ -856,7 +777,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
if (net->cc_mod.rtcc.lbw) {
if (cc_bw_limit(stcb, net, nbw)) {
/* Hold here, no update */
goto skip_cwnd_update;
continue;
}
} else {
uint64_t vtag, probepoint;
@ -1049,26 +970,24 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
SCTP_CWND_LOG_NO_CUMACK);
}
}
skip_cwnd_update:
/*
* NOW, according to Karn's rule do we need to restore the
* RTO timer back? Check our net_ack2. If not set then we
* have a ambiguity.. i.e. all data ack'd was sent to more
* than one place.
*/
if (net->net_ack2) {
/* restore any doubled timers */
net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
if (net->RTO < stcb->asoc.minrto) {
net->RTO = stcb->asoc.minrto;
}
if (net->RTO > stcb->asoc.maxrto) {
net->RTO = stcb->asoc.maxrto;
}
}
}
}
static void
sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net)
{
int old_cwnd;
old_cwnd = net->cwnd;
net->cwnd = net->mtu;
SDT_PROBE(sctp, cwnd, net, ack,
stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
old_cwnd, net->cwnd);
SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
net, net->cwnd);
}
static void
sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net)
{
@ -1343,32 +1262,6 @@ sctp_cwnd_update_after_output(struct sctp_tcb *stcb,
}
}
static void
sctp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp,
struct sctp_tcb *stcb, struct sctp_nets *net)
{
int old_cwnd = net->cwnd;
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
/*
* make a small adjustment to cwnd and force to CA.
*/
if (net->cwnd > net->mtu)
/* drop down one MTU after sending */
net->cwnd -= net->mtu;
if (net->cwnd < net->ssthresh)
/* still in SS move to CA */
net->ssthresh = net->cwnd - 1;
SDT_PROBE(sctp, cwnd, net, fr,
stcb->asoc.my_vtag,
((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
net,
old_cwnd, net->cwnd);
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR);
}
}
static void
sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
struct sctp_association *asoc,
@ -1858,40 +1751,6 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
}
}
#endif
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
/*
* So, first of all do we need to have a Early FR
* timer running?
*/
if ((!TAILQ_EMPTY(&asoc->sent_queue) &&
(net->ref_count > 1) &&
(net->flight_size < net->cwnd)) ||
(reneged_all)) {
/*
* yes, so in this case stop it if its
* running, and then restart it. Reneging
* all is a special case where we want to
* run the Early FR timer and then force the
* last few unacked to be sent, causing us
* to illicit a sack with gaps to force out
* the others.
*/
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck2);
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
}
SCTP_STAT_INCR(sctps_earlyfrstrid);
sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
} else {
/* No, stop it if its running */
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck3);
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_21);
}
}
}
/* if nothing was acked on this destination skip it */
if (net->net_ack == 0) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
@ -1899,47 +1758,6 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
}
continue;
}
if (net->net_ack2 > 0) {
/*
* Karn's rule applies to clearing error count, this
* is optional.
*/
net->error_count = 0;
if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
SCTP_ADDR_NOT_REACHABLE) {
/* addr came good */
net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
/* now was it the primary? if so restore */
if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
}
}
/*
* JRS 5/14/07 - If CMT PF is on and the destination
* is in PF state, set the destination to active
* state and set the cwnd to one or two MTU's based
* on whether PF1 or PF2 is being used.
*
* Should we stop any running T3 timer here?
*/
if ((asoc->sctp_cmt_on_off > 0) &&
(asoc->sctp_cmt_pf > 0) &&
((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
net->dest_state &= ~SCTP_ADDR_PF;
net->cwnd = net->mtu * asoc->sctp_cmt_pf;
SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
net, net->cwnd);
/*
* Since the cwnd value is explicitly set,
* skip the code that updates the cwnd
* value.
*/
goto skip_cwnd_update;
}
}
#ifdef JANA_CMT_FAST_RECOVERY
/*
* CMT fast recovery code
@ -1959,7 +1777,7 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
* If we are in loss recovery we skip any cwnd
* update
*/
goto skip_cwnd_update;
return;
}
/*
* CMT: CUC algorithm. Update cwnd if pseudo-cumack has
@ -2004,23 +1822,6 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
SCTP_CWND_LOG_NO_CUMACK);
}
}
skip_cwnd_update:
/*
* NOW, according to Karn's rule do we need to restore the
* RTO timer back? Check our net_ack2. If not set then we
* have a ambiguity.. i.e. all data ack'd was sent to more
* than one place.
*/
if (net->net_ack2) {
/* restore any doubled timers */
net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
if (net->RTO < stcb->asoc.minrto) {
net->RTO = stcb->asoc.minrto;
}
if (net->RTO > stcb->asoc.maxrto) {
net->RTO = stcb->asoc.maxrto;
}
}
}
}
@ -2340,40 +2141,6 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
}
}
#endif
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
/*
* So, first of all do we need to have a Early FR
* timer running?
*/
if ((!TAILQ_EMPTY(&asoc->sent_queue) &&
(net->ref_count > 1) &&
(net->flight_size < net->cwnd)) ||
(reneged_all)) {
/*
* yes, so in this case stop it if its
* running, and then restart it. Reneging
* all is a special case where we want to
* run the Early FR timer and then force the
* last few unacked to be sent, causing us
* to illicit a sack with gaps to force out
* the others.
*/
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck2);
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
}
SCTP_STAT_INCR(sctps_earlyfrstrid);
sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
} else {
/* No, stop it if its running */
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck3);
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_21);
}
}
}
/* if nothing was acked on this destination skip it */
if (net->net_ack == 0) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
@ -2381,47 +2148,6 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
}
continue;
}
if (net->net_ack2 > 0) {
/*
* Karn's rule applies to clearing error count, this
* is optional.
*/
net->error_count = 0;
if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
SCTP_ADDR_NOT_REACHABLE) {
/* addr came good */
net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
/* now was it the primary? if so restore */
if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
}
}
/*
* JRS 5/14/07 - If CMT PF is on and the destination
* is in PF state, set the destination to active
* state and set the cwnd to one or two MTU's based
* on whether PF1 or PF2 is being used.
*
* Should we stop any running T3 timer here?
*/
if ((asoc->sctp_cmt_on_off > 0) &&
(asoc->sctp_cmt_pf > 0) &&
((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
net->dest_state &= ~SCTP_ADDR_PF;
net->cwnd = net->mtu * asoc->sctp_cmt_pf;
SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
net, net->cwnd);
/*
* Since the cwnd value is explicitly set,
* skip the code that updates the cwnd
* value.
*/
goto skip_cwnd_update;
}
}
#ifdef JANA_CMT_FAST_RECOVERY
/*
* CMT fast recovery code
@ -2441,7 +2167,7 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
* If we are in loss recovery we skip any cwnd
* update
*/
goto skip_cwnd_update;
return;
}
/*
* CMT: CUC algorithm. Update cwnd if pseudo-cumack has
@ -2457,23 +2183,6 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
SCTP_CWND_LOG_NO_CUMACK);
}
}
skip_cwnd_update:
/*
* NOW, according to Karn's rule do we need to restore the
* RTO timer back? Check our net_ack2. If not set then we
* have a ambiguity.. i.e. all data ack'd was sent to more
* than one place.
*/
if (net->net_ack2) {
/* restore any doubled timers */
net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
if (net->RTO < stcb->asoc.minrto) {
net->RTO = stcb->asoc.minrto;
}
if (net->RTO > stcb->asoc.maxrto) {
net->RTO = stcb->asoc.maxrto;
}
}
}
}
@ -2565,30 +2274,6 @@ sctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb,
}
}
static void
sctp_htcp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp,
struct sctp_tcb *stcb, struct sctp_nets *net)
{
int old_cwnd;
old_cwnd = net->cwnd;
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
net->cc_mod.htcp_ca.last_cong = sctp_get_tick_count();
/*
* make a small adjustment to cwnd and force to CA.
*/
if (net->cwnd > net->mtu)
/* drop down one MTU after sending */
net->cwnd -= net->mtu;
if (net->cwnd < net->ssthresh)
/* still in SS move to CA */
net->ssthresh = net->cwnd - 1;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR);
}
}
static void
sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb,
struct sctp_nets *net, int in_window, int num_pkt_lost)
@ -2618,42 +2303,42 @@ struct sctp_cc_functions sctp_cc_functions[] = {
{
.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
.sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack,
.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
.sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
.sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer
},
{
.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
.sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack,
.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
.sctp_cwnd_update_after_fr = sctp_hs_cwnd_update_after_fr,
.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
.sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer
},
{
.sctp_set_initial_cc_param = sctp_htcp_set_initial_cc_param,
.sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack,
.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
.sctp_cwnd_update_after_fr = sctp_htcp_cwnd_update_after_fr,
.sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout,
.sctp_cwnd_update_after_ecn_echo = sctp_htcp_cwnd_update_after_ecn_echo,
.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
.sctp_cwnd_update_after_fr_timer = sctp_htcp_cwnd_update_after_fr_timer
},
{
.sctp_set_initial_cc_param = sctp_set_rtcc_initial_cc_param,
.sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack,
.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
.sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_rtcc_after_ecn_echo,
.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
.sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer,
.sctp_cwnd_update_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted,
.sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged,
.sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins,

View File

@ -416,7 +416,7 @@ __FBSDID("$FreeBSD$");
#define SCTP_STR_RESET_IN_REQUEST 0x000e
#define SCTP_STR_RESET_TSN_REQUEST 0x000f
#define SCTP_STR_RESET_RESPONSE 0x0010
#define SCTP_STR_RESET_ADD_STREAMS 0x0011
#define SCTP_STR_RESET_ADD_STREAMS 0x0011
#define SCTP_MAX_RESET_PARAMS 2
#define SCTP_STREAM_RESET_TSN_DELTA 0x1000
@ -508,14 +508,10 @@ __FBSDID("$FreeBSD$");
/* SCTP reachability state for each address */
#define SCTP_ADDR_REACHABLE 0x001
#define SCTP_ADDR_NOT_REACHABLE 0x002
#define SCTP_ADDR_NOHB 0x004
#define SCTP_ADDR_BEING_DELETED 0x008
#define SCTP_ADDR_NOT_IN_ASSOC 0x010
#define SCTP_ADDR_WAS_PRIMARY 0x020
#define SCTP_ADDR_SWITCH_PRIMARY 0x040
#define SCTP_ADDR_OUT_OF_SCOPE 0x080
#define SCTP_ADDR_DOUBLE_SWITCH 0x100
#define SCTP_ADDR_UNCONFIRMED 0x200
#define SCTP_ADDR_REQ_PRIMARY 0x400
/* JRS 5/13/07 - Added potentially failed state for CMT PF */
@ -579,14 +575,13 @@ __FBSDID("$FreeBSD$");
#define SCTP_TIMER_TYPE_EVENTWAKE 13
#define SCTP_TIMER_TYPE_STRRESET 14
#define SCTP_TIMER_TYPE_INPKILL 15
#define SCTP_TIMER_TYPE_EARLYFR 17
#define SCTP_TIMER_TYPE_ASOCKILL 18
#define SCTP_TIMER_TYPE_ADDR_WQ 19
#define SCTP_TIMER_TYPE_ZERO_COPY 20
#define SCTP_TIMER_TYPE_ZCOPY_SENDQ 21
#define SCTP_TIMER_TYPE_PRIM_DELETED 22
#define SCTP_TIMER_TYPE_ASOCKILL 16
#define SCTP_TIMER_TYPE_ADDR_WQ 17
#define SCTP_TIMER_TYPE_ZERO_COPY 18
#define SCTP_TIMER_TYPE_ZCOPY_SENDQ 19
#define SCTP_TIMER_TYPE_PRIM_DELETED 20
/* add new timers here - and increment LAST */
#define SCTP_TIMER_TYPE_LAST 23
#define SCTP_TIMER_TYPE_LAST 21
#define SCTP_IS_TIMER_TYPE_VALID(t) (((t) > SCTP_TIMER_TYPE_NONE) && \
((t) < SCTP_TIMER_TYPE_LAST))
@ -655,16 +650,17 @@ __FBSDID("$FreeBSD$");
#define SCTP_DEFAULT_SECRET_LIFE_SEC 3600
#define SCTP_RTO_UPPER_BOUND (60000) /* 60 sec in ms */
#define SCTP_RTO_LOWER_BOUND (300) /* 0.3 sec is ms */
#define SCTP_RTO_LOWER_BOUND (1000) /* 1 sec is ms */
#define SCTP_RTO_INITIAL (3000) /* 3 sec in ms */
#define SCTP_INP_KILL_TIMEOUT 20/* number of ms to retry kill of inpcb */
#define SCTP_ASOC_KILL_TIMEOUT 10 /* number of ms to retry kill of inpcb */
#define SCTP_DEF_MAX_INIT 8
#define SCTP_DEF_MAX_SEND 10
#define SCTP_DEF_MAX_PATH_RTX 5
#define SCTP_DEF_MAX_INIT 8
#define SCTP_DEF_MAX_SEND 10
#define SCTP_DEF_MAX_PATH_RTX 5
#define SCTP_DEF_PATH_PF_THRESHOLD SCTP_DEF_MAX_PATH_RTX
#define SCTP_DEF_PMTU_RAISE_SEC 600 /* 10 min between raise attempts */
@ -679,7 +675,7 @@ __FBSDID("$FreeBSD$");
/* Send window update (incr * this > hiwat). Should be a power of 2 */
#define SCTP_MINIMAL_RWND (4096) /* minimal rwnd */
#define SCTP_ADDRMAX 24
#define SCTP_ADDRMAX 16
/* SCTP DEBUG Switch parameters */
#define SCTP_DEBUG_TIMER1 0x00000001

View File

@ -98,9 +98,10 @@ struct sctp_heartbeat_info_param {
uint32_t time_value_2;
uint32_t random_value1;
uint32_t random_value2;
uint16_t user_req;
uint8_t addr_family;
uint8_t addr_len;
/* make sure that this structure is 4 byte aligned */
uint8_t padding[2];
char address[SCTP_ADDRMAX];
} SCTP_PACKED;

View File

@ -2434,7 +2434,8 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap, int *abort_flag)
sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_INDATA + SCTP_LOC_18);
}
sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
sctp_send_shutdown(stcb,
((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination));
sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
} else {
int is_a_gap;
@ -4054,9 +4055,50 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
}
/* JRS - Use the congestion control given in the CC module */
if ((asoc->last_acked_seq != cumack) && (ecne_seen == 0))
if ((asoc->last_acked_seq != cumack) && (ecne_seen == 0)) {
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
if (net->net_ack2 > 0) {
/*
* Karn's rule applies to clearing error
* count, this is optional.
*/
net->error_count = 0;
if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
/* addr came good */
net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
}
if (net == stcb->asoc.primary_destination) {
if (stcb->asoc.alternate) {
/*
* release the alternate,
* primary is good
*/
sctp_free_remote_addr(stcb->asoc.alternate);
stcb->asoc.alternate = NULL;
}
}
if (net->dest_state & SCTP_ADDR_PF) {
net->dest_state &= ~SCTP_ADDR_PF;
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
/* Done with this net */
net->net_ack = 0;
}
/* restore any doubled timers */
net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
if (net->RTO < stcb->asoc.minrto) {
net->RTO = stcb->asoc.minrto;
}
if (net->RTO > stcb->asoc.maxrto) {
net->RTO = stcb->asoc.maxrto;
}
}
}
asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, 1, 0, 0);
}
asoc->last_acked_seq = cumack;
if (TAILQ_EMPTY(&asoc->sent_queue)) {
@ -4127,13 +4169,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_22);
}
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck4);
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_23);
}
}
}
}
if ((j == 0) &&
@ -4222,6 +4257,8 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24;
sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper, SCTP_SO_NOT_LOCKED);
} else {
struct sctp_nets *netp;
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
@ -4229,26 +4266,36 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb,
stcb->asoc.primary_destination);
if (asoc->alternate) {
netp = asoc->alternate;
} else {
netp = asoc->primary_destination;
}
sctp_send_shutdown(stcb, netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb, asoc->primary_destination);
stcb->sctp_ep, stcb, netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, asoc->primary_destination);
stcb->sctp_ep, stcb, netp);
}
} else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
(asoc->stream_queue_cnt == 0)) {
struct sctp_nets *netp;
if (asoc->alternate) {
netp = asoc->alternate;
} else {
netp = asoc->primary_destination;
}
if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
goto abort_out_now;
}
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_send_shutdown_ack(stcb,
stcb->asoc.primary_destination);
sctp_send_shutdown_ack(stcb, netp);
sctp_stop_timers_for_shutdown(stcb);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK,
stcb->sctp_ep, stcb, asoc->primary_destination);
stcb->sctp_ep, stcb, netp);
}
}
/*********************************************/
@ -4380,7 +4427,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
num_dup,
SCTP_LOG_NEW_SACK);
}
if ((num_dup) && (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_FR_LOGGING_ENABLE | SCTP_EARLYFR_LOGGING_ENABLE))) {
if ((num_dup) && (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE)) {
uint16_t i;
uint32_t *dupdata, dblock;
@ -4468,13 +4515,6 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_26);
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck1);
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_26);
}
}
net->partial_bytes_acked = 0;
net->flight_size = 0;
}
@ -4830,20 +4870,54 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
asoc->saw_sack_with_nr_frags = 0;
/* JRS - Use the congestion control given in the CC module */
if (ecne_seen == 0)
if (ecne_seen == 0) {
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
if (net->net_ack2 > 0) {
/*
* Karn's rule applies to clearing error
* count, this is optional.
*/
net->error_count = 0;
if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
/* addr came good */
net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
}
if (net == stcb->asoc.primary_destination) {
if (stcb->asoc.alternate) {
/*
* release the alternate,
* primary is good
*/
sctp_free_remote_addr(stcb->asoc.alternate);
stcb->asoc.alternate = NULL;
}
}
if (net->dest_state & SCTP_ADDR_PF) {
net->dest_state &= ~SCTP_ADDR_PF;
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
/* Done with this net */
net->net_ack = 0;
}
/* restore any doubled timers */
net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
if (net->RTO < stcb->asoc.minrto) {
net->RTO = stcb->asoc.minrto;
}
if (net->RTO > stcb->asoc.maxrto) {
net->RTO = stcb->asoc.maxrto;
}
}
}
asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, accum_moved, reneged_all, will_exit_fast_recovery);
}
if (TAILQ_EMPTY(&asoc->sent_queue)) {
/* nothing left in-flight */
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
/* stop all timers */
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck4);
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_29);
}
}
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30);
net->flight_size = 0;
@ -4918,6 +4992,13 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper, SCTP_SO_NOT_LOCKED);
return;
} else {
struct sctp_nets *netp;
if (asoc->alternate) {
netp = asoc->alternate;
} else {
netp = asoc->primary_destination;
}
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
@ -4925,27 +5006,32 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb,
stcb->asoc.primary_destination);
sctp_send_shutdown(stcb, netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb, asoc->primary_destination);
stcb->sctp_ep, stcb, netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, asoc->primary_destination);
stcb->sctp_ep, stcb, netp);
}
return;
} else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
(asoc->stream_queue_cnt == 0)) {
struct sctp_nets *netp;
if (asoc->alternate) {
netp = asoc->alternate;
} else {
netp = asoc->primary_destination;
}
if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
goto abort_out_now;
}
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_send_shutdown_ack(stcb,
stcb->asoc.primary_destination);
sctp_send_shutdown_ack(stcb, netp);
sctp_stop_timers_for_shutdown(stcb);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK,
stcb->sctp_ep, stcb, asoc->primary_destination);
stcb->sctp_ep, stcb, netp);
return;
}
}
@ -5056,13 +5142,6 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_22);
}
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpidsck4);
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_23);
}
}
}
}
if ((j == 0) &&

View File

@ -537,6 +537,7 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
struct sctp_nets *r_net, *f_net;
struct timeval tv;
int req_prim = 0;
uint16_t old_error_counter;
#ifdef INET
struct sockaddr_in *sin;
@ -599,7 +600,6 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
r_net->dest_state &= ~SCTP_ADDR_UNCONFIRMED;
if (r_net->dest_state & SCTP_ADDR_REQ_PRIMARY) {
stcb->asoc.primary_destination = r_net;
r_net->dest_state &= ~SCTP_ADDR_WAS_PRIMARY;
r_net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY;
f_net = TAILQ_FIRST(&stcb->asoc.nets);
if (f_net != r_net) {
@ -616,44 +616,37 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
}
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED,
stcb, 0, (void *)r_net, SCTP_SO_NOT_LOCKED);
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net);
}
old_error_counter = r_net->error_count;
r_net->error_count = 0;
r_net->hb_responded = 1;
tv.tv_sec = cp->heartbeat.hb_info.time_value_1;
tv.tv_usec = cp->heartbeat.hb_info.time_value_2;
if (r_net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
r_net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
r_net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
SCTP_HEARTBEAT_SUCCESS, (void *)r_net, SCTP_SO_NOT_LOCKED);
/* now was it the primary? if so restore */
if (r_net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, r_net);
}
}
/*
* JRS 5/14/07 - If CMT PF is on and the destination is in PF state,
* set the destination to active state and set the cwnd to one or
* two MTU's based on whether PF1 or PF2 is being used. If a T3
* timer is running, for the destination, stop the timer because a
* PF-heartbeat was received.
*/
if ((stcb->asoc.sctp_cmt_on_off > 0) &&
(stcb->asoc.sctp_cmt_pf > 0) &&
((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
stcb, net,
SCTP_FROM_SCTP_INPUT + SCTP_LOC_5);
}
net->dest_state &= ~SCTP_ADDR_PF;
net->cwnd = net->mtu * stcb->asoc.sctp_cmt_pf;
SCTPDBG(SCTP_DEBUG_INPUT1, "Destination %p moved from PF to reachable with cwnd %d.\n",
net, net->cwnd);
}
/* Now lets do a RTO with this */
r_net->RTO = sctp_calculate_rto(stcb, &stcb->asoc, r_net, &tv, sctp_align_safe_nocopy,
SCTP_RTT_FROM_NON_DATA);
if (!(r_net->dest_state & SCTP_ADDR_REACHABLE)) {
r_net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
SCTP_HEARTBEAT_SUCCESS, (void *)r_net, SCTP_SO_NOT_LOCKED);
}
if (r_net->dest_state & SCTP_ADDR_PF) {
r_net->dest_state &= ~SCTP_ADDR_PF;
stcb->asoc.cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
}
if (old_error_counter > 0) {
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net);
}
if (r_net == stcb->asoc.primary_destination) {
if (stcb->asoc.alternate) {
/* release the alternate, primary is good */
sctp_free_remote_addr(stcb->asoc.alternate);
stcb->asoc.alternate = NULL;
}
}
/* Mobility adaptation */
if (req_prim) {
if ((sctp_is_mobility_feature_on(stcb->sctp_ep,
@ -824,6 +817,35 @@ sctp_handle_abort(struct sctp_abort_chunk *cp,
SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_abort: finished\n");
}
static void
sctp_start_net_timers(struct sctp_tcb *stcb)
{
uint32_t cnt_hb_sent;
struct sctp_nets *net;
cnt_hb_sent = 0;
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
/*
* For each network start: 1) A pmtu timer. 2) A HB timer 3)
* If the dest in unconfirmed send a hb as well if under
* max_hb_burst have been sent.
*/
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
(cnt_hb_sent < SCTP_BASE_SYSCTL(sctp_hb_maxburst))) {
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
cnt_hb_sent++;
}
}
if (cnt_hb_sent) {
sctp_chunk_output(stcb->sctp_ep, stcb,
SCTP_OUTPUT_FROM_COOKIE_ACK,
SCTP_SO_NOT_LOCKED);
}
}
static void
sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
struct sctp_tcb *stcb, struct sctp_nets *net, int *abort_flag)
@ -916,7 +938,7 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
} else {
/* no outstanding data to send, so move on... */
/* send SHUTDOWN-ACK */
sctp_send_shutdown_ack(stcb, stcb->asoc.primary_destination);
sctp_send_shutdown_ack(stcb, net);
/* move to SHUTDOWN-ACK-SENT state */
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
@ -2685,7 +2707,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
/* TSNH! Huh, why do I need to add this address here? */
int ret;
ret = sctp_add_remote_addr(*stcb, to, SCTP_DONOT_SETSCOPE,
ret = sctp_add_remote_addr(*stcb, to, NULL, SCTP_DONOT_SETSCOPE,
SCTP_IN_COOKIE_PROC);
netl = sctp_findnet(*stcb, to);
}
@ -2697,10 +2719,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
send_int_conf = 1;
}
}
if (*stcb) {
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, *inp_p,
*stcb, NULL);
}
sctp_start_net_timers(*stcb);
if ((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
if (!had_a_existing_tcb ||
(((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
@ -2890,6 +2909,7 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp,
/* state change only needed when I am in right state */
SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n");
SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
sctp_start_net_timers(stcb);
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, asoc->primary_destination);
@ -3380,7 +3400,7 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
* Only retransmit if we KNOW we wont destroy the
* tcb
*/
(void)sctp_send_hb(stcb, 1, net, SCTP_SO_NOT_LOCKED);
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
}
break;
case SCTP_SHUTDOWN:
@ -3999,8 +4019,7 @@ __attribute__((noinline))
/* setup chunk parameters */
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
chk->whoTo = stcb->asoc.primary_destination;
atomic_add_int(&chk->whoTo->ref_count, 1);
chk->whoTo = NULL;
ch = mtod(chk->data, struct sctp_chunkhdr *);
ch->chunk_type = SCTP_STREAM_RESET;
@ -4630,8 +4649,7 @@ __attribute__((noinline))
if ((stcb != NULL) &&
(SCTP_GET_STATE(&stcb->asoc) ==
SCTP_STATE_SHUTDOWN_ACK_SENT)) {
sctp_send_shutdown_ack(stcb,
stcb->asoc.primary_destination);
sctp_send_shutdown_ack(stcb, NULL);
*offset = length;
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED);
if (locked_tcb) {

View File

@ -3543,7 +3543,8 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
*error = EINVAL;
return (-1);
}
if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL,
SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
*error = ENOBUFS;
return (1);
}
@ -3574,13 +3575,15 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
*error = EINVAL;
return (-1);
}
if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL,
SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
*error = ENOBUFS;
return (1);
}
} else
#endif
if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, NULL,
SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
*error = ENOBUFS;
return (1);
}
@ -3828,28 +3831,7 @@ sctp_handle_no_route(struct sctp_tcb *stcb,
(void *)net,
so_locked);
net->dest_state &= ~SCTP_ADDR_REACHABLE;
net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
/*
* JRS 5/14/07 - If a destination is
* unreachable, the PF bit is turned off.
* This allows an unambiguous use of the PF
* bit for destinations that are reachable
* but potentially failed. If the
* destination is set to the unreachable
* state, also set the destination to the PF
* state.
*/
/*
* Add debug message here if destination is
* not in PF state.
*/
/* Stop any running T3 timers here? */
if ((stcb->asoc.sctp_cmt_on_off > 0) &&
(stcb->asoc.sctp_cmt_pf > 0)) {
net->dest_state &= ~SCTP_ADDR_PF;
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Destination %p moved from PF to unreachable.\n",
net);
}
net->dest_state &= ~SCTP_ADDR_PF;
}
}
if (stcb) {
@ -3859,14 +3841,16 @@ sctp_handle_no_route(struct sctp_tcb *stcb,
alt = sctp_find_alternate_net(stcb, net, 0);
if (alt != net) {
if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, alt) == 0) {
net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
if (net->ro._s_addr) {
sctp_free_ifa(net->ro._s_addr);
net->ro._s_addr = NULL;
}
net->src_addr_selected = 0;
if (stcb->asoc.alternate) {
sctp_free_remote_addr(stcb->asoc.alternate);
}
stcb->asoc.alternate = alt;
atomic_add_int(&stcb->asoc.alternate->ref_count, 1);
if (net->ro._s_addr) {
sctp_free_ifa(net->ro._s_addr);
net->ro._s_addr = NULL;
}
net->src_addr_selected = 0;
}
}
}
@ -6498,6 +6482,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
int added_control = 0;
int un_sent, do_chunk_output = 1;
struct sctp_association *asoc;
struct sctp_nets *net;
ca = (struct sctp_copy_all *)ptr;
if (ca->m == NULL) {
@ -6531,6 +6516,11 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
m = NULL;
}
SCTP_TCB_LOCK_ASSERT(stcb);
if (stcb->asoc.alternate) {
net = stcb->asoc.alternate;
} else {
net = stcb->asoc.primary_destination;
}
if (ca->sndrcv.sinfo_flags & SCTP_ABORT) {
/* Abort this assoc with m as the user defined reason */
if (m) {
@ -6569,7 +6559,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
}
} else {
if (m) {
ret = sctp_msg_append(stcb, stcb->asoc.primary_destination, m,
ret = sctp_msg_append(stcb, net, m,
&ca->sndrcv, 1);
}
asoc = &stcb->asoc;
@ -6596,14 +6586,14 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
* only send SHUTDOWN the first time
* through
*/
sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
sctp_send_shutdown(stcb, net);
if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb,
asoc->primary_destination);
net);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
asoc->primary_destination);
added_control = 1;
@ -7733,13 +7723,13 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
struct sctp_auth_chunk *auth = NULL;
uint16_t auth_keyid;
int override_ok = 1;
int skip_fill_up = 0;
int data_auth_reqd = 0;
/*
* JRS 5/14/07 - Add flag for whether a heartbeat is sent to the
* destination.
*/
int pf_hbflag = 0;
int quit_now = 0;
*num_out = 0;
@ -7806,7 +7796,22 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
max_send_per_dest = SCTP_SB_LIMIT_SND(stcb->sctp_socket) / asoc->numnets;
else
max_send_per_dest = 0;
if (no_data_chunks == 0) {
/* How many non-directed chunks are there? */
TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
if (chk->whoTo == NULL) {
/*
* We already have non-directed chunks on
* the queue, no need to do a fill-up.
*/
skip_fill_up = 1;
break;
}
}
}
if ((no_data_chunks == 0) &&
(skip_fill_up == 0) &&
(!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc))) {
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
/*
@ -7821,8 +7826,10 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
* copy by reference (we hope).
*/
net->window_probe = 0;
if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ||
(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
if ((net != stcb->asoc.alternate) &&
((net->dest_state & SCTP_ADDR_PF) ||
(!(net->dest_state & SCTP_ADDR_REACHABLE)) ||
(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
sctp_log_cwnd(stcb, net, 1,
SCTP_CWND_LOG_FILL_OUTQ_CALLED);
@ -7833,16 +7840,6 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
(net->flight_size == 0)) {
(*stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) (stcb, net);
}
if ((asoc->sctp_cmt_on_off == 0) &&
(asoc->primary_destination != net) &&
(net->ref_count < 2)) {
/* nothing can be in queue for this guy */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
sctp_log_cwnd(stcb, net, 2,
SCTP_CWND_LOG_FILL_OUTQ_CALLED);
}
continue;
}
if (net->flight_size >= net->cwnd) {
/* skip this network, no room - can't fill */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
@ -7886,6 +7883,16 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
} else {
start_at = TAILQ_FIRST(&asoc->nets);
}
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
if (chk->whoTo == NULL) {
if (asoc->alternate) {
chk->whoTo = asoc->alternate;
} else {
chk->whoTo = asoc->primary_destination;
}
atomic_add_int(&chk->whoTo->ref_count, 1);
}
}
old_start_at = NULL;
again_one_more_time:
for (net = start_at; net != NULL; net = TAILQ_NEXT(net, sctp_next)) {
@ -7896,15 +7903,6 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
break;
}
tsns_sent = 0xa;
if ((asoc->sctp_cmt_on_off == 0) &&
(asoc->primary_destination != net) &&
(net->ref_count < 2)) {
/*
* Ref-count of 1 so we cannot have data or control
* queued to this address. Skip it (non-CMT).
*/
continue;
}
if (TAILQ_EMPTY(&asoc->control_send_queue) &&
TAILQ_EMPTY(&asoc->asconf_send_queue) &&
(net->flight_size >= net->cwnd)) {
@ -8266,15 +8264,8 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
(chk->rec.chunk_id.id == SCTP_ECN_CWR) ||
(chk->rec.chunk_id.id == SCTP_PACKET_DROPPED) ||
(chk->rec.chunk_id.id == SCTP_ASCONF_ACK)) {
if (chk->rec.chunk_id.id == SCTP_HEARTBEAT_REQUEST) {
hbflag = 1;
/*
* JRS 5/14/07 - Set the
* flag to say a heartbeat
* is being sent.
*/
pf_hbflag = 1;
}
/* remove these chunks at the end */
if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) ||
@ -8408,7 +8399,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
}
/* JRI: if dest is in PF state, do not send data to it */
if ((asoc->sctp_cmt_on_off > 0) &&
(asoc->sctp_cmt_pf > 0) &&
(net != stcb->asoc.alternate) &&
(net->dest_state & SCTP_ADDR_PF)) {
goto no_data_fill;
}
@ -8486,6 +8477,17 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
/* Don't send the chunk on this net */
continue;
}
if (asoc->sctp_cmt_on_off == 0) {
if ((asoc->alternate) &&
(asoc->alternate != net) &&
(chk->whoTo == NULL)) {
continue;
} else if ((net != asoc->primary_destination) &&
(asoc->alternate == NULL) &&
(chk->whoTo == NULL)) {
continue;
}
}
if ((chk->send_size > omtu) && ((chk->flags & CHUNK_FLAGS_FRAGMENT_OK) == 0)) {
/*-
* strange, we have a chunk that is
@ -8646,18 +8648,6 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
* restart it.
*/
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
} else if ((asoc->sctp_cmt_on_off > 0) &&
(asoc->sctp_cmt_pf > 0) &&
pf_hbflag &&
((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF) &&
(!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer))) {
/*
* JRS 5/14/07 - If a HB has been sent to a
* PF destination and no T3 timer is
* currently running, start the T3 timer to
* track the HBs that were sent.
*/
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
}
/* Now send it, if there is anything to send :> */
if ((error = sctp_lowlevel_chunk_output(inp,
@ -8747,24 +8737,6 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
}
SCTP_STAT_INCR_BY(sctps_senddata, bundle_at);
sctp_clean_up_datalist(stcb, asoc, data_list, bundle_at, net);
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
if (net->flight_size < net->cwnd) {
/* start or restart it */
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net,
SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_2);
}
SCTP_STAT_INCR(sctps_earlyfrstrout);
sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net);
} else {
/* stop it if its running */
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
SCTP_STAT_INCR(sctps_earlyfrstpout);
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net,
SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_3);
}
}
}
}
if (one_chunk) {
break;
@ -8833,8 +8805,7 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err)
chk->flags = 0;
chk->asoc = &stcb->asoc;
chk->data = op_err;
chk->whoTo = chk->asoc->primary_destination;
atomic_add_int(&chk->whoTo->ref_count, 1);
chk->whoTo = NULL;
hdr = mtod(op_err, struct sctp_chunkhdr *);
hdr->chunk_type = SCTP_OPERATION_ERROR;
hdr->chunk_flags = 0;
@ -8929,7 +8900,7 @@ sctp_send_cookie_echo(struct mbuf *m,
chk->flags = CHUNK_FLAGS_FRAGMENT_OK;
chk->asoc = &stcb->asoc;
chk->data = cookie;
chk->whoTo = chk->asoc->primary_destination;
chk->whoTo = net;
atomic_add_int(&chk->whoTo->ref_count, 1);
TAILQ_INSERT_HEAD(&chk->asoc->control_send_queue, chk, sctp_next);
chk->asoc->ctrl_queue_cnt++;
@ -9039,10 +9010,10 @@ sctp_send_cookie_ack(struct sctp_tcb *stcb)
chk->data = cookie_ack;
if (chk->asoc->last_control_chunk_from != NULL) {
chk->whoTo = chk->asoc->last_control_chunk_from;
atomic_add_int(&chk->whoTo->ref_count, 1);
} else {
chk->whoTo = chk->asoc->primary_destination;
chk->whoTo = NULL;
}
atomic_add_int(&chk->whoTo->ref_count, 1);
hdr = mtod(cookie_ack, struct sctp_chunkhdr *);
hdr->chunk_type = SCTP_COOKIE_ACK;
hdr->chunk_flags = 0;
@ -9084,8 +9055,9 @@ sctp_send_shutdown_ack(struct sctp_tcb *stcb, struct sctp_nets *net)
chk->asoc = &stcb->asoc;
chk->data = m_shutdown_ack;
chk->whoTo = net;
atomic_add_int(&net->ref_count, 1);
if (chk->whoTo) {
atomic_add_int(&chk->whoTo->ref_count, 1);
}
ack_cp = mtod(m_shutdown_ack, struct sctp_shutdown_ack_chunk *);
ack_cp->ch.chunk_type = SCTP_SHUTDOWN_ACK;
ack_cp->ch.chunk_flags = 0;
@ -9126,8 +9098,9 @@ sctp_send_shutdown(struct sctp_tcb *stcb, struct sctp_nets *net)
chk->asoc = &stcb->asoc;
chk->data = m_shutdown;
chk->whoTo = net;
atomic_add_int(&net->ref_count, 1);
if (chk->whoTo) {
atomic_add_int(&chk->whoTo->ref_count, 1);
}
shutdown_cp = mtod(m_shutdown, struct sctp_shutdown_chunk *);
shutdown_cp->ch.chunk_type = SCTP_SHUTDOWN;
shutdown_cp->ch.chunk_flags = 0;
@ -9178,7 +9151,9 @@ sctp_send_asconf(struct sctp_tcb *stcb, struct sctp_nets *net, int addr_locked)
chk->flags = CHUNK_FLAGS_FRAGMENT_OK;
chk->asoc = &stcb->asoc;
chk->whoTo = net;
atomic_add_int(&chk->whoTo->ref_count, 1);
if (chk->whoTo) {
atomic_add_int(&chk->whoTo->ref_count, 1);
}
TAILQ_INSERT_TAIL(&chk->asoc->asconf_send_queue, chk, sctp_next);
chk->asoc->ctrl_queue_cnt++;
return;
@ -9208,17 +9183,27 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb)
net = sctp_find_alternate_net(stcb, stcb->asoc.last_control_chunk_from, 0);
if (net == NULL) {
/* no alternate */
if (stcb->asoc.last_control_chunk_from == NULL)
net = stcb->asoc.primary_destination;
else
if (stcb->asoc.last_control_chunk_from == NULL) {
if (stcb->asoc.alternate) {
net = stcb->asoc.alternate;
} else {
net = stcb->asoc.primary_destination;
}
} else {
net = stcb->asoc.last_control_chunk_from;
}
}
} else {
/* normal case */
if (stcb->asoc.last_control_chunk_from == NULL)
net = stcb->asoc.primary_destination;
else
if (stcb->asoc.last_control_chunk_from == NULL) {
if (stcb->asoc.alternate) {
net = stcb->asoc.alternate;
} else {
net = stcb->asoc.primary_destination;
}
} else {
net = stcb->asoc.last_control_chunk_from;
}
}
latest_ack->last_sent_to = net;
@ -9256,6 +9241,9 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb)
chk->copy_by_ref = 0;
chk->whoTo = net;
if (chk->whoTo) {
atomic_add_int(&chk->whoTo->ref_count, 1);
}
chk->data = m_ack;
chk->send_size = 0;
/* Get size */
@ -9267,7 +9255,6 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb)
chk->snd_count = 0;
chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; /* XXX */
chk->asoc = &stcb->asoc;
atomic_add_int(&chk->whoTo->ref_count, 1);
TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next);
chk->asoc->ctrl_queue_cnt++;
@ -9797,7 +9784,11 @@ sctp_timer_validation(struct sctp_inpcb *inp,
SCTP_TCB_LOCK_ASSERT(stcb);
/* Gak, we did not have a timer somewhere */
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Deadlock avoided starting timer on a dest at retran\n");
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->primary_destination);
if (asoc->alternate) {
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->alternate);
} else {
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->primary_destination);
}
return (ret);
}
@ -9945,8 +9936,7 @@ sctp_chunk_output(struct sctp_inpcb *inp,
#endif
/* Check for bad destinations, if they exist move chunks around. */
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
SCTP_ADDR_NOT_REACHABLE) {
if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
/*-
* if possible move things off of this address we
* still may send below due to the dormant state but
@ -9956,16 +9946,6 @@ sctp_chunk_output(struct sctp_inpcb *inp,
*/
if (net->ref_count > 1)
sctp_move_chunks_from_net(stcb, net);
} else if ((asoc->sctp_cmt_on_off > 0) &&
(asoc->sctp_cmt_pf > 0) &&
((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
/*
* JRS 5/14/07 - If CMT PF is on and the current
* destination is in PF state, move all queued data
* to an alternate desination.
*/
if (net->ref_count > 1)
sctp_move_chunks_from_net(stcb, net);
} else {
/*-
* if ((asoc->sat_network) || (net->addr_is_local))
@ -10123,10 +10103,9 @@ send_forward_tsn(struct sctp_tcb *stcb,
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
/* Do we correct its output location? */
if (chk->whoTo != asoc->primary_destination) {
if (chk->whoTo) {
sctp_free_remote_addr(chk->whoTo);
chk->whoTo = asoc->primary_destination;
atomic_add_int(&chk->whoTo->ref_count, 1);
chk->whoTo = NULL;
}
goto sctp_fill_in_rest;
}
@ -10150,8 +10129,6 @@ send_forward_tsn(struct sctp_tcb *stcb,
SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD);
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
chk->whoTo = asoc->primary_destination;
atomic_add_int(&chk->whoTo->ref_count, 1);
TAILQ_INSERT_TAIL(&asoc->control_send_queue, chk, sctp_next);
asoc->ctrl_queue_cnt++;
sctp_fill_in_rest:
@ -10346,8 +10323,10 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
sctp_m_freem(a_chk->data);
a_chk->data = NULL;
}
sctp_free_remote_addr(a_chk->whoTo);
a_chk->whoTo = NULL;
if (a_chk->whoTo) {
sctp_free_remote_addr(a_chk->whoTo);
a_chk->whoTo = NULL;
}
break;
}
}
@ -10379,13 +10358,13 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
a_chk->whoTo = NULL;
if ((asoc->numduptsns) ||
(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_NOT_REACHABLE)) {
(!(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE))) {
/*-
* Ok, we have some duplicates or the destination for the
* sack is unreachable, lets see if we can select an
* alternate than asoc->last_data_chunk_from
*/
if ((!(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_NOT_REACHABLE)) &&
if ((asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE) &&
(asoc->used_alt_onsack > asoc->numnets)) {
/* We used an alt last time, don't this time */
a_chk->whoTo = NULL;
@ -10710,6 +10689,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
int sz;
uint32_t auth_offset = 0;
struct sctp_auth_chunk *auth = NULL;
struct sctp_nets *net;
/*-
* Add an AUTH chunk, if chunk requires it and save the offset into
@ -10750,16 +10730,19 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
/* Put AUTH chunk at the front of the chain */
SCTP_BUF_NEXT(m_end) = m_abort;
}
if (stcb->asoc.alternate) {
net = stcb->asoc.alternate;
} else {
net = stcb->asoc.primary_destination;
}
/* fill in the ABORT chunk */
abort = mtod(m_abort, struct sctp_abort_chunk *);
abort->ch.chunk_type = SCTP_ABORT_ASSOCIATION;
abort->ch.chunk_flags = 0;
abort->ch.chunk_length = htons(sizeof(*abort) + sz);
(void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb,
stcb->asoc.primary_destination,
(struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr,
(void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, NULL, 0,
stcb->sctp_ep->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag),
stcb->asoc.primary_destination->port, so_locked, NULL, NULL);
@ -11030,120 +11013,22 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh,
}
static struct sctp_nets *
sctp_select_hb_destination(struct sctp_tcb *stcb, struct timeval *now)
{
struct sctp_nets *net, *hnet;
int ms_goneby, highest_ms, state_overide = 0;
(void)SCTP_GETTIME_TIMEVAL(now);
highest_ms = 0;
hnet = NULL;
SCTP_TCB_LOCK_ASSERT(stcb);
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
if (
((net->dest_state & SCTP_ADDR_NOHB) && ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0)) ||
(net->dest_state & SCTP_ADDR_OUT_OF_SCOPE)
) {
/*
* Skip this guy from consideration if HB is off AND
* its confirmed
*/
continue;
}
if (sctp_destination_is_reachable(stcb, (struct sockaddr *)&net->ro._l_addr) == 0) {
/* skip this dest net from consideration */
continue;
}
if (net->last_sent_time.tv_sec) {
/* Sent to so we subtract */
ms_goneby = (now->tv_sec - net->last_sent_time.tv_sec) * 1000;
} else
/* Never been sent to */
ms_goneby = 0x7fffffff;
/*-
* When the address state is unconfirmed but still
* considered reachable, we HB at a higher rate. Once it
* goes confirmed OR reaches the "unreachable" state, thenw
* we cut it back to HB at a more normal pace.
*/
if ((net->dest_state & (SCTP_ADDR_UNCONFIRMED | SCTP_ADDR_NOT_REACHABLE)) == SCTP_ADDR_UNCONFIRMED) {
state_overide = 1;
} else {
state_overide = 0;
}
if ((((unsigned int)ms_goneby >= net->RTO) || (state_overide)) &&
(ms_goneby > highest_ms)) {
highest_ms = ms_goneby;
hnet = net;
}
}
if (hnet &&
((hnet->dest_state & (SCTP_ADDR_UNCONFIRMED | SCTP_ADDR_NOT_REACHABLE)) == SCTP_ADDR_UNCONFIRMED)) {
state_overide = 1;
} else {
state_overide = 0;
}
if (hnet && highest_ms && (((unsigned int)highest_ms >= hnet->RTO) || state_overide)) {
/*-
* Found the one with longest delay bounds OR it is
* unconfirmed and still not marked unreachable.
*/
SCTPDBG(SCTP_DEBUG_OUTPUT4, "net:%p is the hb winner -", hnet);
#ifdef SCTP_DEBUG
if (hnet) {
SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT4,
(struct sockaddr *)&hnet->ro._l_addr);
} else {
SCTPDBG(SCTP_DEBUG_OUTPUT4, " none\n");
}
#endif
/* update the timer now */
hnet->last_sent_time = *now;
return (hnet);
}
/* Nothing to HB */
return (NULL);
}
int
sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int so_locked
void
sctp_send_hb(struct sctp_tcb *stcb, struct sctp_nets *net, int so_locked
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
SCTP_UNUSED
#endif
)
{
struct sctp_tmit_chunk *chk;
struct sctp_nets *net;
struct sctp_heartbeat_chunk *hb;
struct timeval now;
SCTP_TCB_LOCK_ASSERT(stcb);
if (user_req == 0) {
net = sctp_select_hb_destination(stcb, &now);
if (net == NULL) {
/*-
* All our busy none to send to, just start the
* timer again.
*/
if (stcb->asoc.state == 0) {
return (0);
}
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT,
stcb->sctp_ep,
stcb,
net);
return (0);
}
} else {
net = u_net;
if (net == NULL) {
return (0);
}
(void)SCTP_GETTIME_TIMEVAL(&now);
if (net == NULL) {
return;
}
(void)SCTP_GETTIME_TIMEVAL(&now);
switch (net->ro._l_addr.sa.sa_family) {
#ifdef INET
case AF_INET:
@ -11154,12 +11039,12 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s
break;
#endif
default:
return (0);
return;
}
sctp_alloc_a_chunk(stcb, chk);
if (chk == NULL) {
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak, can't get a chunk for hb\n");
return (0);
return;
}
chk->copy_by_ref = 0;
chk->rec.chunk_id.id = SCTP_HEARTBEAT_REQUEST;
@ -11170,7 +11055,7 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s
chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_DONTWAIT, 1, MT_HEADER);
if (chk->data == NULL) {
sctp_free_a_chunk(stcb, chk, so_locked);
return (0);
return;
}
SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD);
SCTP_BUF_LEN(chk->data) = chk->send_size;
@ -11191,7 +11076,6 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s
hb->heartbeat.hb_info.time_value_1 = now.tv_sec;
hb->heartbeat.hb_info.time_value_2 = now.tv_usec;
/* Did our user request this one, put it in */
hb->heartbeat.hb_info.user_req = user_req;
hb->heartbeat.hb_info.addr_family = net->ro._l_addr.sa.sa_family;
hb->heartbeat.hb_info.addr_len = net->ro._l_addr.sa.sa_len;
if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
@ -11221,57 +11105,14 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s
break;
#endif
default:
return (0);
return;
break;
}
/*
* JRS 5/14/07 - In CMT PF, the T3 timer is used to track
* PF-heartbeats. Because of this, threshold management is done by
* the t3 timer handler, and does not need to be done upon the send
* of a PF-heartbeat. If CMT PF is on and the destination to which a
* heartbeat is being sent is in PF state, do NOT do threshold
* management.
*/
if ((stcb->asoc.sctp_cmt_pf == 0) ||
((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF)) {
/* ok we have a destination that needs a beat */
/* lets do the theshold management Qiaobing style */
if (sctp_threshold_management(stcb->sctp_ep, stcb, net,
stcb->asoc.max_send_times)) {
/*-
* we have lost the association, in a way this is
* quite bad since we really are one less time since
* we really did not send yet. This is the down side
* to the Q's style as defined in the RFC and not my
* alternate style defined in the RFC.
*/
if (chk->data != NULL) {
sctp_m_freem(chk->data);
chk->data = NULL;
}
/*
* Here we do NOT use the macro since the
* association is now gone.
*/
if (chk->whoTo) {
sctp_free_remote_addr(chk->whoTo);
chk->whoTo = NULL;
}
sctp_free_a_chunk((struct sctp_tcb *)NULL, chk, so_locked);
return (-1);
}
}
net->hb_responded = 0;
TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next);
stcb->asoc.ctrl_queue_cnt++;
SCTP_STAT_INCR(sctps_sendheartbeat);
/*-
* Call directly med level routine to put out the chunk. It will
* always tumble out control chunks aka HB but it may even tumble
* out data too.
*/
return (1);
return;
}
void
@ -11282,6 +11123,9 @@ sctp_send_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
struct sctp_ecne_chunk *ecne;
struct sctp_tmit_chunk *chk;
if (net == NULL) {
return;
}
asoc = &stcb->asoc;
SCTP_TCB_LOCK_ASSERT(stcb);
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
@ -11323,6 +11167,7 @@ sctp_send_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
chk->snd_count = 0;
chk->whoTo = net;
atomic_add_int(&chk->whoTo->ref_count, 1);
stcb->asoc.ecn_echo_cnt_onq++;
ecne = mtod(chk->data, struct sctp_ecne_chunk *);
ecne->ch.chunk_type = SCTP_ECN_ECHO;
@ -11477,10 +11322,10 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net,
if (net) {
/* we should hit here */
chk->whoTo = net;
atomic_add_int(&chk->whoTo->ref_count, 1);
} else {
chk->whoTo = asoc->primary_destination;
chk->whoTo = NULL;
}
atomic_add_int(&chk->whoTo->ref_count, 1);
chk->rec.chunk_id.id = SCTP_PACKET_DROPPED;
chk->rec.chunk_id.can_take_data = 1;
drp->ch.chunk_type = SCTP_PACKET_DROPPED;
@ -11518,8 +11363,9 @@ sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn, u
asoc = &stcb->asoc;
SCTP_TCB_LOCK_ASSERT(stcb);
if (net == NULL) {
return;
}
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
if ((chk->rec.chunk_id.id == SCTP_ECN_CWR) && (net == chk->whoTo)) {
/*
@ -11849,9 +11695,12 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
/* setup chunk parameters */
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
chk->whoTo = asoc->primary_destination;
if (stcb->asoc.alternate) {
chk->whoTo = stcb->asoc.alternate;
} else {
chk->whoTo = stcb->asoc.primary_destination;
}
atomic_add_int(&chk->whoTo->ref_count, 1);
ch = mtod(chk->data, struct sctp_chunkhdr *);
ch->chunk_type = SCTP_STREAM_RESET;
ch->chunk_flags = 0;
@ -12910,7 +12759,11 @@ sctp_lower_sosend(struct socket *so,
goto out_unlocked;
}
} else {
net = stcb->asoc.primary_destination;
if (stcb->asoc.alternate) {
net = stcb->asoc.alternate;
} else {
net = stcb->asoc.primary_destination;
}
}
atomic_add_int(&stcb->total_sends, 1);
/* Keep the stcb from being freed under our feet */
@ -13579,15 +13432,22 @@ sctp_lower_sosend(struct socket *so,
if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
struct sctp_nets *netp;
if (stcb->asoc.alternate) {
netp = stcb->asoc.alternate;
} else {
netp = stcb->asoc.primary_destination;
}
/* only send SHUTDOWN the first time through */
sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
sctp_send_shutdown(stcb, netp);
if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb,
asoc->primary_destination);
netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
asoc->primary_destination);
}

View File

@ -155,7 +155,7 @@ void send_forward_tsn(struct sctp_tcb *, struct sctp_association *);
void sctp_send_sack(struct sctp_tcb *, int);
int sctp_send_hb(struct sctp_tcb *, int, struct sctp_nets *, int);
void sctp_send_hb(struct sctp_tcb *, struct sctp_nets *, int);
void sctp_send_ecn_echo(struct sctp_tcb *, struct sctp_nets *, uint32_t);

View File

@ -1096,8 +1096,15 @@ sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to)
continue;
}
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
if (sctp_is_addr_restricted(stcb, sctp_ifa))
if (sctp_is_addr_restricted(stcb, sctp_ifa) &&
(!sctp_is_addr_pending(stcb, sctp_ifa))) {
/*
* We allow pending addresses, where
* we have sent an asconf-add to be
* considered valid.
*/
continue;
}
switch (sctp_ifa->address.sa.sa_family) {
#ifdef INET
case AF_INET:
@ -1155,7 +1162,13 @@ sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to)
struct sctp_laddr *laddr;
LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
if (sctp_is_addr_restricted(stcb, laddr->ifa) &&
(!sctp_is_addr_pending(stcb, laddr->ifa))) {
/*
* We allow pending addresses, where we have
* sent an asconf-add to be considered
* valid.
*/
continue;
}
if (laddr->ifa->address.sa.sa_family != to->sa_family) {
@ -2614,6 +2627,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
m->max_init_times = SCTP_BASE_SYSCTL(sctp_init_rtx_max_default);
m->max_send_times = SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default);
m->def_net_failure = SCTP_BASE_SYSCTL(sctp_path_rtx_max_default);
m->def_net_pf_threshold = SCTP_BASE_SYSCTL(sctp_path_pf_threshold);
m->sctp_sws_sender = SCTP_SWS_SENDER_DEF;
m->sctp_sws_receiver = SCTP_SWS_RECEIVER_DEF;
m->max_burst = SCTP_BASE_SYSCTL(sctp_max_burst_default);
@ -2768,7 +2782,6 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
* all of them.
*/
stcb->asoc.hb_timer.ep = (void *)new_inp;
stcb->asoc.dack_timer.ep = (void *)new_inp;
stcb->asoc.asconf_timer.ep = (void *)new_inp;
stcb->asoc.strreset_timer.ep = (void *)new_inp;
@ -2780,7 +2793,6 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
net->pmtu_timer.ep = (void *)new_inp;
net->rxt_timer.ep = (void *)new_inp;
net->fr_timer.ep = (void *)new_inp;
}
SCTP_INP_WUNLOCK(new_inp);
SCTP_INP_WUNLOCK(old_inp);
@ -3452,11 +3464,18 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
}
if ((SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
(SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
struct sctp_nets *netp;
if (asoc->asoc.alternate) {
netp = asoc->asoc.alternate;
} else {
netp = asoc->asoc.primary_destination;
}
/*
* there is nothing queued to send,
* so I send shutdown
*/
sctp_send_shutdown(asoc, asoc->asoc.primary_destination);
sctp_send_shutdown(asoc, netp);
if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
@ -3464,7 +3483,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
SCTP_SET_STATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_SENT);
SCTP_CLEAR_SUBSTATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, asoc->sctp_ep, asoc,
asoc->asoc.primary_destination);
netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc,
asoc->asoc.primary_destination);
sctp_chunk_output(inp, asoc, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_LOCKED);
@ -3808,7 +3827,7 @@ sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id)
*/
int
sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
int set_scope, int from)
struct sctp_nets **netp, int set_scope, int from)
{
/*
* The following is redundant to the same lines in the
@ -3942,7 +3961,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
return (-1);
}
SCTP_INCR_RADDR_COUNT();
bzero(net, sizeof(*net));
bzero(net, sizeof(struct sctp_nets));
(void)SCTP_GETTIME_TIMEVAL(&net->start_time);
memcpy(&net->ro._l_addr, newaddr, newaddr->sa_len);
switch (newaddr->sa_family) {
@ -3968,6 +3987,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
addr_inscope = 1;
}
net->failure_threshold = stcb->asoc.def_net_failure;
net->pf_threshold = stcb->asoc.def_net_pf_threshold;
if (addr_inscope == 0) {
net->dest_state = (SCTP_ADDR_REACHABLE |
SCTP_ADDR_OUT_OF_SCOPE);
@ -4003,10 +4023,16 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
if (newaddr->sa_family == AF_INET6)
net->tos_flowlabel = stcb->asoc.default_flowlabel;
#endif
if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
net->dest_state |= SCTP_ADDR_NOHB;
} else {
net->dest_state &= ~SCTP_ADDR_NOHB;
}
net->heart_beat_delay = stcb->asoc.heart_beat_delay;
/* Init the timer structure */
SCTP_OS_TIMER_INIT(&net->rxt_timer.timer);
SCTP_OS_TIMER_INIT(&net->fr_timer.timer);
SCTP_OS_TIMER_INIT(&net->pmtu_timer.timer);
SCTP_OS_TIMER_INIT(&net->hb_timer.timer);
/* Now generate a route for this guy */
#ifdef INET6
@ -4153,8 +4179,6 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
/* No route to current primary adopt new primary */
stcb->asoc.primary_destination = net;
}
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb,
net);
/* Validate primary is first */
net = TAILQ_FIRST(&stcb->asoc.nets);
if ((net != stcb->asoc.primary_destination) &&
@ -4169,6 +4193,9 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
TAILQ_INSERT_HEAD(&stcb->asoc.nets,
stcb->asoc.primary_destination, sctp_next);
}
if (netp) {
*netp = net;
}
return (0);
}
@ -4393,7 +4420,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
LIST_INSERT_HEAD(head, stcb, sctp_asocs);
SCTP_INP_INFO_WUNLOCK();
if ((err = sctp_add_remote_addr(stcb, firstaddr, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) {
if ((err = sctp_add_remote_addr(stcb, firstaddr, NULL, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) {
/* failure.. memory error? */
if (asoc->strmout) {
SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
@ -4418,7 +4445,6 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
return (NULL);
}
/* Init all the timers */
SCTP_OS_TIMER_INIT(&asoc->hb_timer.timer);
SCTP_OS_TIMER_INIT(&asoc->dack_timer.timer);
SCTP_OS_TIMER_INIT(&asoc->strreset_timer.timer);
SCTP_OS_TIMER_INIT(&asoc->asconf_timer.timer);
@ -4488,6 +4514,10 @@ sctp_remove_net(struct sctp_tcb *stcb, struct sctp_nets *net)
/* Clear net */
asoc->last_control_chunk_from = NULL;
}
if (net == stcb->asoc.alternate) {
sctp_free_remote_addr(stcb->asoc.alternate);
stcb->asoc.alternate = NULL;
}
sctp_free_remote_addr(net);
}
@ -4699,6 +4729,10 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
/* there is no asoc, really TSNH :-0 */
return (1);
}
if (stcb->asoc.alternate) {
sctp_free_remote_addr(stcb->asoc.alternate);
stcb->asoc.alternate = NULL;
}
/* TEMP CODE */
if (stcb->freed_from_where == 0) {
/* Only record the first place free happened from */
@ -4737,8 +4771,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
}
}
/* now clean up any other timers */
(void)SCTP_OS_TIMER_STOP(&asoc->hb_timer.timer);
asoc->hb_timer.self = NULL;
(void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
asoc->dack_timer.self = NULL;
(void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
@ -4762,12 +4794,12 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
(void)SCTP_OS_TIMER_STOP(&asoc->delete_prim_timer.timer);
asoc->delete_prim_timer.self = NULL;
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
(void)SCTP_OS_TIMER_STOP(&net->fr_timer.timer);
net->fr_timer.self = NULL;
(void)SCTP_OS_TIMER_STOP(&net->rxt_timer.timer);
net->rxt_timer.self = NULL;
(void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer);
net->pmtu_timer.self = NULL;
(void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer);
net->hb_timer.self = NULL;
}
/* Now the read queue needs to be cleaned up (only once) */
if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) {
@ -4935,7 +4967,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
* Now restop the timers to be sure this is paranoia at is finest!
*/
(void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->hb_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer);
@ -4943,9 +4974,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
(void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer);
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
(void)SCTP_OS_TIMER_STOP(&net->fr_timer.timer);
(void)SCTP_OS_TIMER_STOP(&net->rxt_timer.timer);
(void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer);
(void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer);
}
asoc->strreset_timer.type = SCTP_TIMER_TYPE_NONE;
@ -6189,7 +6220,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
#ifdef INET
case AF_INET:
if (stcb->asoc.ipv4_addr_legal) {
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) {
if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) {
return (-1);
}
}
@ -6198,7 +6229,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
#ifdef INET6
case AF_INET6:
if (stcb->asoc.ipv6_addr_legal) {
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) {
if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) {
return (-2);
}
}
@ -6289,7 +6320,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
/* the assoc was freed? */
return (-7);
}
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_4)) {
if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_4)) {
return (-8);
}
} else if (stcb_tmp == stcb) {
@ -6376,7 +6407,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
* we must add the address, no scope
* set
*/
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_5)) {
if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_5)) {
return (-17);
}
} else if (stcb_tmp == stcb) {
@ -6748,7 +6779,10 @@ sctp_set_primary_addr(struct sctp_tcb *stcb, struct sockaddr *sa,
return (0);
}
stcb->asoc.primary_destination = net;
net->dest_state &= ~SCTP_ADDR_WAS_PRIMARY;
if (!(net->dest_state & SCTP_ADDR_PF) && (stcb->asoc.alternate)) {
sctp_free_remote_addr(stcb->asoc.alternate);
stcb->asoc.alternate = NULL;
}
net = TAILQ_FIRST(&stcb->asoc.nets);
if (net != stcb->asoc.primary_destination) {
/*

View File

@ -293,6 +293,8 @@ struct sctp_pcb {
uint16_t def_net_failure;
uint16_t def_net_pf_threshold;
/* number of streams to pre-open on a association */
uint16_t pre_open_stream_count;
uint16_t max_open_streams_intome;
@ -582,7 +584,7 @@ void sctp_remove_laddr(struct sctp_laddr *);
void sctp_del_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *);
int sctp_add_remote_addr(struct sctp_tcb *, struct sockaddr *, int, int);
int sctp_add_remote_addr(struct sctp_tcb *, struct sockaddr *, struct sctp_nets **, int, int);
void sctp_remove_net(struct sctp_tcb *, struct sctp_nets *);

View File

@ -251,6 +251,7 @@ struct sctp_nets {
* structure shared by all.
*/
struct sctp_timer pmtu_timer;
struct sctp_timer hb_timer;
/*
* The following two in combination equate to a route entry for v6
@ -273,7 +274,6 @@ struct sctp_nets {
/* This is used for SHUTDOWN/SHUTDOWN-ACK/SEND or INIT timers */
struct sctp_timer rxt_timer;
struct sctp_timer fr_timer; /* for early fr */
/* last time in seconds I sent to it */
struct timeval last_sent_time;
@ -327,12 +327,15 @@ struct sctp_nets {
uint32_t marked_retrans;/* number or DATA chunks marked for timer
* based retransmissions */
uint32_t marked_fastretrans;
uint32_t heart_beat_delay; /* Heart Beat delay in ms */
/* if this guy is ok or not ... status */
uint16_t dest_state;
/* number of transmit failures to down this guy */
/* number of timeouts to consider the destination unreachable */
uint16_t failure_threshold;
/* error stats on destination */
/* number of timeouts to consider the destination potentially failed */
uint16_t pf_threshold;
/* error stats on the destination */
uint16_t error_count;
/* UDP port number in case of UDP tunneling */
uint16_t port;
@ -661,6 +664,7 @@ struct sctp_cc_functions {
void (*sctp_cwnd_update_after_sack) (struct sctp_tcb *stcb,
struct sctp_association *asoc,
int accum_moved, int reneged_all, int will_exit);
void (*sctp_cwnd_update_exit_pf) (struct sctp_tcb *stcb, struct sctp_nets *net);
void (*sctp_cwnd_update_after_fr) (struct sctp_tcb *stcb,
struct sctp_association *asoc);
void (*sctp_cwnd_update_after_timeout) (struct sctp_tcb *stcb,
@ -672,8 +676,6 @@ struct sctp_cc_functions {
uint32_t * bottle_bw, uint32_t * on_queue);
void (*sctp_cwnd_update_after_output) (struct sctp_tcb *stcb,
struct sctp_nets *net, int burst_limit);
void (*sctp_cwnd_update_after_fr_timer) (struct sctp_inpcb *inp,
struct sctp_tcb *stcb, struct sctp_nets *net);
void (*sctp_cwnd_update_packet_transmitted) (struct sctp_tcb *stcb,
struct sctp_nets *net);
void (*sctp_cwnd_update_tsn_acknowledged) (struct sctp_nets *net,
@ -753,7 +755,6 @@ struct sctp_association {
struct sctp_nonpad_sndrcvinfo def_send;
/* timers and such */
struct sctp_timer hb_timer; /* hb timer */
struct sctp_timer dack_timer; /* Delayed ack timer */
struct sctp_timer asconf_timer; /* asconf */
struct sctp_timer strreset_timer; /* stream reset */
@ -828,6 +829,7 @@ struct sctp_association {
uint8_t *mapping_array;
/* primary destination to use */
struct sctp_nets *primary_destination;
struct sctp_nets *alternate; /* If primary is down or PF */
/* For CMT */
struct sctp_nets *last_net_cmt_send_started;
/* last place I got a data chunk from */
@ -1023,8 +1025,8 @@ struct sctp_association {
unsigned int size_on_all_streams;
unsigned int cnt_on_all_streams;
/* Heart Beat delay in ticks */
unsigned int heart_beat_delay;
/* Heart Beat delay in ms */
uint32_t heart_beat_delay;
/* autoclose */
unsigned int sctp_autoclose_ticks;
@ -1094,6 +1096,8 @@ struct sctp_association {
uint16_t def_net_failure;
uint16_t def_net_pf_threshold;
/*
* lock flag: 0 is ok to send, 1+ (duals as a retran count) is
* awaiting ACK
@ -1133,7 +1137,6 @@ struct sctp_association {
uint8_t last_flags_delivered;
uint8_t hb_ect_randombit;
uint8_t hb_random_idx;
uint8_t hb_is_disabled; /* is the hb disabled? */
uint8_t default_tos;
uint8_t asconf_del_pending; /* asconf delete last addr pending */

View File

@ -83,16 +83,14 @@ sctp_init_sysctls()
SCTP_BASE_SYSCTL(sctp_init_rtx_max_default) = SCTPCTL_INIT_RTX_MAX_DEFAULT;
SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default) = SCTPCTL_ASSOC_RTX_MAX_DEFAULT;
SCTP_BASE_SYSCTL(sctp_path_rtx_max_default) = SCTPCTL_PATH_RTX_MAX_DEFAULT;
SCTP_BASE_SYSCTL(sctp_path_pf_threshold) = SCTPCTL_PATH_PF_THRESHOLD_DEFAULT;
SCTP_BASE_SYSCTL(sctp_add_more_threshold) = SCTPCTL_ADD_MORE_ON_OUTPUT_DEFAULT;
SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default) = SCTPCTL_OUTGOING_STREAMS_DEFAULT;
SCTP_BASE_SYSCTL(sctp_cmt_on_off) = SCTPCTL_CMT_ON_OFF_DEFAULT;
/* EY */
SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) = SCTPCTL_NR_SACK_ON_OFF_DEFAULT;
SCTP_BASE_SYSCTL(sctp_cmt_use_dac) = SCTPCTL_CMT_USE_DAC_DEFAULT;
SCTP_BASE_SYSCTL(sctp_cmt_pf) = SCTPCTL_CMT_PF_DEFAULT;
SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst) = SCTPCTL_CWND_MAXBURST_DEFAULT;
SCTP_BASE_SYSCTL(sctp_early_fr) = SCTPCTL_EARLY_FAST_RETRAN_DEFAULT;
SCTP_BASE_SYSCTL(sctp_early_fr_msec) = SCTPCTL_EARLY_FAST_RETRAN_MSEC_DEFAULT;
SCTP_BASE_SYSCTL(sctp_asconf_auth_nochk) = SCTPCTL_ASCONF_AUTH_NOCHK_DEFAULT;
SCTP_BASE_SYSCTL(sctp_auth_disable) = SCTPCTL_AUTH_DISABLE_DEFAULT;
SCTP_BASE_SYSCTL(sctp_nat_friendly) = SCTPCTL_NAT_FRIENDLY_DEFAULT;
@ -494,6 +492,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
xraddr.active = ((net->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE);
xraddr.confirmed = ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0);
xraddr.heartbeat_enabled = ((net->dest_state & SCTP_ADDR_NOHB) == 0);
xraddr.potentially_failed = ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF);
xraddr.rto = net->RTO;
xraddr.max_path_rtx = net->failure_threshold;
xraddr.rtx = net->marked_retrans;
@ -502,6 +501,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
xraddr.flight_size = net->flight_size;
xraddr.mtu = net->mtu;
xraddr.rtt = net->rtt / 1000;
xraddr.heartbeat_interval = net->heart_beat_delay;
xraddr.start_time.tv_sec = (uint32_t) net->start_time.tv_sec;
xraddr.start_time.tv_usec = (uint32_t) net->start_time.tv_usec;
SCTP_INP_RUNLOCK(inp);
@ -633,16 +633,14 @@ sysctl_sctp_check(SYSCTL_HANDLER_ARGS)
RANGECHK(SCTP_BASE_SYSCTL(sctp_init_rtx_max_default), SCTPCTL_INIT_RTX_MAX_MIN, SCTPCTL_INIT_RTX_MAX_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default), SCTPCTL_ASSOC_RTX_MAX_MIN, SCTPCTL_ASSOC_RTX_MAX_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_path_rtx_max_default), SCTPCTL_PATH_RTX_MAX_MIN, SCTPCTL_PATH_RTX_MAX_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_path_pf_threshold), SCTPCTL_PATH_PF_THRESHOLD_MIN, SCTPCTL_PATH_PF_THRESHOLD_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTPCTL_ADD_MORE_ON_OUTPUT_MIN, SCTPCTL_ADD_MORE_ON_OUTPUT_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default), SCTPCTL_OUTGOING_STREAMS_MIN, SCTPCTL_OUTGOING_STREAMS_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_on_off), SCTPCTL_CMT_ON_OFF_MIN, SCTPCTL_CMT_ON_OFF_MAX);
/* EY */
RANGECHK(SCTP_BASE_SYSCTL(sctp_nr_sack_on_off), SCTPCTL_NR_SACK_ON_OFF_MIN, SCTPCTL_NR_SACK_ON_OFF_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_use_dac), SCTPCTL_CMT_USE_DAC_MIN, SCTPCTL_CMT_USE_DAC_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_pf), SCTPCTL_CMT_PF_MIN, SCTPCTL_CMT_PF_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst), SCTPCTL_CWND_MAXBURST_MIN, SCTPCTL_CWND_MAXBURST_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_early_fr), SCTPCTL_EARLY_FAST_RETRAN_MIN, SCTPCTL_EARLY_FAST_RETRAN_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_early_fr_msec), SCTPCTL_EARLY_FAST_RETRAN_MSEC_MIN, SCTPCTL_EARLY_FAST_RETRAN_MSEC_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_asconf_auth_nochk), SCTPCTL_ASCONF_AUTH_NOCHK_MIN, SCTPCTL_ASCONF_AUTH_NOCHK_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_auth_disable), SCTPCTL_AUTH_DISABLE_MIN, SCTPCTL_AUTH_DISABLE_MAX);
RANGECHK(SCTP_BASE_SYSCTL(sctp_nat_friendly), SCTPCTL_NAT_FRIENDLY_MIN, SCTPCTL_NAT_FRIENDLY_MAX);
@ -793,17 +791,6 @@ sysctl_stat_get(SYSCTL_HANDLER_ARGS)
sb.sctps_timoautoclose += sarry->sctps_timoautoclose;
sb.sctps_timoassockill += sarry->sctps_timoassockill;
sb.sctps_timoinpkill += sarry->sctps_timoinpkill;
sb.sctps_earlyfrstart += sarry->sctps_earlyfrstart;
sb.sctps_earlyfrstop += sarry->sctps_earlyfrstop;
sb.sctps_earlyfrmrkretrans += sarry->sctps_earlyfrmrkretrans;
sb.sctps_earlyfrstpout += sarry->sctps_earlyfrstpout;
sb.sctps_earlyfrstpidsck1 += sarry->sctps_earlyfrstpidsck1;
sb.sctps_earlyfrstpidsck2 += sarry->sctps_earlyfrstpidsck2;
sb.sctps_earlyfrstpidsck3 += sarry->sctps_earlyfrstpidsck3;
sb.sctps_earlyfrstpidsck4 += sarry->sctps_earlyfrstpidsck4;
sb.sctps_earlyfrstrid += sarry->sctps_earlyfrstrid;
sb.sctps_earlyfrstrout += sarry->sctps_earlyfrstrout;
sb.sctps_earlyfrstrtmr += sarry->sctps_earlyfrstrtmr;
sb.sctps_hdrops += sarry->sctps_hdrops;
sb.sctps_badsum += sarry->sctps_badsum;
sb.sctps_noport += sarry->sctps_noport;
@ -994,6 +981,10 @@ SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, path_rtx_max, CTLTYPE_UINT | CTLFLAG_
&SCTP_BASE_SYSCTL(sctp_path_rtx_max_default), 0, sysctl_sctp_check, "IU",
SCTPCTL_PATH_RTX_MAX_DESC);
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, path_pf_threshold, CTLTYPE_UINT | CTLFLAG_RW,
&SCTP_BASE_SYSCTL(sctp_path_pf_threshold), 0, sysctl_sctp_check, "IU",
SCTPCTL_PATH_PF_THRESHOLD_DESC);
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, add_more_on_output, CTLTYPE_UINT | CTLFLAG_RW,
&SCTP_BASE_SYSCTL(sctp_add_more_threshold), 0, sysctl_sctp_check, "IU",
SCTPCTL_ADD_MORE_ON_OUTPUT_DESC);
@ -1014,22 +1005,10 @@ SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, cmt_use_dac, CTLTYPE_UINT | CTLFLAG_R
&SCTP_BASE_SYSCTL(sctp_cmt_use_dac), 0, sysctl_sctp_check, "IU",
SCTPCTL_CMT_USE_DAC_DESC);
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, cmt_pf, CTLTYPE_UINT | CTLFLAG_RW,
&SCTP_BASE_SYSCTL(sctp_cmt_pf), 0, sysctl_sctp_check, "IU",
SCTPCTL_CMT_PF_DESC);
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, cwnd_maxburst, CTLTYPE_UINT | CTLFLAG_RW,
&SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst), 0, sysctl_sctp_check, "IU",
SCTPCTL_CWND_MAXBURST_DESC);
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, early_fast_retran, CTLTYPE_UINT | CTLFLAG_RW,
&SCTP_BASE_SYSCTL(sctp_early_fr), 0, sysctl_sctp_check, "IU",
SCTPCTL_EARLY_FAST_RETRAN_DESC);
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, early_fast_retran_msec, CTLTYPE_UINT | CTLFLAG_RW,
&SCTP_BASE_SYSCTL(sctp_early_fr_msec), 0, sysctl_sctp_check, "IU",
SCTPCTL_EARLY_FAST_RETRAN_MSEC_DESC);
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, asconf_auth_nochk, CTLTYPE_UINT | CTLFLAG_RW,
&SCTP_BASE_SYSCTL(sctp_asconf_auth_nochk), 0, sysctl_sctp_check, "IU",
SCTPCTL_ASCONF_AUTH_NOCHK_DESC);

View File

@ -74,16 +74,14 @@ struct sctp_sysctl {
uint32_t sctp_init_rtx_max_default;
uint32_t sctp_assoc_rtx_max_default;
uint32_t sctp_path_rtx_max_default;
uint32_t sctp_path_pf_threshold;
uint32_t sctp_add_more_threshold;
uint32_t sctp_nr_outgoing_streams_default;
uint32_t sctp_cmt_on_off;
uint32_t sctp_cmt_use_dac;
/* EY 5/5/08 - nr_sack flag variable */
uint32_t sctp_nr_sack_on_off;
uint32_t sctp_cmt_pf;
uint32_t sctp_use_cwnd_based_maxburst;
uint32_t sctp_early_fr;
uint32_t sctp_early_fr_msec;
uint32_t sctp_asconf_auth_nochk;
uint32_t sctp_auth_disable;
uint32_t sctp_nat_friendly;
@ -322,6 +320,12 @@ struct sctp_sysctl {
#define SCTPCTL_PATH_RTX_MAX_MAX 0xFFFFFFFF
#define SCTPCTL_PATH_RTX_MAX_DEFAULT SCTP_DEF_MAX_PATH_RTX
/* path_pf_threshold: threshold for considering the path potentially failed */
#define SCTPCTL_PATH_PF_THRESHOLD_DESC "Default potentially failed threshold"
#define SCTPCTL_PATH_PF_THRESHOLD_MIN 0
#define SCTPCTL_PATH_PF_THRESHOLD_MAX 0xFFFF
#define SCTPCTL_PATH_PF_THRESHOLD_DEFAULT SCTPCTL_PATH_PF_THRESHOLD_MAX
/* add_more_on_output: When space-wise is it worthwhile to try to add more to a socket send buffer */
#define SCTPCTL_ADD_MORE_ON_OUTPUT_DESC "When space-wise is it worthwhile to try to add more to a socket send buffer"
#define SCTPCTL_ADD_MORE_ON_OUTPUT_MIN 0
@ -352,30 +356,12 @@ struct sctp_sysctl {
#define SCTPCTL_CMT_USE_DAC_MAX 1
#define SCTPCTL_CMT_USE_DAC_DEFAULT 0
/* JRS 5/2107 - CMT PF type flag */
#define SCTPCTL_CMT_PF_DESC "CMT PF type flag"
#define SCTPCTL_CMT_PF_MIN 0
#define SCTPCTL_CMT_PF_MAX 2
#define SCTPCTL_CMT_PF_DEFAULT 0
/* cwnd_maxburst: Use a CWND adjusting maxburst */
#define SCTPCTL_CWND_MAXBURST_DESC "Use a CWND adjusting maxburst"
#define SCTPCTL_CWND_MAXBURST_MIN 0
#define SCTPCTL_CWND_MAXBURST_MAX 1
#define SCTPCTL_CWND_MAXBURST_DEFAULT 1
/* early_fast_retran: Early Fast Retransmit with timer */
#define SCTPCTL_EARLY_FAST_RETRAN_DESC "Early Fast Retransmit with timer"
#define SCTPCTL_EARLY_FAST_RETRAN_MIN 0
#define SCTPCTL_EARLY_FAST_RETRAN_MAX 0xFFFFFFFF
#define SCTPCTL_EARLY_FAST_RETRAN_DEFAULT 0
/* early_fast_retran_msec: Early Fast Retransmit minimum timer value */
#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_DESC "Early Fast Retransmit minimum timer value"
#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_MIN 0
#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_MAX 0xFFFFFFFF
#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_DEFAULT SCTP_MINFR_MSEC_TIMER
/* asconf_auth_nochk: Disable SCTP ASCONF AUTH requirement */
#define SCTPCTL_ASCONF_AUTH_NOCHK_DESC "Disable SCTP ASCONF AUTH requirement"
#define SCTPCTL_ASCONF_AUTH_NOCHK_MIN 0

View File

@ -54,103 +54,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/udp.h>
void
sctp_early_fr_timer(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
struct sctp_nets *net)
{
struct sctp_tmit_chunk *chk, *pchk;
struct timeval now, min_wait, tv;
unsigned int cur_rto, cnt = 0, cnt_resend = 0;
/* an early FR is occuring. */
(void)SCTP_GETTIME_TIMEVAL(&now);
/* get cur rto in micro-seconds */
if (net->lastsa == 0) {
/* Hmm no rtt estimate yet? */
cur_rto = stcb->asoc.initial_rto >> 2;
} else {
cur_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
}
if (cur_rto < SCTP_BASE_SYSCTL(sctp_early_fr_msec)) {
cur_rto = SCTP_BASE_SYSCTL(sctp_early_fr_msec);
}
cur_rto *= 1000;
tv.tv_sec = cur_rto / 1000000;
tv.tv_usec = cur_rto % 1000000;
min_wait = now;
timevalsub(&min_wait, &tv);
if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) {
/*
* if we hit here, we don't have enough seconds on the clock
* to account for the RTO. We just let the lower seconds be
* the bounds and don't worry about it. This may mean we
* will mark a lot more than we should.
*/
min_wait.tv_sec = min_wait.tv_usec = 0;
}
TAILQ_FOREACH_REVERSE_SAFE(chk, &stcb->asoc.sent_queue, sctpchunk_listhead, sctp_next, pchk) {
if (chk->whoTo != net) {
continue;
}
if (chk->sent == SCTP_DATAGRAM_RESEND)
cnt_resend++;
else if ((chk->sent > SCTP_DATAGRAM_UNSENT) &&
(chk->sent < SCTP_DATAGRAM_RESEND)) {
/* pending, may need retran */
if (chk->sent_rcv_time.tv_sec > min_wait.tv_sec) {
/*
* we have reached a chunk that was sent
* some seconds past our min.. forget it we
* will find no more to send.
*/
continue;
} else if (chk->sent_rcv_time.tv_sec == min_wait.tv_sec) {
/*
* we must look at the micro seconds to
* know.
*/
if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) {
/*
* ok it was sent after our boundary
* time.
*/
continue;
}
}
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_EARLYFR_LOGGING_ENABLE) {
sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count,
4, SCTP_FR_MARKED_EARLY);
}
SCTP_STAT_INCR(sctps_earlyfrmrkretrans);
chk->sent = SCTP_DATAGRAM_RESEND;
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
/* double book size since we are doing an early FR */
chk->book_size_scale++;
cnt += chk->send_size;
if ((cnt + net->flight_size) > net->cwnd) {
/* Mark all we could possibly resend */
break;
}
}
}
if (cnt) {
/*
* JRS - Use the congestion control given in the congestion
* control module
*/
stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer(inp, stcb, net);
} else if (cnt_resend) {
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
}
/* Restart it? */
if (net->flight_size < net->cwnd) {
SCTP_STAT_INCR(sctps_earlyfrstrtmr);
sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
}
}
void
sctp_audit_retranmission_queue(struct sctp_association *asoc)
{
@ -195,44 +98,23 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
/* We had a threshold failure */
if (net->dest_state & SCTP_ADDR_REACHABLE) {
net->dest_state &= ~SCTP_ADDR_REACHABLE;
net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY;
if (net == stcb->asoc.primary_destination) {
net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
}
/*
* JRS 5/14/07 - If a destination is
* unreachable, the PF bit is turned off.
* This allows an unambiguous use of the PF
* bit for destinations that are reachable
* but potentially failed. If the
* destination is set to the unreachable
* state, also set the destination to the PF
* state.
*/
/*
* Add debug message here if destination is
* not in PF state.
*/
/* Stop any running T3 timers here? */
if ((stcb->asoc.sctp_cmt_on_off > 0) &&
(stcb->asoc.sctp_cmt_pf > 0)) {
net->dest_state &= ~SCTP_ADDR_PF;
SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
net);
}
net->dest_state &= ~SCTP_ADDR_PF;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
stcb,
SCTP_FAILED_THRESHOLD,
(void *)net, SCTP_SO_NOT_LOCKED);
}
} else if ((net->pf_threshold < net->failure_threshold) &&
(net->error_count > net->pf_threshold)) {
if (!(net->dest_state & SCTP_ADDR_PF)) {
net->dest_state |= SCTP_ADDR_PF;
net->last_active = sctp_get_tick_count();
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
}
}
/*********HOLD THIS COMMENT FOR PATCH OF ALTERNATE
*********ROUTING CODE
*/
/*********HOLD THIS COMMENT FOR END OF PATCH OF ALTERNATE
*********ROUTING CODE
*/
}
if (stcb == NULL)
return (0);
@ -407,31 +289,10 @@ sctp_find_alternate_net(struct sctp_tcb *stcb,
}
}
}
/*
* JRS 5/14/07 - After all destination have been considered
* as alternates, check to see if there was some active
* destination (not in PF state). If not, check to see if
* there was some PF destination with the minimum number of
* errors. If not, return the original destination. If
* there is a min_errors_net, remove the PF flag from that
* destination, set the cwnd to one or two MTUs, and return
* the destination as an alt. If there was some active
* destination with a highest cwnd, return the destination
* as an alt.
*/
if (max_cwnd_net == NULL) {
if (min_errors_net == NULL) {
return (net);
}
min_errors_net->dest_state &= ~SCTP_ADDR_PF;
min_errors_net->cwnd = min_errors_net->mtu * stcb->asoc.sctp_cmt_pf;
if (SCTP_OS_TIMER_PENDING(&min_errors_net->rxt_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
stcb, min_errors_net,
SCTP_FROM_SCTP_TIMER + SCTP_LOC_2);
}
SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to active with %d errors.\n",
min_errors_net, min_errors_net->error_count);
return (min_errors_net);
} else {
return (max_cwnd_net);
@ -646,15 +507,12 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
/* get cur rto in micro-seconds */
cur_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
cur_rto *= 1000;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
sctp_log_fr(cur_rto,
stcb->asoc.peers_rwnd,
window_probe,
SCTP_FR_T3_MARK_TIME);
sctp_log_fr(net->flight_size,
SCTP_OS_TIMER_PENDING(&net->fr_timer.timer),
SCTP_OS_TIMER_ACTIVE(&net->fr_timer.timer),
SCTP_FR_CWND_REPORT);
sctp_log_fr(net->flight_size, 0, 0, SCTP_FR_CWND_REPORT);
sctp_log_fr(net->flight_size, net->cwnd, stcb->asoc.total_flight, SCTP_FR_CWND_REPORT);
}
tv.tv_sec = cur_rto / 1000000;
@ -670,7 +528,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
*/
min_wait.tv_sec = min_wait.tv_usec = 0;
}
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
sctp_log_fr(cur_rto, now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME);
sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME);
}
@ -717,7 +575,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
*/
/* validate its been outstanding long enough */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
sctp_log_fr(chk->rec.data.TSN_seq,
chk->sent_rcv_time.tv_sec,
chk->sent_rcv_time.tv_usec,
@ -729,7 +587,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
* some seconds past our min.. forget it we
* will find no more to send.
*/
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
sctp_log_fr(0,
chk->sent_rcv_time.tv_sec,
chk->sent_rcv_time.tv_usec,
@ -747,12 +605,6 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
* ok it was sent after our boundary
* time.
*/
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
sctp_log_fr(0,
chk->sent_rcv_time.tv_sec,
chk->sent_rcv_time.tv_usec,
SCTP_FR_T3_STOPPED);
}
continue;
}
}
@ -791,7 +643,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
tsnfirst = chk->rec.data.TSN_seq;
}
tsnlast = chk->rec.data.TSN_seq;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count,
0, SCTP_FR_T3_MARKED);
}
@ -860,7 +712,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
/* we did not subtract the same things? */
audit_tf = 1;
}
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT);
}
#ifdef SCTP_DEBUG
@ -978,40 +830,72 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
win_probe = 0;
}
/*
* JRS 5/14/07 - If CMT PF is on and the destination if not already
* in PF state, set the destination to PF state and store the
* current time as the time that the destination was last active. In
* addition, find an alternate destination with PF-based
* find_alt_net().
*/
if ((stcb->asoc.sctp_cmt_on_off > 0) &&
(stcb->asoc.sctp_cmt_pf > 0)) {
if ((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF) {
net->dest_state |= SCTP_ADDR_PF;
net->last_active = sctp_get_tick_count();
SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from active to PF.\n",
net);
if (win_probe == 0) {
/* We don't do normal threshold management on window probes */
if (sctp_threshold_management(inp, stcb, net,
stcb->asoc.max_send_times)) {
/* Association was destroyed */
return (1);
} else {
if (net != stcb->asoc.primary_destination) {
/* send a immediate HB if our RTO is stale */
struct timeval now;
unsigned int ms_goneby;
(void)SCTP_GETTIME_TIMEVAL(&now);
if (net->last_sent_time.tv_sec) {
ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000;
} else {
ms_goneby = 0;
}
if ((net->dest_state & SCTP_ADDR_PF) == 0) {
if ((ms_goneby > net->RTO) || (net->RTO == 0)) {
/*
* no recent feed back in an
* RTO or more, request a
* RTT update
*/
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
}
}
}
}
alt = sctp_find_alternate_net(stcb, net, 2);
} else if (stcb->asoc.sctp_cmt_on_off > 0) {
} else {
/*
* CMT: Using RTX_SSTHRESH policy for CMT. If CMT is being
* used, then pick dest with largest ssthresh for any
* retransmission.
* For a window probe we don't penalize the net's but only
* the association. This may fail it if SACKs are not coming
* back. If sack's are coming with rwnd locked at 0, we will
* continue to hold things waiting for rwnd to raise
*/
alt = sctp_find_alternate_net(stcb, net, 1);
/*
* CUCv2: If a different dest is picked for the
* retransmission, then new (rtx-)pseudo_cumack needs to be
* tracked for orig dest. Let CUCv2 track new (rtx-)
* pseudo-cumack always.
*/
net->find_pseudo_cumack = 1;
net->find_rtx_pseudo_cumack = 1;
} else { /* CMT is OFF */
if (sctp_threshold_management(inp, stcb, NULL,
stcb->asoc.max_send_times)) {
/* Association was destroyed */
return (1);
}
}
if (stcb->asoc.sctp_cmt_on_off > 0) {
if (net->pf_threshold < net->failure_threshold) {
alt = sctp_find_alternate_net(stcb, net, 2);
} else {
/*
* CMT: Using RTX_SSTHRESH policy for CMT. If CMT is
* being used, then pick dest with largest ssthresh
* for any retransmission.
*/
alt = sctp_find_alternate_net(stcb, net, 1);
/*
* CUCv2: If a different dest is picked for the
* retransmission, then new (rtx-)pseudo_cumack
* needs to be tracked for orig dest. Let CUCv2
* track new (rtx-) pseudo-cumack always.
*/
net->find_pseudo_cumack = 1;
net->find_rtx_pseudo_cumack = 1;
}
} else {
alt = sctp_find_alternate_net(stcb, net, 0);
}
num_mk = 0;
num_abandoned = 0;
(void)sctp_mark_all_for_resend(stcb, net, alt, win_probe,
@ -1033,52 +917,8 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
/* Backoff the timer and cwnd */
sctp_backoff_on_timeout(stcb, net, win_probe, num_mk, num_abandoned);
if (win_probe == 0) {
/* We don't do normal threshold management on window probes */
if (sctp_threshold_management(inp, stcb, net,
stcb->asoc.max_send_times)) {
/* Association was destroyed */
return (1);
} else {
if (net != stcb->asoc.primary_destination) {
/* send a immediate HB if our RTO is stale */
struct timeval now;
unsigned int ms_goneby;
(void)SCTP_GETTIME_TIMEVAL(&now);
if (net->last_sent_time.tv_sec) {
ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000;
} else {
ms_goneby = 0;
}
if ((ms_goneby > net->RTO) || (net->RTO == 0)) {
/*
* no recent feed back in an RTO or
* more, request a RTT update
*/
if (sctp_send_hb(stcb, 1, net, SCTP_SO_NOT_LOCKED) < 0)
/*
* Less than 0 means we lost
* the assoc
*/
return (1);
}
}
}
} else {
/*
* For a window probe we don't penalize the net's but only
* the association. This may fail it if SACKs are not coming
* back. If sack's are coming with rwnd locked at 0, we will
* continue to hold things waiting for rwnd to raise
*/
if (sctp_threshold_management(inp, stcb, NULL,
stcb->asoc.max_send_times)) {
/* Association was destroyed */
return (1);
}
}
if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
if ((!(net->dest_state & SCTP_ADDR_REACHABLE)) ||
(net->dest_state & SCTP_ADDR_PF)) {
/* Move all pending over too */
sctp_move_chunks_from_net(stcb, net);
@ -1106,23 +946,12 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
* change-primary then this flag must be cleared
* from any net structures.
*/
if (sctp_set_primary_addr(stcb,
(struct sockaddr *)NULL,
alt) == 0) {
net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
if (stcb->asoc.alternate) {
sctp_free_remote_addr(stcb->asoc.alternate);
}
stcb->asoc.alternate = alt;
atomic_add_int(&stcb->asoc.alternate->ref_count, 1);
}
} else if ((stcb->asoc.sctp_cmt_on_off > 0) &&
(stcb->asoc.sctp_cmt_pf > 0) &&
((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
/*
* JRS 5/14/07 - If the destination hasn't failed completely
* but is in PF state, a PF-heartbeat needs to be sent
* manually.
*/
if (sctp_send_hb(stcb, 1, net, SCTP_SO_NOT_LOCKED) < 0)
/* Return less than 0 means we lost the association */
return (1);
}
/*
* Special case for cookie-echo'ed case, we don't do output but must
@ -1324,7 +1153,7 @@ sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
atomic_add_int(&alt->ref_count, 1);
}
}
if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
/*
* If the address went un-reachable, we need to move to
* alternates for ALL chk's in queue
@ -1414,7 +1243,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
chk->sent = SCTP_DATAGRAM_RESEND;
}
if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
/*
* If the address went un-reachable, we need to move
* to the alternate for ALL chunks in queue
@ -1569,11 +1398,15 @@ sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp,
int
sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct sctp_nets *net, int cnt_of_unconf)
struct sctp_nets *net)
{
int ret;
uint8_t net_was_pf;
net_was_pf = 0;
if (net) {
if (net->dest_state & SCTP_ADDR_PF) {
net_was_pf = 1;
}
if (net->hb_responded == 0) {
if (net->ro._s_addr) {
/*
@ -1585,6 +1418,10 @@ sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
net->src_addr_selected = 0;
}
sctp_backoff_on_timeout(stcb, net, 1, 0, 0);
if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
/* Assoc is over */
return (1);
}
}
/* Zero PBA, if it needs it */
if (net->partial_bytes_acked) {
@ -1596,41 +1433,13 @@ sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
(TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
sctp_audit_stream_queues_for_size(inp, stcb);
}
/* Send a new HB, this will do threshold managment, pick a new dest */
if (cnt_of_unconf == 0) {
if (sctp_send_hb(stcb, 0, NULL, SCTP_SO_NOT_LOCKED) < 0) {
return (1);
}
} else {
if (!(net->dest_state & SCTP_ADDR_NOHB) &&
!((net_was_pf == 0) && (net->dest_state & SCTP_ADDR_PF))) {
/*
* this will send out extra hb's up to maxburst if there are
* any unconfirmed addresses.
* when move to PF during threshold mangement, a HB has been
* queued in that routine
*/
uint32_t cnt_sent = 0;
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
(net->dest_state & SCTP_ADDR_REACHABLE)) {
cnt_sent++;
if (net->hb_responded == 0) {
/* Did we respond last time? */
if (net->ro._s_addr) {
sctp_free_ifa(net->ro._s_addr);
net->ro._s_addr = NULL;
net->src_addr_selected = 0;
}
}
ret = sctp_send_hb(stcb, 1, net, SCTP_SO_NOT_LOCKED);
if (ret < 0)
return 1;
else if (ret == 0) {
break;
}
if (SCTP_BASE_SYSCTL(sctp_hb_maxburst) &&
(cnt_sent >= SCTP_BASE_SYSCTL(sctp_hb_maxburst)))
break;
}
}
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
}
return (0);
}
@ -1733,7 +1542,14 @@ sctp_autoclose_timer(struct sctp_inpcb *inp,
*/
if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
/* only send SHUTDOWN 1st time thru */
sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
struct sctp_nets *netp;
if (stcb->asoc.alternate) {
netp = stcb->asoc.alternate;
} else {
netp = stcb->asoc.primary_destination;
}
sctp_send_shutdown(stcb, netp);
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
@ -1742,10 +1558,10 @@ sctp_autoclose_timer(struct sctp_inpcb *inp,
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb,
asoc->primary_destination);
netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb,
asoc->primary_destination);
netp);
}
}
} else {

View File

@ -42,10 +42,6 @@ __FBSDID("$FreeBSD$");
#define SCTP_RTT_SHIFT 3
#define SCTP_RTT_VAR_SHIFT 2
void
sctp_early_fr_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct sctp_nets *net);
struct sctp_nets *
sctp_find_alternate_net(struct sctp_tcb *,
struct sctp_nets *, int mode);
@ -65,7 +61,7 @@ sctp_shutdown_timer(struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *);
int
sctp_heartbeat_timer(struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *, int);
struct sctp_nets *);
int
sctp_cookie_timer(struct sctp_inpcb *, struct sctp_tcb *,

View File

@ -329,7 +329,8 @@ struct sctp_paddr_change {
#define SCTP_ADDR_CONFIRMED 0x0006
#define SCTP_ACTIVE 0x0001 /* SCTP_ADDR_REACHABLE */
#define SCTP_INACTIVE 0x0002 /* SCTP_ADDR_NOT_REACHABLE */
#define SCTP_INACTIVE 0x0002 /* neither SCTP_ADDR_REACHABLE nor
* SCTP_ADDR_UNCONFIRMED */
#define SCTP_UNCONFIRMED 0x0200 /* SCTP_ADDR_UNCONFIRMED */
/* remote error events */
@ -516,6 +517,13 @@ struct sctp_paddrparams {
#define SPP_IPV6_FLOWLABEL 0x00000100
#define SPP_IPV4_TOS 0x00000200
struct sctp_paddrthlds {
sctp_assoc_t spt_assoc_id;
struct sockaddr_storage spt_address;
uint16_t spt_pathmaxrxt;
uint16_t spt_pathpfthld;
};
struct sctp_paddrinfo {
struct sockaddr_storage spinfo_address;
sctp_assoc_t spinfo_assoc_id;
@ -978,18 +986,8 @@ struct sctpstat {
* fired */
uint32_t sctps_timoassockill; /* Number of asoc free timers expired */
uint32_t sctps_timoinpkill; /* Number of inp free timers expired */
/* Early fast retransmission counters */
uint32_t sctps_earlyfrstart;
uint32_t sctps_earlyfrstop;
uint32_t sctps_earlyfrmrkretrans;
uint32_t sctps_earlyfrstpout;
uint32_t sctps_earlyfrstpidsck1;
uint32_t sctps_earlyfrstpidsck2;
uint32_t sctps_earlyfrstpidsck3;
uint32_t sctps_earlyfrstpidsck4;
uint32_t sctps_earlyfrstrid;
uint32_t sctps_earlyfrstrout;
uint32_t sctps_earlyfrstrtmr;
/* former early FR counters */
uint32_t sctps_spare[11];
/* others */
uint32_t sctps_hdrops; /* packet shorter than header */
uint32_t sctps_badsum; /* checksum error */
@ -1162,9 +1160,11 @@ struct xsctp_raddr {
uint8_t active; /* sctpAssocLocalRemEntry 3 */
uint8_t confirmed; /* */
uint8_t heartbeat_enabled; /* sctpAssocLocalRemEntry 4 */
uint8_t potentially_failed;
struct sctp_timeval start_time; /* sctpAssocLocalRemEntry 8 */
uint32_t rtt;
uint32_t extra_padding[32]; /* future */
uint32_t heartbeat_interval;
uint32_t extra_padding[31]; /* future */
};
#define SCTP_MAX_LOGGING_SIZE 30000

View File

@ -275,33 +275,8 @@ sctp_notify(struct sctp_inpcb *inp,
*/
if (net->dest_state & SCTP_ADDR_REACHABLE) {
/* Ok that destination is NOT reachable */
SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n",
net->error_count,
net->failure_threshold,
net);
net->dest_state &= ~SCTP_ADDR_REACHABLE;
net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
/*
* JRS 5/14/07 - If a destination is unreachable,
* the PF bit is turned off. This allows an
* unambiguous use of the PF bit for destinations
* that are reachable but potentially failed. If the
* destination is set to the unreachable state, also
* set the destination to the PF state.
*/
/*
* Add debug message here if destination is not in
* PF state.
*/
/* Stop any running T3 timers here? */
if ((stcb->asoc.sctp_cmt_on_off > 0) &&
(stcb->asoc.sctp_cmt_pf > 0)) {
net->dest_state &= ~SCTP_ADDR_PF;
SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
net);
}
net->error_count = net->failure_threshold + 1;
net->dest_state &= ~SCTP_ADDR_PF;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
stcb, SCTP_FAILED_THRESHOLD,
(void *)net, SCTP_SO_NOT_LOCKED);
@ -837,9 +812,15 @@ sctp_disconnect(struct socket *so)
if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
/* only send SHUTDOWN 1st time thru */
struct sctp_nets *netp;
if (stcb->asoc.alternate) {
netp = stcb->asoc.alternate;
} else {
netp = stcb->asoc.primary_destination;
}
sctp_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb,
stcb->asoc.primary_destination);
sctp_send_shutdown(stcb, netp);
sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
@ -848,11 +829,10 @@ sctp_disconnect(struct socket *so)
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb,
asoc->primary_destination);
stcb->sctp_ep, stcb, netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb,
asoc->primary_destination);
stcb->sctp_ep, stcb, netp);
}
} else {
/*
@ -865,9 +845,17 @@ sctp_disconnect(struct socket *so)
* we will allow user data to be sent first
* and move to SHUTDOWN-PENDING
*/
struct sctp_nets *netp;
if (stcb->asoc.alternate) {
netp = stcb->asoc.alternate;
} else {
netp = stcb->asoc.primary_destination;
}
asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
asoc->primary_destination);
netp);
if (asoc->locked_on_sending) {
/* Locked to send out the data */
struct sctp_stream_queue_pending *sp;
@ -1047,9 +1035,15 @@ sctp_shutdown(struct socket *so)
/* there is nothing queued to send, so I'm done... */
if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
/* only send SHUTDOWN the first time through */
struct sctp_nets *netp;
if (stcb->asoc.alternate) {
netp = stcb->asoc.alternate;
} else {
netp = stcb->asoc.primary_destination;
}
sctp_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb,
stcb->asoc.primary_destination);
sctp_send_shutdown(stcb, netp);
sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
@ -1058,20 +1052,26 @@ sctp_shutdown(struct socket *so)
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb,
asoc->primary_destination);
stcb->sctp_ep, stcb, netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb,
asoc->primary_destination);
stcb->sctp_ep, stcb, netp);
}
} else {
/*
* we still got (or just got) data to send, so set
* SHUTDOWN_PENDING
*/
struct sctp_nets *netp;
if (stcb->asoc.alternate) {
netp = stcb->asoc.alternate;
} else {
netp = stcb->asoc.primary_destination;
}
asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
asoc->primary_destination);
netp);
if (asoc->locked_on_sending) {
/* Locked to send out the data */
@ -2389,7 +2389,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
}
}
if (stcb) {
/* Applys to the specific association */
/* Applies to the specific association */
paddrp->spp_flags = 0;
if (net) {
int ovh;
@ -2400,7 +2400,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
ovh = SCTP_MED_V4_OVERHEAD;
}
paddrp->spp_hbinterval = net->heart_beat_delay;
paddrp->spp_pathmaxrxt = net->failure_threshold;
paddrp->spp_pathmtu = net->mtu - ovh;
/* get flags for HB */
@ -2444,11 +2444,12 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
#endif
/* default settings should be these */
if (stcb->asoc.hb_is_disabled == 0) {
paddrp->spp_flags |= SPP_HB_ENABLE;
} else {
if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
paddrp->spp_flags |= SPP_HB_DISABLE;
} else {
paddrp->spp_flags |= SPP_HB_ENABLE;
}
paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
cnt++;
@ -2458,7 +2459,6 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
paddrp->spp_flags |= SPP_PMTUD_ENABLE;
}
}
paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
paddrp->spp_assoc_id = sctp_get_associd(stcb);
SCTP_TCB_UNLOCK(stcb);
} else {
@ -3080,6 +3080,95 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
}
break;
}
case SCTP_PEER_ADDR_THLDS:
{
struct sctp_paddrthlds *thlds;
struct sctp_nets *net;
SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize);
SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
net = NULL;
if (stcb) {
net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_address);
} else {
/*
* We increment here since
* sctp_findassociation_ep_addr() wil do a
* decrement if it finds the stcb as long as
* the locked tcb (last argument) is NOT a
* TCB.. aka NULL.
*/
SCTP_INP_INCR_REF(inp);
stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&thlds->spt_address, &net, NULL, NULL);
if (stcb == NULL) {
SCTP_INP_DECR_REF(inp);
}
}
if (stcb && (net == NULL)) {
struct sockaddr *sa;
sa = (struct sockaddr *)&thlds->spt_address;
#ifdef INET
if (sa->sa_family == AF_INET) {
struct sockaddr_in *sin;
sin = (struct sockaddr_in *)sa;
if (sin->sin_addr.s_addr) {
error = EINVAL;
SCTP_TCB_UNLOCK(stcb);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
}
} else
#endif
#ifdef INET6
if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)sa;
if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
error = EINVAL;
SCTP_TCB_UNLOCK(stcb);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
}
} else
#endif
{
error = EAFNOSUPPORT;
SCTP_TCB_UNLOCK(stcb);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
}
}
if (stcb) {
if (net) {
thlds->spt_pathmaxrxt = net->failure_threshold;
thlds->spt_pathpfthld = net->pf_threshold;
} else {
thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure;
thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold;
}
thlds->spt_assoc_id = sctp_get_associd(stcb);
SCTP_TCB_UNLOCK(stcb);
} else {
if (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC) {
/* Use endpoint defaults */
SCTP_INP_RLOCK(inp);
thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure;
thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold;
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_paddrthlds);
}
break;
}
default:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = ENOPROTOOPT;
@ -3138,6 +3227,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
*/
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
/* only valid for bound all sockets */
if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) &&
(*mopt != 0)) {
/* forbidden by admin */
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM);
return (EPERM);
}
set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
} else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@ -4368,7 +4463,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
break;
}
case SCTP_PEER_ADDR_PARAMS:
/* Applys to the specific association */
/* Applies to the specific association */
{
struct sctp_paddrparams *paddrp;
struct sctp_nets *net;
@ -4459,29 +4554,33 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
ovh = SCTP_MED_V4_OVERHEAD;
}
if (paddrp->spp_hbinterval)
stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
stcb->asoc.heart_beat_delay = 0;
/* network sets ? */
if (net) {
/************************NET SPECIFIC SET ******************/
if (paddrp->spp_flags & SPP_HB_DEMAND) {
/* on demand HB */
if (sctp_send_hb(stcb, 1, net, SCTP_SO_LOCKED) < 0) {
/* asoc destroyed */
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
}
if (paddrp->spp_flags & SPP_HB_DISABLE) {
if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
!(net->dest_state & SCTP_ADDR_NOHB)) {
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
}
net->dest_state |= SCTP_ADDR_NOHB;
}
if (paddrp->spp_flags & SPP_HB_ENABLE) {
if (paddrp->spp_hbinterval) {
net->heart_beat_delay = paddrp->spp_hbinterval;
} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
net->heart_beat_delay = 0;
}
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
net->dest_state &= ~SCTP_ADDR_NOHB;
}
if (paddrp->spp_flags & SPP_HB_DEMAND) {
/* on demand HB */
sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
}
if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
@ -4499,8 +4598,33 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
}
}
if (paddrp->spp_pathmaxrxt)
if (paddrp->spp_pathmaxrxt) {
if (net->dest_state & SCTP_ADDR_PF) {
if (net->error_count > paddrp->spp_pathmaxrxt) {
net->dest_state &= ~SCTP_ADDR_PF;
}
} else {
if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
(net->error_count > net->pf_threshold)) {
net->dest_state |= SCTP_ADDR_PF;
sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
}
}
if (net->dest_state & SCTP_ADDR_REACHABLE) {
if (net->error_count > paddrp->spp_pathmaxrxt) {
net->dest_state &= ~SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
}
} else {
if (net->error_count <= paddrp->spp_pathmaxrxt) {
net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
}
}
net->failure_threshold = paddrp->spp_pathmaxrxt;
}
#ifdef INET
if (paddrp->spp_flags & SPP_IPV4_TOS) {
if (net->ro._l_addr.sin.sin_family == AF_INET) {
@ -4517,13 +4641,67 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
#endif
} else {
/************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/
if (paddrp->spp_pathmaxrxt)
if (paddrp->spp_pathmaxrxt) {
stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt;
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
if (net->dest_state & SCTP_ADDR_PF) {
if (net->error_count > paddrp->spp_pathmaxrxt) {
net->dest_state &= ~SCTP_ADDR_PF;
}
} else {
if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
(net->error_count > net->pf_threshold)) {
net->dest_state |= SCTP_ADDR_PF;
sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
}
}
if (net->dest_state & SCTP_ADDR_REACHABLE) {
if (net->error_count > paddrp->spp_pathmaxrxt) {
net->dest_state &= ~SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
}
} else {
if (net->error_count <= paddrp->spp_pathmaxrxt) {
net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
}
}
net->failure_threshold = paddrp->spp_pathmaxrxt;
}
}
if (paddrp->spp_flags & SPP_HB_ENABLE) {
if (paddrp->spp_hbinterval) {
stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
stcb->asoc.heart_beat_delay = 0;
}
/* Turn back on the timer */
stcb->asoc.hb_is_disabled = 0;
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
if (paddrp->spp_hbinterval) {
net->heart_beat_delay = paddrp->spp_hbinterval;
} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
net->heart_beat_delay = 0;
}
if (net->dest_state & SCTP_ADDR_NOHB) {
net->dest_state &= ~SCTP_ADDR_NOHB;
}
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
}
}
if (paddrp->spp_flags & SPP_HB_DISABLE) {
/* Turn back on the timer */
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
if (!(net->dest_state & SCTP_ADDR_NOHB)) {
net->dest_state |= SCTP_ADDR_NOHB;
if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
}
}
}
}
if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
@ -4546,41 +4724,25 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
}
}
if (paddrp->spp_flags & SPP_HB_DISABLE) {
int cnt_of_unconf = 0;
struct sctp_nets *lnet;
stcb->asoc.hb_is_disabled = 1;
TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) {
cnt_of_unconf++;
}
}
/*
* stop the timer ONLY if we
* have no unconfirmed
* addresses
*/
if (cnt_of_unconf == 0) {
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11);
}
}
}
if (paddrp->spp_flags & SPP_HB_ENABLE) {
/* start up the timer. */
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
}
}
#ifdef INET
if (paddrp->spp_flags & SPP_IPV4_TOS)
if (paddrp->spp_flags & SPP_IPV4_TOS) {
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
if (net->ro._l_addr.sin.sin_family == AF_INET) {
net->tos_flowlabel = paddrp->spp_ipv4_tos & 0x000000fc;
}
}
stcb->asoc.default_tos = paddrp->spp_ipv4_tos & 0x000000fc;
}
#endif
#ifdef INET6
if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL)
if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
if (net->ro._l_addr.sin6.sin6_family == AF_INET6) {
net->tos_flowlabel = paddrp->spp_ipv6_flowlabel;
}
}
stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel;
}
#endif
}
@ -4605,8 +4767,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
}
if (paddrp->spp_flags & SPP_HB_ENABLE) {
if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
} else if (paddrp->spp_hbinterval) {
inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
}
sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
} else if (paddrp->spp_flags & SPP_HB_DISABLE) {
sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
}
@ -4769,10 +4935,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
(!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
/* Ok we need to set it */
if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) {
net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH;
if ((stcb->asoc.alternate) &&
(!(net->dest_state & SCTP_ADDR_PF)) &&
(net->dest_state & SCTP_ADDR_REACHABLE)) {
sctp_free_remote_addr(stcb->asoc.alternate);
stcb->asoc.alternate = NULL;
}
net->dest_state |= SCTP_ADDR_SWITCH_PRIMARY;
}
}
} else {
@ -4930,7 +5098,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = EINVAL;
break;
}
if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
if (td != NULL &&
(error = prison_local_ip6(td->td_ucred,
&(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
(SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
@ -5170,6 +5340,146 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
break;
}
case SCTP_PEER_ADDR_THLDS:
/* Applies to the specific association */
{
struct sctp_paddrthlds *thlds;
struct sctp_nets *net;
SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize);
SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
net = NULL;
if (stcb) {
net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_assoc_id);
} else {
/*
* We increment here since
* sctp_findassociation_ep_addr() wil do a
* decrement if it finds the stcb as long as
* the locked tcb (last argument) is NOT a
* TCB.. aka NULL.
*/
SCTP_INP_INCR_REF(inp);
stcb = sctp_findassociation_ep_addr(&inp,
(struct sockaddr *)&thlds->spt_assoc_id,
&net, NULL, NULL);
if (stcb == NULL) {
SCTP_INP_DECR_REF(inp);
}
}
if (stcb && (net == NULL)) {
struct sockaddr *sa;
sa = (struct sockaddr *)&thlds->spt_assoc_id;
#ifdef INET
if (sa->sa_family == AF_INET) {
struct sockaddr_in *sin;
sin = (struct sockaddr_in *)sa;
if (sin->sin_addr.s_addr) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
SCTP_TCB_UNLOCK(stcb);
error = EINVAL;
break;
}
} else
#endif
#ifdef INET6
if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)sa;
if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
SCTP_TCB_UNLOCK(stcb);
error = EINVAL;
break;
}
} else
#endif
{
error = EAFNOSUPPORT;
SCTP_TCB_UNLOCK(stcb);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
break;
}
}
if (stcb) {
if (net) {
if (net->dest_state & SCTP_ADDR_PF) {
if ((net->failure_threshold > thlds->spt_pathmaxrxt) ||
(net->failure_threshold <= thlds->spt_pathpfthld)) {
net->dest_state &= ~SCTP_ADDR_PF;
}
} else {
if ((net->failure_threshold > thlds->spt_pathpfthld) &&
(net->failure_threshold <= thlds->spt_pathmaxrxt)) {
net->dest_state |= SCTP_ADDR_PF;
sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
}
}
if (net->dest_state & SCTP_ADDR_REACHABLE) {
if (net->failure_threshold > thlds->spt_pathmaxrxt) {
net->dest_state &= ~SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
}
} else {
if (net->failure_threshold <= thlds->spt_pathmaxrxt) {
net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
}
}
net->failure_threshold = thlds->spt_pathmaxrxt;
net->pf_threshold = thlds->spt_pathpfthld;
} else {
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
if (net->dest_state & SCTP_ADDR_PF) {
if ((net->failure_threshold > thlds->spt_pathmaxrxt) ||
(net->failure_threshold <= thlds->spt_pathpfthld)) {
net->dest_state &= ~SCTP_ADDR_PF;
}
} else {
if ((net->failure_threshold > thlds->spt_pathpfthld) &&
(net->failure_threshold <= thlds->spt_pathmaxrxt)) {
net->dest_state |= SCTP_ADDR_PF;
sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
}
}
if (net->dest_state & SCTP_ADDR_REACHABLE) {
if (net->failure_threshold > thlds->spt_pathmaxrxt) {
net->dest_state &= ~SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
}
} else {
if (net->failure_threshold <= thlds->spt_pathmaxrxt) {
net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
}
}
net->failure_threshold = thlds->spt_pathmaxrxt;
net->pf_threshold = thlds->spt_pathpfthld;
}
stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt;
stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld;
}
} else {
if (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC) {
SCTP_INP_WLOCK(inp);
inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt;
inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld;
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;

View File

@ -179,7 +179,6 @@ extern struct pr_usrreqs sctp_usrreqs;
if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&(__net)->ref_count)) { \
(void)SCTP_OS_TIMER_STOP(&(__net)->rxt_timer.timer); \
(void)SCTP_OS_TIMER_STOP(&(__net)->pmtu_timer.timer); \
(void)SCTP_OS_TIMER_STOP(&(__net)->fr_timer.timer); \
if ((__net)->ro.ro_rt) { \
RTFREE((__net)->ro.ro_rt); \
(__net)->ro.ro_rt = NULL; \
@ -189,7 +188,7 @@ extern struct pr_usrreqs sctp_usrreqs;
(__net)->ro._s_addr = NULL; \
} \
(__net)->src_addr_selected = 0; \
(__net)->dest_state = SCTP_ADDR_NOT_REACHABLE; \
(__net)->dest_state &= ~SCTP_ADDR_REACHABLE; \
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_net), (__net)); \
SCTP_DECR_RADDR_COUNT(); \
} \
@ -312,6 +311,8 @@ extern struct pr_usrreqs sctp_usrreqs;
#endif
#define SCTP_PF_ENABLED(_net) (_net->pf_threshold < _net->failure_threshold)
#define SCTP_NET_IS_PF(_net) (_net->pf_threshold < _net->error_count)
struct sctp_nets;
struct sctp_inpcb;

View File

@ -739,15 +739,14 @@ sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb)
asoc = &stcb->asoc;
(void)SCTP_OS_TIMER_STOP(&asoc->hb_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer);
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
(void)SCTP_OS_TIMER_STOP(&net->fr_timer.timer);
(void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer);
(void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer);
}
}
@ -921,7 +920,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
asoc->sctp_cmt_on_off = m->sctp_cmt_on_off;
asoc->ecn_allowed = m->sctp_ecn_enable;
asoc->sctp_nr_sack_on_off = (uint8_t) SCTP_BASE_SYSCTL(sctp_nr_sack_on_off);
asoc->sctp_cmt_pf = (uint8_t) SCTP_BASE_SYSCTL(sctp_cmt_pf);
asoc->sctp_cmt_pf = (uint8_t) 0;
asoc->sctp_frag_point = m->sctp_frag_point;
asoc->sctp_features = m->sctp_features;
#ifdef INET
@ -946,11 +945,6 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
asoc->peer_vtag_nonce = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
asoc->vrf_id = vrf_id;
if (sctp_is_feature_on(m, SCTP_PCB_FLAGS_DONOT_HEARTBEAT))
asoc->hb_is_disabled = 1;
else
asoc->hb_is_disabled = 0;
#ifdef SCTP_ASOCLOG_OF_TSNS
asoc->tsn_in_at = 0;
asoc->tsn_out_at = 0;
@ -989,6 +983,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
asoc->max_init_times = m->sctp_ep.max_init_times;
asoc->max_send_times = m->sctp_ep.max_send_times;
asoc->def_net_failure = m->sctp_ep.def_net_failure;
asoc->def_net_pf_threshold = m->sctp_ep.def_net_pf_threshold;
asoc->free_chunk_cnt = 0;
asoc->iam_blocking = 0;
@ -1632,11 +1627,10 @@ sctp_timeout_handler(void *t)
case SCTP_TIMER_TYPE_RECV:
if ((stcb == NULL) || (inp == NULL)) {
break;
} {
SCTP_STAT_INCR(sctps_timosack);
stcb->asoc.timosack++;
sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
}
SCTP_STAT_INCR(sctps_timosack);
stcb->asoc.timosack++;
sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
@ -1658,33 +1652,20 @@ sctp_timeout_handler(void *t)
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_HEARTBEAT:
{
struct sctp_nets *lnet;
int cnt_of_unconf = 0;
if ((stcb == NULL) || (inp == NULL)) {
break;
}
SCTP_STAT_INCR(sctps_timoheartbeat);
stcb->asoc.timoheartbeat++;
TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) &&
(lnet->dest_state & SCTP_ADDR_REACHABLE)) {
cnt_of_unconf++;
}
}
if (cnt_of_unconf == 0) {
if (sctp_heartbeat_timer(inp, stcb, lnet,
cnt_of_unconf)) {
/* no need to unlock on tcb its gone */
goto out_decr;
}
}
if ((stcb == NULL) || (inp == NULL) || (net == NULL)) {
break;
}
SCTP_STAT_INCR(sctps_timoheartbeat);
stcb->asoc.timoheartbeat++;
if (sctp_heartbeat_timer(inp, stcb, net)) {
/* no need to unlock on tcb its gone */
goto out_decr;
}
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, lnet);
sctp_auditing(4, inp, stcb, net);
#endif
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT,
stcb->sctp_ep, stcb, lnet);
if (!(net->dest_state & SCTP_ADDR_NOHB)) {
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED);
}
break;
@ -1780,14 +1761,6 @@ sctp_timeout_handler(void *t)
SCTP_STAT_INCR(sctps_timostrmrst);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_EARLYFR:
/* Need to do FR of things for net */
if ((stcb == NULL) || (inp == NULL)) {
break;
}
SCTP_STAT_INCR(sctps_timoearlyfr);
sctp_early_fr_timer(inp, stcb, net);
break;
case SCTP_TIMER_TYPE_ASCONF:
if ((stcb == NULL) || (inp == NULL)) {
break;
@ -1898,7 +1871,7 @@ void
sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct sctp_nets *net)
{
int to_ticks;
uint32_t to_ticks;
struct sctp_timer *tmr;
if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL))
@ -1985,71 +1958,38 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
* though we use a different timer. We also add the HB timer
* PLUS a random jitter.
*/
if ((inp == NULL) || (stcb == NULL)) {
if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
return;
} else {
uint32_t rndval;
uint8_t this_random;
int cnt_of_unconf = 0;
struct sctp_nets *lnet;
uint32_t jitter;
TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) &&
(lnet->dest_state & SCTP_ADDR_REACHABLE)) {
cnt_of_unconf++;
}
}
if (cnt_of_unconf) {
net = lnet = NULL;
(void)sctp_heartbeat_timer(inp, stcb, lnet, cnt_of_unconf);
}
if (stcb->asoc.hb_random_idx > 3) {
rndval = sctp_select_initial_TSN(&inp->sctp_ep);
memcpy(stcb->asoc.hb_random_values, &rndval,
sizeof(stcb->asoc.hb_random_values));
stcb->asoc.hb_random_idx = 0;
}
this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx];
stcb->asoc.hb_random_idx++;
stcb->asoc.hb_ect_randombit = 0;
/*
* this_random will be 0 - 256 ms RTO is in ms.
*/
if ((stcb->asoc.hb_is_disabled) &&
(cnt_of_unconf == 0)) {
if ((net->dest_state & SCTP_ADDR_NOHB) &&
!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
return;
}
if (net) {
int delay;
delay = stcb->asoc.heart_beat_delay;
TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) &&
((lnet->dest_state & SCTP_ADDR_OUT_OF_SCOPE) == 0) &&
(lnet->dest_state & SCTP_ADDR_REACHABLE)) {
delay = 0;
}
}
if (net->RTO == 0) {
/* Never been checked */
to_ticks = this_random + stcb->asoc.initial_rto + delay;
} else {
/* set rto_val to the ms */
to_ticks = delay + net->RTO + this_random;
}
if (net->RTO == 0) {
to_ticks = stcb->asoc.initial_rto;
} else {
if (cnt_of_unconf) {
to_ticks = this_random + stcb->asoc.initial_rto;
} else {
to_ticks = stcb->asoc.heart_beat_delay + this_random + stcb->asoc.initial_rto;
}
to_ticks = net->RTO;
}
rndval = sctp_select_initial_TSN(&inp->sctp_ep);
jitter = rndval % to_ticks;
if (jitter >= (to_ticks >> 1)) {
to_ticks = to_ticks + (jitter - (to_ticks >> 1));
} else {
to_ticks = to_ticks - jitter;
}
if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
!(net->dest_state & SCTP_ADDR_PF)) {
to_ticks += net->heart_beat_delay;
}
/*
* Now we must convert the to_ticks that are now in
* ms to ticks.
*/
to_ticks = MSEC_TO_TICKS(to_ticks);
tmr = &stcb->asoc.hb_timer;
tmr = &net->hb_timer;
}
break;
case SCTP_TIMER_TYPE_COOKIE:
@ -2150,35 +2090,6 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
}
tmr = &stcb->asoc.strreset_timer;
break;
case SCTP_TIMER_TYPE_EARLYFR:
{
unsigned int msec;
if ((stcb == NULL) || (net == NULL)) {
return;
}
if (net->flight_size > net->cwnd) {
/* no need to start */
return;
}
SCTP_STAT_INCR(sctps_earlyfrstart);
if (net->lastsa == 0) {
/* Hmm no rtt estimate yet? */
msec = stcb->asoc.initial_rto >> 2;
} else {
msec = ((net->lastsa >> 2) + net->lastsv) >> 1;
}
if (msec < SCTP_BASE_SYSCTL(sctp_early_fr_msec)) {
msec = SCTP_BASE_SYSCTL(sctp_early_fr_msec);
if (msec < SCTP_MINFR_MSEC_FLOOR) {
msec = SCTP_MINFR_MSEC_FLOOR;
}
}
to_ticks = MSEC_TO_TICKS(msec);
tmr = &net->fr_timer;
}
break;
case SCTP_TIMER_TYPE_ASCONF:
/*
* Here the timer comes from the stcb but its value is from
@ -2273,13 +2184,6 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
case SCTP_TIMER_TYPE_ADDR_WQ:
tmr = &SCTP_BASE_INFO(addr_wq_timer);
break;
case SCTP_TIMER_TYPE_EARLYFR:
if ((stcb == NULL) || (net == NULL)) {
return;
}
tmr = &net->fr_timer;
SCTP_STAT_INCR(sctps_earlyfrstop);
break;
case SCTP_TIMER_TYPE_SEND:
if ((stcb == NULL) || (net == NULL)) {
return;
@ -2305,10 +2209,10 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
tmr = &net->rxt_timer;
break;
case SCTP_TIMER_TYPE_HEARTBEAT:
if (stcb == NULL) {
if ((stcb == NULL) || (net == NULL)) {
return;
}
tmr = &stcb->asoc.hb_timer;
tmr = &net->hb_timer;
break;
case SCTP_TIMER_TYPE_COOKIE:
if ((stcb == NULL) || (net == NULL)) {
@ -6209,7 +6113,7 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
#ifdef INET
case AF_INET:
incr = sizeof(struct sockaddr_in);
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
/* assoc gone no un-lock */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
@ -6222,7 +6126,7 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
#ifdef INET6
case AF_INET6:
incr = sizeof(struct sockaddr_in6);
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
/* assoc gone no un-lock */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);

View File

@ -420,33 +420,8 @@ sctp6_notify(struct sctp_inpcb *inp,
*/
if (net->dest_state & SCTP_ADDR_REACHABLE) {
/* Ok that destination is NOT reachable */
SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n",
net->error_count,
net->failure_threshold,
net);
net->dest_state &= ~SCTP_ADDR_REACHABLE;
net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
/*
* JRS 5/14/07 - If a destination is unreachable,
* the PF bit is turned off. This allows an
* unambiguous use of the PF bit for destinations
* that are reachable but potentially failed. If the
* destination is set to the unreachable state, also
* set the destination to the PF state.
*/
/*
* Add debug message here if destination is not in
* PF state.
*/
/* Stop any running T3 timers here? */
if ((stcb->asoc.sctp_cmt_on_off > 0) &&
(stcb->asoc.sctp_cmt_pf > 0)) {
net->dest_state &= ~SCTP_ADDR_PF;
SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
net);
}
net->error_count = net->failure_threshold + 1;
net->dest_state &= ~SCTP_ADDR_PF;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
stcb, SCTP_FAILED_THRESHOLD,
(void *)net, SCTP_SO_NOT_LOCKED);