/* * 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); }
/* * 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); }