static void
sctp_rc_timer(sctp_t *sctp, sctp_faddr_t *fp)
{
#define	SCTP_CLR_SENT_FLAG(mp)	((mp)->b_flag &= ~SCTP_CHUNK_FLAG_SENT)
	sctp_faddr_t	*nfp;
	sctp_faddr_t	*ofp;
	sctp_stack_t	*sctps = sctp->sctp_sctps;

	ASSERT(fp != NULL);

	fp->rc_timer_running = 0;

	if (sctp->sctp_state != SCTPS_ESTABLISHED ||
	    sctp->sctp_cxmit_list == NULL) {
		return;
	}
	/*
	 * Not a retransmission, this was deferred due to some error
	 * condition
	 */
	if (!SCTP_CHUNK_ISSENT(sctp->sctp_cxmit_list)) {
		sctp_wput_asconf(sctp, fp);
		return;
	}
	/*
	 * The sent flag indicates if the msg has been sent on this fp.
	 */
	SCTP_CLR_SENT_FLAG(sctp->sctp_cxmit_list);
	/* Retransmission */
	if (sctp->sctp_strikes >= sctp->sctp_pa_max_rxt) {
		/* time to give up */
		BUMP_MIB(&sctps->sctps_mib, sctpAborted);
		sctp_assoc_event(sctp, SCTP_COMM_LOST, 0, NULL);
		sctp_clean_death(sctp, ETIMEDOUT);
		return;
	}
	if (fp->strikes >= fp->max_retr) {
		if (sctp_faddr_dead(sctp, fp, SCTP_FADDRS_DOWN) == -1)
			return;
	}

	fp->strikes++;
	sctp->sctp_strikes++;
	SCTP_CALC_RXT(sctp, fp);

	nfp = sctp_rotate_faddr(sctp, fp);
	sctp->sctp_cchunk_pend = 0;
	ofp = SCTP_CHUNK_DEST(sctp->sctp_cxmit_list);
	SCTP_SET_CHUNK_DEST(sctp->sctp_cxmit_list, NULL);
	ASSERT(ofp != NULL && ofp == fp);
	ASSERT(ofp->suna >= MBLKL(sctp->sctp_cxmit_list));
	/*
	 * Enter slow start for this destination.
	 * XXX anything in the data path that needs to be considered?
	 */
	ofp->ssthresh = ofp->cwnd / 2;
	if (ofp->ssthresh < 2 * ofp->sfa_pmss)
		ofp->ssthresh = 2 * ofp->sfa_pmss;
	ofp->cwnd = ofp->sfa_pmss;
	ofp->pba = 0;
	ofp->suna -= MBLKL(sctp->sctp_cxmit_list);
	/*
	 * The rexmit flags is used to determine if a serial number needs to
	 * be assigned or not, so once set we leave it there.
	 */
	if (!SCTP_CHUNK_WANT_REXMIT(sctp->sctp_cxmit_list))
		SCTP_CHUNK_REXMIT(sctp->sctp_cxmit_list);
	sctp_wput_asconf(sctp, nfp);
#undef	SCTP_CLR_SENT_FLAG
}
/*
 * Returns 0 if there is at leave one other active faddr, -1 if there
 * are none. If there are none left, faddr_dead() will start killing the
 * association.
 * If the downed faddr was the current faddr, a new current faddr
 * will be chosen.
 */
int
sctp_faddr_dead(sctp_t *sctp, sctp_faddr_t *fp, int newstate)
{
	sctp_faddr_t *ofp;
	sctp_stack_t *sctps = sctp->sctp_sctps;

	if (fp->state == SCTP_FADDRS_ALIVE) {
		sctp_intf_event(sctp, fp->faddr, SCTP_ADDR_UNREACHABLE, 0);
	}
	fp->state = newstate;

	dprint(1, ("sctp_faddr_dead: %x:%x:%x:%x down (state=%d)\n",
	    SCTP_PRINTADDR(fp->faddr), newstate));

	if (fp == sctp->sctp_current) {
		/* Current faddr down; need to switch it */
		sctp->sctp_current = NULL;
	}

	/* Find next alive faddr */
	ofp = fp;
	for (fp = fp->next; fp != NULL; fp = fp->next) {
		if (fp->state == SCTP_FADDRS_ALIVE) {
			break;
		}
	}

	if (fp == NULL) {
		/* Continue from beginning of list */
		for (fp = sctp->sctp_faddrs; fp != ofp; fp = fp->next) {
			if (fp->state == SCTP_FADDRS_ALIVE) {
				break;
			}
		}
	}

	/*
	 * Find a new fp, so if the current faddr is dead, use the new fp
	 * as the current one.
	 */
	if (fp != ofp) {
		if (sctp->sctp_current == NULL) {
			dprint(1, ("sctp_faddr_dead: failover->%x:%x:%x:%x\n",
			    SCTP_PRINTADDR(fp->faddr)));
			/*
			 * Note that we don't need to reset the source addr
			 * of the new fp.
			 */
			sctp_set_faddr_current(sctp, fp);
		}
		return (0);
	}


	/* All faddrs are down; kill the association */
	dprint(1, ("sctp_faddr_dead: all faddrs down, killing assoc\n"));
	BUMP_MIB(&sctps->sctps_mib, sctpAborted);
	sctp_assoc_event(sctp, sctp->sctp_state < SCTPS_ESTABLISHED ?
	    SCTP_CANT_STR_ASSOC : SCTP_COMM_LOST, 0, NULL);
	sctp_clean_death(sctp, sctp->sctp_client_errno ?
	    sctp->sctp_client_errno : ETIMEDOUT);

	return (-1);
}
Esempio n. 3
0
void
sctp_user_abort(sctp_t *sctp, mblk_t *data)
{
	mblk_t *mp;
	int len, hdrlen;
	char *cause;
	sctp_faddr_t *fp = sctp->sctp_current;
	ip_xmit_attr_t	*ixa = fp->sf_ixa;
	sctp_stack_t	*sctps = sctp->sctp_sctps;

	/*
	 * Don't need notification if connection is not yet setup,
	 * call sctp_clean_death() to reclaim resources.
	 * Any pending connect call(s) will error out.
	 */
	if (sctp->sctp_state < SCTPS_COOKIE_WAIT) {
		sctp_clean_death(sctp, ECONNABORTED);
		return;
	}

	mp = sctp_make_mp(sctp, fp, 0);
	if (mp == NULL) {
		SCTP_KSTAT(sctps, sctp_send_user_abort_failed);
		return;
	}

	/*
	 * Create abort chunk.
	 */
	if (data) {
		if (fp->sf_isv4) {
			hdrlen = sctp->sctp_hdr_len;
		} else {
			hdrlen = sctp->sctp_hdr6_len;
		}
		hdrlen += sizeof (sctp_chunk_hdr_t) + sizeof (sctp_parm_hdr_t);
		cause = (char *)data->b_rptr;
		len = data->b_wptr - data->b_rptr;

		if (len + hdrlen > fp->sf_pmss) {
			len = fp->sf_pmss - hdrlen;
		}
	} else {
		cause = NULL;
		len = 0;
	}
	/*
	 * Since it is a user abort, we should have the sctp_t and hence
	 * the correct verification tag.  So we should not set the T-bit
	 * in the ABORT.
	 */
	if ((len = sctp_link_abort(mp, SCTP_ERR_USER_ABORT, cause, len, 0,
	    B_FALSE)) < 0) {
		freemsg(mp);
		return;
	}
	SCTPS_BUMP_MIB(sctps, sctpAborted);
	BUMP_LOCAL(sctp->sctp_opkts);
	BUMP_LOCAL(sctp->sctp_obchunks);

	sctp_set_iplen(sctp, mp, ixa);
	ASSERT(ixa->ixa_ire != NULL);
	ASSERT(ixa->ixa_cred != NULL);

	(void) conn_ip_output(mp, ixa);

	sctp_assoc_event(sctp, SCTP_COMM_LOST, 0, NULL);
	sctp_clean_death(sctp, ECONNABORTED);
}