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
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: case SCTP_DEFAULT_PRINFO:
((struct sctp_default_prinfo *)arg)->pr_assoc_id = id; ((struct sctp_default_prinfo *)arg)->pr_assoc_id = id;
break; break;
case SCTP_PEER_ADDR_THLDS:
((struct sctp_paddrthlds *)arg)->spt_assoc_id = id;
break;
case SCTP_MAX_BURST: case SCTP_MAX_BURST:
((struct sctp_assoc_value *)arg)->assoc_id = id; ((struct sctp_assoc_value *)arg)->assoc_id = id;
break; break;

View File

@ -119,6 +119,7 @@ struct sctp_paramhdr {
#define SCTP_RECVNXTINFO 0x00000020 #define SCTP_RECVNXTINFO 0x00000020
#define SCTP_DEFAULT_SNDINFO 0x00000021 #define SCTP_DEFAULT_SNDINFO 0x00000021
#define SCTP_DEFAULT_PRINFO 0x00000022 #define SCTP_DEFAULT_PRINFO 0x00000022
#define SCTP_PEER_ADDR_THLDS 0x00000023
/* /*
* read-only options * read-only options
@ -564,7 +565,6 @@ struct sctp_error_unrecognized_chunk {
#define SCTP_BLK_LOGGING_ENABLE 0x00000001 #define SCTP_BLK_LOGGING_ENABLE 0x00000001
#define SCTP_CWND_MONITOR_ENABLE 0x00000002 #define SCTP_CWND_MONITOR_ENABLE 0x00000002
#define SCTP_CWND_LOGGING_ENABLE 0x00000004 #define SCTP_CWND_LOGGING_ENABLE 0x00000004
#define SCTP_EARLYFR_LOGGING_ENABLE 0x00000010
#define SCTP_FLIGHT_LOGGING_ENABLE 0x00000020 #define SCTP_FLIGHT_LOGGING_ENABLE 0x00000020
#define SCTP_FR_LOGGING_ENABLE 0x00000040 #define SCTP_FR_LOGGING_ENABLE 0x00000040
#define SCTP_LOCK_LOGGING_ENABLE 0x00000080 #define SCTP_LOCK_LOGGING_ENABLE 0x00000080
@ -572,23 +572,23 @@ struct sctp_error_unrecognized_chunk {
#define SCTP_MBCNT_LOGGING_ENABLE 0x00000200 #define SCTP_MBCNT_LOGGING_ENABLE 0x00000200
#define SCTP_MBUF_LOGGING_ENABLE 0x00000400 #define SCTP_MBUF_LOGGING_ENABLE 0x00000400
#define SCTP_NAGLE_LOGGING_ENABLE 0x00000800 #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_RTTVAR_LOGGING_ENABLE 0x00002000
#define SCTP_SACK_LOGGING_ENABLE 0x00004000 #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_SB_LOGGING_ENABLE 0x00010000
#define SCTP_STR_LOGGING_ENABLE 0x00020000 #define SCTP_STR_LOGGING_ENABLE 0x00020000
#define SCTP_WAKE_LOGGING_ENABLE 0x00040000 #define SCTP_WAKE_LOGGING_ENABLE 0x00040000
#define SCTP_LOG_MAXBURST_ENABLE 0x00080000 #define SCTP_LOG_MAXBURST_ENABLE 0x00080000
#define SCTP_LOG_RWND_ENABLE 0x00100000 #define SCTP_LOG_RWND_ENABLE 0x00100000
#define SCTP_LOG_SACK_ARRIVALS_ENABLE 0x00200000 #define SCTP_LOG_SACK_ARRIVALS_ENABLE 0x00200000
#define SCTP_LTRACE_CHUNK_ENABLE 0x00400000 #define SCTP_LTRACE_CHUNK_ENABLE 0x00400000
#define SCTP_LTRACE_ERROR_ENABLE 0x00800000 #define SCTP_LTRACE_ERROR_ENABLE 0x00800000
#define SCTP_LAST_PACKET_TRACING 0x01000000 #define SCTP_LAST_PACKET_TRACING 0x01000000
#define SCTP_THRESHOLD_LOGGING 0x02000000 #define SCTP_THRESHOLD_LOGGING 0x02000000
#define SCTP_LOG_AT_SEND_2_SCTP 0x04000000 #define SCTP_LOG_AT_SEND_2_SCTP 0x04000000
#define SCTP_LOG_AT_SEND_2_OUTQ 0x08000000 #define SCTP_LOG_AT_SEND_2_OUTQ 0x08000000
#define SCTP_LOG_TRY_ADVANCE 0x10000000 #define SCTP_LOG_TRY_ADVANCE 0x10000000
#undef SCTP_PACKED #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 * static struct mbuf *
sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, 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 mbuf *m_reply = NULL;
struct sockaddr_storage sa_source, sa_store; struct sockaddr_storage sa_source, sa_store;
struct sctp_paramhdr *ph; 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); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
} }
/* add the address */ /* 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) { SCTP_ADDR_DYNAMIC_ADDED) != 0) {
SCTPDBG(SCTP_DEBUG_ASCONF1, SCTPDBG(SCTP_DEBUG_ASCONF1,
"process_asconf_add_ip: error adding address\n"); "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 = m_reply =
sctp_asconf_success_response(aph->correlation_id); sctp_asconf_success_response(aph->correlation_id);
} }
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
NULL, SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, 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; return m_reply;
} }
@ -554,7 +557,12 @@ sctp_process_asconf_set_primary(struct mbuf *m,
"process_asconf_set_primary: primary address set\n"); "process_asconf_set_primary: primary address set\n");
/* notify upper layer */ /* notify upper layer */
sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa, SCTP_SO_NOT_LOCKED); 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) { if (response_required) {
m_reply = sctp_asconf_success_response(aph->correlation_id); 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_ack_chunk *ack_cp;
struct sctp_asconf_paramhdr *aph, *ack_aph; struct sctp_asconf_paramhdr *aph, *ack_aph;
struct sctp_ipv6addr_param *p_addr; struct sctp_ipv6addr_param *p_addr;
unsigned int asconf_limit; unsigned int asconf_limit, cnt;
int error = 0; /* did an error occur? */ int error = 0; /* did an error occur? */
/* asconf param buffer */ /* asconf param buffer */
@ -717,6 +725,7 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
goto send_reply; goto send_reply;
} }
/* process through all parameters */ /* process through all parameters */
cnt = 0;
while (aph != NULL) { while (aph != NULL) {
unsigned int param_length, param_type; unsigned int param_length, param_type;
@ -749,7 +758,8 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
case SCTP_ADD_IP_ADDRESS: case SCTP_ADD_IP_ADDRESS:
asoc->peer_supports_asconf = 1; asoc->peer_supports_asconf = 1;
m_result = sctp_process_asconf_add_ip(m, aph, stcb, m_result = sctp_process_asconf_add_ip(m, aph, stcb,
error); (cnt < SCTP_BASE_SYSCTL(sctp_hb_maxburst)), error);
cnt++;
break; break;
case SCTP_DEL_IP_ADDRESS: case SCTP_DEL_IP_ADDRESS:
asoc->peer_supports_asconf = 1; asoc->peer_supports_asconf = 1;
@ -1959,7 +1969,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
int status; 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)) { sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
/* subset bound, no ASCONF allowed case, so ignore */ /* subset bound, no ASCONF allowed case, so ignore */
return; 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, sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
stcb, stcb->asoc.primary_destination); stcb, stcb->asoc.primary_destination);
#else #else
sctp_send_asconf(stcb, stcb->asoc.primary_destination, sctp_send_asconf(stcb, NULL, addr_locked);
addr_locked);
#endif #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 we have queued params in the open state, send out an ASCONF.
*/ */
if (num_queued > 0) { if (num_queued > 0) {
sctp_send_asconf(stcb, stcb->asoc.primary_destination, sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
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->sctp_ep, stcb,
stcb->asoc.primary_destination); stcb->asoc.primary_destination);
#else #else
sctp_send_asconf(stcb, stcb->asoc.primary_destination, sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
SCTP_ADDR_NOT_LOCKED);
#endif #endif
} }
} else { } else {
@ -2421,8 +2428,7 @@ sctp_set_primary_ip_address(struct sctp_ifa *ifa)
stcb->sctp_ep, stcb, stcb->sctp_ep, stcb,
stcb->asoc.primary_destination); stcb->asoc.primary_destination);
#else #else
sctp_send_asconf(stcb, stcb->asoc.primary_destination, sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
SCTP_ADDR_NOT_LOCKED);
#endif #endif
} }
} }
@ -2965,8 +2971,7 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
stcb->sctp_ep, stcb, stcb->sctp_ep, stcb,
stcb->asoc.primary_destination); stcb->asoc.primary_destination);
#else #else
sctp_send_asconf(stcb, stcb->asoc.primary_destination, sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
SCTP_ADDR_NOT_LOCKED);
#endif #endif
} }
} }
@ -3540,5 +3545,5 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
} }
skip_rest: skip_rest:
/* Now we must send the asconf into the queue */ /* 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 #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 nothing was acked on this destination skip it */
if (net->net_ack == 0) { if (net->net_ack == 0) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 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; 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 #ifdef JANA_CMT_FAST_RECOVERY
/* /*
* CMT fast recovery code * 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 * If we are in loss recovery we skip any cwnd
* update * update
*/ */
goto skip_cwnd_update; return;
} }
/* /*
* Did any measurements go on for this network? * 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 (net->cc_mod.rtcc.lbw) {
if (cc_bw_limit(stcb, net, nbw)) { if (cc_bw_limit(stcb, net, nbw)) {
/* Hold here, no update */ /* Hold here, no update */
goto skip_cwnd_update; continue;
} }
} else { } else {
uint64_t vtag, probepoint; uint64_t vtag, probepoint;
@ -1049,26 +970,24 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
SCTP_CWND_LOG_NO_CUMACK); 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 static void
sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net) 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 static void
sctp_cwnd_update_after_sack(struct sctp_tcb *stcb, sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
struct sctp_association *asoc, struct sctp_association *asoc,
@ -1858,40 +1751,6 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
} }
} }
#endif #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 nothing was acked on this destination skip it */
if (net->net_ack == 0) { if (net->net_ack == 0) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 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; 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 #ifdef JANA_CMT_FAST_RECOVERY
/* /*
* CMT fast recovery code * 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 * If we are in loss recovery we skip any cwnd
* update * update
*/ */
goto skip_cwnd_update; return;
} }
/* /*
* CMT: CUC algorithm. Update cwnd if pseudo-cumack has * 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); 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 #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 nothing was acked on this destination skip it */
if (net->net_ack == 0) { if (net->net_ack == 0) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 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; 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 #ifdef JANA_CMT_FAST_RECOVERY
/* /*
* CMT fast recovery code * 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 * If we are in loss recovery we skip any cwnd
* update * update
*/ */
goto skip_cwnd_update; return;
} }
/* /*
* CMT: CUC algorithm. Update cwnd if pseudo-cumack has * 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); 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 static void
sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb,
struct sctp_nets *net, int in_window, int num_pkt_lost) 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_set_initial_cc_param = sctp_set_initial_cc_param,
.sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack, .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_fr = sctp_cwnd_update_after_fr,
.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, .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_ecn_echo = sctp_cwnd_update_after_ecn_echo,
.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, .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_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_set_initial_cc_param = sctp_set_initial_cc_param,
.sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack, .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_fr = sctp_hs_cwnd_update_after_fr,
.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, .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_ecn_echo = sctp_cwnd_update_after_ecn_echo,
.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, .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_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_set_initial_cc_param = sctp_htcp_set_initial_cc_param,
.sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack, .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_fr = sctp_htcp_cwnd_update_after_fr,
.sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout, .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_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_packet_dropped = sctp_cwnd_update_after_packet_dropped,
.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, .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_set_initial_cc_param = sctp_set_rtcc_initial_cc_param,
.sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack, .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_fr = sctp_cwnd_update_after_fr,
.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, .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_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_packet_dropped = sctp_cwnd_update_after_packet_dropped,
.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, .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_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted,
.sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged, .sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged,
.sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins, .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_IN_REQUEST 0x000e
#define SCTP_STR_RESET_TSN_REQUEST 0x000f #define SCTP_STR_RESET_TSN_REQUEST 0x000f
#define SCTP_STR_RESET_RESPONSE 0x0010 #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_MAX_RESET_PARAMS 2
#define SCTP_STREAM_RESET_TSN_DELTA 0x1000 #define SCTP_STREAM_RESET_TSN_DELTA 0x1000
@ -508,14 +508,10 @@ __FBSDID("$FreeBSD$");
/* SCTP reachability state for each address */ /* SCTP reachability state for each address */
#define SCTP_ADDR_REACHABLE 0x001 #define SCTP_ADDR_REACHABLE 0x001
#define SCTP_ADDR_NOT_REACHABLE 0x002
#define SCTP_ADDR_NOHB 0x004 #define SCTP_ADDR_NOHB 0x004
#define SCTP_ADDR_BEING_DELETED 0x008 #define SCTP_ADDR_BEING_DELETED 0x008
#define SCTP_ADDR_NOT_IN_ASSOC 0x010 #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_OUT_OF_SCOPE 0x080
#define SCTP_ADDR_DOUBLE_SWITCH 0x100
#define SCTP_ADDR_UNCONFIRMED 0x200 #define SCTP_ADDR_UNCONFIRMED 0x200
#define SCTP_ADDR_REQ_PRIMARY 0x400 #define SCTP_ADDR_REQ_PRIMARY 0x400
/* JRS 5/13/07 - Added potentially failed state for CMT PF */ /* 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_EVENTWAKE 13
#define SCTP_TIMER_TYPE_STRRESET 14 #define SCTP_TIMER_TYPE_STRRESET 14
#define SCTP_TIMER_TYPE_INPKILL 15 #define SCTP_TIMER_TYPE_INPKILL 15
#define SCTP_TIMER_TYPE_EARLYFR 17 #define SCTP_TIMER_TYPE_ASOCKILL 16
#define SCTP_TIMER_TYPE_ASOCKILL 18 #define SCTP_TIMER_TYPE_ADDR_WQ 17
#define SCTP_TIMER_TYPE_ADDR_WQ 19 #define SCTP_TIMER_TYPE_ZERO_COPY 18
#define SCTP_TIMER_TYPE_ZERO_COPY 20 #define SCTP_TIMER_TYPE_ZCOPY_SENDQ 19
#define SCTP_TIMER_TYPE_ZCOPY_SENDQ 21 #define SCTP_TIMER_TYPE_PRIM_DELETED 20
#define SCTP_TIMER_TYPE_PRIM_DELETED 22
/* add new timers here - and increment LAST */ /* 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) && \ #define SCTP_IS_TIMER_TYPE_VALID(t) (((t) > SCTP_TIMER_TYPE_NONE) && \
((t) < SCTP_TIMER_TYPE_LAST)) ((t) < SCTP_TIMER_TYPE_LAST))
@ -655,16 +650,17 @@ __FBSDID("$FreeBSD$");
#define SCTP_DEFAULT_SECRET_LIFE_SEC 3600 #define SCTP_DEFAULT_SECRET_LIFE_SEC 3600
#define SCTP_RTO_UPPER_BOUND (60000) /* 60 sec in ms */ #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_RTO_INITIAL (3000) /* 3 sec in ms */
#define SCTP_INP_KILL_TIMEOUT 20/* number of ms to retry kill of inpcb */ #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_ASOC_KILL_TIMEOUT 10 /* number of ms to retry kill of inpcb */
#define SCTP_DEF_MAX_INIT 8 #define SCTP_DEF_MAX_INIT 8
#define SCTP_DEF_MAX_SEND 10 #define SCTP_DEF_MAX_SEND 10
#define SCTP_DEF_MAX_PATH_RTX 5 #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 */ #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 */ /* Send window update (incr * this > hiwat). Should be a power of 2 */
#define SCTP_MINIMAL_RWND (4096) /* minimal rwnd */ #define SCTP_MINIMAL_RWND (4096) /* minimal rwnd */
#define SCTP_ADDRMAX 24 #define SCTP_ADDRMAX 16
/* SCTP DEBUG Switch parameters */ /* SCTP DEBUG Switch parameters */
#define SCTP_DEBUG_TIMER1 0x00000001 #define SCTP_DEBUG_TIMER1 0x00000001

View File

@ -98,9 +98,10 @@ struct sctp_heartbeat_info_param {
uint32_t time_value_2; uint32_t time_value_2;
uint32_t random_value1; uint32_t random_value1;
uint32_t random_value2; uint32_t random_value2;
uint16_t user_req;
uint8_t addr_family; uint8_t addr_family;
uint8_t addr_len; uint8_t addr_len;
/* make sure that this structure is 4 byte aligned */
uint8_t padding[2];
char address[SCTP_ADDRMAX]; char address[SCTP_ADDRMAX];
} SCTP_PACKED; } 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, sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_INDATA + SCTP_LOC_18); 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); sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
} else { } else {
int is_a_gap; 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 */ /* 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->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, 1, 0, 0);
}
asoc->last_acked_seq = cumack; asoc->last_acked_seq = cumack;
if (TAILQ_EMPTY(&asoc->sent_queue)) { if (TAILQ_EMPTY(&asoc->sent_queue)) {
@ -4127,13 +4169,6 @@ again:
stcb, net, stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_22); 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) && if ((j == 0) &&
@ -4222,6 +4257,8 @@ again:
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24; 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); sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper, SCTP_SO_NOT_LOCKED);
} else { } else {
struct sctp_nets *netp;
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab); SCTP_STAT_DECR_GAUGE32(sctps_currestab);
@ -4229,26 +4266,36 @@ again:
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_stop_timers_for_shutdown(stcb); sctp_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb, if (asoc->alternate) {
stcb->asoc.primary_destination); netp = asoc->alternate;
} else {
netp = asoc->primary_destination;
}
sctp_send_shutdown(stcb, netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 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, 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) && } else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
(asoc->stream_queue_cnt == 0)) { (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) { if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
goto abort_out_now; goto abort_out_now;
} }
SCTP_STAT_DECR_GAUGE32(sctps_currestab); SCTP_STAT_DECR_GAUGE32(sctps_currestab);
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT); SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_send_shutdown_ack(stcb, sctp_send_shutdown_ack(stcb, netp);
stcb->asoc.primary_destination);
sctp_stop_timers_for_shutdown(stcb); sctp_stop_timers_for_shutdown(stcb);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, 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, num_dup,
SCTP_LOG_NEW_SACK); 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; uint16_t i;
uint32_t *dupdata, dblock; 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) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_26); 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->partial_bytes_acked = 0;
net->flight_size = 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; asoc->saw_sack_with_nr_frags = 0;
/* JRS - Use the congestion control given in the CC module */ /* 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); asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, accum_moved, reneged_all, will_exit_fast_recovery);
}
if (TAILQ_EMPTY(&asoc->sent_queue)) { if (TAILQ_EMPTY(&asoc->sent_queue)) {
/* nothing left in-flight */ /* nothing left in-flight */
TAILQ_FOREACH(net, &asoc->nets, sctp_next) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
/* stop all timers */ /* 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, sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30); stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30);
net->flight_size = 0; 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); sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper, SCTP_SO_NOT_LOCKED);
return; return;
} else { } else {
struct sctp_nets *netp;
if (asoc->alternate) {
netp = asoc->alternate;
} else {
netp = asoc->primary_destination;
}
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab); 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_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_stop_timers_for_shutdown(stcb); sctp_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb, sctp_send_shutdown(stcb, netp);
stcb->asoc.primary_destination);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 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, sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, asoc->primary_destination); stcb->sctp_ep, stcb, netp);
} }
return; return;
} else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) && } else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
(asoc->stream_queue_cnt == 0)) { (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) { if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
goto abort_out_now; goto abort_out_now;
} }
SCTP_STAT_DECR_GAUGE32(sctps_currestab); SCTP_STAT_DECR_GAUGE32(sctps_currestab);
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT); SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_send_shutdown_ack(stcb, sctp_send_shutdown_ack(stcb, netp);
stcb->asoc.primary_destination);
sctp_stop_timers_for_shutdown(stcb); sctp_stop_timers_for_shutdown(stcb);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK,
stcb->sctp_ep, stcb, asoc->primary_destination); stcb->sctp_ep, stcb, netp);
return; return;
} }
} }
@ -5056,13 +5142,6 @@ again:
stcb, net, stcb, net,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_22); 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) && 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 sctp_nets *r_net, *f_net;
struct timeval tv; struct timeval tv;
int req_prim = 0; int req_prim = 0;
uint16_t old_error_counter;
#ifdef INET #ifdef INET
struct sockaddr_in *sin; struct sockaddr_in *sin;
@ -599,7 +600,6 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
r_net->dest_state &= ~SCTP_ADDR_UNCONFIRMED; r_net->dest_state &= ~SCTP_ADDR_UNCONFIRMED;
if (r_net->dest_state & SCTP_ADDR_REQ_PRIMARY) { if (r_net->dest_state & SCTP_ADDR_REQ_PRIMARY) {
stcb->asoc.primary_destination = r_net; stcb->asoc.primary_destination = r_net;
r_net->dest_state &= ~SCTP_ADDR_WAS_PRIMARY;
r_net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY; r_net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY;
f_net = TAILQ_FIRST(&stcb->asoc.nets); f_net = TAILQ_FIRST(&stcb->asoc.nets);
if (f_net != r_net) { 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, sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED,
stcb, 0, (void *)r_net, SCTP_SO_NOT_LOCKED); 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->error_count = 0;
r_net->hb_responded = 1; r_net->hb_responded = 1;
tv.tv_sec = cp->heartbeat.hb_info.time_value_1; tv.tv_sec = cp->heartbeat.hb_info.time_value_1;
tv.tv_usec = cp->heartbeat.hb_info.time_value_2; 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 */ /* Now lets do a RTO with this */
r_net->RTO = sctp_calculate_rto(stcb, &stcb->asoc, r_net, &tv, sctp_align_safe_nocopy, r_net->RTO = sctp_calculate_rto(stcb, &stcb->asoc, r_net, &tv, sctp_align_safe_nocopy,
SCTP_RTT_FROM_NON_DATA); 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 */ /* Mobility adaptation */
if (req_prim) { if (req_prim) {
if ((sctp_is_mobility_feature_on(stcb->sctp_ep, 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"); 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 static void
sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
struct sctp_tcb *stcb, struct sctp_nets *net, int *abort_flag) struct sctp_tcb *stcb, struct sctp_nets *net, int *abort_flag)
@ -916,7 +938,7 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
} else { } else {
/* no outstanding data to send, so move on... */ /* no outstanding data to send, so move on... */
/* send SHUTDOWN-ACK */ /* send SHUTDOWN-ACK */
sctp_send_shutdown_ack(stcb, stcb->asoc.primary_destination); sctp_send_shutdown_ack(stcb, net);
/* move to SHUTDOWN-ACK-SENT state */ /* move to SHUTDOWN-ACK-SENT state */
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { (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? */ /* TSNH! Huh, why do I need to add this address here? */
int ret; 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); SCTP_IN_COOKIE_PROC);
netl = sctp_findnet(*stcb, to); netl = sctp_findnet(*stcb, to);
} }
@ -2697,10 +2719,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
send_int_conf = 1; send_int_conf = 1;
} }
} }
if (*stcb) { sctp_start_net_timers(*stcb);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, *inp_p,
*stcb, NULL);
}
if ((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { if ((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
if (!had_a_existing_tcb || if (!had_a_existing_tcb ||
(((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { (((*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 */ /* state change only needed when I am in right state */
SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n"); SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n");
SCTP_SET_STATE(asoc, SCTP_STATE_OPEN); SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
sctp_start_net_timers(stcb);
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, asoc->primary_destination); 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 * Only retransmit if we KNOW we wont destroy the
* tcb * tcb
*/ */
(void)sctp_send_hb(stcb, 1, net, SCTP_SO_NOT_LOCKED); sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
} }
break; break;
case SCTP_SHUTDOWN: case SCTP_SHUTDOWN:
@ -3999,8 +4019,7 @@ strres_nochunk:
/* setup chunk parameters */ /* setup chunk parameters */
chk->sent = SCTP_DATAGRAM_UNSENT; chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0; chk->snd_count = 0;
chk->whoTo = stcb->asoc.primary_destination; chk->whoTo = NULL;
atomic_add_int(&chk->whoTo->ref_count, 1);
ch = mtod(chk->data, struct sctp_chunkhdr *); ch = mtod(chk->data, struct sctp_chunkhdr *);
ch->chunk_type = SCTP_STREAM_RESET; ch->chunk_type = SCTP_STREAM_RESET;
@ -4630,8 +4649,7 @@ process_control_chunks:
if ((stcb != NULL) && if ((stcb != NULL) &&
(SCTP_GET_STATE(&stcb->asoc) == (SCTP_GET_STATE(&stcb->asoc) ==
SCTP_STATE_SHUTDOWN_ACK_SENT)) { SCTP_STATE_SHUTDOWN_ACK_SENT)) {
sctp_send_shutdown_ack(stcb, sctp_send_shutdown_ack(stcb, NULL);
stcb->asoc.primary_destination);
*offset = length; *offset = length;
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED); sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED);
if (locked_tcb) { 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; *error = EINVAL;
return (-1); 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; *error = ENOBUFS;
return (1); return (1);
} }
@ -3574,13 +3575,15 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
*error = EINVAL; *error = EINVAL;
return (-1); 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; *error = ENOBUFS;
return (1); return (1);
} }
} else } else
#endif #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; *error = ENOBUFS;
return (1); return (1);
} }
@ -3828,28 +3831,7 @@ sctp_handle_no_route(struct sctp_tcb *stcb,
(void *)net, (void *)net,
so_locked); so_locked);
net->dest_state &= ~SCTP_ADDR_REACHABLE; net->dest_state &= ~SCTP_ADDR_REACHABLE;
net->dest_state |= SCTP_ADDR_NOT_REACHABLE; net->dest_state &= ~SCTP_ADDR_PF;
/*
* 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);
}
} }
} }
if (stcb) { if (stcb) {
@ -3859,14 +3841,16 @@ sctp_handle_no_route(struct sctp_tcb *stcb,
alt = sctp_find_alternate_net(stcb, net, 0); alt = sctp_find_alternate_net(stcb, net, 0);
if (alt != net) { if (alt != net) {
if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, alt) == 0) { if (stcb->asoc.alternate) {
net->dest_state |= SCTP_ADDR_WAS_PRIMARY; sctp_free_remote_addr(stcb->asoc.alternate);
if (net->ro._s_addr) {
sctp_free_ifa(net->ro._s_addr);
net->ro._s_addr = NULL;
}
net->src_addr_selected = 0;
} }
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 added_control = 0;
int un_sent, do_chunk_output = 1; int un_sent, do_chunk_output = 1;
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_nets *net;
ca = (struct sctp_copy_all *)ptr; ca = (struct sctp_copy_all *)ptr;
if (ca->m == NULL) { if (ca->m == NULL) {
@ -6531,6 +6516,11 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
m = NULL; m = NULL;
} }
SCTP_TCB_LOCK_ASSERT(stcb); 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) { if (ca->sndrcv.sinfo_flags & SCTP_ABORT) {
/* Abort this assoc with m as the user defined reason */ /* Abort this assoc with m as the user defined reason */
if (m) { if (m) {
@ -6569,7 +6559,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
} }
} else { } else {
if (m) { if (m) {
ret = sctp_msg_append(stcb, stcb->asoc.primary_destination, m, ret = sctp_msg_append(stcb, net, m,
&ca->sndrcv, 1); &ca->sndrcv, 1);
} }
asoc = &stcb->asoc; 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 * only send SHUTDOWN the first time
* through * through
*/ */
sctp_send_shutdown(stcb, stcb->asoc.primary_destination); sctp_send_shutdown(stcb, net);
if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) { if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab); SCTP_STAT_DECR_GAUGE32(sctps_currestab);
} }
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, 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, sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
asoc->primary_destination); asoc->primary_destination);
added_control = 1; added_control = 1;
@ -7733,13 +7723,13 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
struct sctp_auth_chunk *auth = NULL; struct sctp_auth_chunk *auth = NULL;
uint16_t auth_keyid; uint16_t auth_keyid;
int override_ok = 1; int override_ok = 1;
int skip_fill_up = 0;
int data_auth_reqd = 0; int data_auth_reqd = 0;
/* /*
* JRS 5/14/07 - Add flag for whether a heartbeat is sent to the * JRS 5/14/07 - Add flag for whether a heartbeat is sent to the
* destination. * destination.
*/ */
int pf_hbflag = 0;
int quit_now = 0; int quit_now = 0;
*num_out = 0; *num_out = 0;
@ -7806,7 +7796,22 @@ nothing_to_send:
max_send_per_dest = SCTP_SB_LIMIT_SND(stcb->sctp_socket) / asoc->numnets; max_send_per_dest = SCTP_SB_LIMIT_SND(stcb->sctp_socket) / asoc->numnets;
else else
max_send_per_dest = 0; 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) && if ((no_data_chunks == 0) &&
(skip_fill_up == 0) &&
(!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc))) { (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc))) {
TAILQ_FOREACH(net, &asoc->nets, sctp_next) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
/* /*
@ -7821,8 +7826,10 @@ nothing_to_send:
* copy by reference (we hope). * copy by reference (we hope).
*/ */
net->window_probe = 0; net->window_probe = 0;
if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) || if ((net != stcb->asoc.alternate) &&
(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { ((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) { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
sctp_log_cwnd(stcb, net, 1, sctp_log_cwnd(stcb, net, 1,
SCTP_CWND_LOG_FILL_OUTQ_CALLED); SCTP_CWND_LOG_FILL_OUTQ_CALLED);
@ -7833,16 +7840,6 @@ nothing_to_send:
(net->flight_size == 0)) { (net->flight_size == 0)) {
(*stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) (stcb, net); (*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) { if (net->flight_size >= net->cwnd) {
/* skip this network, no room - can't fill */ /* skip this network, no room - can't fill */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
@ -7886,6 +7883,16 @@ nothing_to_send:
} else { } else {
start_at = TAILQ_FIRST(&asoc->nets); 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; old_start_at = NULL;
again_one_more_time: again_one_more_time:
for (net = start_at; net != NULL; net = TAILQ_NEXT(net, sctp_next)) { for (net = start_at; net != NULL; net = TAILQ_NEXT(net, sctp_next)) {
@ -7896,15 +7903,6 @@ again_one_more_time:
break; break;
} }
tsns_sent = 0xa; 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) && if (TAILQ_EMPTY(&asoc->control_send_queue) &&
TAILQ_EMPTY(&asoc->asconf_send_queue) && TAILQ_EMPTY(&asoc->asconf_send_queue) &&
(net->flight_size >= net->cwnd)) { (net->flight_size >= net->cwnd)) {
@ -8266,15 +8264,8 @@ again_one_more_time:
(chk->rec.chunk_id.id == SCTP_ECN_CWR) || (chk->rec.chunk_id.id == SCTP_ECN_CWR) ||
(chk->rec.chunk_id.id == SCTP_PACKET_DROPPED) || (chk->rec.chunk_id.id == SCTP_PACKET_DROPPED) ||
(chk->rec.chunk_id.id == SCTP_ASCONF_ACK)) { (chk->rec.chunk_id.id == SCTP_ASCONF_ACK)) {
if (chk->rec.chunk_id.id == SCTP_HEARTBEAT_REQUEST) { if (chk->rec.chunk_id.id == SCTP_HEARTBEAT_REQUEST) {
hbflag = 1; 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 */ /* remove these chunks at the end */
if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) || if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) ||
@ -8408,7 +8399,7 @@ again_one_more_time:
} }
/* JRI: if dest is in PF state, do not send data to it */ /* JRI: if dest is in PF state, do not send data to it */
if ((asoc->sctp_cmt_on_off > 0) && if ((asoc->sctp_cmt_on_off > 0) &&
(asoc->sctp_cmt_pf > 0) && (net != stcb->asoc.alternate) &&
(net->dest_state & SCTP_ADDR_PF)) { (net->dest_state & SCTP_ADDR_PF)) {
goto no_data_fill; goto no_data_fill;
} }
@ -8486,6 +8477,17 @@ again_one_more_time:
/* Don't send the chunk on this net */ /* Don't send the chunk on this net */
continue; 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)) { if ((chk->send_size > omtu) && ((chk->flags & CHUNK_FLAGS_FRAGMENT_OK) == 0)) {
/*- /*-
* strange, we have a chunk that is * strange, we have a chunk that is
@ -8646,18 +8648,6 @@ no_data_fill:
* restart it. * restart it.
*/ */
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); 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 :> */ /* Now send it, if there is anything to send :> */
if ((error = sctp_lowlevel_chunk_output(inp, if ((error = sctp_lowlevel_chunk_output(inp,
@ -8747,24 +8737,6 @@ no_data_fill:
} }
SCTP_STAT_INCR_BY(sctps_senddata, bundle_at); SCTP_STAT_INCR_BY(sctps_senddata, bundle_at);
sctp_clean_up_datalist(stcb, asoc, data_list, bundle_at, net); 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) { if (one_chunk) {
break; break;
@ -8833,8 +8805,7 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err)
chk->flags = 0; chk->flags = 0;
chk->asoc = &stcb->asoc; chk->asoc = &stcb->asoc;
chk->data = op_err; chk->data = op_err;
chk->whoTo = chk->asoc->primary_destination; chk->whoTo = NULL;
atomic_add_int(&chk->whoTo->ref_count, 1);
hdr = mtod(op_err, struct sctp_chunkhdr *); hdr = mtod(op_err, struct sctp_chunkhdr *);
hdr->chunk_type = SCTP_OPERATION_ERROR; hdr->chunk_type = SCTP_OPERATION_ERROR;
hdr->chunk_flags = 0; hdr->chunk_flags = 0;
@ -8929,7 +8900,7 @@ sctp_send_cookie_echo(struct mbuf *m,
chk->flags = CHUNK_FLAGS_FRAGMENT_OK; chk->flags = CHUNK_FLAGS_FRAGMENT_OK;
chk->asoc = &stcb->asoc; chk->asoc = &stcb->asoc;
chk->data = cookie; chk->data = cookie;
chk->whoTo = chk->asoc->primary_destination; chk->whoTo = net;
atomic_add_int(&chk->whoTo->ref_count, 1); atomic_add_int(&chk->whoTo->ref_count, 1);
TAILQ_INSERT_HEAD(&chk->asoc->control_send_queue, chk, sctp_next); TAILQ_INSERT_HEAD(&chk->asoc->control_send_queue, chk, sctp_next);
chk->asoc->ctrl_queue_cnt++; chk->asoc->ctrl_queue_cnt++;
@ -9039,10 +9010,10 @@ sctp_send_cookie_ack(struct sctp_tcb *stcb)
chk->data = cookie_ack; chk->data = cookie_ack;
if (chk->asoc->last_control_chunk_from != NULL) { if (chk->asoc->last_control_chunk_from != NULL) {
chk->whoTo = chk->asoc->last_control_chunk_from; chk->whoTo = chk->asoc->last_control_chunk_from;
atomic_add_int(&chk->whoTo->ref_count, 1);
} else { } 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 = mtod(cookie_ack, struct sctp_chunkhdr *);
hdr->chunk_type = SCTP_COOKIE_ACK; hdr->chunk_type = SCTP_COOKIE_ACK;
hdr->chunk_flags = 0; 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->asoc = &stcb->asoc;
chk->data = m_shutdown_ack; chk->data = m_shutdown_ack;
chk->whoTo = net; 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 = mtod(m_shutdown_ack, struct sctp_shutdown_ack_chunk *);
ack_cp->ch.chunk_type = SCTP_SHUTDOWN_ACK; ack_cp->ch.chunk_type = SCTP_SHUTDOWN_ACK;
ack_cp->ch.chunk_flags = 0; 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->asoc = &stcb->asoc;
chk->data = m_shutdown; chk->data = m_shutdown;
chk->whoTo = net; 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 = mtod(m_shutdown, struct sctp_shutdown_chunk *);
shutdown_cp->ch.chunk_type = SCTP_SHUTDOWN; shutdown_cp->ch.chunk_type = SCTP_SHUTDOWN;
shutdown_cp->ch.chunk_flags = 0; 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->flags = CHUNK_FLAGS_FRAGMENT_OK;
chk->asoc = &stcb->asoc; chk->asoc = &stcb->asoc;
chk->whoTo = net; 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); TAILQ_INSERT_TAIL(&chk->asoc->asconf_send_queue, chk, sctp_next);
chk->asoc->ctrl_queue_cnt++; chk->asoc->ctrl_queue_cnt++;
return; 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); net = sctp_find_alternate_net(stcb, stcb->asoc.last_control_chunk_from, 0);
if (net == NULL) { if (net == NULL) {
/* no alternate */ /* no alternate */
if (stcb->asoc.last_control_chunk_from == NULL) if (stcb->asoc.last_control_chunk_from == NULL) {
net = stcb->asoc.primary_destination; if (stcb->asoc.alternate) {
else net = stcb->asoc.alternate;
} else {
net = stcb->asoc.primary_destination;
}
} else {
net = stcb->asoc.last_control_chunk_from; net = stcb->asoc.last_control_chunk_from;
}
} }
} else { } else {
/* normal case */ /* normal case */
if (stcb->asoc.last_control_chunk_from == NULL) if (stcb->asoc.last_control_chunk_from == NULL) {
net = stcb->asoc.primary_destination; if (stcb->asoc.alternate) {
else net = stcb->asoc.alternate;
} else {
net = stcb->asoc.primary_destination;
}
} else {
net = stcb->asoc.last_control_chunk_from; net = stcb->asoc.last_control_chunk_from;
}
} }
latest_ack->last_sent_to = net; latest_ack->last_sent_to = net;
@ -9256,6 +9241,9 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb)
chk->copy_by_ref = 0; chk->copy_by_ref = 0;
chk->whoTo = net; chk->whoTo = net;
if (chk->whoTo) {
atomic_add_int(&chk->whoTo->ref_count, 1);
}
chk->data = m_ack; chk->data = m_ack;
chk->send_size = 0; chk->send_size = 0;
/* Get size */ /* Get size */
@ -9267,7 +9255,6 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb)
chk->snd_count = 0; chk->snd_count = 0;
chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; /* XXX */ chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; /* XXX */
chk->asoc = &stcb->asoc; chk->asoc = &stcb->asoc;
atomic_add_int(&chk->whoTo->ref_count, 1);
TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next);
chk->asoc->ctrl_queue_cnt++; chk->asoc->ctrl_queue_cnt++;
@ -9797,7 +9784,11 @@ sctp_timer_validation(struct sctp_inpcb *inp,
SCTP_TCB_LOCK_ASSERT(stcb); SCTP_TCB_LOCK_ASSERT(stcb);
/* Gak, we did not have a timer somewhere */ /* Gak, we did not have a timer somewhere */
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Deadlock avoided starting timer on a dest at retran\n"); 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); return (ret);
} }
@ -9945,8 +9936,7 @@ sctp_chunk_output(struct sctp_inpcb *inp,
#endif #endif
/* Check for bad destinations, if they exist move chunks around. */ /* Check for bad destinations, if they exist move chunks around. */
TAILQ_FOREACH(net, &asoc->nets, sctp_next) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
SCTP_ADDR_NOT_REACHABLE) {
/*- /*-
* if possible move things off of this address we * if possible move things off of this address we
* still may send below due to the dormant state but * 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) if (net->ref_count > 1)
sctp_move_chunks_from_net(stcb, net); 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 { } else {
/*- /*-
* if ((asoc->sat_network) || (net->addr_is_local)) * 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->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0; chk->snd_count = 0;
/* Do we correct its output location? */ /* Do we correct its output location? */
if (chk->whoTo != asoc->primary_destination) { if (chk->whoTo) {
sctp_free_remote_addr(chk->whoTo); sctp_free_remote_addr(chk->whoTo);
chk->whoTo = asoc->primary_destination; chk->whoTo = NULL;
atomic_add_int(&chk->whoTo->ref_count, 1);
} }
goto sctp_fill_in_rest; 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); SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD);
chk->sent = SCTP_DATAGRAM_UNSENT; chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0; 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); TAILQ_INSERT_TAIL(&asoc->control_send_queue, chk, sctp_next);
asoc->ctrl_queue_cnt++; asoc->ctrl_queue_cnt++;
sctp_fill_in_rest: sctp_fill_in_rest:
@ -10346,8 +10323,10 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
sctp_m_freem(a_chk->data); sctp_m_freem(a_chk->data);
a_chk->data = NULL; a_chk->data = NULL;
} }
sctp_free_remote_addr(a_chk->whoTo); if (a_chk->whoTo) {
a_chk->whoTo = NULL; sctp_free_remote_addr(a_chk->whoTo);
a_chk->whoTo = NULL;
}
break; break;
} }
} }
@ -10379,13 +10358,13 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
a_chk->whoTo = NULL; a_chk->whoTo = NULL;
if ((asoc->numduptsns) || 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 * Ok, we have some duplicates or the destination for the
* sack is unreachable, lets see if we can select an * sack is unreachable, lets see if we can select an
* alternate than asoc->last_data_chunk_from * 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)) { (asoc->used_alt_onsack > asoc->numnets)) {
/* We used an alt last time, don't this time */ /* We used an alt last time, don't this time */
a_chk->whoTo = NULL; a_chk->whoTo = NULL;
@ -10710,6 +10689,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
int sz; int sz;
uint32_t auth_offset = 0; uint32_t auth_offset = 0;
struct sctp_auth_chunk *auth = NULL; struct sctp_auth_chunk *auth = NULL;
struct sctp_nets *net;
/*- /*-
* Add an AUTH chunk, if chunk requires it and save the offset into * 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 */ /* Put AUTH chunk at the front of the chain */
SCTP_BUF_NEXT(m_end) = m_abort; 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 */ /* fill in the ABORT chunk */
abort = mtod(m_abort, struct sctp_abort_chunk *); abort = mtod(m_abort, struct sctp_abort_chunk *);
abort->ch.chunk_type = SCTP_ABORT_ASSOCIATION; abort->ch.chunk_type = SCTP_ABORT_ASSOCIATION;
abort->ch.chunk_flags = 0; abort->ch.chunk_flags = 0;
abort->ch.chunk_length = htons(sizeof(*abort) + sz); abort->ch.chunk_length = htons(sizeof(*abort) + sz);
(void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, (void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net,
stcb->asoc.primary_destination, (struct sockaddr *)&net->ro._l_addr,
(struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr,
m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, NULL, 0, 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->sctp_ep->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag),
stcb->asoc.primary_destination->port, so_locked, NULL, NULL); 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 * void
sctp_select_hb_destination(struct sctp_tcb *stcb, struct timeval *now) sctp_send_hb(struct sctp_tcb *stcb, struct sctp_nets *net, int so_locked
{
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
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
SCTP_UNUSED SCTP_UNUSED
#endif #endif
) )
{ {
struct sctp_tmit_chunk *chk; struct sctp_tmit_chunk *chk;
struct sctp_nets *net;
struct sctp_heartbeat_chunk *hb; struct sctp_heartbeat_chunk *hb;
struct timeval now; struct timeval now;
SCTP_TCB_LOCK_ASSERT(stcb); SCTP_TCB_LOCK_ASSERT(stcb);
if (user_req == 0) { if (net == NULL) {
net = sctp_select_hb_destination(stcb, &now); return;
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);
} }
(void)SCTP_GETTIME_TIMEVAL(&now);
switch (net->ro._l_addr.sa.sa_family) { switch (net->ro._l_addr.sa.sa_family) {
#ifdef INET #ifdef INET
case AF_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; break;
#endif #endif
default: default:
return (0); return;
} }
sctp_alloc_a_chunk(stcb, chk); sctp_alloc_a_chunk(stcb, chk);
if (chk == NULL) { if (chk == NULL) {
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak, can't get a chunk for hb\n"); SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak, can't get a chunk for hb\n");
return (0); return;
} }
chk->copy_by_ref = 0; chk->copy_by_ref = 0;
chk->rec.chunk_id.id = SCTP_HEARTBEAT_REQUEST; 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); chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_DONTWAIT, 1, MT_HEADER);
if (chk->data == NULL) { if (chk->data == NULL) {
sctp_free_a_chunk(stcb, chk, so_locked); sctp_free_a_chunk(stcb, chk, so_locked);
return (0); return;
} }
SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD);
SCTP_BUF_LEN(chk->data) = chk->send_size; 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_1 = now.tv_sec;
hb->heartbeat.hb_info.time_value_2 = now.tv_usec; hb->heartbeat.hb_info.time_value_2 = now.tv_usec;
/* Did our user request this one, put it in */ /* 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_family = net->ro._l_addr.sa.sa_family;
hb->heartbeat.hb_info.addr_len = net->ro._l_addr.sa.sa_len; hb->heartbeat.hb_info.addr_len = net->ro._l_addr.sa.sa_len;
if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { 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; break;
#endif #endif
default: default:
return (0); return;
break; 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; net->hb_responded = 0;
TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next); TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next);
stcb->asoc.ctrl_queue_cnt++; stcb->asoc.ctrl_queue_cnt++;
SCTP_STAT_INCR(sctps_sendheartbeat); SCTP_STAT_INCR(sctps_sendheartbeat);
/*- return;
* 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);
} }
void void
@ -11282,6 +11123,9 @@ sctp_send_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
struct sctp_ecne_chunk *ecne; struct sctp_ecne_chunk *ecne;
struct sctp_tmit_chunk *chk; struct sctp_tmit_chunk *chk;
if (net == NULL) {
return;
}
asoc = &stcb->asoc; asoc = &stcb->asoc;
SCTP_TCB_LOCK_ASSERT(stcb); SCTP_TCB_LOCK_ASSERT(stcb);
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { 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->snd_count = 0;
chk->whoTo = net; chk->whoTo = net;
atomic_add_int(&chk->whoTo->ref_count, 1); atomic_add_int(&chk->whoTo->ref_count, 1);
stcb->asoc.ecn_echo_cnt_onq++; stcb->asoc.ecn_echo_cnt_onq++;
ecne = mtod(chk->data, struct sctp_ecne_chunk *); ecne = mtod(chk->data, struct sctp_ecne_chunk *);
ecne->ch.chunk_type = SCTP_ECN_ECHO; ecne->ch.chunk_type = SCTP_ECN_ECHO;
@ -11477,10 +11322,10 @@ jump_out:
if (net) { if (net) {
/* we should hit here */ /* we should hit here */
chk->whoTo = net; chk->whoTo = net;
atomic_add_int(&chk->whoTo->ref_count, 1);
} else { } 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.id = SCTP_PACKET_DROPPED;
chk->rec.chunk_id.can_take_data = 1; chk->rec.chunk_id.can_take_data = 1;
drp->ch.chunk_type = SCTP_PACKET_DROPPED; 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; asoc = &stcb->asoc;
SCTP_TCB_LOCK_ASSERT(stcb); SCTP_TCB_LOCK_ASSERT(stcb);
if (net == NULL) {
return;
}
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
if ((chk->rec.chunk_id.id == SCTP_ECN_CWR) && (net == chk->whoTo)) { 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 */ /* setup chunk parameters */
chk->sent = SCTP_DATAGRAM_UNSENT; chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0; 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); atomic_add_int(&chk->whoTo->ref_count, 1);
ch = mtod(chk->data, struct sctp_chunkhdr *); ch = mtod(chk->data, struct sctp_chunkhdr *);
ch->chunk_type = SCTP_STREAM_RESET; ch->chunk_type = SCTP_STREAM_RESET;
ch->chunk_flags = 0; ch->chunk_flags = 0;
@ -12910,7 +12759,11 @@ sctp_lower_sosend(struct socket *so,
goto out_unlocked; goto out_unlocked;
} }
} else { } 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); atomic_add_int(&stcb->total_sends, 1);
/* Keep the stcb from being freed under our feet */ /* Keep the stcb from being freed under our feet */
@ -13579,15 +13432,22 @@ dataless_eof:
if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) && (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { (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 */ /* 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) { if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab); SCTP_STAT_DECR_GAUGE32(sctps_currestab);
} }
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, 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, sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
asoc->primary_destination); 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); 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); 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; continue;
} }
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 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; continue;
}
switch (sctp_ifa->address.sa.sa_family) { switch (sctp_ifa->address.sa.sa_family) {
#ifdef INET #ifdef INET
case AF_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; struct sctp_laddr *laddr;
LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) { 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; continue;
} }
if (laddr->ifa->address.sa.sa_family != to->sa_family) { 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_init_times = SCTP_BASE_SYSCTL(sctp_init_rtx_max_default);
m->max_send_times = SCTP_BASE_SYSCTL(sctp_assoc_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_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_sender = SCTP_SWS_SENDER_DEF;
m->sctp_sws_receiver = SCTP_SWS_RECEIVER_DEF; m->sctp_sws_receiver = SCTP_SWS_RECEIVER_DEF;
m->max_burst = SCTP_BASE_SYSCTL(sctp_max_burst_default); 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. * all of them.
*/ */
stcb->asoc.hb_timer.ep = (void *)new_inp;
stcb->asoc.dack_timer.ep = (void *)new_inp; stcb->asoc.dack_timer.ep = (void *)new_inp;
stcb->asoc.asconf_timer.ep = (void *)new_inp; stcb->asoc.asconf_timer.ep = (void *)new_inp;
stcb->asoc.strreset_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) { TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
net->pmtu_timer.ep = (void *)new_inp; net->pmtu_timer.ep = (void *)new_inp;
net->rxt_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(new_inp);
SCTP_INP_WUNLOCK(old_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) && if ((SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
(SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_ACK_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, * there is nothing queued to send,
* so I send shutdown * 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) || if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab); 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_SET_STATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_SENT);
SCTP_CLEAR_SUBSTATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_PENDING); SCTP_CLEAR_SUBSTATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, asoc->sctp_ep, asoc, 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, sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc,
asoc->asoc.primary_destination); asoc->asoc.primary_destination);
sctp_chunk_output(inp, asoc, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_LOCKED); 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 int
sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, 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 * 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); return (-1);
} }
SCTP_INCR_RADDR_COUNT(); SCTP_INCR_RADDR_COUNT();
bzero(net, sizeof(*net)); bzero(net, sizeof(struct sctp_nets));
(void)SCTP_GETTIME_TIMEVAL(&net->start_time); (void)SCTP_GETTIME_TIMEVAL(&net->start_time);
memcpy(&net->ro._l_addr, newaddr, newaddr->sa_len); memcpy(&net->ro._l_addr, newaddr, newaddr->sa_len);
switch (newaddr->sa_family) { switch (newaddr->sa_family) {
@ -3968,6 +3987,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
addr_inscope = 1; addr_inscope = 1;
} }
net->failure_threshold = stcb->asoc.def_net_failure; net->failure_threshold = stcb->asoc.def_net_failure;
net->pf_threshold = stcb->asoc.def_net_pf_threshold;
if (addr_inscope == 0) { if (addr_inscope == 0) {
net->dest_state = (SCTP_ADDR_REACHABLE | net->dest_state = (SCTP_ADDR_REACHABLE |
SCTP_ADDR_OUT_OF_SCOPE); 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) if (newaddr->sa_family == AF_INET6)
net->tos_flowlabel = stcb->asoc.default_flowlabel; net->tos_flowlabel = stcb->asoc.default_flowlabel;
#endif #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 */ /* Init the timer structure */
SCTP_OS_TIMER_INIT(&net->rxt_timer.timer); 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->pmtu_timer.timer);
SCTP_OS_TIMER_INIT(&net->hb_timer.timer);
/* Now generate a route for this guy */ /* Now generate a route for this guy */
#ifdef INET6 #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 */ /* No route to current primary adopt new primary */
stcb->asoc.primary_destination = net; stcb->asoc.primary_destination = net;
} }
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb,
net);
/* Validate primary is first */ /* Validate primary is first */
net = TAILQ_FIRST(&stcb->asoc.nets); net = TAILQ_FIRST(&stcb->asoc.nets);
if ((net != stcb->asoc.primary_destination) && 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, TAILQ_INSERT_HEAD(&stcb->asoc.nets,
stcb->asoc.primary_destination, sctp_next); stcb->asoc.primary_destination, sctp_next);
} }
if (netp) {
*netp = net;
}
return (0); return (0);
} }
@ -4393,7 +4420,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
LIST_INSERT_HEAD(head, stcb, sctp_asocs); LIST_INSERT_HEAD(head, stcb, sctp_asocs);
SCTP_INP_INFO_WUNLOCK(); 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? */ /* failure.. memory error? */
if (asoc->strmout) { if (asoc->strmout) {
SCTP_FREE(asoc->strmout, SCTP_M_STRMO); SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
@ -4418,7 +4445,6 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
return (NULL); return (NULL);
} }
/* Init all the timers */ /* 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->dack_timer.timer);
SCTP_OS_TIMER_INIT(&asoc->strreset_timer.timer); SCTP_OS_TIMER_INIT(&asoc->strreset_timer.timer);
SCTP_OS_TIMER_INIT(&asoc->asconf_timer.timer); SCTP_OS_TIMER_INIT(&asoc->asconf_timer.timer);
@ -4488,6 +4514,10 @@ out:
/* Clear net */ /* Clear net */
asoc->last_control_chunk_from = NULL; 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); 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 */ /* there is no asoc, really TSNH :-0 */
return (1); return (1);
} }
if (stcb->asoc.alternate) {
sctp_free_remote_addr(stcb->asoc.alternate);
stcb->asoc.alternate = NULL;
}
/* TEMP CODE */ /* TEMP CODE */
if (stcb->freed_from_where == 0) { if (stcb->freed_from_where == 0) {
/* Only record the first place free happened from */ /* 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 */ /* 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); (void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
asoc->dack_timer.self = NULL; asoc->dack_timer.self = NULL;
(void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer); (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); (void)SCTP_OS_TIMER_STOP(&asoc->delete_prim_timer.timer);
asoc->delete_prim_timer.self = NULL; asoc->delete_prim_timer.self = NULL;
TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 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); (void)SCTP_OS_TIMER_STOP(&net->rxt_timer.timer);
net->rxt_timer.self = NULL; net->rxt_timer.self = NULL;
(void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer); (void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer);
net->pmtu_timer.self = NULL; 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) */ /* Now the read queue needs to be cleaned up (only once) */
if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) { 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! * 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->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->dack_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->strreset_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->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->autoclose_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer);
TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 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->rxt_timer.timer);
(void)SCTP_OS_TIMER_STOP(&net->pmtu_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; 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 #ifdef INET
case AF_INET: case AF_INET:
if (stcb->asoc.ipv4_addr_legal) { 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); return (-1);
} }
} }
@ -6198,7 +6229,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
#ifdef INET6 #ifdef INET6
case AF_INET6: case AF_INET6:
if (stcb->asoc.ipv6_addr_legal) { 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); return (-2);
} }
} }
@ -6289,7 +6320,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
/* the assoc was freed? */ /* the assoc was freed? */
return (-7); 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); return (-8);
} }
} else if (stcb_tmp == stcb) { } 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 * we must add the address, no scope
* set * 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); return (-17);
} }
} else if (stcb_tmp == stcb) { } else if (stcb_tmp == stcb) {
@ -6748,7 +6779,10 @@ sctp_set_primary_addr(struct sctp_tcb *stcb, struct sockaddr *sa,
return (0); return (0);
} }
stcb->asoc.primary_destination = net; 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); net = TAILQ_FIRST(&stcb->asoc.nets);
if (net != stcb->asoc.primary_destination) { if (net != stcb->asoc.primary_destination) {
/* /*

View File

@ -293,6 +293,8 @@ struct sctp_pcb {
uint16_t def_net_failure; uint16_t def_net_failure;
uint16_t def_net_pf_threshold;
/* number of streams to pre-open on a association */ /* number of streams to pre-open on a association */
uint16_t pre_open_stream_count; uint16_t pre_open_stream_count;
uint16_t max_open_streams_intome; 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 *); 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 *); void sctp_remove_net(struct sctp_tcb *, struct sctp_nets *);

View File

@ -251,6 +251,7 @@ struct sctp_nets {
* structure shared by all. * structure shared by all.
*/ */
struct sctp_timer pmtu_timer; struct sctp_timer pmtu_timer;
struct sctp_timer hb_timer;
/* /*
* The following two in combination equate to a route entry for v6 * 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 */ /* This is used for SHUTDOWN/SHUTDOWN-ACK/SEND or INIT timers */
struct sctp_timer rxt_timer; struct sctp_timer rxt_timer;
struct sctp_timer fr_timer; /* for early fr */
/* last time in seconds I sent to it */ /* last time in seconds I sent to it */
struct timeval last_sent_time; struct timeval last_sent_time;
@ -327,12 +327,15 @@ struct sctp_nets {
uint32_t marked_retrans;/* number or DATA chunks marked for timer uint32_t marked_retrans;/* number or DATA chunks marked for timer
* based retransmissions */ * based retransmissions */
uint32_t marked_fastretrans; uint32_t marked_fastretrans;
uint32_t heart_beat_delay; /* Heart Beat delay in ms */
/* if this guy is ok or not ... status */ /* if this guy is ok or not ... status */
uint16_t dest_state; uint16_t dest_state;
/* number of transmit failures to down this guy */ /* number of timeouts to consider the destination unreachable */
uint16_t failure_threshold; 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; uint16_t error_count;
/* UDP port number in case of UDP tunneling */ /* UDP port number in case of UDP tunneling */
uint16_t port; uint16_t port;
@ -661,6 +664,7 @@ struct sctp_cc_functions {
void (*sctp_cwnd_update_after_sack) (struct sctp_tcb *stcb, void (*sctp_cwnd_update_after_sack) (struct sctp_tcb *stcb,
struct sctp_association *asoc, struct sctp_association *asoc,
int accum_moved, int reneged_all, int will_exit); 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, void (*sctp_cwnd_update_after_fr) (struct sctp_tcb *stcb,
struct sctp_association *asoc); struct sctp_association *asoc);
void (*sctp_cwnd_update_after_timeout) (struct sctp_tcb *stcb, 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); uint32_t * bottle_bw, uint32_t * on_queue);
void (*sctp_cwnd_update_after_output) (struct sctp_tcb *stcb, void (*sctp_cwnd_update_after_output) (struct sctp_tcb *stcb,
struct sctp_nets *net, int burst_limit); 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, void (*sctp_cwnd_update_packet_transmitted) (struct sctp_tcb *stcb,
struct sctp_nets *net); struct sctp_nets *net);
void (*sctp_cwnd_update_tsn_acknowledged) (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; struct sctp_nonpad_sndrcvinfo def_send;
/* timers and such */ /* timers and such */
struct sctp_timer hb_timer; /* hb timer */
struct sctp_timer dack_timer; /* Delayed ack timer */ struct sctp_timer dack_timer; /* Delayed ack timer */
struct sctp_timer asconf_timer; /* asconf */ struct sctp_timer asconf_timer; /* asconf */
struct sctp_timer strreset_timer; /* stream reset */ struct sctp_timer strreset_timer; /* stream reset */
@ -828,6 +829,7 @@ struct sctp_association {
uint8_t *mapping_array; uint8_t *mapping_array;
/* primary destination to use */ /* primary destination to use */
struct sctp_nets *primary_destination; struct sctp_nets *primary_destination;
struct sctp_nets *alternate; /* If primary is down or PF */
/* For CMT */ /* For CMT */
struct sctp_nets *last_net_cmt_send_started; struct sctp_nets *last_net_cmt_send_started;
/* last place I got a data chunk from */ /* last place I got a data chunk from */
@ -1023,8 +1025,8 @@ struct sctp_association {
unsigned int size_on_all_streams; unsigned int size_on_all_streams;
unsigned int cnt_on_all_streams; unsigned int cnt_on_all_streams;
/* Heart Beat delay in ticks */ /* Heart Beat delay in ms */
unsigned int heart_beat_delay; uint32_t heart_beat_delay;
/* autoclose */ /* autoclose */
unsigned int sctp_autoclose_ticks; unsigned int sctp_autoclose_ticks;
@ -1094,6 +1096,8 @@ struct sctp_association {
uint16_t def_net_failure; 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 * lock flag: 0 is ok to send, 1+ (duals as a retran count) is
* awaiting ACK * awaiting ACK
@ -1133,7 +1137,6 @@ struct sctp_association {
uint8_t last_flags_delivered; uint8_t last_flags_delivered;
uint8_t hb_ect_randombit; uint8_t hb_ect_randombit;
uint8_t hb_random_idx; uint8_t hb_random_idx;
uint8_t hb_is_disabled; /* is the hb disabled? */
uint8_t default_tos; uint8_t default_tos;
uint8_t asconf_del_pending; /* asconf delete last addr pending */ 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_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_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_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_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_nr_outgoing_streams_default) = SCTPCTL_OUTGOING_STREAMS_DEFAULT;
SCTP_BASE_SYSCTL(sctp_cmt_on_off) = SCTPCTL_CMT_ON_OFF_DEFAULT; SCTP_BASE_SYSCTL(sctp_cmt_on_off) = SCTPCTL_CMT_ON_OFF_DEFAULT;
/* EY */ /* EY */
SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) = SCTPCTL_NR_SACK_ON_OFF_DEFAULT; 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_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_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_asconf_auth_nochk) = SCTPCTL_ASCONF_AUTH_NOCHK_DEFAULT;
SCTP_BASE_SYSCTL(sctp_auth_disable) = SCTPCTL_AUTH_DISABLE_DEFAULT; SCTP_BASE_SYSCTL(sctp_auth_disable) = SCTPCTL_AUTH_DISABLE_DEFAULT;
SCTP_BASE_SYSCTL(sctp_nat_friendly) = SCTPCTL_NAT_FRIENDLY_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.active = ((net->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE);
xraddr.confirmed = ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0); xraddr.confirmed = ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0);
xraddr.heartbeat_enabled = ((net->dest_state & SCTP_ADDR_NOHB) == 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.rto = net->RTO;
xraddr.max_path_rtx = net->failure_threshold; xraddr.max_path_rtx = net->failure_threshold;
xraddr.rtx = net->marked_retrans; xraddr.rtx = net->marked_retrans;
@ -502,6 +501,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
xraddr.flight_size = net->flight_size; xraddr.flight_size = net->flight_size;
xraddr.mtu = net->mtu; xraddr.mtu = net->mtu;
xraddr.rtt = net->rtt / 1000; 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_sec = (uint32_t) net->start_time.tv_sec;
xraddr.start_time.tv_usec = (uint32_t) net->start_time.tv_usec; xraddr.start_time.tv_usec = (uint32_t) net->start_time.tv_usec;
SCTP_INP_RUNLOCK(inp); 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_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_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_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_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_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); RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_on_off), SCTPCTL_CMT_ON_OFF_MIN, SCTPCTL_CMT_ON_OFF_MAX);
/* EY */ /* 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_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_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_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_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_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); 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_timoautoclose += sarry->sctps_timoautoclose;
sb.sctps_timoassockill += sarry->sctps_timoassockill; sb.sctps_timoassockill += sarry->sctps_timoassockill;
sb.sctps_timoinpkill += sarry->sctps_timoinpkill; 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_hdrops += sarry->sctps_hdrops;
sb.sctps_badsum += sarry->sctps_badsum; sb.sctps_badsum += sarry->sctps_badsum;
sb.sctps_noport += sarry->sctps_noport; 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", &SCTP_BASE_SYSCTL(sctp_path_rtx_max_default), 0, sysctl_sctp_check, "IU",
SCTPCTL_PATH_RTX_MAX_DESC); 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, 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", &SCTP_BASE_SYSCTL(sctp_add_more_threshold), 0, sysctl_sctp_check, "IU",
SCTPCTL_ADD_MORE_ON_OUTPUT_DESC); 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", &SCTP_BASE_SYSCTL(sctp_cmt_use_dac), 0, sysctl_sctp_check, "IU",
SCTPCTL_CMT_USE_DAC_DESC); 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, 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", &SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst), 0, sysctl_sctp_check, "IU",
SCTPCTL_CWND_MAXBURST_DESC); 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, 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", &SCTP_BASE_SYSCTL(sctp_asconf_auth_nochk), 0, sysctl_sctp_check, "IU",
SCTPCTL_ASCONF_AUTH_NOCHK_DESC); SCTPCTL_ASCONF_AUTH_NOCHK_DESC);

View File

@ -74,16 +74,14 @@ struct sctp_sysctl {
uint32_t sctp_init_rtx_max_default; uint32_t sctp_init_rtx_max_default;
uint32_t sctp_assoc_rtx_max_default; uint32_t sctp_assoc_rtx_max_default;
uint32_t sctp_path_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_add_more_threshold;
uint32_t sctp_nr_outgoing_streams_default; uint32_t sctp_nr_outgoing_streams_default;
uint32_t sctp_cmt_on_off; uint32_t sctp_cmt_on_off;
uint32_t sctp_cmt_use_dac; uint32_t sctp_cmt_use_dac;
/* EY 5/5/08 - nr_sack flag variable */ /* EY 5/5/08 - nr_sack flag variable */
uint32_t sctp_nr_sack_on_off; uint32_t sctp_nr_sack_on_off;
uint32_t sctp_cmt_pf;
uint32_t sctp_use_cwnd_based_maxburst; 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_asconf_auth_nochk;
uint32_t sctp_auth_disable; uint32_t sctp_auth_disable;
uint32_t sctp_nat_friendly; uint32_t sctp_nat_friendly;
@ -322,6 +320,12 @@ struct sctp_sysctl {
#define SCTPCTL_PATH_RTX_MAX_MAX 0xFFFFFFFF #define SCTPCTL_PATH_RTX_MAX_MAX 0xFFFFFFFF
#define SCTPCTL_PATH_RTX_MAX_DEFAULT SCTP_DEF_MAX_PATH_RTX #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 */ /* 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_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 #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_MAX 1
#define SCTPCTL_CMT_USE_DAC_DEFAULT 0 #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 */ /* cwnd_maxburst: Use a CWND adjusting maxburst */
#define SCTPCTL_CWND_MAXBURST_DESC "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_MIN 0
#define SCTPCTL_CWND_MAXBURST_MAX 1 #define SCTPCTL_CWND_MAXBURST_MAX 1
#define SCTPCTL_CWND_MAXBURST_DEFAULT 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 */ /* asconf_auth_nochk: Disable SCTP ASCONF AUTH requirement */
#define SCTPCTL_ASCONF_AUTH_NOCHK_DESC "Disable SCTP ASCONF AUTH requirement" #define SCTPCTL_ASCONF_AUTH_NOCHK_DESC "Disable SCTP ASCONF AUTH requirement"
#define SCTPCTL_ASCONF_AUTH_NOCHK_MIN 0 #define SCTPCTL_ASCONF_AUTH_NOCHK_MIN 0

View File

@ -54,103 +54,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/udp.h> #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 void
sctp_audit_retranmission_queue(struct sctp_association *asoc) 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 */ /* We had a threshold failure */
if (net->dest_state & SCTP_ADDR_REACHABLE) { if (net->dest_state & SCTP_ADDR_REACHABLE) {
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; net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY;
if (net == stcb->asoc.primary_destination) { net->dest_state &= ~SCTP_ADDR_PF;
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);
}
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
stcb, stcb,
SCTP_FAILED_THRESHOLD, SCTP_FAILED_THRESHOLD,
(void *)net, SCTP_SO_NOT_LOCKED); (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) if (stcb == NULL)
return (0); 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 (max_cwnd_net == NULL) {
if (min_errors_net == NULL) { if (min_errors_net == NULL) {
return (net); 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); return (min_errors_net);
} else { } else {
return (max_cwnd_net); return (max_cwnd_net);
@ -646,15 +507,12 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
/* get cur rto in micro-seconds */ /* get cur rto in micro-seconds */
cur_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; cur_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
cur_rto *= 1000; 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, sctp_log_fr(cur_rto,
stcb->asoc.peers_rwnd, stcb->asoc.peers_rwnd,
window_probe, window_probe,
SCTP_FR_T3_MARK_TIME); SCTP_FR_T3_MARK_TIME);
sctp_log_fr(net->flight_size, sctp_log_fr(net->flight_size, 0, 0, SCTP_FR_CWND_REPORT);
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, net->cwnd, stcb->asoc.total_flight, 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; 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; 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(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); sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME);
} }
@ -717,7 +575,7 @@ start_again:
*/ */
/* validate its been outstanding long enough */ /* 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, sctp_log_fr(chk->rec.data.TSN_seq,
chk->sent_rcv_time.tv_sec, chk->sent_rcv_time.tv_sec,
chk->sent_rcv_time.tv_usec, chk->sent_rcv_time.tv_usec,
@ -729,7 +587,7 @@ start_again:
* some seconds past our min.. forget it we * some seconds past our min.. forget it we
* will find no more to send. * 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, sctp_log_fr(0,
chk->sent_rcv_time.tv_sec, chk->sent_rcv_time.tv_sec,
chk->sent_rcv_time.tv_usec, chk->sent_rcv_time.tv_usec,
@ -747,12 +605,6 @@ start_again:
* ok it was sent after our boundary * ok it was sent after our boundary
* time. * 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; continue;
} }
} }
@ -791,7 +643,7 @@ start_again:
tsnfirst = chk->rec.data.TSN_seq; tsnfirst = chk->rec.data.TSN_seq;
} }
tsnlast = 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, sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count,
0, SCTP_FR_T3_MARKED); 0, SCTP_FR_T3_MARKED);
} }
@ -860,7 +712,7 @@ start_again:
/* we did not subtract the same things? */ /* we did not subtract the same things? */
audit_tf = 1; 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); sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT);
} }
#ifdef SCTP_DEBUG #ifdef SCTP_DEBUG
@ -978,40 +830,72 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
win_probe = 0; win_probe = 0;
} }
/* if (win_probe == 0) {
* JRS 5/14/07 - If CMT PF is on and the destination if not already /* We don't do normal threshold management on window probes */
* in PF state, set the destination to PF state and store the if (sctp_threshold_management(inp, stcb, net,
* current time as the time that the destination was last active. In stcb->asoc.max_send_times)) {
* addition, find an alternate destination with PF-based /* Association was destroyed */
* find_alt_net(). return (1);
*/ } else {
if ((stcb->asoc.sctp_cmt_on_off > 0) && if (net != stcb->asoc.primary_destination) {
(stcb->asoc.sctp_cmt_pf > 0)) { /* send a immediate HB if our RTO is stale */
if ((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF) { struct timeval now;
net->dest_state |= SCTP_ADDR_PF; unsigned int ms_goneby;
net->last_active = sctp_get_tick_count();
SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from active to PF.\n", (void)SCTP_GETTIME_TIMEVAL(&now);
net); 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 {
} else if (stcb->asoc.sctp_cmt_on_off > 0) {
/* /*
* CMT: Using RTX_SSTHRESH policy for CMT. If CMT is being * For a window probe we don't penalize the net's but only
* used, then pick dest with largest ssthresh for any * the association. This may fail it if SACKs are not coming
* retransmission. * 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); if (sctp_threshold_management(inp, stcb, NULL,
/* stcb->asoc.max_send_times)) {
* CUCv2: If a different dest is picked for the /* Association was destroyed */
* retransmission, then new (rtx-)pseudo_cumack needs to be return (1);
* tracked for orig dest. Let CUCv2 track new (rtx-) }
* pseudo-cumack always. }
*/ if (stcb->asoc.sctp_cmt_on_off > 0) {
net->find_pseudo_cumack = 1; if (net->pf_threshold < net->failure_threshold) {
net->find_rtx_pseudo_cumack = 1; alt = sctp_find_alternate_net(stcb, net, 2);
} else { /* CMT is OFF */ } 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); alt = sctp_find_alternate_net(stcb, net, 0);
} }
num_mk = 0; num_mk = 0;
num_abandoned = 0; num_abandoned = 0;
(void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, (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 */ /* Backoff the timer and cwnd */
sctp_backoff_on_timeout(stcb, net, win_probe, num_mk, num_abandoned); sctp_backoff_on_timeout(stcb, net, win_probe, num_mk, num_abandoned);
if (win_probe == 0) { if ((!(net->dest_state & SCTP_ADDR_REACHABLE)) ||
/* We don't do normal threshold management on window probes */ (net->dest_state & SCTP_ADDR_PF)) {
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) {
/* Move all pending over too */ /* Move all pending over too */
sctp_move_chunks_from_net(stcb, net); 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 * change-primary then this flag must be cleared
* from any net structures. * from any net structures.
*/ */
if (sctp_set_primary_addr(stcb, if (stcb->asoc.alternate) {
(struct sockaddr *)NULL, sctp_free_remote_addr(stcb->asoc.alternate);
alt) == 0) {
net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
} }
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 * 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); 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 * If the address went un-reachable, we need to move to
* alternates for ALL chk's in queue * 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); sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
chk->sent = SCTP_DATAGRAM_RESEND; 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 * If the address went un-reachable, we need to move
* to the alternate for ALL chunks in queue * to the alternate for ALL chunks in queue
@ -1569,11 +1398,15 @@ sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp,
int int
sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 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) {
if (net->dest_state & SCTP_ADDR_PF) {
net_was_pf = 1;
}
if (net->hb_responded == 0) { if (net->hb_responded == 0) {
if (net->ro._s_addr) { 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; net->src_addr_selected = 0;
} }
sctp_backoff_on_timeout(stcb, net, 1, 0, 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 */ /* Zero PBA, if it needs it */
if (net->partial_bytes_acked) { 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))) { (TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
sctp_audit_stream_queues_for_size(inp, stcb); sctp_audit_stream_queues_for_size(inp, stcb);
} }
/* Send a new HB, this will do threshold managment, pick a new dest */ if (!(net->dest_state & SCTP_ADDR_NOHB) &&
if (cnt_of_unconf == 0) { !((net_was_pf == 0) && (net->dest_state & SCTP_ADDR_PF))) {
if (sctp_send_hb(stcb, 0, NULL, SCTP_SO_NOT_LOCKED) < 0) {
return (1);
}
} else {
/* /*
* this will send out extra hb's up to maxburst if there are * when move to PF during threshold mangement, a HB has been
* any unconfirmed addresses. * queued in that routine
*/ */
uint32_t cnt_sent = 0; sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
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;
}
}
} }
return (0); return (0);
} }
@ -1733,7 +1542,14 @@ sctp_autoclose_timer(struct sctp_inpcb *inp,
*/ */
if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
/* only send SHUTDOWN 1st time thru */ /* 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) || if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab); 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_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb, stcb->sctp_ep, stcb,
asoc->primary_destination); netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, stcb->sctp_ep, stcb,
asoc->primary_destination); netp);
} }
} }
} else { } else {

View File

@ -42,10 +42,6 @@ __FBSDID("$FreeBSD$");
#define SCTP_RTT_SHIFT 3 #define SCTP_RTT_SHIFT 3
#define SCTP_RTT_VAR_SHIFT 2 #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 * struct sctp_nets *
sctp_find_alternate_net(struct sctp_tcb *, sctp_find_alternate_net(struct sctp_tcb *,
struct sctp_nets *, int mode); struct sctp_nets *, int mode);
@ -65,7 +61,7 @@ sctp_shutdown_timer(struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *); struct sctp_nets *);
int int
sctp_heartbeat_timer(struct sctp_inpcb *, struct sctp_tcb *, sctp_heartbeat_timer(struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *, int); struct sctp_nets *);
int int
sctp_cookie_timer(struct sctp_inpcb *, struct sctp_tcb *, 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_ADDR_CONFIRMED 0x0006
#define SCTP_ACTIVE 0x0001 /* SCTP_ADDR_REACHABLE */ #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 */ #define SCTP_UNCONFIRMED 0x0200 /* SCTP_ADDR_UNCONFIRMED */
/* remote error events */ /* remote error events */
@ -516,6 +517,13 @@ struct sctp_paddrparams {
#define SPP_IPV6_FLOWLABEL 0x00000100 #define SPP_IPV6_FLOWLABEL 0x00000100
#define SPP_IPV4_TOS 0x00000200 #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 sctp_paddrinfo {
struct sockaddr_storage spinfo_address; struct sockaddr_storage spinfo_address;
sctp_assoc_t spinfo_assoc_id; sctp_assoc_t spinfo_assoc_id;
@ -978,18 +986,8 @@ struct sctpstat {
* fired */ * fired */
uint32_t sctps_timoassockill; /* Number of asoc free timers expired */ uint32_t sctps_timoassockill; /* Number of asoc free timers expired */
uint32_t sctps_timoinpkill; /* Number of inp free timers expired */ uint32_t sctps_timoinpkill; /* Number of inp free timers expired */
/* Early fast retransmission counters */ /* former early FR counters */
uint32_t sctps_earlyfrstart; uint32_t sctps_spare[11];
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;
/* others */ /* others */
uint32_t sctps_hdrops; /* packet shorter than header */ uint32_t sctps_hdrops; /* packet shorter than header */
uint32_t sctps_badsum; /* checksum error */ uint32_t sctps_badsum; /* checksum error */
@ -1162,9 +1160,11 @@ struct xsctp_raddr {
uint8_t active; /* sctpAssocLocalRemEntry 3 */ uint8_t active; /* sctpAssocLocalRemEntry 3 */
uint8_t confirmed; /* */ uint8_t confirmed; /* */
uint8_t heartbeat_enabled; /* sctpAssocLocalRemEntry 4 */ uint8_t heartbeat_enabled; /* sctpAssocLocalRemEntry 4 */
uint8_t potentially_failed;
struct sctp_timeval start_time; /* sctpAssocLocalRemEntry 8 */ struct sctp_timeval start_time; /* sctpAssocLocalRemEntry 8 */
uint32_t rtt; 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 #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) { if (net->dest_state & SCTP_ADDR_REACHABLE) {
/* Ok that destination is NOT 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_REACHABLE;
net->dest_state |= SCTP_ADDR_NOT_REACHABLE; net->dest_state &= ~SCTP_ADDR_PF;
/*
* 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;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
stcb, SCTP_FAILED_THRESHOLD, stcb, SCTP_FAILED_THRESHOLD,
(void *)net, SCTP_SO_NOT_LOCKED); (void *)net, SCTP_SO_NOT_LOCKED);
@ -837,9 +812,15 @@ sctp_disconnect(struct socket *so)
if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
/* only send SHUTDOWN 1st time thru */ /* 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_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb, sctp_send_shutdown(stcb, netp);
stcb->asoc.primary_destination);
sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { (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_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb, stcb->sctp_ep, stcb, netp);
asoc->primary_destination);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, stcb->sctp_ep, stcb, netp);
asoc->primary_destination);
} }
} else { } else {
/* /*
@ -865,9 +845,17 @@ sctp_disconnect(struct socket *so)
* we will allow user data to be sent first * we will allow user data to be sent first
* and move to SHUTDOWN-PENDING * 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; asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
asoc->primary_destination); netp);
if (asoc->locked_on_sending) { if (asoc->locked_on_sending) {
/* Locked to send out the data */ /* Locked to send out the data */
struct sctp_stream_queue_pending *sp; 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... */ /* there is nothing queued to send, so I'm done... */
if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
/* only send SHUTDOWN the first time through */ /* 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_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb, sctp_send_shutdown(stcb, netp);
stcb->asoc.primary_destination);
sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { (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_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb, stcb->sctp_ep, stcb, netp);
asoc->primary_destination);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, stcb->sctp_ep, stcb, netp);
asoc->primary_destination);
} }
} else { } else {
/* /*
* we still got (or just got) data to send, so set * we still got (or just got) data to send, so set
* SHUTDOWN_PENDING * 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; asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
asoc->primary_destination); netp);
if (asoc->locked_on_sending) { if (asoc->locked_on_sending) {
/* Locked to send out the data */ /* Locked to send out the data */
@ -2389,7 +2389,7 @@ flags_out:
} }
} }
if (stcb) { if (stcb) {
/* Applys to the specific association */ /* Applies to the specific association */
paddrp->spp_flags = 0; paddrp->spp_flags = 0;
if (net) { if (net) {
int ovh; int ovh;
@ -2400,7 +2400,7 @@ flags_out:
ovh = SCTP_MED_V4_OVERHEAD; ovh = SCTP_MED_V4_OVERHEAD;
} }
paddrp->spp_hbinterval = net->heart_beat_delay;
paddrp->spp_pathmaxrxt = net->failure_threshold; paddrp->spp_pathmaxrxt = net->failure_threshold;
paddrp->spp_pathmtu = net->mtu - ovh; paddrp->spp_pathmtu = net->mtu - ovh;
/* get flags for HB */ /* get flags for HB */
@ -2444,11 +2444,12 @@ flags_out:
paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
#endif #endif
/* default settings should be these */ /* default settings should be these */
if (stcb->asoc.hb_is_disabled == 0) { if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
paddrp->spp_flags |= SPP_HB_ENABLE;
} else {
paddrp->spp_flags |= SPP_HB_DISABLE; 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) { TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
cnt++; cnt++;
@ -2458,7 +2459,6 @@ flags_out:
paddrp->spp_flags |= SPP_PMTUD_ENABLE; paddrp->spp_flags |= SPP_PMTUD_ENABLE;
} }
} }
paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
paddrp->spp_assoc_id = sctp_get_associd(stcb); paddrp->spp_assoc_id = sctp_get_associd(stcb);
SCTP_TCB_UNLOCK(stcb); SCTP_TCB_UNLOCK(stcb);
} else { } else {
@ -3080,6 +3080,95 @@ flags_out:
} }
break; 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: default:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = 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) { if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
/* only valid for bound all sockets */ /* 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; set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
} else { } else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 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; break;
} }
case SCTP_PEER_ADDR_PARAMS: case SCTP_PEER_ADDR_PARAMS:
/* Applys to the specific association */ /* Applies to the specific association */
{ {
struct sctp_paddrparams *paddrp; struct sctp_paddrparams *paddrp;
struct sctp_nets *net; 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; 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 ? */ /* network sets ? */
if (net) { if (net) {
/************************NET SPECIFIC SET ******************/ /************************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 (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; net->dest_state |= SCTP_ADDR_NOHB;
} }
if (paddrp->spp_flags & SPP_HB_ENABLE) { 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; 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 ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 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); 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; net->failure_threshold = paddrp->spp_pathmaxrxt;
}
#ifdef INET #ifdef INET
if (paddrp->spp_flags & SPP_IPV4_TOS) { if (paddrp->spp_flags & SPP_IPV4_TOS) {
if (net->ro._l_addr.sin.sin_family == AF_INET) { 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 #endif
} else { } else {
/************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/ /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/
if (paddrp->spp_pathmaxrxt) if (paddrp->spp_pathmaxrxt) {
stcb->asoc.def_net_failure = 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_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 */ /* Turn back on the timer */
stcb->asoc.hb_is_disabled = 0; TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 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)) { if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 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 #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; stcb->asoc.default_tos = paddrp->spp_ipv4_tos & 0x000000fc;
}
#endif #endif
#ifdef INET6 #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; stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel;
}
#endif #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); 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_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); sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
} else if (paddrp->spp_flags & SPP_HB_DISABLE) { } else if (paddrp->spp_flags & SPP_HB_DISABLE) {
sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 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))) { (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
/* Ok we need to set it */ /* Ok we need to set it */
if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) { if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) { if ((stcb->asoc.alternate) &&
net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH; (!(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 { } else {
@ -4930,7 +5098,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = EINVAL; error = EINVAL;
break; 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_IPV6_V6ONLY(inp) != 0))) != 0) {
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
break; break;
@ -5170,6 +5340,146 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
} }
break; 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: default:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = ENOPROTOOPT; error = ENOPROTOOPT;

View File

@ -179,7 +179,6 @@ extern struct pr_usrreqs sctp_usrreqs;
if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&(__net)->ref_count)) { \ if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&(__net)->ref_count)) { \
(void)SCTP_OS_TIMER_STOP(&(__net)->rxt_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)->pmtu_timer.timer); \
(void)SCTP_OS_TIMER_STOP(&(__net)->fr_timer.timer); \
if ((__net)->ro.ro_rt) { \ if ((__net)->ro.ro_rt) { \
RTFREE((__net)->ro.ro_rt); \ RTFREE((__net)->ro.ro_rt); \
(__net)->ro.ro_rt = NULL; \ (__net)->ro.ro_rt = NULL; \
@ -189,7 +188,7 @@ extern struct pr_usrreqs sctp_usrreqs;
(__net)->ro._s_addr = NULL; \ (__net)->ro._s_addr = NULL; \
} \ } \
(__net)->src_addr_selected = 0; \ (__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_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_net), (__net)); \
SCTP_DECR_RADDR_COUNT(); \ SCTP_DECR_RADDR_COUNT(); \
} \ } \
@ -312,6 +311,8 @@ extern struct pr_usrreqs sctp_usrreqs;
#endif #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_nets;
struct sctp_inpcb; struct sctp_inpcb;

View File

@ -739,15 +739,14 @@ sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb)
asoc = &stcb->asoc; 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->dack_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->strreset_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->asconf_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer);
TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 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->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->sctp_cmt_on_off = m->sctp_cmt_on_off;
asoc->ecn_allowed = m->sctp_ecn_enable; 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_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_frag_point = m->sctp_frag_point;
asoc->sctp_features = m->sctp_features; asoc->sctp_features = m->sctp_features;
#ifdef INET #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->peer_vtag_nonce = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
asoc->vrf_id = vrf_id; 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 #ifdef SCTP_ASOCLOG_OF_TSNS
asoc->tsn_in_at = 0; asoc->tsn_in_at = 0;
asoc->tsn_out_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_init_times = m->sctp_ep.max_init_times;
asoc->max_send_times = m->sctp_ep.max_send_times; asoc->max_send_times = m->sctp_ep.max_send_times;
asoc->def_net_failure = m->sctp_ep.def_net_failure; 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->free_chunk_cnt = 0;
asoc->iam_blocking = 0; asoc->iam_blocking = 0;
@ -1632,11 +1627,10 @@ sctp_timeout_handler(void *t)
case SCTP_TIMER_TYPE_RECV: case SCTP_TIMER_TYPE_RECV:
if ((stcb == NULL) || (inp == NULL)) { if ((stcb == NULL) || (inp == NULL)) {
break; 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 #ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net); sctp_auditing(4, inp, stcb, net);
#endif #endif
@ -1658,33 +1652,20 @@ sctp_timeout_handler(void *t)
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED); sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED);
break; break;
case SCTP_TIMER_TYPE_HEARTBEAT: case SCTP_TIMER_TYPE_HEARTBEAT:
{ if ((stcb == NULL) || (inp == NULL) || (net == NULL)) {
struct sctp_nets *lnet; break;
int cnt_of_unconf = 0; }
SCTP_STAT_INCR(sctps_timoheartbeat);
if ((stcb == NULL) || (inp == NULL)) { stcb->asoc.timoheartbeat++;
break; if (sctp_heartbeat_timer(inp, stcb, net)) {
} /* no need to unlock on tcb its gone */
SCTP_STAT_INCR(sctps_timoheartbeat); goto out_decr;
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;
}
}
#ifdef SCTP_AUDITING_ENABLED #ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, lnet); sctp_auditing(4, inp, stcb, net);
#endif #endif
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, if (!(net->dest_state & SCTP_ADDR_NOHB)) {
stcb->sctp_ep, stcb, lnet); 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); sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED);
} }
break; break;
@ -1780,14 +1761,6 @@ sctp_timeout_handler(void *t)
SCTP_STAT_INCR(sctps_timostrmrst); SCTP_STAT_INCR(sctps_timostrmrst);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED); sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED);
break; 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: case SCTP_TIMER_TYPE_ASCONF:
if ((stcb == NULL) || (inp == NULL)) { if ((stcb == NULL) || (inp == NULL)) {
break; break;
@ -1898,7 +1871,7 @@ void
sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct sctp_nets *net) struct sctp_nets *net)
{ {
int to_ticks; uint32_t to_ticks;
struct sctp_timer *tmr; struct sctp_timer *tmr;
if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL)) 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 * though we use a different timer. We also add the HB timer
* PLUS a random jitter. * PLUS a random jitter.
*/ */
if ((inp == NULL) || (stcb == NULL)) { if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
return; return;
} else { } else {
uint32_t rndval; uint32_t rndval;
uint8_t this_random; uint32_t jitter;
int cnt_of_unconf = 0;
struct sctp_nets *lnet;
TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { if ((net->dest_state & SCTP_ADDR_NOHB) &&
if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) && !(net->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)) {
return; return;
} }
if (net) { if (net->RTO == 0) {
int delay; to_ticks = stcb->asoc.initial_rto;
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;
}
} else { } else {
if (cnt_of_unconf) { to_ticks = net->RTO;
to_ticks = this_random + stcb->asoc.initial_rto; }
} else { rndval = sctp_select_initial_TSN(&inp->sctp_ep);
to_ticks = stcb->asoc.heart_beat_delay + this_random + stcb->asoc.initial_rto; 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 * Now we must convert the to_ticks that are now in
* ms to ticks. * ms to ticks.
*/ */
to_ticks = MSEC_TO_TICKS(to_ticks); to_ticks = MSEC_TO_TICKS(to_ticks);
tmr = &stcb->asoc.hb_timer; tmr = &net->hb_timer;
} }
break; break;
case SCTP_TIMER_TYPE_COOKIE: 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; tmr = &stcb->asoc.strreset_timer;
break; 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: case SCTP_TIMER_TYPE_ASCONF:
/* /*
* Here the timer comes from the stcb but its value is from * 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: case SCTP_TIMER_TYPE_ADDR_WQ:
tmr = &SCTP_BASE_INFO(addr_wq_timer); tmr = &SCTP_BASE_INFO(addr_wq_timer);
break; 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: case SCTP_TIMER_TYPE_SEND:
if ((stcb == NULL) || (net == NULL)) { if ((stcb == NULL) || (net == NULL)) {
return; return;
@ -2305,10 +2209,10 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
tmr = &net->rxt_timer; tmr = &net->rxt_timer;
break; break;
case SCTP_TIMER_TYPE_HEARTBEAT: case SCTP_TIMER_TYPE_HEARTBEAT:
if (stcb == NULL) { if ((stcb == NULL) || (net == NULL)) {
return; return;
} }
tmr = &stcb->asoc.hb_timer; tmr = &net->hb_timer;
break; break;
case SCTP_TIMER_TYPE_COOKIE: case SCTP_TIMER_TYPE_COOKIE:
if ((stcb == NULL) || (net == NULL)) { if ((stcb == NULL) || (net == NULL)) {
@ -6209,7 +6113,7 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
#ifdef INET #ifdef INET
case AF_INET: case AF_INET:
incr = sizeof(struct sockaddr_in); 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 */ /* assoc gone no un-lock */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 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); (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 #ifdef INET6
case AF_INET6: case AF_INET6:
incr = sizeof(struct sockaddr_in6); 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 */ /* assoc gone no un-lock */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 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); (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) { if (net->dest_state & SCTP_ADDR_REACHABLE) {
/* Ok that destination is NOT 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_REACHABLE;
net->dest_state |= SCTP_ADDR_NOT_REACHABLE; net->dest_state &= ~SCTP_ADDR_PF;
/*
* 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;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
stcb, SCTP_FAILED_THRESHOLD, stcb, SCTP_FAILED_THRESHOLD,
(void *)net, SCTP_SO_NOT_LOCKED); (void *)net, SCTP_SO_NOT_LOCKED);