コード例 #1
0
ファイル: sctp_error.c プロジェクト: apprisi/illumos-gate
/*
 * Called from sctp_input_data() to add one error chunk to the error
 * chunks list.  The error chunks list will be processed at the end
 * of sctp_input_data() by calling sctp_process_err().
 */
void
sctp_add_err(sctp_t *sctp, uint16_t serror, void *details, size_t len,
    sctp_faddr_t *dest)
{
	sctp_stack_t *sctps = sctp->sctp_sctps;
	mblk_t *emp;
	uint32_t emp_len;
	uint32_t mss;
	mblk_t *sendmp;
	sctp_faddr_t *fp;

	emp = sctp_make_err(sctp, serror, details, len);
	if (emp == NULL)
		return;
	emp_len = MBLKL(emp);
	if (sctp->sctp_err_chunks != NULL) {
		fp = SCTP_CHUNK_DEST(sctp->sctp_err_chunks);
	} else {
		fp = dest;
		SCTP_SET_CHUNK_DEST(emp, dest);
	}
	mss = fp->sf_pmss;

	/*
	 * If the current output packet cannot include the new error chunk,
	 * send out the current packet and then add the new error chunk
	 * to the new output packet.
	 */
	if (sctp->sctp_err_len + emp_len > mss) {
		if ((sendmp = sctp_make_mp(sctp, fp, 0)) == NULL) {
			SCTP_KSTAT(sctps, sctp_send_err_failed);
			/* Just free the latest error chunk. */
			freeb(emp);
			return;
		}
		sendmp->b_cont = sctp->sctp_err_chunks;
		sctp_set_iplen(sctp, sendmp, fp->sf_ixa);
		(void) conn_ip_output(sendmp, fp->sf_ixa);
		BUMP_LOCAL(sctp->sctp_opkts);

		sctp->sctp_err_chunks = emp;
		sctp->sctp_err_len = emp_len;
		SCTP_SET_CHUNK_DEST(emp, dest);
	} else {
		if (sctp->sctp_err_chunks != NULL)
			linkb(sctp->sctp_err_chunks, emp);
		else
			sctp->sctp_err_chunks = emp;
		sctp->sctp_err_len += emp_len;
	}
	/* Assume that we will send it out... */
	BUMP_LOCAL(sctp->sctp_obchunks);
}
コード例 #2
0
ファイル: sctp_error.c プロジェクト: apprisi/illumos-gate
/*
 * Called from sctp_input_data() to send out error chunks created during
 * the processing of all the chunks in an incoming packet.
 */
void
sctp_process_err(sctp_t *sctp)
{
	sctp_stack_t *sctps = sctp->sctp_sctps;
	mblk_t *errmp;
	mblk_t *sendmp;
	sctp_faddr_t *fp;

	ASSERT(sctp->sctp_err_chunks != NULL);
	errmp = sctp->sctp_err_chunks;
	fp = SCTP_CHUNK_DEST(errmp);
	if ((sendmp = sctp_make_mp(sctp, fp, 0)) == NULL) {
		SCTP_KSTAT(sctps, sctp_send_err_failed);
		freemsg(errmp);
		goto done;
	}
	sendmp->b_cont = errmp;
	sctp_set_iplen(sctp, sendmp, fp->sf_ixa);
	(void) conn_ip_output(sendmp, fp->sf_ixa);
	BUMP_LOCAL(sctp->sctp_opkts);
done:
	sctp->sctp_err_chunks = NULL;
	sctp->sctp_err_len = 0;
}
コード例 #3
0
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
}
コード例 #4
0
void
sctp_input_asconf_ack(sctp_t *sctp, sctp_chunk_hdr_t *ch, sctp_faddr_t *fp)
{
	const dispatch_t	*dp;
	uint32_t		*idp;
	uint32_t		*snp;
	ssize_t			rlen;
	ssize_t			plen;
	sctp_parm_hdr_t		*ph;
	sctp_parm_hdr_t		*oph;
	sctp_parm_hdr_t		*fph;
	mblk_t			*mp;
	sctp_chunk_hdr_t	*och;
	int			redosrcs = 0;
	uint16_t		param_len;
	uchar_t			*alist;
	uchar_t			*dlist;
	uint_t			acount = 0;
	uint_t			dcount = 0;
	uchar_t			*aptr;
	uchar_t			*dptr;
	sctp_cl_ainfo_t		*ainfo;
	in6_addr_t		addr;

	ASSERT(ch->sch_id == CHUNK_ASCONF_ACK);

	snp = (uint32_t *)(ch + 1);
	rlen = ntohs(ch->sch_len) - sizeof (*ch) - sizeof (*snp);
	if (rlen < 0) {
		return;
	}

	/* Accept only an ACK for the current serial number */
	*snp = ntohl(*snp);
	if (sctp->sctp_cxmit_list == NULL || *snp != (sctp->sctp_lcsn - 1)) {
		/* Need to send an abort */
		return;
	}
	sctp->sctp_cchunk_pend = 0;
	SCTP_FADDR_RC_TIMER_STOP(fp);

	mp = sctp->sctp_cxmit_list;
	/*
	 * We fill in the addresses here to update the clustering's state for
	 * this assoc.
	 */
	if (mp != NULL && cl_sctp_assoc_change != NULL) {
		ASSERT(mp->b_prev != NULL);
		ainfo = (sctp_cl_ainfo_t *)mp->b_prev;
		alist = ainfo->sctp_cl_alist;
		dlist = ainfo->sctp_cl_dlist;
		aptr = alist;
		dptr = dlist;
	}

	/*
	 * Pass explicit replies to callbacks:
	 * For each reply in the ACK, look up the corresponding
	 * original parameter in the request using the correlation
	 * ID, and pass it to the right callback.
	 */
	och = (sctp_chunk_hdr_t *)sctp->sctp_cxmit_list->b_rptr;

	plen = ntohs(och->sch_len) - sizeof (*och) - sizeof (*idp);
	idp = (uint32_t *)(och + 1);

	/* Get to the 1st ASCONF param, need to skip Address TLV parm */
	fph = (sctp_parm_hdr_t *)(idp + 1);
	plen -= ntohs(fph->sph_len);
	fph = (sctp_parm_hdr_t *)((char *)fph + ntohs(fph->sph_len));
	ph = (sctp_parm_hdr_t *)(snp + 1);
	while (rlen > 0) {
		/* Sanity checks */
		if (rlen < sizeof (*ph)) {
			break;
		}
		param_len = ntohs(ph->sph_len);
		if (param_len < sizeof (*ph) || param_len > rlen) {
			break;
		}
		idp = (uint32_t *)(ph + 1);
		oph = sctp_lookup_asconf_param(fph, *idp, plen);
		if (oph != NULL) {
			dp = sctp_lookup_asconf_dispatch(ntohs(oph->sph_type));
			ASSERT(dp);
			if (dp->asconf_ack) {
				dp->asconf_ack(sctp, ph, oph, fp, &addr);

				/* hack. see below */
				if (oph->sph_type == htons(PARM_ADD_IP) ||
				    oph->sph_type == htons(PARM_DEL_IP)) {
					redosrcs = 1;
					/*
					 * If the address was sucessfully
					 * processed, add it to the add/delete
					 * list to send to the clustering
					 * module.
					 */
					if (cl_sctp_assoc_change != NULL &&
					    !SCTP_IS_ADDR_UNSPEC(
					    IN6_IS_ADDR_V4MAPPED(&addr),
					    addr)) {
						if (oph->sph_type ==
						    htons(PARM_ADD_IP)) {
							bcopy(&addr, aptr,
							    sizeof (addr));
							aptr += sizeof (addr);
							acount++;
						} else {
							bcopy(&addr, dptr,
							    sizeof (addr));
							dptr += sizeof (addr);
							dcount++;
						}
					}
				}
			}
		}

		ph = sctp_next_parm(ph, &rlen);
		if (ph == NULL)
			break;
	}

	/*
	 * Pass implicit replies to callbacks:
	 * For each original request, look up its parameter
	 * in the ACK. If there is no corresponding reply,
	 * call the callback with a NULL parameter, indicating
	 * success.
	 */
	rlen = plen;
	plen = ntohs(ch->sch_len) - sizeof (*ch) - sizeof (*idp);
	oph = fph;
	fph = (sctp_parm_hdr_t *)((char *)ch + sizeof (sctp_chunk_hdr_t) +
	    sizeof (uint32_t));
	while (rlen > 0) {
		idp = (uint32_t *)(oph + 1);
		ph = sctp_lookup_asconf_param(fph, *idp, plen);
		if (ph == NULL) {
			dp = sctp_lookup_asconf_dispatch(ntohs(oph->sph_type));
			ASSERT(dp);
			if (dp->asconf_ack) {
				dp->asconf_ack(sctp, NULL, oph, fp, &addr);

				/* hack. see below */
				if (oph->sph_type == htons(PARM_ADD_IP) ||
				    oph->sph_type == htons(PARM_DEL_IP)) {
					redosrcs = 1;
					/*
					 * If the address was sucessfully
					 * processed, add it to the add/delete
					 * list to send to the clustering
					 * module.
					 */
					if (cl_sctp_assoc_change != NULL &&
					    !SCTP_IS_ADDR_UNSPEC(
					    IN6_IS_ADDR_V4MAPPED(&addr),
					    addr)) {
						if (oph->sph_type ==
						    htons(PARM_ADD_IP)) {
							bcopy(&addr, aptr,
							    sizeof (addr));
							aptr += sizeof (addr);
							acount++;
						} else {
							bcopy(&addr, dptr,
							    sizeof (addr));
							dptr += sizeof (addr);
							dcount++;
						}
					}
				}
			}
		}
		oph = sctp_next_parm(oph, &rlen);
		if (oph == NULL) {
			break;
		}
	}

	/* We can now free up the first chunk in the cxmit list */
	sctp->sctp_cxmit_list = mp->b_cont;
	mp->b_cont = NULL;

	fp = SCTP_CHUNK_DEST(mp);
	ASSERT(fp != NULL && fp->suna >= MBLKL(mp));
	fp->suna -= MBLKL(mp);

	/*
	 * Update clustering's state for this assoc. Note acount/dcount
	 * could be zero (i.e. if the add/delete address(es) did not
	 * succeed). Regardless, if the ?size is > 0, it is the clustering
	 * module's responsibility to free the lists.
	 */
	if (cl_sctp_assoc_change != NULL) {
		ASSERT(mp->b_prev != NULL);
		mp->b_prev = NULL;
		ainfo->sctp_cl_alist = NULL;
		ainfo->sctp_cl_dlist = NULL;
		(*cl_sctp_assoc_change)(sctp->sctp_connp->conn_family, alist,
		    ainfo->sctp_cl_asize, acount, dlist, ainfo->sctp_cl_dsize,
		    dcount, SCTP_CL_LADDR, (cl_sctp_handle_t)sctp);
		/* alist and dlist will be freed by the clustering module */
		ainfo->sctp_cl_asize = 0;
		ainfo->sctp_cl_dsize = 0;
		kmem_free(ainfo, sizeof (*ainfo));
	}
	freeb(mp);

	/* can now send the next control chunk */
	if (sctp->sctp_cxmit_list != NULL)
		sctp_wput_asconf(sctp, NULL);

	/*
	 * If an add-ip or del-ip has completed (successfully or
	 * unsuccessfully), the pool of available source addresses
	 * may have changed, so we need to redo faddr source
	 * address selections. This is a bit of a hack since
	 * this really belongs in the add/del-ip code. However,
	 * that code consists of callbacks called for *each*
	 * add/del-ip parameter, and sctp_redo_faddr_srcs() is
	 * expensive enough that we really don't want to be
	 * doing it for each one. So we do it once here.
	 */
	if (redosrcs)
		sctp_redo_faddr_srcs(sctp);
}