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:
parent
f36e5acfc1
commit
ca85e9482a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=224641
@ -410,6 +410,9 @@ sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size)
|
||||
case SCTP_DEFAULT_PRINFO:
|
||||
((struct sctp_default_prinfo *)arg)->pr_assoc_id = id;
|
||||
break;
|
||||
case SCTP_PEER_ADDR_THLDS:
|
||||
((struct sctp_paddrthlds *)arg)->spt_assoc_id = id;
|
||||
break;
|
||||
case SCTP_MAX_BURST:
|
||||
((struct sctp_assoc_value *)arg)->assoc_id = id;
|
||||
break;
|
||||
|
@ -119,6 +119,7 @@ struct sctp_paramhdr {
|
||||
#define SCTP_RECVNXTINFO 0x00000020
|
||||
#define SCTP_DEFAULT_SNDINFO 0x00000021
|
||||
#define SCTP_DEFAULT_PRINFO 0x00000022
|
||||
#define SCTP_PEER_ADDR_THLDS 0x00000023
|
||||
|
||||
/*
|
||||
* read-only options
|
||||
@ -564,7 +565,6 @@ struct sctp_error_unrecognized_chunk {
|
||||
#define SCTP_BLK_LOGGING_ENABLE 0x00000001
|
||||
#define SCTP_CWND_MONITOR_ENABLE 0x00000002
|
||||
#define SCTP_CWND_LOGGING_ENABLE 0x00000004
|
||||
#define SCTP_EARLYFR_LOGGING_ENABLE 0x00000010
|
||||
#define SCTP_FLIGHT_LOGGING_ENABLE 0x00000020
|
||||
#define SCTP_FR_LOGGING_ENABLE 0x00000040
|
||||
#define SCTP_LOCK_LOGGING_ENABLE 0x00000080
|
||||
@ -572,23 +572,23 @@ struct sctp_error_unrecognized_chunk {
|
||||
#define SCTP_MBCNT_LOGGING_ENABLE 0x00000200
|
||||
#define SCTP_MBUF_LOGGING_ENABLE 0x00000400
|
||||
#define SCTP_NAGLE_LOGGING_ENABLE 0x00000800
|
||||
#define SCTP_RECV_RWND_LOGGING_ENABLE 0x00001000
|
||||
#define SCTP_RECV_RWND_LOGGING_ENABLE 0x00001000
|
||||
#define SCTP_RTTVAR_LOGGING_ENABLE 0x00002000
|
||||
#define SCTP_SACK_LOGGING_ENABLE 0x00004000
|
||||
#define SCTP_SACK_RWND_LOGGING_ENABLE 0x00008000
|
||||
#define SCTP_SACK_RWND_LOGGING_ENABLE 0x00008000
|
||||
#define SCTP_SB_LOGGING_ENABLE 0x00010000
|
||||
#define SCTP_STR_LOGGING_ENABLE 0x00020000
|
||||
#define SCTP_WAKE_LOGGING_ENABLE 0x00040000
|
||||
#define SCTP_LOG_MAXBURST_ENABLE 0x00080000
|
||||
#define SCTP_LOG_RWND_ENABLE 0x00100000
|
||||
#define SCTP_LOG_SACK_ARRIVALS_ENABLE 0x00200000
|
||||
#define SCTP_LTRACE_CHUNK_ENABLE 0x00400000
|
||||
#define SCTP_LTRACE_ERROR_ENABLE 0x00800000
|
||||
#define SCTP_LAST_PACKET_TRACING 0x01000000
|
||||
#define SCTP_THRESHOLD_LOGGING 0x02000000
|
||||
#define SCTP_LOG_AT_SEND_2_SCTP 0x04000000
|
||||
#define SCTP_LOG_AT_SEND_2_OUTQ 0x08000000
|
||||
#define SCTP_LOG_TRY_ADVANCE 0x10000000
|
||||
#define SCTP_LOG_SACK_ARRIVALS_ENABLE 0x00200000
|
||||
#define SCTP_LTRACE_CHUNK_ENABLE 0x00400000
|
||||
#define SCTP_LTRACE_ERROR_ENABLE 0x00800000
|
||||
#define SCTP_LAST_PACKET_TRACING 0x01000000
|
||||
#define SCTP_THRESHOLD_LOGGING 0x02000000
|
||||
#define SCTP_LOG_AT_SEND_2_SCTP 0x04000000
|
||||
#define SCTP_LOG_AT_SEND_2_OUTQ 0x08000000
|
||||
#define SCTP_LOG_TRY_ADVANCE 0x10000000
|
||||
|
||||
|
||||
#undef SCTP_PACKED
|
||||
|
@ -198,8 +198,9 @@ sctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t * error_tlv,
|
||||
|
||||
static struct mbuf *
|
||||
sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
|
||||
struct sctp_tcb *stcb, int response_required)
|
||||
struct sctp_tcb *stcb, int send_hb, int response_required)
|
||||
{
|
||||
struct sctp_nets *net;
|
||||
struct mbuf *m_reply = NULL;
|
||||
struct sockaddr_storage sa_source, sa_store;
|
||||
struct sctp_paramhdr *ph;
|
||||
@ -284,7 +285,7 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
|
||||
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
|
||||
}
|
||||
/* add the address */
|
||||
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE,
|
||||
if (sctp_add_remote_addr(stcb, sa, &net, SCTP_DONOT_SETSCOPE,
|
||||
SCTP_ADDR_DYNAMIC_ADDED) != 0) {
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
||||
"process_asconf_add_ip: error adding address\n");
|
||||
@ -298,10 +299,12 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
|
||||
m_reply =
|
||||
sctp_asconf_success_response(aph->correlation_id);
|
||||
}
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb,
|
||||
NULL, SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep,
|
||||
stcb, NULL);
|
||||
stcb, net);
|
||||
if (send_hb) {
|
||||
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
}
|
||||
return m_reply;
|
||||
}
|
||||
@ -554,7 +557,12 @@ sctp_process_asconf_set_primary(struct mbuf *m,
|
||||
"process_asconf_set_primary: primary address set\n");
|
||||
/* notify upper layer */
|
||||
sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
|
||||
|
||||
if ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_REACHABLE) &&
|
||||
(!(stcb->asoc.primary_destination->dest_state & SCTP_ADDR_PF)) &&
|
||||
(stcb->asoc.alternate)) {
|
||||
sctp_free_remote_addr(stcb->asoc.alternate);
|
||||
stcb->asoc.alternate = NULL;
|
||||
}
|
||||
if (response_required) {
|
||||
m_reply = sctp_asconf_success_response(aph->correlation_id);
|
||||
}
|
||||
@ -622,7 +630,7 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
|
||||
struct sctp_asconf_ack_chunk *ack_cp;
|
||||
struct sctp_asconf_paramhdr *aph, *ack_aph;
|
||||
struct sctp_ipv6addr_param *p_addr;
|
||||
unsigned int asconf_limit;
|
||||
unsigned int asconf_limit, cnt;
|
||||
int error = 0; /* did an error occur? */
|
||||
|
||||
/* asconf param buffer */
|
||||
@ -717,6 +725,7 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
|
||||
goto send_reply;
|
||||
}
|
||||
/* process through all parameters */
|
||||
cnt = 0;
|
||||
while (aph != NULL) {
|
||||
unsigned int param_length, param_type;
|
||||
|
||||
@ -749,7 +758,8 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
|
||||
case SCTP_ADD_IP_ADDRESS:
|
||||
asoc->peer_supports_asconf = 1;
|
||||
m_result = sctp_process_asconf_add_ip(m, aph, stcb,
|
||||
error);
|
||||
(cnt < SCTP_BASE_SYSCTL(sctp_hb_maxburst)), error);
|
||||
cnt++;
|
||||
break;
|
||||
case SCTP_DEL_IP_ADDRESS:
|
||||
asoc->peer_supports_asconf = 1;
|
||||
@ -1959,7 +1969,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
int status;
|
||||
|
||||
|
||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 &&
|
||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 ||
|
||||
sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
|
||||
/* subset bound, no ASCONF allowed case, so ignore */
|
||||
return;
|
||||
@ -2075,8 +2085,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
|
||||
stcb, stcb->asoc.primary_destination);
|
||||
#else
|
||||
sctp_send_asconf(stcb, stcb->asoc.primary_destination,
|
||||
addr_locked);
|
||||
sctp_send_asconf(stcb, NULL, addr_locked);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -2328,8 +2337,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
* If we have queued params in the open state, send out an ASCONF.
|
||||
*/
|
||||
if (num_queued > 0) {
|
||||
sctp_send_asconf(stcb, stcb->asoc.primary_destination,
|
||||
SCTP_ADDR_NOT_LOCKED);
|
||||
sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2384,8 +2392,7 @@ sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
|
||||
stcb->sctp_ep, stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
#else
|
||||
sctp_send_asconf(stcb, stcb->asoc.primary_destination,
|
||||
SCTP_ADDR_NOT_LOCKED);
|
||||
sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
@ -2421,8 +2428,7 @@ sctp_set_primary_ip_address(struct sctp_ifa *ifa)
|
||||
stcb->sctp_ep, stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
#else
|
||||
sctp_send_asconf(stcb, stcb->asoc.primary_destination,
|
||||
SCTP_ADDR_NOT_LOCKED);
|
||||
sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -2965,8 +2971,7 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
|
||||
stcb->sctp_ep, stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
#else
|
||||
sctp_send_asconf(stcb, stcb->asoc.primary_destination,
|
||||
SCTP_ADDR_NOT_LOCKED);
|
||||
sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -3540,5 +3545,5 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
|
||||
}
|
||||
skip_rest:
|
||||
/* Now we must send the asconf into the queue */
|
||||
sctp_send_asconf(stcb, net, 0);
|
||||
sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED);
|
||||
}
|
||||
|
@ -728,40 +728,6 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
|
||||
/*
|
||||
* So, first of all do we need to have a Early FR
|
||||
* timer running?
|
||||
*/
|
||||
if ((!TAILQ_EMPTY(&asoc->sent_queue) &&
|
||||
(net->ref_count > 1) &&
|
||||
(net->flight_size < net->cwnd)) ||
|
||||
(reneged_all)) {
|
||||
/*
|
||||
* yes, so in this case stop it if its
|
||||
* running, and then restart it. Reneging
|
||||
* all is a special case where we want to
|
||||
* run the Early FR timer and then force the
|
||||
* last few unacked to be sent, causing us
|
||||
* to illicit a sack with gaps to force out
|
||||
* the others.
|
||||
*/
|
||||
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
|
||||
SCTP_STAT_INCR(sctps_earlyfrstpidsck2);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
|
||||
SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_earlyfrstrid);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
|
||||
} else {
|
||||
/* No, stop it if its running */
|
||||
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
|
||||
SCTP_STAT_INCR(sctps_earlyfrstpidsck3);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
|
||||
SCTP_FROM_SCTP_INDATA + SCTP_LOC_21);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* if nothing was acked on this destination skip it */
|
||||
if (net->net_ack == 0) {
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
|
||||
@ -769,51 +735,6 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (net->net_ack2 > 0) {
|
||||
/*
|
||||
* Karn's rule applies to clearing error count, this
|
||||
* is optional.
|
||||
*/
|
||||
net->error_count = 0;
|
||||
if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
|
||||
SCTP_ADDR_NOT_REACHABLE) {
|
||||
/* addr came good */
|
||||
net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
|
||||
net->dest_state |= SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
|
||||
SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
|
||||
/* now was it the primary? if so restore */
|
||||
if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
|
||||
(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* JRS 5/14/07 - If CMT PF is on and the destination
|
||||
* is in PF state, set the destination to active
|
||||
* state and set the cwnd to one or two MTU's based
|
||||
* on whether PF1 or PF2 is being used.
|
||||
*
|
||||
* Should we stop any running T3 timer here?
|
||||
*/
|
||||
if ((asoc->sctp_cmt_on_off > 0) &&
|
||||
(asoc->sctp_cmt_pf > 0) &&
|
||||
((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
old_cwnd = net->cwnd;
|
||||
net->cwnd = net->mtu * asoc->sctp_cmt_pf;
|
||||
SDT_PROBE(sctp, cwnd, net, ack,
|
||||
stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
|
||||
old_cwnd, net->cwnd);
|
||||
SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
|
||||
net, net->cwnd);
|
||||
/*
|
||||
* Since the cwnd value is explicitly set,
|
||||
* skip the code that updates the cwnd
|
||||
* value.
|
||||
*/
|
||||
goto skip_cwnd_update;
|
||||
}
|
||||
}
|
||||
#ifdef JANA_CMT_FAST_RECOVERY
|
||||
/*
|
||||
* CMT fast recovery code
|
||||
@ -833,7 +754,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
|
||||
* If we are in loss recovery we skip any cwnd
|
||||
* update
|
||||
*/
|
||||
goto skip_cwnd_update;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Did any measurements go on for this network?
|
||||
@ -856,7 +777,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
|
||||
if (net->cc_mod.rtcc.lbw) {
|
||||
if (cc_bw_limit(stcb, net, nbw)) {
|
||||
/* Hold here, no update */
|
||||
goto skip_cwnd_update;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
uint64_t vtag, probepoint;
|
||||
@ -1049,26 +970,24 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
|
||||
SCTP_CWND_LOG_NO_CUMACK);
|
||||
}
|
||||
}
|
||||
skip_cwnd_update:
|
||||
/*
|
||||
* NOW, according to Karn's rule do we need to restore the
|
||||
* RTO timer back? Check our net_ack2. If not set then we
|
||||
* have a ambiguity.. i.e. all data ack'd was sent to more
|
||||
* than one place.
|
||||
*/
|
||||
if (net->net_ack2) {
|
||||
/* restore any doubled timers */
|
||||
net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
|
||||
if (net->RTO < stcb->asoc.minrto) {
|
||||
net->RTO = stcb->asoc.minrto;
|
||||
}
|
||||
if (net->RTO > stcb->asoc.maxrto) {
|
||||
net->RTO = stcb->asoc.maxrto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
{
|
||||
int old_cwnd;
|
||||
|
||||
old_cwnd = net->cwnd;
|
||||
net->cwnd = net->mtu;
|
||||
SDT_PROBE(sctp, cwnd, net, ack,
|
||||
stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
|
||||
old_cwnd, net->cwnd);
|
||||
SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
|
||||
net, net->cwnd);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
{
|
||||
@ -1343,32 +1262,6 @@ sctp_cwnd_update_after_output(struct sctp_tcb *stcb,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp,
|
||||
struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
{
|
||||
int old_cwnd = net->cwnd;
|
||||
|
||||
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
|
||||
/*
|
||||
* make a small adjustment to cwnd and force to CA.
|
||||
*/
|
||||
if (net->cwnd > net->mtu)
|
||||
/* drop down one MTU after sending */
|
||||
net->cwnd -= net->mtu;
|
||||
if (net->cwnd < net->ssthresh)
|
||||
/* still in SS move to CA */
|
||||
net->ssthresh = net->cwnd - 1;
|
||||
SDT_PROBE(sctp, cwnd, net, fr,
|
||||
stcb->asoc.my_vtag,
|
||||
((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
|
||||
net,
|
||||
old_cwnd, net->cwnd);
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
|
||||
struct sctp_association *asoc,
|
||||
@ -1858,40 +1751,6 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
|
||||
/*
|
||||
* So, first of all do we need to have a Early FR
|
||||
* timer running?
|
||||
*/
|
||||
if ((!TAILQ_EMPTY(&asoc->sent_queue) &&
|
||||
(net->ref_count > 1) &&
|
||||
(net->flight_size < net->cwnd)) ||
|
||||
(reneged_all)) {
|
||||
/*
|
||||
* yes, so in this case stop it if its
|
||||
* running, and then restart it. Reneging
|
||||
* all is a special case where we want to
|
||||
* run the Early FR timer and then force the
|
||||
* last few unacked to be sent, causing us
|
||||
* to illicit a sack with gaps to force out
|
||||
* the others.
|
||||
*/
|
||||
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
|
||||
SCTP_STAT_INCR(sctps_earlyfrstpidsck2);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
|
||||
SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_earlyfrstrid);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
|
||||
} else {
|
||||
/* No, stop it if its running */
|
||||
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
|
||||
SCTP_STAT_INCR(sctps_earlyfrstpidsck3);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
|
||||
SCTP_FROM_SCTP_INDATA + SCTP_LOC_21);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* if nothing was acked on this destination skip it */
|
||||
if (net->net_ack == 0) {
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
|
||||
@ -1899,47 +1758,6 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (net->net_ack2 > 0) {
|
||||
/*
|
||||
* Karn's rule applies to clearing error count, this
|
||||
* is optional.
|
||||
*/
|
||||
net->error_count = 0;
|
||||
if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
|
||||
SCTP_ADDR_NOT_REACHABLE) {
|
||||
/* addr came good */
|
||||
net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
|
||||
net->dest_state |= SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
|
||||
SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
|
||||
/* now was it the primary? if so restore */
|
||||
if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
|
||||
(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* JRS 5/14/07 - If CMT PF is on and the destination
|
||||
* is in PF state, set the destination to active
|
||||
* state and set the cwnd to one or two MTU's based
|
||||
* on whether PF1 or PF2 is being used.
|
||||
*
|
||||
* Should we stop any running T3 timer here?
|
||||
*/
|
||||
if ((asoc->sctp_cmt_on_off > 0) &&
|
||||
(asoc->sctp_cmt_pf > 0) &&
|
||||
((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
net->cwnd = net->mtu * asoc->sctp_cmt_pf;
|
||||
SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
|
||||
net, net->cwnd);
|
||||
/*
|
||||
* Since the cwnd value is explicitly set,
|
||||
* skip the code that updates the cwnd
|
||||
* value.
|
||||
*/
|
||||
goto skip_cwnd_update;
|
||||
}
|
||||
}
|
||||
#ifdef JANA_CMT_FAST_RECOVERY
|
||||
/*
|
||||
* CMT fast recovery code
|
||||
@ -1959,7 +1777,7 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
|
||||
* If we are in loss recovery we skip any cwnd
|
||||
* update
|
||||
*/
|
||||
goto skip_cwnd_update;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* CMT: CUC algorithm. Update cwnd if pseudo-cumack has
|
||||
@ -2004,23 +1822,6 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
|
||||
SCTP_CWND_LOG_NO_CUMACK);
|
||||
}
|
||||
}
|
||||
skip_cwnd_update:
|
||||
/*
|
||||
* NOW, according to Karn's rule do we need to restore the
|
||||
* RTO timer back? Check our net_ack2. If not set then we
|
||||
* have a ambiguity.. i.e. all data ack'd was sent to more
|
||||
* than one place.
|
||||
*/
|
||||
if (net->net_ack2) {
|
||||
/* restore any doubled timers */
|
||||
net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
|
||||
if (net->RTO < stcb->asoc.minrto) {
|
||||
net->RTO = stcb->asoc.minrto;
|
||||
}
|
||||
if (net->RTO > stcb->asoc.maxrto) {
|
||||
net->RTO = stcb->asoc.maxrto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2340,40 +2141,6 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
|
||||
/*
|
||||
* So, first of all do we need to have a Early FR
|
||||
* timer running?
|
||||
*/
|
||||
if ((!TAILQ_EMPTY(&asoc->sent_queue) &&
|
||||
(net->ref_count > 1) &&
|
||||
(net->flight_size < net->cwnd)) ||
|
||||
(reneged_all)) {
|
||||
/*
|
||||
* yes, so in this case stop it if its
|
||||
* running, and then restart it. Reneging
|
||||
* all is a special case where we want to
|
||||
* run the Early FR timer and then force the
|
||||
* last few unacked to be sent, causing us
|
||||
* to illicit a sack with gaps to force out
|
||||
* the others.
|
||||
*/
|
||||
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
|
||||
SCTP_STAT_INCR(sctps_earlyfrstpidsck2);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
|
||||
SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_earlyfrstrid);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
|
||||
} else {
|
||||
/* No, stop it if its running */
|
||||
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
|
||||
SCTP_STAT_INCR(sctps_earlyfrstpidsck3);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
|
||||
SCTP_FROM_SCTP_INDATA + SCTP_LOC_21);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* if nothing was acked on this destination skip it */
|
||||
if (net->net_ack == 0) {
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
|
||||
@ -2381,47 +2148,6 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (net->net_ack2 > 0) {
|
||||
/*
|
||||
* Karn's rule applies to clearing error count, this
|
||||
* is optional.
|
||||
*/
|
||||
net->error_count = 0;
|
||||
if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
|
||||
SCTP_ADDR_NOT_REACHABLE) {
|
||||
/* addr came good */
|
||||
net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
|
||||
net->dest_state |= SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
|
||||
SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
|
||||
/* now was it the primary? if so restore */
|
||||
if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
|
||||
(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* JRS 5/14/07 - If CMT PF is on and the destination
|
||||
* is in PF state, set the destination to active
|
||||
* state and set the cwnd to one or two MTU's based
|
||||
* on whether PF1 or PF2 is being used.
|
||||
*
|
||||
* Should we stop any running T3 timer here?
|
||||
*/
|
||||
if ((asoc->sctp_cmt_on_off > 0) &&
|
||||
(asoc->sctp_cmt_pf > 0) &&
|
||||
((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
net->cwnd = net->mtu * asoc->sctp_cmt_pf;
|
||||
SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
|
||||
net, net->cwnd);
|
||||
/*
|
||||
* Since the cwnd value is explicitly set,
|
||||
* skip the code that updates the cwnd
|
||||
* value.
|
||||
*/
|
||||
goto skip_cwnd_update;
|
||||
}
|
||||
}
|
||||
#ifdef JANA_CMT_FAST_RECOVERY
|
||||
/*
|
||||
* CMT fast recovery code
|
||||
@ -2441,7 +2167,7 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
|
||||
* If we are in loss recovery we skip any cwnd
|
||||
* update
|
||||
*/
|
||||
goto skip_cwnd_update;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* CMT: CUC algorithm. Update cwnd if pseudo-cumack has
|
||||
@ -2457,23 +2183,6 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
|
||||
SCTP_CWND_LOG_NO_CUMACK);
|
||||
}
|
||||
}
|
||||
skip_cwnd_update:
|
||||
/*
|
||||
* NOW, according to Karn's rule do we need to restore the
|
||||
* RTO timer back? Check our net_ack2. If not set then we
|
||||
* have a ambiguity.. i.e. all data ack'd was sent to more
|
||||
* than one place.
|
||||
*/
|
||||
if (net->net_ack2) {
|
||||
/* restore any doubled timers */
|
||||
net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
|
||||
if (net->RTO < stcb->asoc.minrto) {
|
||||
net->RTO = stcb->asoc.minrto;
|
||||
}
|
||||
if (net->RTO > stcb->asoc.maxrto) {
|
||||
net->RTO = stcb->asoc.maxrto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2565,30 +2274,6 @@ sctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_htcp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp,
|
||||
struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
{
|
||||
int old_cwnd;
|
||||
|
||||
old_cwnd = net->cwnd;
|
||||
|
||||
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
|
||||
net->cc_mod.htcp_ca.last_cong = sctp_get_tick_count();
|
||||
/*
|
||||
* make a small adjustment to cwnd and force to CA.
|
||||
*/
|
||||
if (net->cwnd > net->mtu)
|
||||
/* drop down one MTU after sending */
|
||||
net->cwnd -= net->mtu;
|
||||
if (net->cwnd < net->ssthresh)
|
||||
/* still in SS move to CA */
|
||||
net->ssthresh = net->cwnd - 1;
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net, int in_window, int num_pkt_lost)
|
||||
@ -2618,42 +2303,42 @@ struct sctp_cc_functions sctp_cc_functions[] = {
|
||||
{
|
||||
.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
|
||||
.sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack,
|
||||
.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
|
||||
.sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
|
||||
.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
|
||||
.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
|
||||
.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
|
||||
.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
|
||||
.sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer
|
||||
},
|
||||
{
|
||||
.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
|
||||
.sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack,
|
||||
.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
|
||||
.sctp_cwnd_update_after_fr = sctp_hs_cwnd_update_after_fr,
|
||||
.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
|
||||
.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
|
||||
.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
|
||||
.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
|
||||
.sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer
|
||||
},
|
||||
{
|
||||
.sctp_set_initial_cc_param = sctp_htcp_set_initial_cc_param,
|
||||
.sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack,
|
||||
.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
|
||||
.sctp_cwnd_update_after_fr = sctp_htcp_cwnd_update_after_fr,
|
||||
.sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout,
|
||||
.sctp_cwnd_update_after_ecn_echo = sctp_htcp_cwnd_update_after_ecn_echo,
|
||||
.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
|
||||
.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
|
||||
.sctp_cwnd_update_after_fr_timer = sctp_htcp_cwnd_update_after_fr_timer
|
||||
},
|
||||
{
|
||||
.sctp_set_initial_cc_param = sctp_set_rtcc_initial_cc_param,
|
||||
.sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack,
|
||||
.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
|
||||
.sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
|
||||
.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
|
||||
.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_rtcc_after_ecn_echo,
|
||||
.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
|
||||
.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
|
||||
.sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer,
|
||||
.sctp_cwnd_update_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted,
|
||||
.sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged,
|
||||
.sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins,
|
||||
|
@ -416,7 +416,7 @@ __FBSDID("$FreeBSD$");
|
||||
#define SCTP_STR_RESET_IN_REQUEST 0x000e
|
||||
#define SCTP_STR_RESET_TSN_REQUEST 0x000f
|
||||
#define SCTP_STR_RESET_RESPONSE 0x0010
|
||||
#define SCTP_STR_RESET_ADD_STREAMS 0x0011
|
||||
#define SCTP_STR_RESET_ADD_STREAMS 0x0011
|
||||
|
||||
#define SCTP_MAX_RESET_PARAMS 2
|
||||
#define SCTP_STREAM_RESET_TSN_DELTA 0x1000
|
||||
@ -508,14 +508,10 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
/* SCTP reachability state for each address */
|
||||
#define SCTP_ADDR_REACHABLE 0x001
|
||||
#define SCTP_ADDR_NOT_REACHABLE 0x002
|
||||
#define SCTP_ADDR_NOHB 0x004
|
||||
#define SCTP_ADDR_BEING_DELETED 0x008
|
||||
#define SCTP_ADDR_NOT_IN_ASSOC 0x010
|
||||
#define SCTP_ADDR_WAS_PRIMARY 0x020
|
||||
#define SCTP_ADDR_SWITCH_PRIMARY 0x040
|
||||
#define SCTP_ADDR_OUT_OF_SCOPE 0x080
|
||||
#define SCTP_ADDR_DOUBLE_SWITCH 0x100
|
||||
#define SCTP_ADDR_UNCONFIRMED 0x200
|
||||
#define SCTP_ADDR_REQ_PRIMARY 0x400
|
||||
/* JRS 5/13/07 - Added potentially failed state for CMT PF */
|
||||
@ -579,14 +575,13 @@ __FBSDID("$FreeBSD$");
|
||||
#define SCTP_TIMER_TYPE_EVENTWAKE 13
|
||||
#define SCTP_TIMER_TYPE_STRRESET 14
|
||||
#define SCTP_TIMER_TYPE_INPKILL 15
|
||||
#define SCTP_TIMER_TYPE_EARLYFR 17
|
||||
#define SCTP_TIMER_TYPE_ASOCKILL 18
|
||||
#define SCTP_TIMER_TYPE_ADDR_WQ 19
|
||||
#define SCTP_TIMER_TYPE_ZERO_COPY 20
|
||||
#define SCTP_TIMER_TYPE_ZCOPY_SENDQ 21
|
||||
#define SCTP_TIMER_TYPE_PRIM_DELETED 22
|
||||
#define SCTP_TIMER_TYPE_ASOCKILL 16
|
||||
#define SCTP_TIMER_TYPE_ADDR_WQ 17
|
||||
#define SCTP_TIMER_TYPE_ZERO_COPY 18
|
||||
#define SCTP_TIMER_TYPE_ZCOPY_SENDQ 19
|
||||
#define SCTP_TIMER_TYPE_PRIM_DELETED 20
|
||||
/* add new timers here - and increment LAST */
|
||||
#define SCTP_TIMER_TYPE_LAST 23
|
||||
#define SCTP_TIMER_TYPE_LAST 21
|
||||
|
||||
#define SCTP_IS_TIMER_TYPE_VALID(t) (((t) > SCTP_TIMER_TYPE_NONE) && \
|
||||
((t) < SCTP_TIMER_TYPE_LAST))
|
||||
@ -655,16 +650,17 @@ __FBSDID("$FreeBSD$");
|
||||
#define SCTP_DEFAULT_SECRET_LIFE_SEC 3600
|
||||
|
||||
#define SCTP_RTO_UPPER_BOUND (60000) /* 60 sec in ms */
|
||||
#define SCTP_RTO_LOWER_BOUND (300) /* 0.3 sec is ms */
|
||||
#define SCTP_RTO_LOWER_BOUND (1000) /* 1 sec is ms */
|
||||
#define SCTP_RTO_INITIAL (3000) /* 3 sec in ms */
|
||||
|
||||
|
||||
#define SCTP_INP_KILL_TIMEOUT 20/* number of ms to retry kill of inpcb */
|
||||
#define SCTP_ASOC_KILL_TIMEOUT 10 /* number of ms to retry kill of inpcb */
|
||||
|
||||
#define SCTP_DEF_MAX_INIT 8
|
||||
#define SCTP_DEF_MAX_SEND 10
|
||||
#define SCTP_DEF_MAX_PATH_RTX 5
|
||||
#define SCTP_DEF_MAX_INIT 8
|
||||
#define SCTP_DEF_MAX_SEND 10
|
||||
#define SCTP_DEF_MAX_PATH_RTX 5
|
||||
#define SCTP_DEF_PATH_PF_THRESHOLD SCTP_DEF_MAX_PATH_RTX
|
||||
|
||||
#define SCTP_DEF_PMTU_RAISE_SEC 600 /* 10 min between raise attempts */
|
||||
|
||||
@ -679,7 +675,7 @@ __FBSDID("$FreeBSD$");
|
||||
/* Send window update (incr * this > hiwat). Should be a power of 2 */
|
||||
#define SCTP_MINIMAL_RWND (4096) /* minimal rwnd */
|
||||
|
||||
#define SCTP_ADDRMAX 24
|
||||
#define SCTP_ADDRMAX 16
|
||||
|
||||
/* SCTP DEBUG Switch parameters */
|
||||
#define SCTP_DEBUG_TIMER1 0x00000001
|
||||
|
@ -98,9 +98,10 @@ struct sctp_heartbeat_info_param {
|
||||
uint32_t time_value_2;
|
||||
uint32_t random_value1;
|
||||
uint32_t random_value2;
|
||||
uint16_t user_req;
|
||||
uint8_t addr_family;
|
||||
uint8_t addr_len;
|
||||
/* make sure that this structure is 4 byte aligned */
|
||||
uint8_t padding[2];
|
||||
char address[SCTP_ADDRMAX];
|
||||
} SCTP_PACKED;
|
||||
|
||||
|
@ -2434,7 +2434,8 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap, int *abort_flag)
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
|
||||
stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_INDATA + SCTP_LOC_18);
|
||||
}
|
||||
sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
|
||||
sctp_send_shutdown(stcb,
|
||||
((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination));
|
||||
sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
|
||||
} else {
|
||||
int is_a_gap;
|
||||
@ -4054,9 +4055,50 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
|
||||
}
|
||||
|
||||
/* JRS - Use the congestion control given in the CC module */
|
||||
if ((asoc->last_acked_seq != cumack) && (ecne_seen == 0))
|
||||
if ((asoc->last_acked_seq != cumack) && (ecne_seen == 0)) {
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
if (net->net_ack2 > 0) {
|
||||
/*
|
||||
* Karn's rule applies to clearing error
|
||||
* count, this is optional.
|
||||
*/
|
||||
net->error_count = 0;
|
||||
if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
|
||||
/* addr came good */
|
||||
net->dest_state |= SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
|
||||
SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
if (net == stcb->asoc.primary_destination) {
|
||||
if (stcb->asoc.alternate) {
|
||||
/*
|
||||
* release the alternate,
|
||||
* primary is good
|
||||
*/
|
||||
sctp_free_remote_addr(stcb->asoc.alternate);
|
||||
stcb->asoc.alternate = NULL;
|
||||
}
|
||||
}
|
||||
if (net->dest_state & SCTP_ADDR_PF) {
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
|
||||
asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
|
||||
/* Done with this net */
|
||||
net->net_ack = 0;
|
||||
}
|
||||
/* restore any doubled timers */
|
||||
net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
|
||||
if (net->RTO < stcb->asoc.minrto) {
|
||||
net->RTO = stcb->asoc.minrto;
|
||||
}
|
||||
if (net->RTO > stcb->asoc.maxrto) {
|
||||
net->RTO = stcb->asoc.maxrto;
|
||||
}
|
||||
}
|
||||
}
|
||||
asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, 1, 0, 0);
|
||||
|
||||
}
|
||||
asoc->last_acked_seq = cumack;
|
||||
|
||||
if (TAILQ_EMPTY(&asoc->sent_queue)) {
|
||||
@ -4127,13 +4169,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
|
||||
stcb, net,
|
||||
SCTP_FROM_SCTP_INDATA + SCTP_LOC_22);
|
||||
}
|
||||
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
|
||||
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
|
||||
SCTP_STAT_INCR(sctps_earlyfrstpidsck4);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
|
||||
SCTP_FROM_SCTP_INDATA + SCTP_LOC_23);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((j == 0) &&
|
||||
@ -4222,6 +4257,8 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
|
||||
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24;
|
||||
sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper, SCTP_SO_NOT_LOCKED);
|
||||
} else {
|
||||
struct sctp_nets *netp;
|
||||
|
||||
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
|
||||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
|
||||
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
|
||||
@ -4229,26 +4266,36 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
|
||||
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
|
||||
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
|
||||
sctp_stop_timers_for_shutdown(stcb);
|
||||
sctp_send_shutdown(stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
if (asoc->alternate) {
|
||||
netp = asoc->alternate;
|
||||
} else {
|
||||
netp = asoc->primary_destination;
|
||||
}
|
||||
sctp_send_shutdown(stcb, netp);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
|
||||
stcb->sctp_ep, stcb, asoc->primary_destination);
|
||||
stcb->sctp_ep, stcb, netp);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
|
||||
stcb->sctp_ep, stcb, asoc->primary_destination);
|
||||
stcb->sctp_ep, stcb, netp);
|
||||
}
|
||||
} else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
|
||||
(asoc->stream_queue_cnt == 0)) {
|
||||
struct sctp_nets *netp;
|
||||
|
||||
if (asoc->alternate) {
|
||||
netp = asoc->alternate;
|
||||
} else {
|
||||
netp = asoc->primary_destination;
|
||||
}
|
||||
if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
|
||||
goto abort_out_now;
|
||||
}
|
||||
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
|
||||
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
|
||||
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
|
||||
sctp_send_shutdown_ack(stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
sctp_send_shutdown_ack(stcb, netp);
|
||||
sctp_stop_timers_for_shutdown(stcb);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK,
|
||||
stcb->sctp_ep, stcb, asoc->primary_destination);
|
||||
stcb->sctp_ep, stcb, netp);
|
||||
}
|
||||
}
|
||||
/*********************************************/
|
||||
@ -4380,7 +4427,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
|
||||
num_dup,
|
||||
SCTP_LOG_NEW_SACK);
|
||||
}
|
||||
if ((num_dup) && (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_FR_LOGGING_ENABLE | SCTP_EARLYFR_LOGGING_ENABLE))) {
|
||||
if ((num_dup) && (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE)) {
|
||||
uint16_t i;
|
||||
uint32_t *dupdata, dblock;
|
||||
|
||||
@ -4468,13 +4515,6 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
|
||||
stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_26);
|
||||
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
|
||||
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
|
||||
SCTP_STAT_INCR(sctps_earlyfrstpidsck1);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
|
||||
SCTP_FROM_SCTP_INDATA + SCTP_LOC_26);
|
||||
}
|
||||
}
|
||||
net->partial_bytes_acked = 0;
|
||||
net->flight_size = 0;
|
||||
}
|
||||
@ -4830,20 +4870,54 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
|
||||
asoc->saw_sack_with_nr_frags = 0;
|
||||
|
||||
/* JRS - Use the congestion control given in the CC module */
|
||||
if (ecne_seen == 0)
|
||||
if (ecne_seen == 0) {
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
if (net->net_ack2 > 0) {
|
||||
/*
|
||||
* Karn's rule applies to clearing error
|
||||
* count, this is optional.
|
||||
*/
|
||||
net->error_count = 0;
|
||||
if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
|
||||
/* addr came good */
|
||||
net->dest_state |= SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
|
||||
SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
if (net == stcb->asoc.primary_destination) {
|
||||
if (stcb->asoc.alternate) {
|
||||
/*
|
||||
* release the alternate,
|
||||
* primary is good
|
||||
*/
|
||||
sctp_free_remote_addr(stcb->asoc.alternate);
|
||||
stcb->asoc.alternate = NULL;
|
||||
}
|
||||
}
|
||||
if (net->dest_state & SCTP_ADDR_PF) {
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
|
||||
asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
|
||||
/* Done with this net */
|
||||
net->net_ack = 0;
|
||||
}
|
||||
/* restore any doubled timers */
|
||||
net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
|
||||
if (net->RTO < stcb->asoc.minrto) {
|
||||
net->RTO = stcb->asoc.minrto;
|
||||
}
|
||||
if (net->RTO > stcb->asoc.maxrto) {
|
||||
net->RTO = stcb->asoc.maxrto;
|
||||
}
|
||||
}
|
||||
}
|
||||
asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, accum_moved, reneged_all, will_exit_fast_recovery);
|
||||
|
||||
}
|
||||
if (TAILQ_EMPTY(&asoc->sent_queue)) {
|
||||
/* nothing left in-flight */
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
/* stop all timers */
|
||||
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
|
||||
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
|
||||
SCTP_STAT_INCR(sctps_earlyfrstpidsck4);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
|
||||
SCTP_FROM_SCTP_INDATA + SCTP_LOC_29);
|
||||
}
|
||||
}
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
|
||||
stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30);
|
||||
net->flight_size = 0;
|
||||
@ -4918,6 +4992,13 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
|
||||
sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper, SCTP_SO_NOT_LOCKED);
|
||||
return;
|
||||
} else {
|
||||
struct sctp_nets *netp;
|
||||
|
||||
if (asoc->alternate) {
|
||||
netp = asoc->alternate;
|
||||
} else {
|
||||
netp = asoc->primary_destination;
|
||||
}
|
||||
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
|
||||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
|
||||
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
|
||||
@ -4925,27 +5006,32 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
|
||||
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
|
||||
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
|
||||
sctp_stop_timers_for_shutdown(stcb);
|
||||
sctp_send_shutdown(stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
sctp_send_shutdown(stcb, netp);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
|
||||
stcb->sctp_ep, stcb, asoc->primary_destination);
|
||||
stcb->sctp_ep, stcb, netp);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
|
||||
stcb->sctp_ep, stcb, asoc->primary_destination);
|
||||
stcb->sctp_ep, stcb, netp);
|
||||
}
|
||||
return;
|
||||
} else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
|
||||
(asoc->stream_queue_cnt == 0)) {
|
||||
struct sctp_nets *netp;
|
||||
|
||||
if (asoc->alternate) {
|
||||
netp = asoc->alternate;
|
||||
} else {
|
||||
netp = asoc->primary_destination;
|
||||
}
|
||||
if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
|
||||
goto abort_out_now;
|
||||
}
|
||||
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
|
||||
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
|
||||
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
|
||||
sctp_send_shutdown_ack(stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
sctp_send_shutdown_ack(stcb, netp);
|
||||
sctp_stop_timers_for_shutdown(stcb);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK,
|
||||
stcb->sctp_ep, stcb, asoc->primary_destination);
|
||||
stcb->sctp_ep, stcb, netp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -5056,13 +5142,6 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
|
||||
stcb, net,
|
||||
SCTP_FROM_SCTP_INDATA + SCTP_LOC_22);
|
||||
}
|
||||
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
|
||||
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
|
||||
SCTP_STAT_INCR(sctps_earlyfrstpidsck4);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
|
||||
SCTP_FROM_SCTP_INDATA + SCTP_LOC_23);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((j == 0) &&
|
||||
|
@ -537,6 +537,7 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
|
||||
struct sctp_nets *r_net, *f_net;
|
||||
struct timeval tv;
|
||||
int req_prim = 0;
|
||||
uint16_t old_error_counter;
|
||||
|
||||
#ifdef INET
|
||||
struct sockaddr_in *sin;
|
||||
@ -599,7 +600,6 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
|
||||
r_net->dest_state &= ~SCTP_ADDR_UNCONFIRMED;
|
||||
if (r_net->dest_state & SCTP_ADDR_REQ_PRIMARY) {
|
||||
stcb->asoc.primary_destination = r_net;
|
||||
r_net->dest_state &= ~SCTP_ADDR_WAS_PRIMARY;
|
||||
r_net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY;
|
||||
f_net = TAILQ_FIRST(&stcb->asoc.nets);
|
||||
if (f_net != r_net) {
|
||||
@ -616,44 +616,37 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
|
||||
}
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED,
|
||||
stcb, 0, (void *)r_net, SCTP_SO_NOT_LOCKED);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net);
|
||||
}
|
||||
old_error_counter = r_net->error_count;
|
||||
r_net->error_count = 0;
|
||||
r_net->hb_responded = 1;
|
||||
tv.tv_sec = cp->heartbeat.hb_info.time_value_1;
|
||||
tv.tv_usec = cp->heartbeat.hb_info.time_value_2;
|
||||
if (r_net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
|
||||
r_net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
|
||||
r_net->dest_state |= SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
|
||||
SCTP_HEARTBEAT_SUCCESS, (void *)r_net, SCTP_SO_NOT_LOCKED);
|
||||
/* now was it the primary? if so restore */
|
||||
if (r_net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
|
||||
(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, r_net);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* JRS 5/14/07 - If CMT PF is on and the destination is in PF state,
|
||||
* set the destination to active state and set the cwnd to one or
|
||||
* two MTU's based on whether PF1 or PF2 is being used. If a T3
|
||||
* timer is running, for the destination, stop the timer because a
|
||||
* PF-heartbeat was received.
|
||||
*/
|
||||
if ((stcb->asoc.sctp_cmt_on_off > 0) &&
|
||||
(stcb->asoc.sctp_cmt_pf > 0) &&
|
||||
((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
|
||||
if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
|
||||
stcb, net,
|
||||
SCTP_FROM_SCTP_INPUT + SCTP_LOC_5);
|
||||
}
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
net->cwnd = net->mtu * stcb->asoc.sctp_cmt_pf;
|
||||
SCTPDBG(SCTP_DEBUG_INPUT1, "Destination %p moved from PF to reachable with cwnd %d.\n",
|
||||
net, net->cwnd);
|
||||
}
|
||||
/* Now lets do a RTO with this */
|
||||
r_net->RTO = sctp_calculate_rto(stcb, &stcb->asoc, r_net, &tv, sctp_align_safe_nocopy,
|
||||
SCTP_RTT_FROM_NON_DATA);
|
||||
if (!(r_net->dest_state & SCTP_ADDR_REACHABLE)) {
|
||||
r_net->dest_state |= SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
|
||||
SCTP_HEARTBEAT_SUCCESS, (void *)r_net, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
if (r_net->dest_state & SCTP_ADDR_PF) {
|
||||
r_net->dest_state &= ~SCTP_ADDR_PF;
|
||||
stcb->asoc.cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
|
||||
}
|
||||
if (old_error_counter > 0) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net);
|
||||
}
|
||||
if (r_net == stcb->asoc.primary_destination) {
|
||||
if (stcb->asoc.alternate) {
|
||||
/* release the alternate, primary is good */
|
||||
sctp_free_remote_addr(stcb->asoc.alternate);
|
||||
stcb->asoc.alternate = NULL;
|
||||
}
|
||||
}
|
||||
/* Mobility adaptation */
|
||||
if (req_prim) {
|
||||
if ((sctp_is_mobility_feature_on(stcb->sctp_ep,
|
||||
@ -824,6 +817,35 @@ sctp_handle_abort(struct sctp_abort_chunk *cp,
|
||||
SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_abort: finished\n");
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_start_net_timers(struct sctp_tcb *stcb)
|
||||
{
|
||||
uint32_t cnt_hb_sent;
|
||||
struct sctp_nets *net;
|
||||
|
||||
cnt_hb_sent = 0;
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
/*
|
||||
* For each network start: 1) A pmtu timer. 2) A HB timer 3)
|
||||
* If the dest in unconfirmed send a hb as well if under
|
||||
* max_hb_burst have been sent.
|
||||
*/
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
|
||||
if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
|
||||
(cnt_hb_sent < SCTP_BASE_SYSCTL(sctp_hb_maxburst))) {
|
||||
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
|
||||
cnt_hb_sent++;
|
||||
}
|
||||
}
|
||||
if (cnt_hb_sent) {
|
||||
sctp_chunk_output(stcb->sctp_ep, stcb,
|
||||
SCTP_OUTPUT_FROM_COOKIE_ACK,
|
||||
SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
|
||||
struct sctp_tcb *stcb, struct sctp_nets *net, int *abort_flag)
|
||||
@ -916,7 +938,7 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
|
||||
} else {
|
||||
/* no outstanding data to send, so move on... */
|
||||
/* send SHUTDOWN-ACK */
|
||||
sctp_send_shutdown_ack(stcb, stcb->asoc.primary_destination);
|
||||
sctp_send_shutdown_ack(stcb, net);
|
||||
/* move to SHUTDOWN-ACK-SENT state */
|
||||
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
|
||||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
|
||||
@ -2685,7 +2707,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
|
||||
/* TSNH! Huh, why do I need to add this address here? */
|
||||
int ret;
|
||||
|
||||
ret = sctp_add_remote_addr(*stcb, to, SCTP_DONOT_SETSCOPE,
|
||||
ret = sctp_add_remote_addr(*stcb, to, NULL, SCTP_DONOT_SETSCOPE,
|
||||
SCTP_IN_COOKIE_PROC);
|
||||
netl = sctp_findnet(*stcb, to);
|
||||
}
|
||||
@ -2697,10 +2719,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
|
||||
send_int_conf = 1;
|
||||
}
|
||||
}
|
||||
if (*stcb) {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, *inp_p,
|
||||
*stcb, NULL);
|
||||
}
|
||||
sctp_start_net_timers(*stcb);
|
||||
if ((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
|
||||
if (!had_a_existing_tcb ||
|
||||
(((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
|
||||
@ -2890,6 +2909,7 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp,
|
||||
/* state change only needed when I am in right state */
|
||||
SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n");
|
||||
SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
|
||||
sctp_start_net_timers(stcb);
|
||||
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
|
||||
stcb->sctp_ep, stcb, asoc->primary_destination);
|
||||
@ -3380,7 +3400,7 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
|
||||
* Only retransmit if we KNOW we wont destroy the
|
||||
* tcb
|
||||
*/
|
||||
(void)sctp_send_hb(stcb, 1, net, SCTP_SO_NOT_LOCKED);
|
||||
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
break;
|
||||
case SCTP_SHUTDOWN:
|
||||
@ -3999,8 +4019,7 @@ __attribute__((noinline))
|
||||
/* setup chunk parameters */
|
||||
chk->sent = SCTP_DATAGRAM_UNSENT;
|
||||
chk->snd_count = 0;
|
||||
chk->whoTo = stcb->asoc.primary_destination;
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
chk->whoTo = NULL;
|
||||
|
||||
ch = mtod(chk->data, struct sctp_chunkhdr *);
|
||||
ch->chunk_type = SCTP_STREAM_RESET;
|
||||
@ -4630,8 +4649,7 @@ __attribute__((noinline))
|
||||
if ((stcb != NULL) &&
|
||||
(SCTP_GET_STATE(&stcb->asoc) ==
|
||||
SCTP_STATE_SHUTDOWN_ACK_SENT)) {
|
||||
sctp_send_shutdown_ack(stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
sctp_send_shutdown_ack(stcb, NULL);
|
||||
*offset = length;
|
||||
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED);
|
||||
if (locked_tcb) {
|
||||
|
@ -3543,7 +3543,8 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
|
||||
*error = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
|
||||
if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL,
|
||||
SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
|
||||
*error = ENOBUFS;
|
||||
return (1);
|
||||
}
|
||||
@ -3574,13 +3575,15 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
|
||||
*error = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
|
||||
if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL,
|
||||
SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
|
||||
*error = ENOBUFS;
|
||||
return (1);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
|
||||
if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, NULL,
|
||||
SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
|
||||
*error = ENOBUFS;
|
||||
return (1);
|
||||
}
|
||||
@ -3828,28 +3831,7 @@ sctp_handle_no_route(struct sctp_tcb *stcb,
|
||||
(void *)net,
|
||||
so_locked);
|
||||
net->dest_state &= ~SCTP_ADDR_REACHABLE;
|
||||
net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
|
||||
/*
|
||||
* JRS 5/14/07 - If a destination is
|
||||
* unreachable, the PF bit is turned off.
|
||||
* This allows an unambiguous use of the PF
|
||||
* bit for destinations that are reachable
|
||||
* but potentially failed. If the
|
||||
* destination is set to the unreachable
|
||||
* state, also set the destination to the PF
|
||||
* state.
|
||||
*/
|
||||
/*
|
||||
* Add debug message here if destination is
|
||||
* not in PF state.
|
||||
*/
|
||||
/* Stop any running T3 timers here? */
|
||||
if ((stcb->asoc.sctp_cmt_on_off > 0) &&
|
||||
(stcb->asoc.sctp_cmt_pf > 0)) {
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Destination %p moved from PF to unreachable.\n",
|
||||
net);
|
||||
}
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
}
|
||||
}
|
||||
if (stcb) {
|
||||
@ -3859,14 +3841,16 @@ sctp_handle_no_route(struct sctp_tcb *stcb,
|
||||
|
||||
alt = sctp_find_alternate_net(stcb, net, 0);
|
||||
if (alt != net) {
|
||||
if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, alt) == 0) {
|
||||
net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
|
||||
if (net->ro._s_addr) {
|
||||
sctp_free_ifa(net->ro._s_addr);
|
||||
net->ro._s_addr = NULL;
|
||||
}
|
||||
net->src_addr_selected = 0;
|
||||
if (stcb->asoc.alternate) {
|
||||
sctp_free_remote_addr(stcb->asoc.alternate);
|
||||
}
|
||||
stcb->asoc.alternate = alt;
|
||||
atomic_add_int(&stcb->asoc.alternate->ref_count, 1);
|
||||
if (net->ro._s_addr) {
|
||||
sctp_free_ifa(net->ro._s_addr);
|
||||
net->ro._s_addr = NULL;
|
||||
}
|
||||
net->src_addr_selected = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6498,6 +6482,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
|
||||
int added_control = 0;
|
||||
int un_sent, do_chunk_output = 1;
|
||||
struct sctp_association *asoc;
|
||||
struct sctp_nets *net;
|
||||
|
||||
ca = (struct sctp_copy_all *)ptr;
|
||||
if (ca->m == NULL) {
|
||||
@ -6531,6 +6516,11 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
|
||||
m = NULL;
|
||||
}
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
if (stcb->asoc.alternate) {
|
||||
net = stcb->asoc.alternate;
|
||||
} else {
|
||||
net = stcb->asoc.primary_destination;
|
||||
}
|
||||
if (ca->sndrcv.sinfo_flags & SCTP_ABORT) {
|
||||
/* Abort this assoc with m as the user defined reason */
|
||||
if (m) {
|
||||
@ -6569,7 +6559,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
|
||||
}
|
||||
} else {
|
||||
if (m) {
|
||||
ret = sctp_msg_append(stcb, stcb->asoc.primary_destination, m,
|
||||
ret = sctp_msg_append(stcb, net, m,
|
||||
&ca->sndrcv, 1);
|
||||
}
|
||||
asoc = &stcb->asoc;
|
||||
@ -6596,14 +6586,14 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
|
||||
* only send SHUTDOWN the first time
|
||||
* through
|
||||
*/
|
||||
sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
|
||||
sctp_send_shutdown(stcb, net);
|
||||
if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
|
||||
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
|
||||
}
|
||||
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
|
||||
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb,
|
||||
asoc->primary_destination);
|
||||
net);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
|
||||
asoc->primary_destination);
|
||||
added_control = 1;
|
||||
@ -7733,13 +7723,13 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
struct sctp_auth_chunk *auth = NULL;
|
||||
uint16_t auth_keyid;
|
||||
int override_ok = 1;
|
||||
int skip_fill_up = 0;
|
||||
int data_auth_reqd = 0;
|
||||
|
||||
/*
|
||||
* JRS 5/14/07 - Add flag for whether a heartbeat is sent to the
|
||||
* destination.
|
||||
*/
|
||||
int pf_hbflag = 0;
|
||||
int quit_now = 0;
|
||||
|
||||
*num_out = 0;
|
||||
@ -7806,7 +7796,22 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
max_send_per_dest = SCTP_SB_LIMIT_SND(stcb->sctp_socket) / asoc->numnets;
|
||||
else
|
||||
max_send_per_dest = 0;
|
||||
if (no_data_chunks == 0) {
|
||||
/* How many non-directed chunks are there? */
|
||||
TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
|
||||
if (chk->whoTo == NULL) {
|
||||
/*
|
||||
* We already have non-directed chunks on
|
||||
* the queue, no need to do a fill-up.
|
||||
*/
|
||||
skip_fill_up = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if ((no_data_chunks == 0) &&
|
||||
(skip_fill_up == 0) &&
|
||||
(!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc))) {
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
/*
|
||||
@ -7821,8 +7826,10 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
* copy by reference (we hope).
|
||||
*/
|
||||
net->window_probe = 0;
|
||||
if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ||
|
||||
(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
|
||||
if ((net != stcb->asoc.alternate) &&
|
||||
((net->dest_state & SCTP_ADDR_PF) ||
|
||||
(!(net->dest_state & SCTP_ADDR_REACHABLE)) ||
|
||||
(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, 1,
|
||||
SCTP_CWND_LOG_FILL_OUTQ_CALLED);
|
||||
@ -7833,16 +7840,6 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
(net->flight_size == 0)) {
|
||||
(*stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) (stcb, net);
|
||||
}
|
||||
if ((asoc->sctp_cmt_on_off == 0) &&
|
||||
(asoc->primary_destination != net) &&
|
||||
(net->ref_count < 2)) {
|
||||
/* nothing can be in queue for this guy */
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, 2,
|
||||
SCTP_CWND_LOG_FILL_OUTQ_CALLED);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (net->flight_size >= net->cwnd) {
|
||||
/* skip this network, no room - can't fill */
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
|
||||
@ -7886,6 +7883,16 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
} else {
|
||||
start_at = TAILQ_FIRST(&asoc->nets);
|
||||
}
|
||||
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
|
||||
if (chk->whoTo == NULL) {
|
||||
if (asoc->alternate) {
|
||||
chk->whoTo = asoc->alternate;
|
||||
} else {
|
||||
chk->whoTo = asoc->primary_destination;
|
||||
}
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
}
|
||||
}
|
||||
old_start_at = NULL;
|
||||
again_one_more_time:
|
||||
for (net = start_at; net != NULL; net = TAILQ_NEXT(net, sctp_next)) {
|
||||
@ -7896,15 +7903,6 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
break;
|
||||
}
|
||||
tsns_sent = 0xa;
|
||||
if ((asoc->sctp_cmt_on_off == 0) &&
|
||||
(asoc->primary_destination != net) &&
|
||||
(net->ref_count < 2)) {
|
||||
/*
|
||||
* Ref-count of 1 so we cannot have data or control
|
||||
* queued to this address. Skip it (non-CMT).
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
if (TAILQ_EMPTY(&asoc->control_send_queue) &&
|
||||
TAILQ_EMPTY(&asoc->asconf_send_queue) &&
|
||||
(net->flight_size >= net->cwnd)) {
|
||||
@ -8266,15 +8264,8 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
(chk->rec.chunk_id.id == SCTP_ECN_CWR) ||
|
||||
(chk->rec.chunk_id.id == SCTP_PACKET_DROPPED) ||
|
||||
(chk->rec.chunk_id.id == SCTP_ASCONF_ACK)) {
|
||||
|
||||
if (chk->rec.chunk_id.id == SCTP_HEARTBEAT_REQUEST) {
|
||||
hbflag = 1;
|
||||
/*
|
||||
* JRS 5/14/07 - Set the
|
||||
* flag to say a heartbeat
|
||||
* is being sent.
|
||||
*/
|
||||
pf_hbflag = 1;
|
||||
}
|
||||
/* remove these chunks at the end */
|
||||
if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) ||
|
||||
@ -8408,7 +8399,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
}
|
||||
/* JRI: if dest is in PF state, do not send data to it */
|
||||
if ((asoc->sctp_cmt_on_off > 0) &&
|
||||
(asoc->sctp_cmt_pf > 0) &&
|
||||
(net != stcb->asoc.alternate) &&
|
||||
(net->dest_state & SCTP_ADDR_PF)) {
|
||||
goto no_data_fill;
|
||||
}
|
||||
@ -8486,6 +8477,17 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
/* Don't send the chunk on this net */
|
||||
continue;
|
||||
}
|
||||
if (asoc->sctp_cmt_on_off == 0) {
|
||||
if ((asoc->alternate) &&
|
||||
(asoc->alternate != net) &&
|
||||
(chk->whoTo == NULL)) {
|
||||
continue;
|
||||
} else if ((net != asoc->primary_destination) &&
|
||||
(asoc->alternate == NULL) &&
|
||||
(chk->whoTo == NULL)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((chk->send_size > omtu) && ((chk->flags & CHUNK_FLAGS_FRAGMENT_OK) == 0)) {
|
||||
/*-
|
||||
* strange, we have a chunk that is
|
||||
@ -8646,18 +8648,6 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
* restart it.
|
||||
*/
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
|
||||
} else if ((asoc->sctp_cmt_on_off > 0) &&
|
||||
(asoc->sctp_cmt_pf > 0) &&
|
||||
pf_hbflag &&
|
||||
((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF) &&
|
||||
(!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer))) {
|
||||
/*
|
||||
* JRS 5/14/07 - If a HB has been sent to a
|
||||
* PF destination and no T3 timer is
|
||||
* currently running, start the T3 timer to
|
||||
* track the HBs that were sent.
|
||||
*/
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
|
||||
}
|
||||
/* Now send it, if there is anything to send :> */
|
||||
if ((error = sctp_lowlevel_chunk_output(inp,
|
||||
@ -8747,24 +8737,6 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
}
|
||||
SCTP_STAT_INCR_BY(sctps_senddata, bundle_at);
|
||||
sctp_clean_up_datalist(stcb, asoc, data_list, bundle_at, net);
|
||||
if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
|
||||
if (net->flight_size < net->cwnd) {
|
||||
/* start or restart it */
|
||||
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net,
|
||||
SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_2);
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_earlyfrstrout);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net);
|
||||
} else {
|
||||
/* stop it if its running */
|
||||
if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
|
||||
SCTP_STAT_INCR(sctps_earlyfrstpout);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net,
|
||||
SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (one_chunk) {
|
||||
break;
|
||||
@ -8833,8 +8805,7 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err)
|
||||
chk->flags = 0;
|
||||
chk->asoc = &stcb->asoc;
|
||||
chk->data = op_err;
|
||||
chk->whoTo = chk->asoc->primary_destination;
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
chk->whoTo = NULL;
|
||||
hdr = mtod(op_err, struct sctp_chunkhdr *);
|
||||
hdr->chunk_type = SCTP_OPERATION_ERROR;
|
||||
hdr->chunk_flags = 0;
|
||||
@ -8929,7 +8900,7 @@ sctp_send_cookie_echo(struct mbuf *m,
|
||||
chk->flags = CHUNK_FLAGS_FRAGMENT_OK;
|
||||
chk->asoc = &stcb->asoc;
|
||||
chk->data = cookie;
|
||||
chk->whoTo = chk->asoc->primary_destination;
|
||||
chk->whoTo = net;
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
TAILQ_INSERT_HEAD(&chk->asoc->control_send_queue, chk, sctp_next);
|
||||
chk->asoc->ctrl_queue_cnt++;
|
||||
@ -9039,10 +9010,10 @@ sctp_send_cookie_ack(struct sctp_tcb *stcb)
|
||||
chk->data = cookie_ack;
|
||||
if (chk->asoc->last_control_chunk_from != NULL) {
|
||||
chk->whoTo = chk->asoc->last_control_chunk_from;
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
} else {
|
||||
chk->whoTo = chk->asoc->primary_destination;
|
||||
chk->whoTo = NULL;
|
||||
}
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
hdr = mtod(cookie_ack, struct sctp_chunkhdr *);
|
||||
hdr->chunk_type = SCTP_COOKIE_ACK;
|
||||
hdr->chunk_flags = 0;
|
||||
@ -9084,8 +9055,9 @@ sctp_send_shutdown_ack(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
chk->asoc = &stcb->asoc;
|
||||
chk->data = m_shutdown_ack;
|
||||
chk->whoTo = net;
|
||||
atomic_add_int(&net->ref_count, 1);
|
||||
|
||||
if (chk->whoTo) {
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
}
|
||||
ack_cp = mtod(m_shutdown_ack, struct sctp_shutdown_ack_chunk *);
|
||||
ack_cp->ch.chunk_type = SCTP_SHUTDOWN_ACK;
|
||||
ack_cp->ch.chunk_flags = 0;
|
||||
@ -9126,8 +9098,9 @@ sctp_send_shutdown(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
chk->asoc = &stcb->asoc;
|
||||
chk->data = m_shutdown;
|
||||
chk->whoTo = net;
|
||||
atomic_add_int(&net->ref_count, 1);
|
||||
|
||||
if (chk->whoTo) {
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
}
|
||||
shutdown_cp = mtod(m_shutdown, struct sctp_shutdown_chunk *);
|
||||
shutdown_cp->ch.chunk_type = SCTP_SHUTDOWN;
|
||||
shutdown_cp->ch.chunk_flags = 0;
|
||||
@ -9178,7 +9151,9 @@ sctp_send_asconf(struct sctp_tcb *stcb, struct sctp_nets *net, int addr_locked)
|
||||
chk->flags = CHUNK_FLAGS_FRAGMENT_OK;
|
||||
chk->asoc = &stcb->asoc;
|
||||
chk->whoTo = net;
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
if (chk->whoTo) {
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
}
|
||||
TAILQ_INSERT_TAIL(&chk->asoc->asconf_send_queue, chk, sctp_next);
|
||||
chk->asoc->ctrl_queue_cnt++;
|
||||
return;
|
||||
@ -9208,17 +9183,27 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb)
|
||||
net = sctp_find_alternate_net(stcb, stcb->asoc.last_control_chunk_from, 0);
|
||||
if (net == NULL) {
|
||||
/* no alternate */
|
||||
if (stcb->asoc.last_control_chunk_from == NULL)
|
||||
net = stcb->asoc.primary_destination;
|
||||
else
|
||||
if (stcb->asoc.last_control_chunk_from == NULL) {
|
||||
if (stcb->asoc.alternate) {
|
||||
net = stcb->asoc.alternate;
|
||||
} else {
|
||||
net = stcb->asoc.primary_destination;
|
||||
}
|
||||
} else {
|
||||
net = stcb->asoc.last_control_chunk_from;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* normal case */
|
||||
if (stcb->asoc.last_control_chunk_from == NULL)
|
||||
net = stcb->asoc.primary_destination;
|
||||
else
|
||||
if (stcb->asoc.last_control_chunk_from == NULL) {
|
||||
if (stcb->asoc.alternate) {
|
||||
net = stcb->asoc.alternate;
|
||||
} else {
|
||||
net = stcb->asoc.primary_destination;
|
||||
}
|
||||
} else {
|
||||
net = stcb->asoc.last_control_chunk_from;
|
||||
}
|
||||
}
|
||||
latest_ack->last_sent_to = net;
|
||||
|
||||
@ -9256,6 +9241,9 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb)
|
||||
chk->copy_by_ref = 0;
|
||||
|
||||
chk->whoTo = net;
|
||||
if (chk->whoTo) {
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
}
|
||||
chk->data = m_ack;
|
||||
chk->send_size = 0;
|
||||
/* Get size */
|
||||
@ -9267,7 +9255,6 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb)
|
||||
chk->snd_count = 0;
|
||||
chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; /* XXX */
|
||||
chk->asoc = &stcb->asoc;
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
|
||||
TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next);
|
||||
chk->asoc->ctrl_queue_cnt++;
|
||||
@ -9797,7 +9784,11 @@ sctp_timer_validation(struct sctp_inpcb *inp,
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
/* Gak, we did not have a timer somewhere */
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Deadlock avoided starting timer on a dest at retran\n");
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->primary_destination);
|
||||
if (asoc->alternate) {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->alternate);
|
||||
} else {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->primary_destination);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -9945,8 +9936,7 @@ sctp_chunk_output(struct sctp_inpcb *inp,
|
||||
#endif
|
||||
/* Check for bad destinations, if they exist move chunks around. */
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
|
||||
SCTP_ADDR_NOT_REACHABLE) {
|
||||
if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
|
||||
/*-
|
||||
* if possible move things off of this address we
|
||||
* still may send below due to the dormant state but
|
||||
@ -9956,16 +9946,6 @@ sctp_chunk_output(struct sctp_inpcb *inp,
|
||||
*/
|
||||
if (net->ref_count > 1)
|
||||
sctp_move_chunks_from_net(stcb, net);
|
||||
} else if ((asoc->sctp_cmt_on_off > 0) &&
|
||||
(asoc->sctp_cmt_pf > 0) &&
|
||||
((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
|
||||
/*
|
||||
* JRS 5/14/07 - If CMT PF is on and the current
|
||||
* destination is in PF state, move all queued data
|
||||
* to an alternate desination.
|
||||
*/
|
||||
if (net->ref_count > 1)
|
||||
sctp_move_chunks_from_net(stcb, net);
|
||||
} else {
|
||||
/*-
|
||||
* if ((asoc->sat_network) || (net->addr_is_local))
|
||||
@ -10123,10 +10103,9 @@ send_forward_tsn(struct sctp_tcb *stcb,
|
||||
chk->sent = SCTP_DATAGRAM_UNSENT;
|
||||
chk->snd_count = 0;
|
||||
/* Do we correct its output location? */
|
||||
if (chk->whoTo != asoc->primary_destination) {
|
||||
if (chk->whoTo) {
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
chk->whoTo = asoc->primary_destination;
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
chk->whoTo = NULL;
|
||||
}
|
||||
goto sctp_fill_in_rest;
|
||||
}
|
||||
@ -10150,8 +10129,6 @@ send_forward_tsn(struct sctp_tcb *stcb,
|
||||
SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD);
|
||||
chk->sent = SCTP_DATAGRAM_UNSENT;
|
||||
chk->snd_count = 0;
|
||||
chk->whoTo = asoc->primary_destination;
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
TAILQ_INSERT_TAIL(&asoc->control_send_queue, chk, sctp_next);
|
||||
asoc->ctrl_queue_cnt++;
|
||||
sctp_fill_in_rest:
|
||||
@ -10346,8 +10323,10 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
|
||||
sctp_m_freem(a_chk->data);
|
||||
a_chk->data = NULL;
|
||||
}
|
||||
sctp_free_remote_addr(a_chk->whoTo);
|
||||
a_chk->whoTo = NULL;
|
||||
if (a_chk->whoTo) {
|
||||
sctp_free_remote_addr(a_chk->whoTo);
|
||||
a_chk->whoTo = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -10379,13 +10358,13 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
|
||||
a_chk->whoTo = NULL;
|
||||
|
||||
if ((asoc->numduptsns) ||
|
||||
(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_NOT_REACHABLE)) {
|
||||
(!(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE))) {
|
||||
/*-
|
||||
* Ok, we have some duplicates or the destination for the
|
||||
* sack is unreachable, lets see if we can select an
|
||||
* alternate than asoc->last_data_chunk_from
|
||||
*/
|
||||
if ((!(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_NOT_REACHABLE)) &&
|
||||
if ((asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE) &&
|
||||
(asoc->used_alt_onsack > asoc->numnets)) {
|
||||
/* We used an alt last time, don't this time */
|
||||
a_chk->whoTo = NULL;
|
||||
@ -10710,6 +10689,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
|
||||
int sz;
|
||||
uint32_t auth_offset = 0;
|
||||
struct sctp_auth_chunk *auth = NULL;
|
||||
struct sctp_nets *net;
|
||||
|
||||
/*-
|
||||
* Add an AUTH chunk, if chunk requires it and save the offset into
|
||||
@ -10750,16 +10730,19 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
|
||||
/* Put AUTH chunk at the front of the chain */
|
||||
SCTP_BUF_NEXT(m_end) = m_abort;
|
||||
}
|
||||
|
||||
if (stcb->asoc.alternate) {
|
||||
net = stcb->asoc.alternate;
|
||||
} else {
|
||||
net = stcb->asoc.primary_destination;
|
||||
}
|
||||
/* fill in the ABORT chunk */
|
||||
abort = mtod(m_abort, struct sctp_abort_chunk *);
|
||||
abort->ch.chunk_type = SCTP_ABORT_ASSOCIATION;
|
||||
abort->ch.chunk_flags = 0;
|
||||
abort->ch.chunk_length = htons(sizeof(*abort) + sz);
|
||||
|
||||
(void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb,
|
||||
stcb->asoc.primary_destination,
|
||||
(struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr,
|
||||
(void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net,
|
||||
(struct sockaddr *)&net->ro._l_addr,
|
||||
m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, NULL, 0,
|
||||
stcb->sctp_ep->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag),
|
||||
stcb->asoc.primary_destination->port, so_locked, NULL, NULL);
|
||||
@ -11030,120 +11013,22 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh,
|
||||
|
||||
}
|
||||
|
||||
static struct sctp_nets *
|
||||
sctp_select_hb_destination(struct sctp_tcb *stcb, struct timeval *now)
|
||||
{
|
||||
struct sctp_nets *net, *hnet;
|
||||
int ms_goneby, highest_ms, state_overide = 0;
|
||||
|
||||
(void)SCTP_GETTIME_TIMEVAL(now);
|
||||
highest_ms = 0;
|
||||
hnet = NULL;
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if (
|
||||
((net->dest_state & SCTP_ADDR_NOHB) && ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0)) ||
|
||||
(net->dest_state & SCTP_ADDR_OUT_OF_SCOPE)
|
||||
) {
|
||||
/*
|
||||
* Skip this guy from consideration if HB is off AND
|
||||
* its confirmed
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
if (sctp_destination_is_reachable(stcb, (struct sockaddr *)&net->ro._l_addr) == 0) {
|
||||
/* skip this dest net from consideration */
|
||||
continue;
|
||||
}
|
||||
if (net->last_sent_time.tv_sec) {
|
||||
/* Sent to so we subtract */
|
||||
ms_goneby = (now->tv_sec - net->last_sent_time.tv_sec) * 1000;
|
||||
} else
|
||||
/* Never been sent to */
|
||||
ms_goneby = 0x7fffffff;
|
||||
/*-
|
||||
* When the address state is unconfirmed but still
|
||||
* considered reachable, we HB at a higher rate. Once it
|
||||
* goes confirmed OR reaches the "unreachable" state, thenw
|
||||
* we cut it back to HB at a more normal pace.
|
||||
*/
|
||||
if ((net->dest_state & (SCTP_ADDR_UNCONFIRMED | SCTP_ADDR_NOT_REACHABLE)) == SCTP_ADDR_UNCONFIRMED) {
|
||||
state_overide = 1;
|
||||
} else {
|
||||
state_overide = 0;
|
||||
}
|
||||
|
||||
if ((((unsigned int)ms_goneby >= net->RTO) || (state_overide)) &&
|
||||
(ms_goneby > highest_ms)) {
|
||||
highest_ms = ms_goneby;
|
||||
hnet = net;
|
||||
}
|
||||
}
|
||||
if (hnet &&
|
||||
((hnet->dest_state & (SCTP_ADDR_UNCONFIRMED | SCTP_ADDR_NOT_REACHABLE)) == SCTP_ADDR_UNCONFIRMED)) {
|
||||
state_overide = 1;
|
||||
} else {
|
||||
state_overide = 0;
|
||||
}
|
||||
|
||||
if (hnet && highest_ms && (((unsigned int)highest_ms >= hnet->RTO) || state_overide)) {
|
||||
/*-
|
||||
* Found the one with longest delay bounds OR it is
|
||||
* unconfirmed and still not marked unreachable.
|
||||
*/
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT4, "net:%p is the hb winner -", hnet);
|
||||
#ifdef SCTP_DEBUG
|
||||
if (hnet) {
|
||||
SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT4,
|
||||
(struct sockaddr *)&hnet->ro._l_addr);
|
||||
} else {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT4, " none\n");
|
||||
}
|
||||
#endif
|
||||
/* update the timer now */
|
||||
hnet->last_sent_time = *now;
|
||||
return (hnet);
|
||||
}
|
||||
/* Nothing to HB */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int so_locked
|
||||
void
|
||||
sctp_send_hb(struct sctp_tcb *stcb, struct sctp_nets *net, int so_locked
|
||||
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
|
||||
SCTP_UNUSED
|
||||
#endif
|
||||
)
|
||||
{
|
||||
struct sctp_tmit_chunk *chk;
|
||||
struct sctp_nets *net;
|
||||
struct sctp_heartbeat_chunk *hb;
|
||||
struct timeval now;
|
||||
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
if (user_req == 0) {
|
||||
net = sctp_select_hb_destination(stcb, &now);
|
||||
if (net == NULL) {
|
||||
/*-
|
||||
* All our busy none to send to, just start the
|
||||
* timer again.
|
||||
*/
|
||||
if (stcb->asoc.state == 0) {
|
||||
return (0);
|
||||
}
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT,
|
||||
stcb->sctp_ep,
|
||||
stcb,
|
||||
net);
|
||||
return (0);
|
||||
}
|
||||
} else {
|
||||
net = u_net;
|
||||
if (net == NULL) {
|
||||
return (0);
|
||||
}
|
||||
(void)SCTP_GETTIME_TIMEVAL(&now);
|
||||
if (net == NULL) {
|
||||
return;
|
||||
}
|
||||
(void)SCTP_GETTIME_TIMEVAL(&now);
|
||||
switch (net->ro._l_addr.sa.sa_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
@ -11154,12 +11039,12 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return (0);
|
||||
return;
|
||||
}
|
||||
sctp_alloc_a_chunk(stcb, chk);
|
||||
if (chk == NULL) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak, can't get a chunk for hb\n");
|
||||
return (0);
|
||||
return;
|
||||
}
|
||||
chk->copy_by_ref = 0;
|
||||
chk->rec.chunk_id.id = SCTP_HEARTBEAT_REQUEST;
|
||||
@ -11170,7 +11055,7 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s
|
||||
chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_DONTWAIT, 1, MT_HEADER);
|
||||
if (chk->data == NULL) {
|
||||
sctp_free_a_chunk(stcb, chk, so_locked);
|
||||
return (0);
|
||||
return;
|
||||
}
|
||||
SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD);
|
||||
SCTP_BUF_LEN(chk->data) = chk->send_size;
|
||||
@ -11191,7 +11076,6 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s
|
||||
hb->heartbeat.hb_info.time_value_1 = now.tv_sec;
|
||||
hb->heartbeat.hb_info.time_value_2 = now.tv_usec;
|
||||
/* Did our user request this one, put it in */
|
||||
hb->heartbeat.hb_info.user_req = user_req;
|
||||
hb->heartbeat.hb_info.addr_family = net->ro._l_addr.sa.sa_family;
|
||||
hb->heartbeat.hb_info.addr_len = net->ro._l_addr.sa.sa_len;
|
||||
if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
|
||||
@ -11221,57 +11105,14 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return (0);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* JRS 5/14/07 - In CMT PF, the T3 timer is used to track
|
||||
* PF-heartbeats. Because of this, threshold management is done by
|
||||
* the t3 timer handler, and does not need to be done upon the send
|
||||
* of a PF-heartbeat. If CMT PF is on and the destination to which a
|
||||
* heartbeat is being sent is in PF state, do NOT do threshold
|
||||
* management.
|
||||
*/
|
||||
if ((stcb->asoc.sctp_cmt_pf == 0) ||
|
||||
((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF)) {
|
||||
/* ok we have a destination that needs a beat */
|
||||
/* lets do the theshold management Qiaobing style */
|
||||
if (sctp_threshold_management(stcb->sctp_ep, stcb, net,
|
||||
stcb->asoc.max_send_times)) {
|
||||
/*-
|
||||
* we have lost the association, in a way this is
|
||||
* quite bad since we really are one less time since
|
||||
* we really did not send yet. This is the down side
|
||||
* to the Q's style as defined in the RFC and not my
|
||||
* alternate style defined in the RFC.
|
||||
*/
|
||||
if (chk->data != NULL) {
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
}
|
||||
/*
|
||||
* Here we do NOT use the macro since the
|
||||
* association is now gone.
|
||||
*/
|
||||
if (chk->whoTo) {
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
chk->whoTo = NULL;
|
||||
}
|
||||
sctp_free_a_chunk((struct sctp_tcb *)NULL, chk, so_locked);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
net->hb_responded = 0;
|
||||
TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next);
|
||||
stcb->asoc.ctrl_queue_cnt++;
|
||||
SCTP_STAT_INCR(sctps_sendheartbeat);
|
||||
/*-
|
||||
* Call directly med level routine to put out the chunk. It will
|
||||
* always tumble out control chunks aka HB but it may even tumble
|
||||
* out data too.
|
||||
*/
|
||||
return (1);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
@ -11282,6 +11123,9 @@ sctp_send_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
struct sctp_ecne_chunk *ecne;
|
||||
struct sctp_tmit_chunk *chk;
|
||||
|
||||
if (net == NULL) {
|
||||
return;
|
||||
}
|
||||
asoc = &stcb->asoc;
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
|
||||
@ -11323,6 +11167,7 @@ sctp_send_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
chk->snd_count = 0;
|
||||
chk->whoTo = net;
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
|
||||
stcb->asoc.ecn_echo_cnt_onq++;
|
||||
ecne = mtod(chk->data, struct sctp_ecne_chunk *);
|
||||
ecne->ch.chunk_type = SCTP_ECN_ECHO;
|
||||
@ -11477,10 +11322,10 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
if (net) {
|
||||
/* we should hit here */
|
||||
chk->whoTo = net;
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
} else {
|
||||
chk->whoTo = asoc->primary_destination;
|
||||
chk->whoTo = NULL;
|
||||
}
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
chk->rec.chunk_id.id = SCTP_PACKET_DROPPED;
|
||||
chk->rec.chunk_id.can_take_data = 1;
|
||||
drp->ch.chunk_type = SCTP_PACKET_DROPPED;
|
||||
@ -11518,8 +11363,9 @@ sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn, u
|
||||
|
||||
asoc = &stcb->asoc;
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
|
||||
|
||||
if (net == NULL) {
|
||||
return;
|
||||
}
|
||||
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
|
||||
if ((chk->rec.chunk_id.id == SCTP_ECN_CWR) && (net == chk->whoTo)) {
|
||||
/*
|
||||
@ -11849,9 +11695,12 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
|
||||
/* setup chunk parameters */
|
||||
chk->sent = SCTP_DATAGRAM_UNSENT;
|
||||
chk->snd_count = 0;
|
||||
chk->whoTo = asoc->primary_destination;
|
||||
if (stcb->asoc.alternate) {
|
||||
chk->whoTo = stcb->asoc.alternate;
|
||||
} else {
|
||||
chk->whoTo = stcb->asoc.primary_destination;
|
||||
}
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
|
||||
ch = mtod(chk->data, struct sctp_chunkhdr *);
|
||||
ch->chunk_type = SCTP_STREAM_RESET;
|
||||
ch->chunk_flags = 0;
|
||||
@ -12910,7 +12759,11 @@ sctp_lower_sosend(struct socket *so,
|
||||
goto out_unlocked;
|
||||
}
|
||||
} else {
|
||||
net = stcb->asoc.primary_destination;
|
||||
if (stcb->asoc.alternate) {
|
||||
net = stcb->asoc.alternate;
|
||||
} else {
|
||||
net = stcb->asoc.primary_destination;
|
||||
}
|
||||
}
|
||||
atomic_add_int(&stcb->total_sends, 1);
|
||||
/* Keep the stcb from being freed under our feet */
|
||||
@ -13579,15 +13432,22 @@ sctp_lower_sosend(struct socket *so,
|
||||
if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
|
||||
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
|
||||
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
|
||||
struct sctp_nets *netp;
|
||||
|
||||
if (stcb->asoc.alternate) {
|
||||
netp = stcb->asoc.alternate;
|
||||
} else {
|
||||
netp = stcb->asoc.primary_destination;
|
||||
}
|
||||
/* only send SHUTDOWN the first time through */
|
||||
sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
|
||||
sctp_send_shutdown(stcb, netp);
|
||||
if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
|
||||
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
|
||||
}
|
||||
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
|
||||
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb,
|
||||
asoc->primary_destination);
|
||||
netp);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
|
||||
asoc->primary_destination);
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ void send_forward_tsn(struct sctp_tcb *, struct sctp_association *);
|
||||
|
||||
void sctp_send_sack(struct sctp_tcb *, int);
|
||||
|
||||
int sctp_send_hb(struct sctp_tcb *, int, struct sctp_nets *, int);
|
||||
void sctp_send_hb(struct sctp_tcb *, struct sctp_nets *, int);
|
||||
|
||||
void sctp_send_ecn_echo(struct sctp_tcb *, struct sctp_nets *, uint32_t);
|
||||
|
||||
|
@ -1096,8 +1096,15 @@ sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to)
|
||||
continue;
|
||||
}
|
||||
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
|
||||
if (sctp_is_addr_restricted(stcb, sctp_ifa))
|
||||
if (sctp_is_addr_restricted(stcb, sctp_ifa) &&
|
||||
(!sctp_is_addr_pending(stcb, sctp_ifa))) {
|
||||
/*
|
||||
* We allow pending addresses, where
|
||||
* we have sent an asconf-add to be
|
||||
* considered valid.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
switch (sctp_ifa->address.sa.sa_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
@ -1155,7 +1162,13 @@ sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to)
|
||||
struct sctp_laddr *laddr;
|
||||
|
||||
LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
|
||||
if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
|
||||
if (sctp_is_addr_restricted(stcb, laddr->ifa) &&
|
||||
(!sctp_is_addr_pending(stcb, laddr->ifa))) {
|
||||
/*
|
||||
* We allow pending addresses, where we have
|
||||
* sent an asconf-add to be considered
|
||||
* valid.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
if (laddr->ifa->address.sa.sa_family != to->sa_family) {
|
||||
@ -2614,6 +2627,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
|
||||
m->max_init_times = SCTP_BASE_SYSCTL(sctp_init_rtx_max_default);
|
||||
m->max_send_times = SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default);
|
||||
m->def_net_failure = SCTP_BASE_SYSCTL(sctp_path_rtx_max_default);
|
||||
m->def_net_pf_threshold = SCTP_BASE_SYSCTL(sctp_path_pf_threshold);
|
||||
m->sctp_sws_sender = SCTP_SWS_SENDER_DEF;
|
||||
m->sctp_sws_receiver = SCTP_SWS_RECEIVER_DEF;
|
||||
m->max_burst = SCTP_BASE_SYSCTL(sctp_max_burst_default);
|
||||
@ -2768,7 +2782,6 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
|
||||
* all of them.
|
||||
*/
|
||||
|
||||
stcb->asoc.hb_timer.ep = (void *)new_inp;
|
||||
stcb->asoc.dack_timer.ep = (void *)new_inp;
|
||||
stcb->asoc.asconf_timer.ep = (void *)new_inp;
|
||||
stcb->asoc.strreset_timer.ep = (void *)new_inp;
|
||||
@ -2780,7 +2793,6 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
net->pmtu_timer.ep = (void *)new_inp;
|
||||
net->rxt_timer.ep = (void *)new_inp;
|
||||
net->fr_timer.ep = (void *)new_inp;
|
||||
}
|
||||
SCTP_INP_WUNLOCK(new_inp);
|
||||
SCTP_INP_WUNLOCK(old_inp);
|
||||
@ -3452,11 +3464,18 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
|
||||
}
|
||||
if ((SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
|
||||
(SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
|
||||
struct sctp_nets *netp;
|
||||
|
||||
if (asoc->asoc.alternate) {
|
||||
netp = asoc->asoc.alternate;
|
||||
} else {
|
||||
netp = asoc->asoc.primary_destination;
|
||||
}
|
||||
/*
|
||||
* there is nothing queued to send,
|
||||
* so I send shutdown
|
||||
*/
|
||||
sctp_send_shutdown(asoc, asoc->asoc.primary_destination);
|
||||
sctp_send_shutdown(asoc, netp);
|
||||
if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) ||
|
||||
(SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
|
||||
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
|
||||
@ -3464,7 +3483,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
|
||||
SCTP_SET_STATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_SENT);
|
||||
SCTP_CLEAR_SUBSTATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_PENDING);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, asoc->sctp_ep, asoc,
|
||||
asoc->asoc.primary_destination);
|
||||
netp);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc,
|
||||
asoc->asoc.primary_destination);
|
||||
sctp_chunk_output(inp, asoc, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_LOCKED);
|
||||
@ -3808,7 +3827,7 @@ sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id)
|
||||
*/
|
||||
int
|
||||
sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
|
||||
int set_scope, int from)
|
||||
struct sctp_nets **netp, int set_scope, int from)
|
||||
{
|
||||
/*
|
||||
* The following is redundant to the same lines in the
|
||||
@ -3942,7 +3961,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
|
||||
return (-1);
|
||||
}
|
||||
SCTP_INCR_RADDR_COUNT();
|
||||
bzero(net, sizeof(*net));
|
||||
bzero(net, sizeof(struct sctp_nets));
|
||||
(void)SCTP_GETTIME_TIMEVAL(&net->start_time);
|
||||
memcpy(&net->ro._l_addr, newaddr, newaddr->sa_len);
|
||||
switch (newaddr->sa_family) {
|
||||
@ -3968,6 +3987,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
|
||||
addr_inscope = 1;
|
||||
}
|
||||
net->failure_threshold = stcb->asoc.def_net_failure;
|
||||
net->pf_threshold = stcb->asoc.def_net_pf_threshold;
|
||||
if (addr_inscope == 0) {
|
||||
net->dest_state = (SCTP_ADDR_REACHABLE |
|
||||
SCTP_ADDR_OUT_OF_SCOPE);
|
||||
@ -4003,10 +4023,16 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
|
||||
if (newaddr->sa_family == AF_INET6)
|
||||
net->tos_flowlabel = stcb->asoc.default_flowlabel;
|
||||
#endif
|
||||
if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
|
||||
net->dest_state |= SCTP_ADDR_NOHB;
|
||||
} else {
|
||||
net->dest_state &= ~SCTP_ADDR_NOHB;
|
||||
}
|
||||
net->heart_beat_delay = stcb->asoc.heart_beat_delay;
|
||||
/* Init the timer structure */
|
||||
SCTP_OS_TIMER_INIT(&net->rxt_timer.timer);
|
||||
SCTP_OS_TIMER_INIT(&net->fr_timer.timer);
|
||||
SCTP_OS_TIMER_INIT(&net->pmtu_timer.timer);
|
||||
SCTP_OS_TIMER_INIT(&net->hb_timer.timer);
|
||||
|
||||
/* Now generate a route for this guy */
|
||||
#ifdef INET6
|
||||
@ -4153,8 +4179,6 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
|
||||
/* No route to current primary adopt new primary */
|
||||
stcb->asoc.primary_destination = net;
|
||||
}
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb,
|
||||
net);
|
||||
/* Validate primary is first */
|
||||
net = TAILQ_FIRST(&stcb->asoc.nets);
|
||||
if ((net != stcb->asoc.primary_destination) &&
|
||||
@ -4169,6 +4193,9 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
|
||||
TAILQ_INSERT_HEAD(&stcb->asoc.nets,
|
||||
stcb->asoc.primary_destination, sctp_next);
|
||||
}
|
||||
if (netp) {
|
||||
*netp = net;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -4393,7 +4420,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
|
||||
LIST_INSERT_HEAD(head, stcb, sctp_asocs);
|
||||
SCTP_INP_INFO_WUNLOCK();
|
||||
|
||||
if ((err = sctp_add_remote_addr(stcb, firstaddr, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) {
|
||||
if ((err = sctp_add_remote_addr(stcb, firstaddr, NULL, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) {
|
||||
/* failure.. memory error? */
|
||||
if (asoc->strmout) {
|
||||
SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
|
||||
@ -4418,7 +4445,6 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
|
||||
return (NULL);
|
||||
}
|
||||
/* Init all the timers */
|
||||
SCTP_OS_TIMER_INIT(&asoc->hb_timer.timer);
|
||||
SCTP_OS_TIMER_INIT(&asoc->dack_timer.timer);
|
||||
SCTP_OS_TIMER_INIT(&asoc->strreset_timer.timer);
|
||||
SCTP_OS_TIMER_INIT(&asoc->asconf_timer.timer);
|
||||
@ -4488,6 +4514,10 @@ sctp_remove_net(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
/* Clear net */
|
||||
asoc->last_control_chunk_from = NULL;
|
||||
}
|
||||
if (net == stcb->asoc.alternate) {
|
||||
sctp_free_remote_addr(stcb->asoc.alternate);
|
||||
stcb->asoc.alternate = NULL;
|
||||
}
|
||||
sctp_free_remote_addr(net);
|
||||
}
|
||||
|
||||
@ -4699,6 +4729,10 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
/* there is no asoc, really TSNH :-0 */
|
||||
return (1);
|
||||
}
|
||||
if (stcb->asoc.alternate) {
|
||||
sctp_free_remote_addr(stcb->asoc.alternate);
|
||||
stcb->asoc.alternate = NULL;
|
||||
}
|
||||
/* TEMP CODE */
|
||||
if (stcb->freed_from_where == 0) {
|
||||
/* Only record the first place free happened from */
|
||||
@ -4737,8 +4771,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
}
|
||||
}
|
||||
/* now clean up any other timers */
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->hb_timer.timer);
|
||||
asoc->hb_timer.self = NULL;
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
|
||||
asoc->dack_timer.self = NULL;
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
|
||||
@ -4762,12 +4794,12 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->delete_prim_timer.timer);
|
||||
asoc->delete_prim_timer.self = NULL;
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
(void)SCTP_OS_TIMER_STOP(&net->fr_timer.timer);
|
||||
net->fr_timer.self = NULL;
|
||||
(void)SCTP_OS_TIMER_STOP(&net->rxt_timer.timer);
|
||||
net->rxt_timer.self = NULL;
|
||||
(void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer);
|
||||
net->pmtu_timer.self = NULL;
|
||||
(void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer);
|
||||
net->hb_timer.self = NULL;
|
||||
}
|
||||
/* Now the read queue needs to be cleaned up (only once) */
|
||||
if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) {
|
||||
@ -4935,7 +4967,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
* Now restop the timers to be sure this is paranoia at is finest!
|
||||
*/
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->hb_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer);
|
||||
@ -4943,9 +4974,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer);
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
(void)SCTP_OS_TIMER_STOP(&net->fr_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&net->rxt_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer);
|
||||
}
|
||||
|
||||
asoc->strreset_timer.type = SCTP_TIMER_TYPE_NONE;
|
||||
@ -6189,7 +6220,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
if (stcb->asoc.ipv4_addr_legal) {
|
||||
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) {
|
||||
if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
@ -6198,7 +6229,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
if (stcb->asoc.ipv6_addr_legal) {
|
||||
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) {
|
||||
if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) {
|
||||
return (-2);
|
||||
}
|
||||
}
|
||||
@ -6289,7 +6320,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
|
||||
/* the assoc was freed? */
|
||||
return (-7);
|
||||
}
|
||||
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_4)) {
|
||||
if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_4)) {
|
||||
return (-8);
|
||||
}
|
||||
} else if (stcb_tmp == stcb) {
|
||||
@ -6376,7 +6407,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
|
||||
* we must add the address, no scope
|
||||
* set
|
||||
*/
|
||||
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_5)) {
|
||||
if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_5)) {
|
||||
return (-17);
|
||||
}
|
||||
} else if (stcb_tmp == stcb) {
|
||||
@ -6748,7 +6779,10 @@ sctp_set_primary_addr(struct sctp_tcb *stcb, struct sockaddr *sa,
|
||||
return (0);
|
||||
}
|
||||
stcb->asoc.primary_destination = net;
|
||||
net->dest_state &= ~SCTP_ADDR_WAS_PRIMARY;
|
||||
if (!(net->dest_state & SCTP_ADDR_PF) && (stcb->asoc.alternate)) {
|
||||
sctp_free_remote_addr(stcb->asoc.alternate);
|
||||
stcb->asoc.alternate = NULL;
|
||||
}
|
||||
net = TAILQ_FIRST(&stcb->asoc.nets);
|
||||
if (net != stcb->asoc.primary_destination) {
|
||||
/*
|
||||
|
@ -293,6 +293,8 @@ struct sctp_pcb {
|
||||
|
||||
uint16_t def_net_failure;
|
||||
|
||||
uint16_t def_net_pf_threshold;
|
||||
|
||||
/* number of streams to pre-open on a association */
|
||||
uint16_t pre_open_stream_count;
|
||||
uint16_t max_open_streams_intome;
|
||||
@ -582,7 +584,7 @@ void sctp_remove_laddr(struct sctp_laddr *);
|
||||
|
||||
void sctp_del_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *);
|
||||
|
||||
int sctp_add_remote_addr(struct sctp_tcb *, struct sockaddr *, int, int);
|
||||
int sctp_add_remote_addr(struct sctp_tcb *, struct sockaddr *, struct sctp_nets **, int, int);
|
||||
|
||||
void sctp_remove_net(struct sctp_tcb *, struct sctp_nets *);
|
||||
|
||||
|
@ -251,6 +251,7 @@ struct sctp_nets {
|
||||
* structure shared by all.
|
||||
*/
|
||||
struct sctp_timer pmtu_timer;
|
||||
struct sctp_timer hb_timer;
|
||||
|
||||
/*
|
||||
* The following two in combination equate to a route entry for v6
|
||||
@ -273,7 +274,6 @@ struct sctp_nets {
|
||||
|
||||
/* This is used for SHUTDOWN/SHUTDOWN-ACK/SEND or INIT timers */
|
||||
struct sctp_timer rxt_timer;
|
||||
struct sctp_timer fr_timer; /* for early fr */
|
||||
|
||||
/* last time in seconds I sent to it */
|
||||
struct timeval last_sent_time;
|
||||
@ -327,12 +327,15 @@ struct sctp_nets {
|
||||
uint32_t marked_retrans;/* number or DATA chunks marked for timer
|
||||
* based retransmissions */
|
||||
uint32_t marked_fastretrans;
|
||||
uint32_t heart_beat_delay; /* Heart Beat delay in ms */
|
||||
|
||||
/* if this guy is ok or not ... status */
|
||||
uint16_t dest_state;
|
||||
/* number of transmit failures to down this guy */
|
||||
/* number of timeouts to consider the destination unreachable */
|
||||
uint16_t failure_threshold;
|
||||
/* error stats on destination */
|
||||
/* number of timeouts to consider the destination potentially failed */
|
||||
uint16_t pf_threshold;
|
||||
/* error stats on the destination */
|
||||
uint16_t error_count;
|
||||
/* UDP port number in case of UDP tunneling */
|
||||
uint16_t port;
|
||||
@ -661,6 +664,7 @@ struct sctp_cc_functions {
|
||||
void (*sctp_cwnd_update_after_sack) (struct sctp_tcb *stcb,
|
||||
struct sctp_association *asoc,
|
||||
int accum_moved, int reneged_all, int will_exit);
|
||||
void (*sctp_cwnd_update_exit_pf) (struct sctp_tcb *stcb, struct sctp_nets *net);
|
||||
void (*sctp_cwnd_update_after_fr) (struct sctp_tcb *stcb,
|
||||
struct sctp_association *asoc);
|
||||
void (*sctp_cwnd_update_after_timeout) (struct sctp_tcb *stcb,
|
||||
@ -672,8 +676,6 @@ struct sctp_cc_functions {
|
||||
uint32_t * bottle_bw, uint32_t * on_queue);
|
||||
void (*sctp_cwnd_update_after_output) (struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net, int burst_limit);
|
||||
void (*sctp_cwnd_update_after_fr_timer) (struct sctp_inpcb *inp,
|
||||
struct sctp_tcb *stcb, struct sctp_nets *net);
|
||||
void (*sctp_cwnd_update_packet_transmitted) (struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net);
|
||||
void (*sctp_cwnd_update_tsn_acknowledged) (struct sctp_nets *net,
|
||||
@ -753,7 +755,6 @@ struct sctp_association {
|
||||
struct sctp_nonpad_sndrcvinfo def_send;
|
||||
|
||||
/* timers and such */
|
||||
struct sctp_timer hb_timer; /* hb timer */
|
||||
struct sctp_timer dack_timer; /* Delayed ack timer */
|
||||
struct sctp_timer asconf_timer; /* asconf */
|
||||
struct sctp_timer strreset_timer; /* stream reset */
|
||||
@ -828,6 +829,7 @@ struct sctp_association {
|
||||
uint8_t *mapping_array;
|
||||
/* primary destination to use */
|
||||
struct sctp_nets *primary_destination;
|
||||
struct sctp_nets *alternate; /* If primary is down or PF */
|
||||
/* For CMT */
|
||||
struct sctp_nets *last_net_cmt_send_started;
|
||||
/* last place I got a data chunk from */
|
||||
@ -1023,8 +1025,8 @@ struct sctp_association {
|
||||
unsigned int size_on_all_streams;
|
||||
unsigned int cnt_on_all_streams;
|
||||
|
||||
/* Heart Beat delay in ticks */
|
||||
unsigned int heart_beat_delay;
|
||||
/* Heart Beat delay in ms */
|
||||
uint32_t heart_beat_delay;
|
||||
|
||||
/* autoclose */
|
||||
unsigned int sctp_autoclose_ticks;
|
||||
@ -1094,6 +1096,8 @@ struct sctp_association {
|
||||
|
||||
uint16_t def_net_failure;
|
||||
|
||||
uint16_t def_net_pf_threshold;
|
||||
|
||||
/*
|
||||
* lock flag: 0 is ok to send, 1+ (duals as a retran count) is
|
||||
* awaiting ACK
|
||||
@ -1133,7 +1137,6 @@ struct sctp_association {
|
||||
uint8_t last_flags_delivered;
|
||||
uint8_t hb_ect_randombit;
|
||||
uint8_t hb_random_idx;
|
||||
uint8_t hb_is_disabled; /* is the hb disabled? */
|
||||
uint8_t default_tos;
|
||||
uint8_t asconf_del_pending; /* asconf delete last addr pending */
|
||||
|
||||
|
@ -83,16 +83,14 @@ sctp_init_sysctls()
|
||||
SCTP_BASE_SYSCTL(sctp_init_rtx_max_default) = SCTPCTL_INIT_RTX_MAX_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default) = SCTPCTL_ASSOC_RTX_MAX_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_path_rtx_max_default) = SCTPCTL_PATH_RTX_MAX_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_path_pf_threshold) = SCTPCTL_PATH_PF_THRESHOLD_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_add_more_threshold) = SCTPCTL_ADD_MORE_ON_OUTPUT_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default) = SCTPCTL_OUTGOING_STREAMS_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_cmt_on_off) = SCTPCTL_CMT_ON_OFF_DEFAULT;
|
||||
/* EY */
|
||||
SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) = SCTPCTL_NR_SACK_ON_OFF_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_cmt_use_dac) = SCTPCTL_CMT_USE_DAC_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_cmt_pf) = SCTPCTL_CMT_PF_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst) = SCTPCTL_CWND_MAXBURST_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_early_fr) = SCTPCTL_EARLY_FAST_RETRAN_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_early_fr_msec) = SCTPCTL_EARLY_FAST_RETRAN_MSEC_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_asconf_auth_nochk) = SCTPCTL_ASCONF_AUTH_NOCHK_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_auth_disable) = SCTPCTL_AUTH_DISABLE_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_nat_friendly) = SCTPCTL_NAT_FRIENDLY_DEFAULT;
|
||||
@ -494,6 +492,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
|
||||
xraddr.active = ((net->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE);
|
||||
xraddr.confirmed = ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0);
|
||||
xraddr.heartbeat_enabled = ((net->dest_state & SCTP_ADDR_NOHB) == 0);
|
||||
xraddr.potentially_failed = ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF);
|
||||
xraddr.rto = net->RTO;
|
||||
xraddr.max_path_rtx = net->failure_threshold;
|
||||
xraddr.rtx = net->marked_retrans;
|
||||
@ -502,6 +501,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
|
||||
xraddr.flight_size = net->flight_size;
|
||||
xraddr.mtu = net->mtu;
|
||||
xraddr.rtt = net->rtt / 1000;
|
||||
xraddr.heartbeat_interval = net->heart_beat_delay;
|
||||
xraddr.start_time.tv_sec = (uint32_t) net->start_time.tv_sec;
|
||||
xraddr.start_time.tv_usec = (uint32_t) net->start_time.tv_usec;
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
@ -633,16 +633,14 @@ sysctl_sctp_check(SYSCTL_HANDLER_ARGS)
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_init_rtx_max_default), SCTPCTL_INIT_RTX_MAX_MIN, SCTPCTL_INIT_RTX_MAX_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default), SCTPCTL_ASSOC_RTX_MAX_MIN, SCTPCTL_ASSOC_RTX_MAX_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_path_rtx_max_default), SCTPCTL_PATH_RTX_MAX_MIN, SCTPCTL_PATH_RTX_MAX_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_path_pf_threshold), SCTPCTL_PATH_PF_THRESHOLD_MIN, SCTPCTL_PATH_PF_THRESHOLD_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTPCTL_ADD_MORE_ON_OUTPUT_MIN, SCTPCTL_ADD_MORE_ON_OUTPUT_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default), SCTPCTL_OUTGOING_STREAMS_MIN, SCTPCTL_OUTGOING_STREAMS_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_on_off), SCTPCTL_CMT_ON_OFF_MIN, SCTPCTL_CMT_ON_OFF_MAX);
|
||||
/* EY */
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_nr_sack_on_off), SCTPCTL_NR_SACK_ON_OFF_MIN, SCTPCTL_NR_SACK_ON_OFF_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_use_dac), SCTPCTL_CMT_USE_DAC_MIN, SCTPCTL_CMT_USE_DAC_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_pf), SCTPCTL_CMT_PF_MIN, SCTPCTL_CMT_PF_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst), SCTPCTL_CWND_MAXBURST_MIN, SCTPCTL_CWND_MAXBURST_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_early_fr), SCTPCTL_EARLY_FAST_RETRAN_MIN, SCTPCTL_EARLY_FAST_RETRAN_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_early_fr_msec), SCTPCTL_EARLY_FAST_RETRAN_MSEC_MIN, SCTPCTL_EARLY_FAST_RETRAN_MSEC_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_asconf_auth_nochk), SCTPCTL_ASCONF_AUTH_NOCHK_MIN, SCTPCTL_ASCONF_AUTH_NOCHK_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_auth_disable), SCTPCTL_AUTH_DISABLE_MIN, SCTPCTL_AUTH_DISABLE_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_nat_friendly), SCTPCTL_NAT_FRIENDLY_MIN, SCTPCTL_NAT_FRIENDLY_MAX);
|
||||
@ -793,17 +791,6 @@ sysctl_stat_get(SYSCTL_HANDLER_ARGS)
|
||||
sb.sctps_timoautoclose += sarry->sctps_timoautoclose;
|
||||
sb.sctps_timoassockill += sarry->sctps_timoassockill;
|
||||
sb.sctps_timoinpkill += sarry->sctps_timoinpkill;
|
||||
sb.sctps_earlyfrstart += sarry->sctps_earlyfrstart;
|
||||
sb.sctps_earlyfrstop += sarry->sctps_earlyfrstop;
|
||||
sb.sctps_earlyfrmrkretrans += sarry->sctps_earlyfrmrkretrans;
|
||||
sb.sctps_earlyfrstpout += sarry->sctps_earlyfrstpout;
|
||||
sb.sctps_earlyfrstpidsck1 += sarry->sctps_earlyfrstpidsck1;
|
||||
sb.sctps_earlyfrstpidsck2 += sarry->sctps_earlyfrstpidsck2;
|
||||
sb.sctps_earlyfrstpidsck3 += sarry->sctps_earlyfrstpidsck3;
|
||||
sb.sctps_earlyfrstpidsck4 += sarry->sctps_earlyfrstpidsck4;
|
||||
sb.sctps_earlyfrstrid += sarry->sctps_earlyfrstrid;
|
||||
sb.sctps_earlyfrstrout += sarry->sctps_earlyfrstrout;
|
||||
sb.sctps_earlyfrstrtmr += sarry->sctps_earlyfrstrtmr;
|
||||
sb.sctps_hdrops += sarry->sctps_hdrops;
|
||||
sb.sctps_badsum += sarry->sctps_badsum;
|
||||
sb.sctps_noport += sarry->sctps_noport;
|
||||
@ -994,6 +981,10 @@ SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, path_rtx_max, CTLTYPE_UINT | CTLFLAG_
|
||||
&SCTP_BASE_SYSCTL(sctp_path_rtx_max_default), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_PATH_RTX_MAX_DESC);
|
||||
|
||||
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, path_pf_threshold, CTLTYPE_UINT | CTLFLAG_RW,
|
||||
&SCTP_BASE_SYSCTL(sctp_path_pf_threshold), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_PATH_PF_THRESHOLD_DESC);
|
||||
|
||||
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, add_more_on_output, CTLTYPE_UINT | CTLFLAG_RW,
|
||||
&SCTP_BASE_SYSCTL(sctp_add_more_threshold), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_ADD_MORE_ON_OUTPUT_DESC);
|
||||
@ -1014,22 +1005,10 @@ SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, cmt_use_dac, CTLTYPE_UINT | CTLFLAG_R
|
||||
&SCTP_BASE_SYSCTL(sctp_cmt_use_dac), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_CMT_USE_DAC_DESC);
|
||||
|
||||
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, cmt_pf, CTLTYPE_UINT | CTLFLAG_RW,
|
||||
&SCTP_BASE_SYSCTL(sctp_cmt_pf), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_CMT_PF_DESC);
|
||||
|
||||
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, cwnd_maxburst, CTLTYPE_UINT | CTLFLAG_RW,
|
||||
&SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_CWND_MAXBURST_DESC);
|
||||
|
||||
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, early_fast_retran, CTLTYPE_UINT | CTLFLAG_RW,
|
||||
&SCTP_BASE_SYSCTL(sctp_early_fr), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_EARLY_FAST_RETRAN_DESC);
|
||||
|
||||
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, early_fast_retran_msec, CTLTYPE_UINT | CTLFLAG_RW,
|
||||
&SCTP_BASE_SYSCTL(sctp_early_fr_msec), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_EARLY_FAST_RETRAN_MSEC_DESC);
|
||||
|
||||
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, asconf_auth_nochk, CTLTYPE_UINT | CTLFLAG_RW,
|
||||
&SCTP_BASE_SYSCTL(sctp_asconf_auth_nochk), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_ASCONF_AUTH_NOCHK_DESC);
|
||||
|
@ -74,16 +74,14 @@ struct sctp_sysctl {
|
||||
uint32_t sctp_init_rtx_max_default;
|
||||
uint32_t sctp_assoc_rtx_max_default;
|
||||
uint32_t sctp_path_rtx_max_default;
|
||||
uint32_t sctp_path_pf_threshold;
|
||||
uint32_t sctp_add_more_threshold;
|
||||
uint32_t sctp_nr_outgoing_streams_default;
|
||||
uint32_t sctp_cmt_on_off;
|
||||
uint32_t sctp_cmt_use_dac;
|
||||
/* EY 5/5/08 - nr_sack flag variable */
|
||||
uint32_t sctp_nr_sack_on_off;
|
||||
uint32_t sctp_cmt_pf;
|
||||
uint32_t sctp_use_cwnd_based_maxburst;
|
||||
uint32_t sctp_early_fr;
|
||||
uint32_t sctp_early_fr_msec;
|
||||
uint32_t sctp_asconf_auth_nochk;
|
||||
uint32_t sctp_auth_disable;
|
||||
uint32_t sctp_nat_friendly;
|
||||
@ -322,6 +320,12 @@ struct sctp_sysctl {
|
||||
#define SCTPCTL_PATH_RTX_MAX_MAX 0xFFFFFFFF
|
||||
#define SCTPCTL_PATH_RTX_MAX_DEFAULT SCTP_DEF_MAX_PATH_RTX
|
||||
|
||||
/* path_pf_threshold: threshold for considering the path potentially failed */
|
||||
#define SCTPCTL_PATH_PF_THRESHOLD_DESC "Default potentially failed threshold"
|
||||
#define SCTPCTL_PATH_PF_THRESHOLD_MIN 0
|
||||
#define SCTPCTL_PATH_PF_THRESHOLD_MAX 0xFFFF
|
||||
#define SCTPCTL_PATH_PF_THRESHOLD_DEFAULT SCTPCTL_PATH_PF_THRESHOLD_MAX
|
||||
|
||||
/* add_more_on_output: When space-wise is it worthwhile to try to add more to a socket send buffer */
|
||||
#define SCTPCTL_ADD_MORE_ON_OUTPUT_DESC "When space-wise is it worthwhile to try to add more to a socket send buffer"
|
||||
#define SCTPCTL_ADD_MORE_ON_OUTPUT_MIN 0
|
||||
@ -352,30 +356,12 @@ struct sctp_sysctl {
|
||||
#define SCTPCTL_CMT_USE_DAC_MAX 1
|
||||
#define SCTPCTL_CMT_USE_DAC_DEFAULT 0
|
||||
|
||||
/* JRS 5/2107 - CMT PF type flag */
|
||||
#define SCTPCTL_CMT_PF_DESC "CMT PF type flag"
|
||||
#define SCTPCTL_CMT_PF_MIN 0
|
||||
#define SCTPCTL_CMT_PF_MAX 2
|
||||
#define SCTPCTL_CMT_PF_DEFAULT 0
|
||||
|
||||
/* cwnd_maxburst: Use a CWND adjusting maxburst */
|
||||
#define SCTPCTL_CWND_MAXBURST_DESC "Use a CWND adjusting maxburst"
|
||||
#define SCTPCTL_CWND_MAXBURST_MIN 0
|
||||
#define SCTPCTL_CWND_MAXBURST_MAX 1
|
||||
#define SCTPCTL_CWND_MAXBURST_DEFAULT 1
|
||||
|
||||
/* early_fast_retran: Early Fast Retransmit with timer */
|
||||
#define SCTPCTL_EARLY_FAST_RETRAN_DESC "Early Fast Retransmit with timer"
|
||||
#define SCTPCTL_EARLY_FAST_RETRAN_MIN 0
|
||||
#define SCTPCTL_EARLY_FAST_RETRAN_MAX 0xFFFFFFFF
|
||||
#define SCTPCTL_EARLY_FAST_RETRAN_DEFAULT 0
|
||||
|
||||
/* early_fast_retran_msec: Early Fast Retransmit minimum timer value */
|
||||
#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_DESC "Early Fast Retransmit minimum timer value"
|
||||
#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_MIN 0
|
||||
#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_MAX 0xFFFFFFFF
|
||||
#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_DEFAULT SCTP_MINFR_MSEC_TIMER
|
||||
|
||||
/* asconf_auth_nochk: Disable SCTP ASCONF AUTH requirement */
|
||||
#define SCTPCTL_ASCONF_AUTH_NOCHK_DESC "Disable SCTP ASCONF AUTH requirement"
|
||||
#define SCTPCTL_ASCONF_AUTH_NOCHK_MIN 0
|
||||
|
@ -54,103 +54,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/udp.h>
|
||||
|
||||
|
||||
void
|
||||
sctp_early_fr_timer(struct sctp_inpcb *inp,
|
||||
struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net)
|
||||
{
|
||||
struct sctp_tmit_chunk *chk, *pchk;
|
||||
struct timeval now, min_wait, tv;
|
||||
unsigned int cur_rto, cnt = 0, cnt_resend = 0;
|
||||
|
||||
/* an early FR is occuring. */
|
||||
(void)SCTP_GETTIME_TIMEVAL(&now);
|
||||
/* get cur rto in micro-seconds */
|
||||
if (net->lastsa == 0) {
|
||||
/* Hmm no rtt estimate yet? */
|
||||
cur_rto = stcb->asoc.initial_rto >> 2;
|
||||
} else {
|
||||
|
||||
cur_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
|
||||
}
|
||||
if (cur_rto < SCTP_BASE_SYSCTL(sctp_early_fr_msec)) {
|
||||
cur_rto = SCTP_BASE_SYSCTL(sctp_early_fr_msec);
|
||||
}
|
||||
cur_rto *= 1000;
|
||||
tv.tv_sec = cur_rto / 1000000;
|
||||
tv.tv_usec = cur_rto % 1000000;
|
||||
min_wait = now;
|
||||
timevalsub(&min_wait, &tv);
|
||||
if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) {
|
||||
/*
|
||||
* if we hit here, we don't have enough seconds on the clock
|
||||
* to account for the RTO. We just let the lower seconds be
|
||||
* the bounds and don't worry about it. This may mean we
|
||||
* will mark a lot more than we should.
|
||||
*/
|
||||
min_wait.tv_sec = min_wait.tv_usec = 0;
|
||||
}
|
||||
TAILQ_FOREACH_REVERSE_SAFE(chk, &stcb->asoc.sent_queue, sctpchunk_listhead, sctp_next, pchk) {
|
||||
if (chk->whoTo != net) {
|
||||
continue;
|
||||
}
|
||||
if (chk->sent == SCTP_DATAGRAM_RESEND)
|
||||
cnt_resend++;
|
||||
else if ((chk->sent > SCTP_DATAGRAM_UNSENT) &&
|
||||
(chk->sent < SCTP_DATAGRAM_RESEND)) {
|
||||
/* pending, may need retran */
|
||||
if (chk->sent_rcv_time.tv_sec > min_wait.tv_sec) {
|
||||
/*
|
||||
* we have reached a chunk that was sent
|
||||
* some seconds past our min.. forget it we
|
||||
* will find no more to send.
|
||||
*/
|
||||
continue;
|
||||
} else if (chk->sent_rcv_time.tv_sec == min_wait.tv_sec) {
|
||||
/*
|
||||
* we must look at the micro seconds to
|
||||
* know.
|
||||
*/
|
||||
if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) {
|
||||
/*
|
||||
* ok it was sent after our boundary
|
||||
* time.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_EARLYFR_LOGGING_ENABLE) {
|
||||
sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count,
|
||||
4, SCTP_FR_MARKED_EARLY);
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_earlyfrmrkretrans);
|
||||
chk->sent = SCTP_DATAGRAM_RESEND;
|
||||
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
|
||||
/* double book size since we are doing an early FR */
|
||||
chk->book_size_scale++;
|
||||
cnt += chk->send_size;
|
||||
if ((cnt + net->flight_size) > net->cwnd) {
|
||||
/* Mark all we could possibly resend */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cnt) {
|
||||
/*
|
||||
* JRS - Use the congestion control given in the congestion
|
||||
* control module
|
||||
*/
|
||||
stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer(inp, stcb, net);
|
||||
} else if (cnt_resend) {
|
||||
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
/* Restart it? */
|
||||
if (net->flight_size < net->cwnd) {
|
||||
SCTP_STAT_INCR(sctps_earlyfrstrtmr);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sctp_audit_retranmission_queue(struct sctp_association *asoc)
|
||||
{
|
||||
@ -195,44 +98,23 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
/* We had a threshold failure */
|
||||
if (net->dest_state & SCTP_ADDR_REACHABLE) {
|
||||
net->dest_state &= ~SCTP_ADDR_REACHABLE;
|
||||
net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
|
||||
net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY;
|
||||
if (net == stcb->asoc.primary_destination) {
|
||||
net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
|
||||
}
|
||||
/*
|
||||
* JRS 5/14/07 - If a destination is
|
||||
* unreachable, the PF bit is turned off.
|
||||
* This allows an unambiguous use of the PF
|
||||
* bit for destinations that are reachable
|
||||
* but potentially failed. If the
|
||||
* destination is set to the unreachable
|
||||
* state, also set the destination to the PF
|
||||
* state.
|
||||
*/
|
||||
/*
|
||||
* Add debug message here if destination is
|
||||
* not in PF state.
|
||||
*/
|
||||
/* Stop any running T3 timers here? */
|
||||
if ((stcb->asoc.sctp_cmt_on_off > 0) &&
|
||||
(stcb->asoc.sctp_cmt_pf > 0)) {
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
|
||||
net);
|
||||
}
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
|
||||
stcb,
|
||||
SCTP_FAILED_THRESHOLD,
|
||||
(void *)net, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
} else if ((net->pf_threshold < net->failure_threshold) &&
|
||||
(net->error_count > net->pf_threshold)) {
|
||||
if (!(net->dest_state & SCTP_ADDR_PF)) {
|
||||
net->dest_state |= SCTP_ADDR_PF;
|
||||
net->last_active = sctp_get_tick_count();
|
||||
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
|
||||
}
|
||||
}
|
||||
/*********HOLD THIS COMMENT FOR PATCH OF ALTERNATE
|
||||
*********ROUTING CODE
|
||||
*/
|
||||
/*********HOLD THIS COMMENT FOR END OF PATCH OF ALTERNATE
|
||||
*********ROUTING CODE
|
||||
*/
|
||||
}
|
||||
if (stcb == NULL)
|
||||
return (0);
|
||||
@ -407,31 +289,10 @@ sctp_find_alternate_net(struct sctp_tcb *stcb,
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* JRS 5/14/07 - After all destination have been considered
|
||||
* as alternates, check to see if there was some active
|
||||
* destination (not in PF state). If not, check to see if
|
||||
* there was some PF destination with the minimum number of
|
||||
* errors. If not, return the original destination. If
|
||||
* there is a min_errors_net, remove the PF flag from that
|
||||
* destination, set the cwnd to one or two MTUs, and return
|
||||
* the destination as an alt. If there was some active
|
||||
* destination with a highest cwnd, return the destination
|
||||
* as an alt.
|
||||
*/
|
||||
if (max_cwnd_net == NULL) {
|
||||
if (min_errors_net == NULL) {
|
||||
return (net);
|
||||
}
|
||||
min_errors_net->dest_state &= ~SCTP_ADDR_PF;
|
||||
min_errors_net->cwnd = min_errors_net->mtu * stcb->asoc.sctp_cmt_pf;
|
||||
if (SCTP_OS_TIMER_PENDING(&min_errors_net->rxt_timer.timer)) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
|
||||
stcb, min_errors_net,
|
||||
SCTP_FROM_SCTP_TIMER + SCTP_LOC_2);
|
||||
}
|
||||
SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to active with %d errors.\n",
|
||||
min_errors_net, min_errors_net->error_count);
|
||||
return (min_errors_net);
|
||||
} else {
|
||||
return (max_cwnd_net);
|
||||
@ -646,15 +507,12 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
|
||||
/* get cur rto in micro-seconds */
|
||||
cur_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
|
||||
cur_rto *= 1000;
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
|
||||
sctp_log_fr(cur_rto,
|
||||
stcb->asoc.peers_rwnd,
|
||||
window_probe,
|
||||
SCTP_FR_T3_MARK_TIME);
|
||||
sctp_log_fr(net->flight_size,
|
||||
SCTP_OS_TIMER_PENDING(&net->fr_timer.timer),
|
||||
SCTP_OS_TIMER_ACTIVE(&net->fr_timer.timer),
|
||||
SCTP_FR_CWND_REPORT);
|
||||
sctp_log_fr(net->flight_size, 0, 0, SCTP_FR_CWND_REPORT);
|
||||
sctp_log_fr(net->flight_size, net->cwnd, stcb->asoc.total_flight, SCTP_FR_CWND_REPORT);
|
||||
}
|
||||
tv.tv_sec = cur_rto / 1000000;
|
||||
@ -670,7 +528,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
|
||||
*/
|
||||
min_wait.tv_sec = min_wait.tv_usec = 0;
|
||||
}
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
|
||||
sctp_log_fr(cur_rto, now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME);
|
||||
sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME);
|
||||
}
|
||||
@ -717,7 +575,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
|
||||
*/
|
||||
|
||||
/* validate its been outstanding long enough */
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
|
||||
sctp_log_fr(chk->rec.data.TSN_seq,
|
||||
chk->sent_rcv_time.tv_sec,
|
||||
chk->sent_rcv_time.tv_usec,
|
||||
@ -729,7 +587,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
|
||||
* some seconds past our min.. forget it we
|
||||
* will find no more to send.
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
|
||||
sctp_log_fr(0,
|
||||
chk->sent_rcv_time.tv_sec,
|
||||
chk->sent_rcv_time.tv_usec,
|
||||
@ -747,12 +605,6 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
|
||||
* ok it was sent after our boundary
|
||||
* time.
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
|
||||
sctp_log_fr(0,
|
||||
chk->sent_rcv_time.tv_sec,
|
||||
chk->sent_rcv_time.tv_usec,
|
||||
SCTP_FR_T3_STOPPED);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -791,7 +643,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
|
||||
tsnfirst = chk->rec.data.TSN_seq;
|
||||
}
|
||||
tsnlast = chk->rec.data.TSN_seq;
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
|
||||
sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count,
|
||||
0, SCTP_FR_T3_MARKED);
|
||||
}
|
||||
@ -860,7 +712,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
|
||||
/* we did not subtract the same things? */
|
||||
audit_tf = 1;
|
||||
}
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
|
||||
sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT);
|
||||
}
|
||||
#ifdef SCTP_DEBUG
|
||||
@ -978,40 +830,72 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
|
||||
win_probe = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* JRS 5/14/07 - If CMT PF is on and the destination if not already
|
||||
* in PF state, set the destination to PF state and store the
|
||||
* current time as the time that the destination was last active. In
|
||||
* addition, find an alternate destination with PF-based
|
||||
* find_alt_net().
|
||||
*/
|
||||
if ((stcb->asoc.sctp_cmt_on_off > 0) &&
|
||||
(stcb->asoc.sctp_cmt_pf > 0)) {
|
||||
if ((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF) {
|
||||
net->dest_state |= SCTP_ADDR_PF;
|
||||
net->last_active = sctp_get_tick_count();
|
||||
SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from active to PF.\n",
|
||||
net);
|
||||
if (win_probe == 0) {
|
||||
/* We don't do normal threshold management on window probes */
|
||||
if (sctp_threshold_management(inp, stcb, net,
|
||||
stcb->asoc.max_send_times)) {
|
||||
/* Association was destroyed */
|
||||
return (1);
|
||||
} else {
|
||||
if (net != stcb->asoc.primary_destination) {
|
||||
/* send a immediate HB if our RTO is stale */
|
||||
struct timeval now;
|
||||
unsigned int ms_goneby;
|
||||
|
||||
(void)SCTP_GETTIME_TIMEVAL(&now);
|
||||
if (net->last_sent_time.tv_sec) {
|
||||
ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000;
|
||||
} else {
|
||||
ms_goneby = 0;
|
||||
}
|
||||
if ((net->dest_state & SCTP_ADDR_PF) == 0) {
|
||||
if ((ms_goneby > net->RTO) || (net->RTO == 0)) {
|
||||
/*
|
||||
* no recent feed back in an
|
||||
* RTO or more, request a
|
||||
* RTT update
|
||||
*/
|
||||
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
alt = sctp_find_alternate_net(stcb, net, 2);
|
||||
} else if (stcb->asoc.sctp_cmt_on_off > 0) {
|
||||
} else {
|
||||
/*
|
||||
* CMT: Using RTX_SSTHRESH policy for CMT. If CMT is being
|
||||
* used, then pick dest with largest ssthresh for any
|
||||
* retransmission.
|
||||
* For a window probe we don't penalize the net's but only
|
||||
* the association. This may fail it if SACKs are not coming
|
||||
* back. If sack's are coming with rwnd locked at 0, we will
|
||||
* continue to hold things waiting for rwnd to raise
|
||||
*/
|
||||
alt = sctp_find_alternate_net(stcb, net, 1);
|
||||
/*
|
||||
* CUCv2: If a different dest is picked for the
|
||||
* retransmission, then new (rtx-)pseudo_cumack needs to be
|
||||
* tracked for orig dest. Let CUCv2 track new (rtx-)
|
||||
* pseudo-cumack always.
|
||||
*/
|
||||
net->find_pseudo_cumack = 1;
|
||||
net->find_rtx_pseudo_cumack = 1;
|
||||
} else { /* CMT is OFF */
|
||||
if (sctp_threshold_management(inp, stcb, NULL,
|
||||
stcb->asoc.max_send_times)) {
|
||||
/* Association was destroyed */
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
if (stcb->asoc.sctp_cmt_on_off > 0) {
|
||||
if (net->pf_threshold < net->failure_threshold) {
|
||||
alt = sctp_find_alternate_net(stcb, net, 2);
|
||||
} else {
|
||||
/*
|
||||
* CMT: Using RTX_SSTHRESH policy for CMT. If CMT is
|
||||
* being used, then pick dest with largest ssthresh
|
||||
* for any retransmission.
|
||||
*/
|
||||
alt = sctp_find_alternate_net(stcb, net, 1);
|
||||
/*
|
||||
* CUCv2: If a different dest is picked for the
|
||||
* retransmission, then new (rtx-)pseudo_cumack
|
||||
* needs to be tracked for orig dest. Let CUCv2
|
||||
* track new (rtx-) pseudo-cumack always.
|
||||
*/
|
||||
net->find_pseudo_cumack = 1;
|
||||
net->find_rtx_pseudo_cumack = 1;
|
||||
}
|
||||
} else {
|
||||
alt = sctp_find_alternate_net(stcb, net, 0);
|
||||
}
|
||||
|
||||
num_mk = 0;
|
||||
num_abandoned = 0;
|
||||
(void)sctp_mark_all_for_resend(stcb, net, alt, win_probe,
|
||||
@ -1033,52 +917,8 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
|
||||
|
||||
/* Backoff the timer and cwnd */
|
||||
sctp_backoff_on_timeout(stcb, net, win_probe, num_mk, num_abandoned);
|
||||
if (win_probe == 0) {
|
||||
/* We don't do normal threshold management on window probes */
|
||||
if (sctp_threshold_management(inp, stcb, net,
|
||||
stcb->asoc.max_send_times)) {
|
||||
/* Association was destroyed */
|
||||
return (1);
|
||||
} else {
|
||||
if (net != stcb->asoc.primary_destination) {
|
||||
/* send a immediate HB if our RTO is stale */
|
||||
struct timeval now;
|
||||
unsigned int ms_goneby;
|
||||
|
||||
(void)SCTP_GETTIME_TIMEVAL(&now);
|
||||
if (net->last_sent_time.tv_sec) {
|
||||
ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000;
|
||||
} else {
|
||||
ms_goneby = 0;
|
||||
}
|
||||
if ((ms_goneby > net->RTO) || (net->RTO == 0)) {
|
||||
/*
|
||||
* no recent feed back in an RTO or
|
||||
* more, request a RTT update
|
||||
*/
|
||||
if (sctp_send_hb(stcb, 1, net, SCTP_SO_NOT_LOCKED) < 0)
|
||||
/*
|
||||
* Less than 0 means we lost
|
||||
* the assoc
|
||||
*/
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* For a window probe we don't penalize the net's but only
|
||||
* the association. This may fail it if SACKs are not coming
|
||||
* back. If sack's are coming with rwnd locked at 0, we will
|
||||
* continue to hold things waiting for rwnd to raise
|
||||
*/
|
||||
if (sctp_threshold_management(inp, stcb, NULL,
|
||||
stcb->asoc.max_send_times)) {
|
||||
/* Association was destroyed */
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
|
||||
if ((!(net->dest_state & SCTP_ADDR_REACHABLE)) ||
|
||||
(net->dest_state & SCTP_ADDR_PF)) {
|
||||
/* Move all pending over too */
|
||||
sctp_move_chunks_from_net(stcb, net);
|
||||
|
||||
@ -1106,23 +946,12 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
|
||||
* change-primary then this flag must be cleared
|
||||
* from any net structures.
|
||||
*/
|
||||
if (sctp_set_primary_addr(stcb,
|
||||
(struct sockaddr *)NULL,
|
||||
alt) == 0) {
|
||||
net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
|
||||
if (stcb->asoc.alternate) {
|
||||
sctp_free_remote_addr(stcb->asoc.alternate);
|
||||
}
|
||||
stcb->asoc.alternate = alt;
|
||||
atomic_add_int(&stcb->asoc.alternate->ref_count, 1);
|
||||
}
|
||||
} else if ((stcb->asoc.sctp_cmt_on_off > 0) &&
|
||||
(stcb->asoc.sctp_cmt_pf > 0) &&
|
||||
((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
|
||||
/*
|
||||
* JRS 5/14/07 - If the destination hasn't failed completely
|
||||
* but is in PF state, a PF-heartbeat needs to be sent
|
||||
* manually.
|
||||
*/
|
||||
if (sctp_send_hb(stcb, 1, net, SCTP_SO_NOT_LOCKED) < 0)
|
||||
/* Return less than 0 means we lost the association */
|
||||
return (1);
|
||||
}
|
||||
/*
|
||||
* Special case for cookie-echo'ed case, we don't do output but must
|
||||
@ -1324,7 +1153,7 @@ sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
atomic_add_int(&alt->ref_count, 1);
|
||||
}
|
||||
}
|
||||
if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
|
||||
if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
|
||||
/*
|
||||
* If the address went un-reachable, we need to move to
|
||||
* alternates for ALL chk's in queue
|
||||
@ -1414,7 +1243,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
|
||||
chk->sent = SCTP_DATAGRAM_RESEND;
|
||||
}
|
||||
if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
|
||||
if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
|
||||
/*
|
||||
* If the address went un-reachable, we need to move
|
||||
* to the alternate for ALL chunks in queue
|
||||
@ -1569,11 +1398,15 @@ sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp,
|
||||
|
||||
int
|
||||
sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net, int cnt_of_unconf)
|
||||
struct sctp_nets *net)
|
||||
{
|
||||
int ret;
|
||||
uint8_t net_was_pf;
|
||||
|
||||
net_was_pf = 0;
|
||||
if (net) {
|
||||
if (net->dest_state & SCTP_ADDR_PF) {
|
||||
net_was_pf = 1;
|
||||
}
|
||||
if (net->hb_responded == 0) {
|
||||
if (net->ro._s_addr) {
|
||||
/*
|
||||
@ -1585,6 +1418,10 @@ sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
net->src_addr_selected = 0;
|
||||
}
|
||||
sctp_backoff_on_timeout(stcb, net, 1, 0, 0);
|
||||
if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
|
||||
/* Assoc is over */
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
/* Zero PBA, if it needs it */
|
||||
if (net->partial_bytes_acked) {
|
||||
@ -1596,41 +1433,13 @@ sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
(TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
|
||||
sctp_audit_stream_queues_for_size(inp, stcb);
|
||||
}
|
||||
/* Send a new HB, this will do threshold managment, pick a new dest */
|
||||
if (cnt_of_unconf == 0) {
|
||||
if (sctp_send_hb(stcb, 0, NULL, SCTP_SO_NOT_LOCKED) < 0) {
|
||||
return (1);
|
||||
}
|
||||
} else {
|
||||
if (!(net->dest_state & SCTP_ADDR_NOHB) &&
|
||||
!((net_was_pf == 0) && (net->dest_state & SCTP_ADDR_PF))) {
|
||||
/*
|
||||
* this will send out extra hb's up to maxburst if there are
|
||||
* any unconfirmed addresses.
|
||||
* when move to PF during threshold mangement, a HB has been
|
||||
* queued in that routine
|
||||
*/
|
||||
uint32_t cnt_sent = 0;
|
||||
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
|
||||
(net->dest_state & SCTP_ADDR_REACHABLE)) {
|
||||
cnt_sent++;
|
||||
if (net->hb_responded == 0) {
|
||||
/* Did we respond last time? */
|
||||
if (net->ro._s_addr) {
|
||||
sctp_free_ifa(net->ro._s_addr);
|
||||
net->ro._s_addr = NULL;
|
||||
net->src_addr_selected = 0;
|
||||
}
|
||||
}
|
||||
ret = sctp_send_hb(stcb, 1, net, SCTP_SO_NOT_LOCKED);
|
||||
if (ret < 0)
|
||||
return 1;
|
||||
else if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
if (SCTP_BASE_SYSCTL(sctp_hb_maxburst) &&
|
||||
(cnt_sent >= SCTP_BASE_SYSCTL(sctp_hb_maxburst)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@ -1733,7 +1542,14 @@ sctp_autoclose_timer(struct sctp_inpcb *inp,
|
||||
*/
|
||||
if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
|
||||
/* only send SHUTDOWN 1st time thru */
|
||||
sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
|
||||
struct sctp_nets *netp;
|
||||
|
||||
if (stcb->asoc.alternate) {
|
||||
netp = stcb->asoc.alternate;
|
||||
} else {
|
||||
netp = stcb->asoc.primary_destination;
|
||||
}
|
||||
sctp_send_shutdown(stcb, netp);
|
||||
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
|
||||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
|
||||
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
|
||||
@ -1742,10 +1558,10 @@ sctp_autoclose_timer(struct sctp_inpcb *inp,
|
||||
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
|
||||
stcb->sctp_ep, stcb,
|
||||
asoc->primary_destination);
|
||||
netp);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
|
||||
stcb->sctp_ep, stcb,
|
||||
asoc->primary_destination);
|
||||
netp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -42,10 +42,6 @@ __FBSDID("$FreeBSD$");
|
||||
#define SCTP_RTT_SHIFT 3
|
||||
#define SCTP_RTT_VAR_SHIFT 2
|
||||
|
||||
void
|
||||
sctp_early_fr_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net);
|
||||
|
||||
struct sctp_nets *
|
||||
sctp_find_alternate_net(struct sctp_tcb *,
|
||||
struct sctp_nets *, int mode);
|
||||
@ -65,7 +61,7 @@ sctp_shutdown_timer(struct sctp_inpcb *, struct sctp_tcb *,
|
||||
struct sctp_nets *);
|
||||
int
|
||||
sctp_heartbeat_timer(struct sctp_inpcb *, struct sctp_tcb *,
|
||||
struct sctp_nets *, int);
|
||||
struct sctp_nets *);
|
||||
|
||||
int
|
||||
sctp_cookie_timer(struct sctp_inpcb *, struct sctp_tcb *,
|
||||
|
@ -329,7 +329,8 @@ struct sctp_paddr_change {
|
||||
#define SCTP_ADDR_CONFIRMED 0x0006
|
||||
|
||||
#define SCTP_ACTIVE 0x0001 /* SCTP_ADDR_REACHABLE */
|
||||
#define SCTP_INACTIVE 0x0002 /* SCTP_ADDR_NOT_REACHABLE */
|
||||
#define SCTP_INACTIVE 0x0002 /* neither SCTP_ADDR_REACHABLE nor
|
||||
* SCTP_ADDR_UNCONFIRMED */
|
||||
#define SCTP_UNCONFIRMED 0x0200 /* SCTP_ADDR_UNCONFIRMED */
|
||||
|
||||
/* remote error events */
|
||||
@ -516,6 +517,13 @@ struct sctp_paddrparams {
|
||||
#define SPP_IPV6_FLOWLABEL 0x00000100
|
||||
#define SPP_IPV4_TOS 0x00000200
|
||||
|
||||
struct sctp_paddrthlds {
|
||||
sctp_assoc_t spt_assoc_id;
|
||||
struct sockaddr_storage spt_address;
|
||||
uint16_t spt_pathmaxrxt;
|
||||
uint16_t spt_pathpfthld;
|
||||
};
|
||||
|
||||
struct sctp_paddrinfo {
|
||||
struct sockaddr_storage spinfo_address;
|
||||
sctp_assoc_t spinfo_assoc_id;
|
||||
@ -978,18 +986,8 @@ struct sctpstat {
|
||||
* fired */
|
||||
uint32_t sctps_timoassockill; /* Number of asoc free timers expired */
|
||||
uint32_t sctps_timoinpkill; /* Number of inp free timers expired */
|
||||
/* Early fast retransmission counters */
|
||||
uint32_t sctps_earlyfrstart;
|
||||
uint32_t sctps_earlyfrstop;
|
||||
uint32_t sctps_earlyfrmrkretrans;
|
||||
uint32_t sctps_earlyfrstpout;
|
||||
uint32_t sctps_earlyfrstpidsck1;
|
||||
uint32_t sctps_earlyfrstpidsck2;
|
||||
uint32_t sctps_earlyfrstpidsck3;
|
||||
uint32_t sctps_earlyfrstpidsck4;
|
||||
uint32_t sctps_earlyfrstrid;
|
||||
uint32_t sctps_earlyfrstrout;
|
||||
uint32_t sctps_earlyfrstrtmr;
|
||||
/* former early FR counters */
|
||||
uint32_t sctps_spare[11];
|
||||
/* others */
|
||||
uint32_t sctps_hdrops; /* packet shorter than header */
|
||||
uint32_t sctps_badsum; /* checksum error */
|
||||
@ -1162,9 +1160,11 @@ struct xsctp_raddr {
|
||||
uint8_t active; /* sctpAssocLocalRemEntry 3 */
|
||||
uint8_t confirmed; /* */
|
||||
uint8_t heartbeat_enabled; /* sctpAssocLocalRemEntry 4 */
|
||||
uint8_t potentially_failed;
|
||||
struct sctp_timeval start_time; /* sctpAssocLocalRemEntry 8 */
|
||||
uint32_t rtt;
|
||||
uint32_t extra_padding[32]; /* future */
|
||||
uint32_t heartbeat_interval;
|
||||
uint32_t extra_padding[31]; /* future */
|
||||
};
|
||||
|
||||
#define SCTP_MAX_LOGGING_SIZE 30000
|
||||
|
@ -275,33 +275,8 @@ sctp_notify(struct sctp_inpcb *inp,
|
||||
*/
|
||||
if (net->dest_state & SCTP_ADDR_REACHABLE) {
|
||||
/* Ok that destination is NOT reachable */
|
||||
SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n",
|
||||
net->error_count,
|
||||
net->failure_threshold,
|
||||
net);
|
||||
|
||||
net->dest_state &= ~SCTP_ADDR_REACHABLE;
|
||||
net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
|
||||
/*
|
||||
* JRS 5/14/07 - If a destination is unreachable,
|
||||
* the PF bit is turned off. This allows an
|
||||
* unambiguous use of the PF bit for destinations
|
||||
* that are reachable but potentially failed. If the
|
||||
* destination is set to the unreachable state, also
|
||||
* set the destination to the PF state.
|
||||
*/
|
||||
/*
|
||||
* Add debug message here if destination is not in
|
||||
* PF state.
|
||||
*/
|
||||
/* Stop any running T3 timers here? */
|
||||
if ((stcb->asoc.sctp_cmt_on_off > 0) &&
|
||||
(stcb->asoc.sctp_cmt_pf > 0)) {
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
|
||||
net);
|
||||
}
|
||||
net->error_count = net->failure_threshold + 1;
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
|
||||
stcb, SCTP_FAILED_THRESHOLD,
|
||||
(void *)net, SCTP_SO_NOT_LOCKED);
|
||||
@ -837,9 +812,15 @@ sctp_disconnect(struct socket *so)
|
||||
if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
|
||||
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
|
||||
/* only send SHUTDOWN 1st time thru */
|
||||
struct sctp_nets *netp;
|
||||
|
||||
if (stcb->asoc.alternate) {
|
||||
netp = stcb->asoc.alternate;
|
||||
} else {
|
||||
netp = stcb->asoc.primary_destination;
|
||||
}
|
||||
sctp_stop_timers_for_shutdown(stcb);
|
||||
sctp_send_shutdown(stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
sctp_send_shutdown(stcb, netp);
|
||||
sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
|
||||
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
|
||||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
|
||||
@ -848,11 +829,10 @@ sctp_disconnect(struct socket *so)
|
||||
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
|
||||
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
|
||||
stcb->sctp_ep, stcb,
|
||||
asoc->primary_destination);
|
||||
stcb->sctp_ep, stcb, netp);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
|
||||
stcb->sctp_ep, stcb,
|
||||
asoc->primary_destination);
|
||||
stcb->sctp_ep, stcb, netp);
|
||||
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@ -865,9 +845,17 @@ sctp_disconnect(struct socket *so)
|
||||
* we will allow user data to be sent first
|
||||
* and move to SHUTDOWN-PENDING
|
||||
*/
|
||||
struct sctp_nets *netp;
|
||||
|
||||
if (stcb->asoc.alternate) {
|
||||
netp = stcb->asoc.alternate;
|
||||
} else {
|
||||
netp = stcb->asoc.primary_destination;
|
||||
}
|
||||
|
||||
asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
|
||||
asoc->primary_destination);
|
||||
netp);
|
||||
if (asoc->locked_on_sending) {
|
||||
/* Locked to send out the data */
|
||||
struct sctp_stream_queue_pending *sp;
|
||||
@ -1047,9 +1035,15 @@ sctp_shutdown(struct socket *so)
|
||||
/* there is nothing queued to send, so I'm done... */
|
||||
if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
|
||||
/* only send SHUTDOWN the first time through */
|
||||
struct sctp_nets *netp;
|
||||
|
||||
if (stcb->asoc.alternate) {
|
||||
netp = stcb->asoc.alternate;
|
||||
} else {
|
||||
netp = stcb->asoc.primary_destination;
|
||||
}
|
||||
sctp_stop_timers_for_shutdown(stcb);
|
||||
sctp_send_shutdown(stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
sctp_send_shutdown(stcb, netp);
|
||||
sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
|
||||
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
|
||||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
|
||||
@ -1058,20 +1052,26 @@ sctp_shutdown(struct socket *so)
|
||||
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
|
||||
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
|
||||
stcb->sctp_ep, stcb,
|
||||
asoc->primary_destination);
|
||||
stcb->sctp_ep, stcb, netp);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
|
||||
stcb->sctp_ep, stcb,
|
||||
asoc->primary_destination);
|
||||
stcb->sctp_ep, stcb, netp);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* we still got (or just got) data to send, so set
|
||||
* SHUTDOWN_PENDING
|
||||
*/
|
||||
struct sctp_nets *netp;
|
||||
|
||||
if (stcb->asoc.alternate) {
|
||||
netp = stcb->asoc.alternate;
|
||||
} else {
|
||||
netp = stcb->asoc.primary_destination;
|
||||
}
|
||||
|
||||
asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
|
||||
asoc->primary_destination);
|
||||
netp);
|
||||
|
||||
if (asoc->locked_on_sending) {
|
||||
/* Locked to send out the data */
|
||||
@ -2389,7 +2389,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
}
|
||||
}
|
||||
if (stcb) {
|
||||
/* Applys to the specific association */
|
||||
/* Applies to the specific association */
|
||||
paddrp->spp_flags = 0;
|
||||
if (net) {
|
||||
int ovh;
|
||||
@ -2400,7 +2400,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
ovh = SCTP_MED_V4_OVERHEAD;
|
||||
}
|
||||
|
||||
|
||||
paddrp->spp_hbinterval = net->heart_beat_delay;
|
||||
paddrp->spp_pathmaxrxt = net->failure_threshold;
|
||||
paddrp->spp_pathmtu = net->mtu - ovh;
|
||||
/* get flags for HB */
|
||||
@ -2444,11 +2444,12 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
|
||||
#endif
|
||||
/* default settings should be these */
|
||||
if (stcb->asoc.hb_is_disabled == 0) {
|
||||
paddrp->spp_flags |= SPP_HB_ENABLE;
|
||||
} else {
|
||||
if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
|
||||
paddrp->spp_flags |= SPP_HB_DISABLE;
|
||||
} else {
|
||||
paddrp->spp_flags |= SPP_HB_ENABLE;
|
||||
}
|
||||
paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
|
||||
cnt++;
|
||||
@ -2458,7 +2459,6 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
paddrp->spp_flags |= SPP_PMTUD_ENABLE;
|
||||
}
|
||||
}
|
||||
paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
|
||||
paddrp->spp_assoc_id = sctp_get_associd(stcb);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
@ -3080,6 +3080,95 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCTP_PEER_ADDR_THLDS:
|
||||
{
|
||||
struct sctp_paddrthlds *thlds;
|
||||
struct sctp_nets *net;
|
||||
|
||||
SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize);
|
||||
SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
|
||||
|
||||
net = NULL;
|
||||
if (stcb) {
|
||||
net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_address);
|
||||
} else {
|
||||
/*
|
||||
* We increment here since
|
||||
* sctp_findassociation_ep_addr() wil do a
|
||||
* decrement if it finds the stcb as long as
|
||||
* the locked tcb (last argument) is NOT a
|
||||
* TCB.. aka NULL.
|
||||
*/
|
||||
SCTP_INP_INCR_REF(inp);
|
||||
stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&thlds->spt_address, &net, NULL, NULL);
|
||||
if (stcb == NULL) {
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
}
|
||||
}
|
||||
if (stcb && (net == NULL)) {
|
||||
struct sockaddr *sa;
|
||||
|
||||
sa = (struct sockaddr *)&thlds->spt_address;
|
||||
#ifdef INET
|
||||
if (sa->sa_family == AF_INET) {
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
sin = (struct sockaddr_in *)sa;
|
||||
if (sin->sin_addr.s_addr) {
|
||||
error = EINVAL;
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
#ifdef INET6
|
||||
if (sa->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
sin6 = (struct sockaddr_in6 *)sa;
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
|
||||
error = EINVAL;
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
error = EAFNOSUPPORT;
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (stcb) {
|
||||
if (net) {
|
||||
thlds->spt_pathmaxrxt = net->failure_threshold;
|
||||
thlds->spt_pathpfthld = net->pf_threshold;
|
||||
} else {
|
||||
thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure;
|
||||
thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold;
|
||||
}
|
||||
thlds->spt_assoc_id = sctp_get_associd(stcb);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
if (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC) {
|
||||
/* Use endpoint defaults */
|
||||
SCTP_INP_RLOCK(inp);
|
||||
thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure;
|
||||
thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold;
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
} else {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
error = EINVAL;
|
||||
}
|
||||
}
|
||||
if (error == 0) {
|
||||
*optsize = sizeof(struct sctp_paddrthlds);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
|
||||
error = ENOPROTOOPT;
|
||||
@ -3138,6 +3227,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
*/
|
||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
|
||||
/* only valid for bound all sockets */
|
||||
if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) &&
|
||||
(*mopt != 0)) {
|
||||
/* forbidden by admin */
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM);
|
||||
return (EPERM);
|
||||
}
|
||||
set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
|
||||
} else {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
@ -4368,7 +4463,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
break;
|
||||
}
|
||||
case SCTP_PEER_ADDR_PARAMS:
|
||||
/* Applys to the specific association */
|
||||
/* Applies to the specific association */
|
||||
{
|
||||
struct sctp_paddrparams *paddrp;
|
||||
struct sctp_nets *net;
|
||||
@ -4459,29 +4554,33 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
ovh = SCTP_MED_V4_OVERHEAD;
|
||||
}
|
||||
|
||||
if (paddrp->spp_hbinterval)
|
||||
stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
|
||||
else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
|
||||
stcb->asoc.heart_beat_delay = 0;
|
||||
|
||||
/* network sets ? */
|
||||
if (net) {
|
||||
/************************NET SPECIFIC SET ******************/
|
||||
if (paddrp->spp_flags & SPP_HB_DEMAND) {
|
||||
/* on demand HB */
|
||||
if (sctp_send_hb(stcb, 1, net, SCTP_SO_LOCKED) < 0) {
|
||||
/* asoc destroyed */
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (paddrp->spp_flags & SPP_HB_DISABLE) {
|
||||
if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
|
||||
!(net->dest_state & SCTP_ADDR_NOHB)) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
|
||||
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
|
||||
}
|
||||
net->dest_state |= SCTP_ADDR_NOHB;
|
||||
}
|
||||
if (paddrp->spp_flags & SPP_HB_ENABLE) {
|
||||
if (paddrp->spp_hbinterval) {
|
||||
net->heart_beat_delay = paddrp->spp_hbinterval;
|
||||
} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
|
||||
net->heart_beat_delay = 0;
|
||||
}
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
|
||||
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
|
||||
net->dest_state &= ~SCTP_ADDR_NOHB;
|
||||
}
|
||||
if (paddrp->spp_flags & SPP_HB_DEMAND) {
|
||||
/* on demand HB */
|
||||
sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
|
||||
}
|
||||
if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
|
||||
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
|
||||
@ -4499,8 +4598,33 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
|
||||
}
|
||||
}
|
||||
if (paddrp->spp_pathmaxrxt)
|
||||
if (paddrp->spp_pathmaxrxt) {
|
||||
if (net->dest_state & SCTP_ADDR_PF) {
|
||||
if (net->error_count > paddrp->spp_pathmaxrxt) {
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
}
|
||||
} else {
|
||||
if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
|
||||
(net->error_count > net->pf_threshold)) {
|
||||
net->dest_state |= SCTP_ADDR_PF;
|
||||
sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
|
||||
}
|
||||
}
|
||||
if (net->dest_state & SCTP_ADDR_REACHABLE) {
|
||||
if (net->error_count > paddrp->spp_pathmaxrxt) {
|
||||
net->dest_state &= ~SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
|
||||
}
|
||||
} else {
|
||||
if (net->error_count <= paddrp->spp_pathmaxrxt) {
|
||||
net->dest_state |= SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
|
||||
}
|
||||
}
|
||||
net->failure_threshold = paddrp->spp_pathmaxrxt;
|
||||
}
|
||||
#ifdef INET
|
||||
if (paddrp->spp_flags & SPP_IPV4_TOS) {
|
||||
if (net->ro._l_addr.sin.sin_family == AF_INET) {
|
||||
@ -4517,13 +4641,67 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
#endif
|
||||
} else {
|
||||
/************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/
|
||||
if (paddrp->spp_pathmaxrxt)
|
||||
if (paddrp->spp_pathmaxrxt) {
|
||||
stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt;
|
||||
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if (net->dest_state & SCTP_ADDR_PF) {
|
||||
if (net->error_count > paddrp->spp_pathmaxrxt) {
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
}
|
||||
} else {
|
||||
if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
|
||||
(net->error_count > net->pf_threshold)) {
|
||||
net->dest_state |= SCTP_ADDR_PF;
|
||||
sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
|
||||
}
|
||||
}
|
||||
if (net->dest_state & SCTP_ADDR_REACHABLE) {
|
||||
if (net->error_count > paddrp->spp_pathmaxrxt) {
|
||||
net->dest_state &= ~SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
|
||||
}
|
||||
} else {
|
||||
if (net->error_count <= paddrp->spp_pathmaxrxt) {
|
||||
net->dest_state |= SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
|
||||
}
|
||||
}
|
||||
net->failure_threshold = paddrp->spp_pathmaxrxt;
|
||||
}
|
||||
}
|
||||
if (paddrp->spp_flags & SPP_HB_ENABLE) {
|
||||
if (paddrp->spp_hbinterval) {
|
||||
stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
|
||||
} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
|
||||
stcb->asoc.heart_beat_delay = 0;
|
||||
}
|
||||
/* Turn back on the timer */
|
||||
stcb->asoc.hb_is_disabled = 0;
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if (paddrp->spp_hbinterval) {
|
||||
net->heart_beat_delay = paddrp->spp_hbinterval;
|
||||
} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
|
||||
net->heart_beat_delay = 0;
|
||||
}
|
||||
if (net->dest_state & SCTP_ADDR_NOHB) {
|
||||
net->dest_state &= ~SCTP_ADDR_NOHB;
|
||||
}
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
|
||||
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
|
||||
}
|
||||
}
|
||||
if (paddrp->spp_flags & SPP_HB_DISABLE) {
|
||||
/* Turn back on the timer */
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if (!(net->dest_state & SCTP_ADDR_NOHB)) {
|
||||
net->dest_state |= SCTP_ADDR_NOHB;
|
||||
if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
@ -4546,41 +4724,25 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (paddrp->spp_flags & SPP_HB_DISABLE) {
|
||||
int cnt_of_unconf = 0;
|
||||
struct sctp_nets *lnet;
|
||||
|
||||
stcb->asoc.hb_is_disabled = 1;
|
||||
TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
|
||||
if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) {
|
||||
cnt_of_unconf++;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* stop the timer ONLY if we
|
||||
* have no unconfirmed
|
||||
* addresses
|
||||
*/
|
||||
if (cnt_of_unconf == 0) {
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
|
||||
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (paddrp->spp_flags & SPP_HB_ENABLE) {
|
||||
/* start up the timer. */
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
|
||||
}
|
||||
}
|
||||
#ifdef INET
|
||||
if (paddrp->spp_flags & SPP_IPV4_TOS)
|
||||
if (paddrp->spp_flags & SPP_IPV4_TOS) {
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if (net->ro._l_addr.sin.sin_family == AF_INET) {
|
||||
net->tos_flowlabel = paddrp->spp_ipv4_tos & 0x000000fc;
|
||||
}
|
||||
}
|
||||
stcb->asoc.default_tos = paddrp->spp_ipv4_tos & 0x000000fc;
|
||||
}
|
||||
#endif
|
||||
#ifdef INET6
|
||||
if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL)
|
||||
if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if (net->ro._l_addr.sin6.sin6_family == AF_INET6) {
|
||||
net->tos_flowlabel = paddrp->spp_ipv6_flowlabel;
|
||||
}
|
||||
}
|
||||
stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
@ -4605,8 +4767,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
|
||||
}
|
||||
if (paddrp->spp_flags & SPP_HB_ENABLE) {
|
||||
if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
|
||||
inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
|
||||
} else if (paddrp->spp_hbinterval) {
|
||||
inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
|
||||
}
|
||||
sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
|
||||
|
||||
} else if (paddrp->spp_flags & SPP_HB_DISABLE) {
|
||||
sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
|
||||
}
|
||||
@ -4769,10 +4935,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
(!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
|
||||
/* Ok we need to set it */
|
||||
if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
|
||||
if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) {
|
||||
net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH;
|
||||
if ((stcb->asoc.alternate) &&
|
||||
(!(net->dest_state & SCTP_ADDR_PF)) &&
|
||||
(net->dest_state & SCTP_ADDR_REACHABLE)) {
|
||||
sctp_free_remote_addr(stcb->asoc.alternate);
|
||||
stcb->asoc.alternate = NULL;
|
||||
}
|
||||
net->dest_state |= SCTP_ADDR_SWITCH_PRIMARY;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -4930,7 +5098,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
|
||||
if (td != NULL &&
|
||||
(error = prison_local_ip6(td->td_ucred,
|
||||
&(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
|
||||
(SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
|
||||
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
|
||||
break;
|
||||
@ -5170,6 +5340,146 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCTP_PEER_ADDR_THLDS:
|
||||
/* Applies to the specific association */
|
||||
{
|
||||
struct sctp_paddrthlds *thlds;
|
||||
struct sctp_nets *net;
|
||||
|
||||
SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize);
|
||||
SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
|
||||
net = NULL;
|
||||
if (stcb) {
|
||||
net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_assoc_id);
|
||||
} else {
|
||||
/*
|
||||
* We increment here since
|
||||
* sctp_findassociation_ep_addr() wil do a
|
||||
* decrement if it finds the stcb as long as
|
||||
* the locked tcb (last argument) is NOT a
|
||||
* TCB.. aka NULL.
|
||||
*/
|
||||
SCTP_INP_INCR_REF(inp);
|
||||
stcb = sctp_findassociation_ep_addr(&inp,
|
||||
(struct sockaddr *)&thlds->spt_assoc_id,
|
||||
&net, NULL, NULL);
|
||||
if (stcb == NULL) {
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
}
|
||||
}
|
||||
if (stcb && (net == NULL)) {
|
||||
struct sockaddr *sa;
|
||||
|
||||
sa = (struct sockaddr *)&thlds->spt_assoc_id;
|
||||
#ifdef INET
|
||||
if (sa->sa_family == AF_INET) {
|
||||
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
sin = (struct sockaddr_in *)sa;
|
||||
if (sin->sin_addr.s_addr) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
#ifdef INET6
|
||||
if (sa->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
sin6 = (struct sockaddr_in6 *)sa;
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
error = EAFNOSUPPORT;
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (stcb) {
|
||||
if (net) {
|
||||
if (net->dest_state & SCTP_ADDR_PF) {
|
||||
if ((net->failure_threshold > thlds->spt_pathmaxrxt) ||
|
||||
(net->failure_threshold <= thlds->spt_pathpfthld)) {
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
}
|
||||
} else {
|
||||
if ((net->failure_threshold > thlds->spt_pathpfthld) &&
|
||||
(net->failure_threshold <= thlds->spt_pathmaxrxt)) {
|
||||
net->dest_state |= SCTP_ADDR_PF;
|
||||
sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
|
||||
}
|
||||
}
|
||||
if (net->dest_state & SCTP_ADDR_REACHABLE) {
|
||||
if (net->failure_threshold > thlds->spt_pathmaxrxt) {
|
||||
net->dest_state &= ~SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
|
||||
}
|
||||
} else {
|
||||
if (net->failure_threshold <= thlds->spt_pathmaxrxt) {
|
||||
net->dest_state |= SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
|
||||
}
|
||||
}
|
||||
net->failure_threshold = thlds->spt_pathmaxrxt;
|
||||
net->pf_threshold = thlds->spt_pathpfthld;
|
||||
} else {
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if (net->dest_state & SCTP_ADDR_PF) {
|
||||
if ((net->failure_threshold > thlds->spt_pathmaxrxt) ||
|
||||
(net->failure_threshold <= thlds->spt_pathpfthld)) {
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
}
|
||||
} else {
|
||||
if ((net->failure_threshold > thlds->spt_pathpfthld) &&
|
||||
(net->failure_threshold <= thlds->spt_pathmaxrxt)) {
|
||||
net->dest_state |= SCTP_ADDR_PF;
|
||||
sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
|
||||
}
|
||||
}
|
||||
if (net->dest_state & SCTP_ADDR_REACHABLE) {
|
||||
if (net->failure_threshold > thlds->spt_pathmaxrxt) {
|
||||
net->dest_state &= ~SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
|
||||
}
|
||||
} else {
|
||||
if (net->failure_threshold <= thlds->spt_pathmaxrxt) {
|
||||
net->dest_state |= SCTP_ADDR_REACHABLE;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED);
|
||||
}
|
||||
}
|
||||
net->failure_threshold = thlds->spt_pathmaxrxt;
|
||||
net->pf_threshold = thlds->spt_pathpfthld;
|
||||
}
|
||||
stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt;
|
||||
stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld;
|
||||
}
|
||||
} else {
|
||||
if (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC) {
|
||||
SCTP_INP_WLOCK(inp);
|
||||
inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt;
|
||||
inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld;
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
} else {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
error = EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
|
||||
error = ENOPROTOOPT;
|
||||
|
@ -179,7 +179,6 @@ extern struct pr_usrreqs sctp_usrreqs;
|
||||
if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&(__net)->ref_count)) { \
|
||||
(void)SCTP_OS_TIMER_STOP(&(__net)->rxt_timer.timer); \
|
||||
(void)SCTP_OS_TIMER_STOP(&(__net)->pmtu_timer.timer); \
|
||||
(void)SCTP_OS_TIMER_STOP(&(__net)->fr_timer.timer); \
|
||||
if ((__net)->ro.ro_rt) { \
|
||||
RTFREE((__net)->ro.ro_rt); \
|
||||
(__net)->ro.ro_rt = NULL; \
|
||||
@ -189,7 +188,7 @@ extern struct pr_usrreqs sctp_usrreqs;
|
||||
(__net)->ro._s_addr = NULL; \
|
||||
} \
|
||||
(__net)->src_addr_selected = 0; \
|
||||
(__net)->dest_state = SCTP_ADDR_NOT_REACHABLE; \
|
||||
(__net)->dest_state &= ~SCTP_ADDR_REACHABLE; \
|
||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_net), (__net)); \
|
||||
SCTP_DECR_RADDR_COUNT(); \
|
||||
} \
|
||||
@ -312,6 +311,8 @@ extern struct pr_usrreqs sctp_usrreqs;
|
||||
|
||||
#endif
|
||||
|
||||
#define SCTP_PF_ENABLED(_net) (_net->pf_threshold < _net->failure_threshold)
|
||||
#define SCTP_NET_IS_PF(_net) (_net->pf_threshold < _net->error_count)
|
||||
|
||||
struct sctp_nets;
|
||||
struct sctp_inpcb;
|
||||
|
@ -739,15 +739,14 @@ sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb)
|
||||
|
||||
asoc = &stcb->asoc;
|
||||
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->hb_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer);
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
(void)SCTP_OS_TIMER_STOP(&net->fr_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer);
|
||||
(void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -921,7 +920,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
|
||||
asoc->sctp_cmt_on_off = m->sctp_cmt_on_off;
|
||||
asoc->ecn_allowed = m->sctp_ecn_enable;
|
||||
asoc->sctp_nr_sack_on_off = (uint8_t) SCTP_BASE_SYSCTL(sctp_nr_sack_on_off);
|
||||
asoc->sctp_cmt_pf = (uint8_t) SCTP_BASE_SYSCTL(sctp_cmt_pf);
|
||||
asoc->sctp_cmt_pf = (uint8_t) 0;
|
||||
asoc->sctp_frag_point = m->sctp_frag_point;
|
||||
asoc->sctp_features = m->sctp_features;
|
||||
#ifdef INET
|
||||
@ -946,11 +945,6 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
|
||||
asoc->peer_vtag_nonce = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
|
||||
asoc->vrf_id = vrf_id;
|
||||
|
||||
if (sctp_is_feature_on(m, SCTP_PCB_FLAGS_DONOT_HEARTBEAT))
|
||||
asoc->hb_is_disabled = 1;
|
||||
else
|
||||
asoc->hb_is_disabled = 0;
|
||||
|
||||
#ifdef SCTP_ASOCLOG_OF_TSNS
|
||||
asoc->tsn_in_at = 0;
|
||||
asoc->tsn_out_at = 0;
|
||||
@ -989,6 +983,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
|
||||
asoc->max_init_times = m->sctp_ep.max_init_times;
|
||||
asoc->max_send_times = m->sctp_ep.max_send_times;
|
||||
asoc->def_net_failure = m->sctp_ep.def_net_failure;
|
||||
asoc->def_net_pf_threshold = m->sctp_ep.def_net_pf_threshold;
|
||||
asoc->free_chunk_cnt = 0;
|
||||
|
||||
asoc->iam_blocking = 0;
|
||||
@ -1632,11 +1627,10 @@ sctp_timeout_handler(void *t)
|
||||
case SCTP_TIMER_TYPE_RECV:
|
||||
if ((stcb == NULL) || (inp == NULL)) {
|
||||
break;
|
||||
} {
|
||||
SCTP_STAT_INCR(sctps_timosack);
|
||||
stcb->asoc.timosack++;
|
||||
sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_timosack);
|
||||
stcb->asoc.timosack++;
|
||||
sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
|
||||
#ifdef SCTP_AUDITING_ENABLED
|
||||
sctp_auditing(4, inp, stcb, net);
|
||||
#endif
|
||||
@ -1658,33 +1652,20 @@ sctp_timeout_handler(void *t)
|
||||
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED);
|
||||
break;
|
||||
case SCTP_TIMER_TYPE_HEARTBEAT:
|
||||
{
|
||||
struct sctp_nets *lnet;
|
||||
int cnt_of_unconf = 0;
|
||||
|
||||
if ((stcb == NULL) || (inp == NULL)) {
|
||||
break;
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_timoheartbeat);
|
||||
stcb->asoc.timoheartbeat++;
|
||||
TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
|
||||
if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) &&
|
||||
(lnet->dest_state & SCTP_ADDR_REACHABLE)) {
|
||||
cnt_of_unconf++;
|
||||
}
|
||||
}
|
||||
if (cnt_of_unconf == 0) {
|
||||
if (sctp_heartbeat_timer(inp, stcb, lnet,
|
||||
cnt_of_unconf)) {
|
||||
/* no need to unlock on tcb its gone */
|
||||
goto out_decr;
|
||||
}
|
||||
}
|
||||
if ((stcb == NULL) || (inp == NULL) || (net == NULL)) {
|
||||
break;
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_timoheartbeat);
|
||||
stcb->asoc.timoheartbeat++;
|
||||
if (sctp_heartbeat_timer(inp, stcb, net)) {
|
||||
/* no need to unlock on tcb its gone */
|
||||
goto out_decr;
|
||||
}
|
||||
#ifdef SCTP_AUDITING_ENABLED
|
||||
sctp_auditing(4, inp, stcb, lnet);
|
||||
sctp_auditing(4, inp, stcb, net);
|
||||
#endif
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT,
|
||||
stcb->sctp_ep, stcb, lnet);
|
||||
if (!(net->dest_state & SCTP_ADDR_NOHB)) {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
|
||||
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
break;
|
||||
@ -1780,14 +1761,6 @@ sctp_timeout_handler(void *t)
|
||||
SCTP_STAT_INCR(sctps_timostrmrst);
|
||||
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED);
|
||||
break;
|
||||
case SCTP_TIMER_TYPE_EARLYFR:
|
||||
/* Need to do FR of things for net */
|
||||
if ((stcb == NULL) || (inp == NULL)) {
|
||||
break;
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_timoearlyfr);
|
||||
sctp_early_fr_timer(inp, stcb, net);
|
||||
break;
|
||||
case SCTP_TIMER_TYPE_ASCONF:
|
||||
if ((stcb == NULL) || (inp == NULL)) {
|
||||
break;
|
||||
@ -1898,7 +1871,7 @@ void
|
||||
sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net)
|
||||
{
|
||||
int to_ticks;
|
||||
uint32_t to_ticks;
|
||||
struct sctp_timer *tmr;
|
||||
|
||||
if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL))
|
||||
@ -1985,71 +1958,38 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
* though we use a different timer. We also add the HB timer
|
||||
* PLUS a random jitter.
|
||||
*/
|
||||
if ((inp == NULL) || (stcb == NULL)) {
|
||||
if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
|
||||
return;
|
||||
} else {
|
||||
uint32_t rndval;
|
||||
uint8_t this_random;
|
||||
int cnt_of_unconf = 0;
|
||||
struct sctp_nets *lnet;
|
||||
uint32_t jitter;
|
||||
|
||||
TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
|
||||
if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) &&
|
||||
(lnet->dest_state & SCTP_ADDR_REACHABLE)) {
|
||||
cnt_of_unconf++;
|
||||
}
|
||||
}
|
||||
if (cnt_of_unconf) {
|
||||
net = lnet = NULL;
|
||||
(void)sctp_heartbeat_timer(inp, stcb, lnet, cnt_of_unconf);
|
||||
}
|
||||
if (stcb->asoc.hb_random_idx > 3) {
|
||||
rndval = sctp_select_initial_TSN(&inp->sctp_ep);
|
||||
memcpy(stcb->asoc.hb_random_values, &rndval,
|
||||
sizeof(stcb->asoc.hb_random_values));
|
||||
stcb->asoc.hb_random_idx = 0;
|
||||
}
|
||||
this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx];
|
||||
stcb->asoc.hb_random_idx++;
|
||||
stcb->asoc.hb_ect_randombit = 0;
|
||||
/*
|
||||
* this_random will be 0 - 256 ms RTO is in ms.
|
||||
*/
|
||||
if ((stcb->asoc.hb_is_disabled) &&
|
||||
(cnt_of_unconf == 0)) {
|
||||
if ((net->dest_state & SCTP_ADDR_NOHB) &&
|
||||
!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
|
||||
return;
|
||||
}
|
||||
if (net) {
|
||||
int delay;
|
||||
|
||||
delay = stcb->asoc.heart_beat_delay;
|
||||
TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
|
||||
if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) &&
|
||||
((lnet->dest_state & SCTP_ADDR_OUT_OF_SCOPE) == 0) &&
|
||||
(lnet->dest_state & SCTP_ADDR_REACHABLE)) {
|
||||
delay = 0;
|
||||
}
|
||||
}
|
||||
if (net->RTO == 0) {
|
||||
/* Never been checked */
|
||||
to_ticks = this_random + stcb->asoc.initial_rto + delay;
|
||||
} else {
|
||||
/* set rto_val to the ms */
|
||||
to_ticks = delay + net->RTO + this_random;
|
||||
}
|
||||
if (net->RTO == 0) {
|
||||
to_ticks = stcb->asoc.initial_rto;
|
||||
} else {
|
||||
if (cnt_of_unconf) {
|
||||
to_ticks = this_random + stcb->asoc.initial_rto;
|
||||
} else {
|
||||
to_ticks = stcb->asoc.heart_beat_delay + this_random + stcb->asoc.initial_rto;
|
||||
}
|
||||
to_ticks = net->RTO;
|
||||
}
|
||||
rndval = sctp_select_initial_TSN(&inp->sctp_ep);
|
||||
jitter = rndval % to_ticks;
|
||||
if (jitter >= (to_ticks >> 1)) {
|
||||
to_ticks = to_ticks + (jitter - (to_ticks >> 1));
|
||||
} else {
|
||||
to_ticks = to_ticks - jitter;
|
||||
}
|
||||
if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
|
||||
!(net->dest_state & SCTP_ADDR_PF)) {
|
||||
to_ticks += net->heart_beat_delay;
|
||||
}
|
||||
/*
|
||||
* Now we must convert the to_ticks that are now in
|
||||
* ms to ticks.
|
||||
*/
|
||||
to_ticks = MSEC_TO_TICKS(to_ticks);
|
||||
tmr = &stcb->asoc.hb_timer;
|
||||
tmr = &net->hb_timer;
|
||||
}
|
||||
break;
|
||||
case SCTP_TIMER_TYPE_COOKIE:
|
||||
@ -2150,35 +2090,6 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
}
|
||||
tmr = &stcb->asoc.strreset_timer;
|
||||
break;
|
||||
|
||||
case SCTP_TIMER_TYPE_EARLYFR:
|
||||
{
|
||||
unsigned int msec;
|
||||
|
||||
if ((stcb == NULL) || (net == NULL)) {
|
||||
return;
|
||||
}
|
||||
if (net->flight_size > net->cwnd) {
|
||||
/* no need to start */
|
||||
return;
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_earlyfrstart);
|
||||
if (net->lastsa == 0) {
|
||||
/* Hmm no rtt estimate yet? */
|
||||
msec = stcb->asoc.initial_rto >> 2;
|
||||
} else {
|
||||
msec = ((net->lastsa >> 2) + net->lastsv) >> 1;
|
||||
}
|
||||
if (msec < SCTP_BASE_SYSCTL(sctp_early_fr_msec)) {
|
||||
msec = SCTP_BASE_SYSCTL(sctp_early_fr_msec);
|
||||
if (msec < SCTP_MINFR_MSEC_FLOOR) {
|
||||
msec = SCTP_MINFR_MSEC_FLOOR;
|
||||
}
|
||||
}
|
||||
to_ticks = MSEC_TO_TICKS(msec);
|
||||
tmr = &net->fr_timer;
|
||||
}
|
||||
break;
|
||||
case SCTP_TIMER_TYPE_ASCONF:
|
||||
/*
|
||||
* Here the timer comes from the stcb but its value is from
|
||||
@ -2273,13 +2184,6 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
case SCTP_TIMER_TYPE_ADDR_WQ:
|
||||
tmr = &SCTP_BASE_INFO(addr_wq_timer);
|
||||
break;
|
||||
case SCTP_TIMER_TYPE_EARLYFR:
|
||||
if ((stcb == NULL) || (net == NULL)) {
|
||||
return;
|
||||
}
|
||||
tmr = &net->fr_timer;
|
||||
SCTP_STAT_INCR(sctps_earlyfrstop);
|
||||
break;
|
||||
case SCTP_TIMER_TYPE_SEND:
|
||||
if ((stcb == NULL) || (net == NULL)) {
|
||||
return;
|
||||
@ -2305,10 +2209,10 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
tmr = &net->rxt_timer;
|
||||
break;
|
||||
case SCTP_TIMER_TYPE_HEARTBEAT:
|
||||
if (stcb == NULL) {
|
||||
if ((stcb == NULL) || (net == NULL)) {
|
||||
return;
|
||||
}
|
||||
tmr = &stcb->asoc.hb_timer;
|
||||
tmr = &net->hb_timer;
|
||||
break;
|
||||
case SCTP_TIMER_TYPE_COOKIE:
|
||||
if ((stcb == NULL) || (net == NULL)) {
|
||||
@ -6209,7 +6113,7 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
incr = sizeof(struct sockaddr_in);
|
||||
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
|
||||
if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
|
||||
/* assoc gone no un-lock */
|
||||
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
|
||||
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
|
||||
@ -6222,7 +6126,7 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
incr = sizeof(struct sockaddr_in6);
|
||||
if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
|
||||
if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
|
||||
/* assoc gone no un-lock */
|
||||
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
|
||||
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
|
||||
|
@ -420,33 +420,8 @@ sctp6_notify(struct sctp_inpcb *inp,
|
||||
*/
|
||||
if (net->dest_state & SCTP_ADDR_REACHABLE) {
|
||||
/* Ok that destination is NOT reachable */
|
||||
SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n",
|
||||
net->error_count,
|
||||
net->failure_threshold,
|
||||
net);
|
||||
|
||||
net->dest_state &= ~SCTP_ADDR_REACHABLE;
|
||||
net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
|
||||
/*
|
||||
* JRS 5/14/07 - If a destination is unreachable,
|
||||
* the PF bit is turned off. This allows an
|
||||
* unambiguous use of the PF bit for destinations
|
||||
* that are reachable but potentially failed. If the
|
||||
* destination is set to the unreachable state, also
|
||||
* set the destination to the PF state.
|
||||
*/
|
||||
/*
|
||||
* Add debug message here if destination is not in
|
||||
* PF state.
|
||||
*/
|
||||
/* Stop any running T3 timers here? */
|
||||
if ((stcb->asoc.sctp_cmt_on_off > 0) &&
|
||||
(stcb->asoc.sctp_cmt_pf > 0)) {
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
|
||||
net);
|
||||
}
|
||||
net->error_count = net->failure_threshold + 1;
|
||||
net->dest_state &= ~SCTP_ADDR_PF;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
|
||||
stcb, SCTP_FAILED_THRESHOLD,
|
||||
(void *)net, SCTP_SO_NOT_LOCKED);
|
||||
|
Loading…
Reference in New Issue
Block a user