예제 #1
0
/*
 * Call this function to get information about a peer addr fp.
 *
 * Uses ip_attr_connect to avoid explicit use of ire and source address
 * selection.
 */
void
sctp_get_dest(sctp_t *sctp, sctp_faddr_t *fp)
{
	in6_addr_t	laddr;
	in6_addr_t	nexthop;
	sctp_saddr_ipif_t *sp;
	int		hdrlen;
	sctp_stack_t	*sctps = sctp->sctp_sctps;
	conn_t		*connp = sctp->sctp_connp;
	iulp_t		uinfo;
	uint_t		pmtu;
	int		error;
	uint32_t	flags = IPDF_VERIFY_DST | IPDF_IPSEC |
	    IPDF_SELECT_SRC | IPDF_UNIQUE_DCE;

	/*
	 * Tell sctp_make_mp it needs to call us again should we not
	 * complete and set the saddr.
	 */
	fp->saddr = ipv6_all_zeros;

	/*
	 * If this addr is not reachable, mark it as unconfirmed for now, the
	 * state will be changed back to unreachable later in this function
	 * if it is still the case.
	 */
	if (fp->state == SCTP_FADDRS_UNREACH) {
		fp->state = SCTP_FADDRS_UNCONFIRMED;
	}

	/*
	 * Socket is connected - enable PMTU discovery.
	 */
	if (!sctps->sctps_ignore_path_mtu)
		fp->ixa->ixa_flags |= IXAF_PMTU_DISCOVERY;

	ip_attr_nexthop(&connp->conn_xmit_ipp, fp->ixa, &fp->faddr,
	    &nexthop);

	laddr = fp->saddr;
	error = ip_attr_connect(connp, fp->ixa, &laddr, &fp->faddr, &nexthop,
	    connp->conn_fport, &laddr, &uinfo, flags);

	if (error != 0) {
		dprint(3, ("sctp_get_dest: no ire for %x:%x:%x:%x\n",
		    SCTP_PRINTADDR(fp->faddr)));
		/*
		 * It is tempting to just leave the src addr
		 * unspecified and let IP figure it out, but we
		 * *cannot* do this, since IP may choose a src addr
		 * that is not part of this association... unless
		 * this sctp has bound to all addrs.  So if the dest
		 * lookup fails, try to find one in our src addr
		 * list, unless the sctp has bound to all addrs, in
		 * which case we change the src addr to unspec.
		 *
		 * Note that if this is a v6 endpoint but it does
		 * not have any v4 address at this point (e.g. may
		 * have been  deleted), sctp_get_valid_addr() will
		 * return mapped INADDR_ANY.  In this case, this
		 * address should be marked not reachable so that
		 * it won't be used to send data.
		 */
		sctp_set_saddr(sctp, fp);
		if (fp->state == SCTP_FADDRS_UNREACH)
			return;
		goto check_current;
	}
	ASSERT(fp->ixa->ixa_ire != NULL);
	ASSERT(!(fp->ixa->ixa_ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)));

	if (!sctp->sctp_loopback)
		sctp->sctp_loopback = uinfo.iulp_loopback;

	/* Make sure the laddr is part of this association */
	if ((sp = sctp_saddr_lookup(sctp, &laddr, 0)) != NULL &&
	    !sp->saddr_ipif_dontsrc) {
		if (sp->saddr_ipif_unconfirmed == 1)
			sp->saddr_ipif_unconfirmed = 0;
		/* We did IPsec policy lookup for laddr already */
		fp->saddr = laddr;
	} else {
		dprint(2, ("sctp_get_dest: src addr is not part of assoc "
		    "%x:%x:%x:%x\n", SCTP_PRINTADDR(laddr)));

		/*
		 * Set the src to the first saddr and hope for the best.
		 * Note that this case should very seldomly
		 * happen.  One scenario this can happen is an app
		 * explicitly bind() to an address.  But that address is
		 * not the preferred source address to send to the peer.
		 */
		sctp_set_saddr(sctp, fp);
		if (fp->state == SCTP_FADDRS_UNREACH) {
			return;
		}
	}

	/*
	 * Pull out RTO information for this faddr and use it if we don't
	 * have any yet.
	 */
	if (fp->srtt == -1 && uinfo.iulp_rtt != 0) {
		/* The cached value is in ms. */
		fp->srtt = MSEC_TO_TICK(uinfo.iulp_rtt);
		fp->rttvar = MSEC_TO_TICK(uinfo.iulp_rtt_sd);
		fp->rto = 3 * fp->srtt;

		/* Bound the RTO by configured min and max values */
		if (fp->rto < sctp->sctp_rto_min) {
			fp->rto = sctp->sctp_rto_min;
		}
		if (fp->rto > sctp->sctp_rto_max) {
			fp->rto = sctp->sctp_rto_max;
		}
		SCTP_MAX_RTO(sctp, fp);
	}
	pmtu = uinfo.iulp_mtu;

	/*
	 * Record the MTU for this faddr. If the MTU for this faddr has
	 * changed, check if the assc MTU will also change.
	 */
	if (fp->isv4) {
		hdrlen = sctp->sctp_hdr_len;
	} else {
		hdrlen = sctp->sctp_hdr6_len;
	}
	if ((fp->sfa_pmss + hdrlen) != pmtu) {
		/* Make sure that sfa_pmss is a multiple of SCTP_ALIGN. */
		fp->sfa_pmss = (pmtu - hdrlen) & ~(SCTP_ALIGN - 1);
		if (fp->cwnd < (fp->sfa_pmss * 2)) {
			SET_CWND(fp, fp->sfa_pmss,
			    sctps->sctps_slow_start_initial);
		}
	}

check_current:
	if (fp == sctp->sctp_current)
		sctp_set_faddr_current(sctp, fp);
}
예제 #2
0
파일: sctp_hash.c 프로젝트: andreiw/polaris
/*
 * Walk the SCTP global list and refrele the ire for this ipif
 * This is called when an address goes down, so that we release any reference
 * to the ire associated with this address. Additionally, for any SCTP if
 * this was the only/last address in its source list, we don't kill the
 * assoc., if there is no address added subsequently, or if this does not
 * come up, then the assoc. will die a natural death (i.e. timeout).
 */
void
sctp_ire_cache_flush(ipif_t *ipif)
{
	sctp_t			*sctp;
	sctp_t			*sctp_prev = NULL;
	sctp_faddr_t		*fp;
	conn_t			*connp;
	ire_t			*ire;

	sctp = gsctp;
	mutex_enter(&sctp_g_lock);
	while (sctp != NULL) {
		mutex_enter(&sctp->sctp_reflock);
		if (sctp->sctp_condemned) {
			mutex_exit(&sctp->sctp_reflock);
			sctp = list_next(&sctp_g_list, sctp);
			continue;
		}
		sctp->sctp_refcnt++;
		mutex_exit(&sctp->sctp_reflock);
		mutex_exit(&sctp_g_lock);
		if (sctp_prev != NULL)
			SCTP_REFRELE(sctp_prev);

		RUN_SCTP(sctp);
		connp = sctp->sctp_connp;
		mutex_enter(&connp->conn_lock);
		ire = connp->conn_ire_cache;
		if (ire != NULL && ire->ire_ipif == ipif) {
			connp->conn_ire_cache = NULL;
			mutex_exit(&connp->conn_lock);
			IRE_REFRELE_NOTR(ire);
		} else {
			mutex_exit(&connp->conn_lock);
		}
		/* check for ires cached in faddr */
		for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) {
			/*
			 * If this ipif is being used as the source address
			 * we need to update it as well, else we will end
			 * up using the dead source address.
			 */
			ire = fp->ire;
			if (ire != NULL && ire->ire_ipif == ipif) {
				fp->ire = NULL;
				IRE_REFRELE_NOTR(ire);
			}
			/*
			 * This may result in setting the fp as unreachable,
			 * i.e. if all the source addresses are down. In
			 * that case the assoc. would timeout.
			 */
			if (IN6_ARE_ADDR_EQUAL(&ipif->ipif_v6lcl_addr,
			    &fp->saddr)) {
				sctp_set_saddr(sctp, fp);
				if (fp == sctp->sctp_current &&
				    fp->state != SCTP_FADDRS_UNREACH) {
					sctp_set_faddr_current(sctp, fp);
				}
			}
		}
		WAKE_SCTP(sctp);
		sctp_prev = sctp;
		mutex_enter(&sctp_g_lock);
		sctp = list_next(&sctp_g_list, sctp);
	}
	mutex_exit(&sctp_g_lock);
	if (sctp_prev != NULL)
		SCTP_REFRELE(sctp_prev);
}