34c34
< __FBSDID("$FreeBSD: head/sys/netinet/sctp_output.c 166675 2007-02-12 23:24:31Z rrs $");
---
> __FBSDID("$FreeBSD: head/sys/netinet/sctp_output.c 167598 2007-03-15 11:27:14Z rrs $");
38a39
> #include <netinet/sctp_sysctl.h>
51,52d51
< #ifdef SCTP_DEBUG
< extern uint32_t sctp_debug_on;
54d52
< #endif
56,57d53
<
<
1862a1859,1877
> int
> sctp_is_address_in_scope(struct sctp_ifa *ifa,
> int ipv4_addr_legal,
> int ipv6_addr_legal,
> int loopback_scope,
> int ipv4_local_scope,
> int local_scope,
> int site_scope,
> int do_update)
> {
> if ((loopback_scope == 0) &&
> (ifa->ifn_p) && SCTP_IFN_IS_IFT_LOOP(ifa->ifn_p)) {
> /*
> * skip loopback if not in scope *
> */
> return (0);
> }
> if ((ifa->address.sa.sa_family == AF_INET) && ipv4_addr_legal) {
> struct sockaddr_in *sin;
1863a1879,1890
> sin = (struct sockaddr_in *)&ifa->address.sin;
> if (sin->sin_addr.s_addr == 0) {
> /* not in scope , unspecified */
> return (0);
> }
> if ((ipv4_local_scope == 0) &&
> (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
> /* private address not in scope */
> return (0);
> }
> } else if ((ifa->address.sa.sa_family == AF_INET6) && ipv6_addr_legal) {
> struct sockaddr_in6 *sin6;
1865c1892,1920
< extern int sctp_peer_chunk_oh;
---
> /*
> * Must update the flags, bummer, which means any IFA locks
> * must now be applied HERE <->
> */
> if (do_update) {
> sctp_gather_internal_ifa_flags(ifa);
> }
> if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
> return (0);
> }
> /* ok to use deprecated addresses? */
> sin6 = (struct sockaddr_in6 *)&ifa->address.sin6;
> if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
> /* skip unspecifed addresses */
> return (0);
> }
> if ( /* (local_scope == 0) && */
> (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
> return (0);
> }
> if ((site_scope == 0) &&
> (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
> return (0);
> }
> } else {
> return (0);
> }
> return (1);
> }
1866a1922,2624
> static struct mbuf *
> sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa)
> {
> struct sctp_paramhdr *parmh;
> struct mbuf *mret;
> int len;
>
> if (ifa->address.sa.sa_family == AF_INET) {
> len = sizeof(struct sctp_ipv4addr_param);
> } else if (ifa->address.sa.sa_family == AF_INET6) {
> len = sizeof(struct sctp_ipv6addr_param);
> } else {
> /* unknown type */
> return (m);
> }
> if (M_TRAILINGSPACE(m) >= len) {
> /* easy side we just drop it on the end */
> parmh = (struct sctp_paramhdr *)(SCTP_BUF_AT(m, SCTP_BUF_LEN(m)));
> mret = m;
> } else {
> /* Need more space */
> mret = m;
> while (SCTP_BUF_NEXT(mret) != NULL) {
> mret = SCTP_BUF_NEXT(mret);
> }
> SCTP_BUF_NEXT(mret) = sctp_get_mbuf_for_msg(len, 0, M_DONTWAIT, 1, MT_DATA);
> if (SCTP_BUF_NEXT(mret) == NULL) {
> /* We are hosed, can't add more addresses */
> return (m);
> }
> mret = SCTP_BUF_NEXT(mret);
> parmh = mtod(mret, struct sctp_paramhdr *);
> }
> /* now add the parameter */
> if (ifa->address.sa.sa_family == AF_INET) {
> struct sctp_ipv4addr_param *ipv4p;
> struct sockaddr_in *sin;
>
> sin = (struct sockaddr_in *)&ifa->address.sin;
> ipv4p = (struct sctp_ipv4addr_param *)parmh;
> parmh->param_type = htons(SCTP_IPV4_ADDRESS);
> parmh->param_length = htons(len);
> ipv4p->addr = sin->sin_addr.s_addr;
> SCTP_BUF_LEN(mret) += len;
> } else if (ifa->address.sa.sa_family == AF_INET6) {
> struct sctp_ipv6addr_param *ipv6p;
> struct sockaddr_in6 *sin6;
>
> sin6 = (struct sockaddr_in6 *)&ifa->address.sin6;
> ipv6p = (struct sctp_ipv6addr_param *)parmh;
> parmh->param_type = htons(SCTP_IPV6_ADDRESS);
> parmh->param_length = htons(len);
> memcpy(ipv6p->addr, &sin6->sin6_addr,
> sizeof(ipv6p->addr));
> /* clear embedded scope in the address */
> in6_clearscope((struct in6_addr *)ipv6p->addr);
> SCTP_BUF_LEN(mret) += len;
> } else {
> return (m);
> }
> return (mret);
> }
>
>
> struct mbuf *
> sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, struct sctp_scoping *scope,
> struct mbuf *m_at, int cnt_inits_to)
> {
> struct sctp_vrf *vrf = NULL;
> int cnt, limit_out = 0, total_count;
> uint32_t vrf_id;
>
> vrf_id = SCTP_DEFAULT_VRFID;
> SCTP_IPI_ADDR_LOCK();
> vrf = sctp_find_vrf(vrf_id);
> if (vrf == NULL) {
> SCTP_IPI_ADDR_UNLOCK();
> return (m_at);
> }
> if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
> struct sctp_ifa *sctp_ifap;
> struct sctp_ifn *sctp_ifnp;
>
> cnt = cnt_inits_to;
> if (vrf->total_ifa_count > SCTP_COUNT_LIMIT) {
> limit_out = 1;
> cnt = SCTP_ADDRESS_LIMIT;
> goto skip_count;
> }
> LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
> if ((scope->loopback_scope == 0) &&
> SCTP_IFN_IS_IFT_LOOP(sctp_ifnp)) {
> /*
> * Skip loopback devices if loopback_scope
> * not set
> */
> continue;
> }
> LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
> if (sctp_is_address_in_scope(sctp_ifap,
> scope->ipv4_addr_legal,
> scope->ipv6_addr_legal,
> scope->loopback_scope,
> scope->ipv4_local_scope,
> scope->local_scope,
> scope->site_scope, 1) == 0) {
> continue;
> }
> cnt++;
> if (cnt > SCTP_ADDRESS_LIMIT) {
> break;
> }
> }
> if (cnt > SCTP_ADDRESS_LIMIT) {
> break;
> }
> }
> skip_count:
> if (cnt > 1) {
> total_count = 0;
> LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
> cnt = 0;
> if ((scope->loopback_scope == 0) &&
> SCTP_IFN_IS_IFT_LOOP(sctp_ifnp)) {
> /*
> * Skip loopback devices if
> * loopback_scope not set
> */
> continue;
> }
> LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
> if (sctp_is_address_in_scope(sctp_ifap,
> scope->ipv4_addr_legal,
> scope->ipv6_addr_legal,
> scope->loopback_scope,
> scope->ipv4_local_scope,
> scope->local_scope,
> scope->site_scope, 0) == 0) {
> continue;
> }
> m_at = sctp_add_addr_to_mbuf(m_at, sctp_ifap);
> if (limit_out) {
> cnt++;
> total_count++;
> if (cnt >= 2) {
> /*
> * two from each
> * address
> */
> break;
> }
> if (total_count > SCTP_ADDRESS_LIMIT) {
> /* No more addresses */
> break;
> }
> }
> }
> }
> }
> } else {
> struct sctp_laddr *laddr;
>
> cnt = cnt_inits_to;
> /* First, how many ? */
> LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
> if (laddr->ifa == NULL) {
> continue;
> }
> if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED)
> /*
> * Address being deleted by the system, dont
> * list.
> */
> continue;
> if (laddr->action == SCTP_DEL_IP_ADDRESS) {
> /*
> * Address being deleted on this ep don't
> * list.
> */
> continue;
> }
> if (sctp_is_address_in_scope(laddr->ifa,
> scope->ipv4_addr_legal,
> scope->ipv6_addr_legal,
> scope->loopback_scope,
> scope->ipv4_local_scope,
> scope->local_scope,
> scope->site_scope, 1) == 0) {
> continue;
> }
> cnt++;
> }
> if (cnt > SCTP_ADDRESS_LIMIT) {
> limit_out = 1;
> }
> /*
> * To get through a NAT we only list addresses if we have
> * more than one. That way if you just bind a single address
> * we let the source of the init dictate our address.
> */
> if (cnt > 1) {
> LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
> cnt = 0;
> if (laddr->ifa == NULL) {
> continue;
> }
> if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED)
> continue;
>
> if (sctp_is_address_in_scope(laddr->ifa,
> scope->ipv4_addr_legal,
> scope->ipv6_addr_legal,
> scope->loopback_scope,
> scope->ipv4_local_scope,
> scope->local_scope,
> scope->site_scope, 0) == 0) {
> continue;
> }
> m_at = sctp_add_addr_to_mbuf(m_at, laddr->ifa);
> cnt++;
> if (cnt >= SCTP_ADDRESS_LIMIT) {
> break;
> }
> }
> }
> }
> SCTP_IPI_ADDR_UNLOCK();
> return (m_at);
> }
>
> static struct sctp_ifa *
> sctp_is_ifa_addr_prefered(struct sctp_ifa *ifa,
> uint8_t dest_is_loop,
> uint8_t dest_is_priv,
> sa_family_t fam)
> {
> uint8_t dest_is_global = 0;
>
> /*
> * is_scope -> dest_is_priv is true if destination is a private
> * address
> */
> /* dest_is_loop is true if destination is a loopback addresses */
>
> /*
> * Here we determine if its a prefered address. A prefered address
> * means it is the same scope or higher scope then the destination.
> * L = loopback, P = private, G = global
> * ----------------------------------------- src | dest | result
> * ---------------------------------------- L | L | yes
> * ----------------------------------------- P | L |
> * yes-v4 no-v6 ----------------------------------------- G |
> * L | yes-v4 no-v6 ----------------------------------------- L
> * | P | no ----------------------------------------- P |
> * P | yes ----------------------------------------- G |
> * P | no ----------------------------------------- L | G
> * | no ----------------------------------------- P | G |
> * no ----------------------------------------- G | G |
> * yes -----------------------------------------
> */
>
> if (ifa->address.sa.sa_family != fam) {
> /* forget mis-matched family */
> return (NULL);
> }
> if ((dest_is_priv == 0) && (dest_is_loop == 0)) {
> dest_is_global = 1;
> }
> /* Ok the address may be ok */
> if (fam == AF_INET6) {
> /* ok to use deprecated addresses? */
> if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
> return (NULL);
> }
> if (ifa->src_is_priv) {
> if (dest_is_loop) {
> return (NULL);
> }
> }
> if (ifa->src_is_glob) {
>
> if (dest_is_loop) {
> return (NULL);
> }
> }
> }
> /*
> * Now that we know what is what, implement or table this could in
> * theory be done slicker (it used to be), but this is
> * straightforward and easier to validate :-)
> */
> if ((ifa->src_is_loop) && (dest_is_priv)) {
> return (NULL);
> }
> if ((ifa->src_is_glob) && (dest_is_priv)) {
> return (NULL);
> }
> if ((ifa->src_is_loop) && (dest_is_global)) {
> return (NULL);
> }
> if ((ifa->src_is_priv) && (dest_is_global)) {
> return (NULL);
> }
> /* its a prefered address */
> return (ifa);
> }
>
> static struct sctp_ifa *
> sctp_is_ifa_addr_acceptable(struct sctp_ifa *ifa,
> uint8_t dest_is_loop,
> uint8_t dest_is_priv,
> sa_family_t fam)
> {
> uint8_t dest_is_global = 0;
>
>
> /*
> * Here we determine if its a acceptable address. A acceptable
> * address means it is the same scope or higher scope but we can
> * allow for NAT which means its ok to have a global dest and a
> * private src.
> *
> * L = loopback, P = private, G = global
> * ----------------------------------------- src | dest | result
> * ----------------------------------------- L | L | yes
> * ----------------------------------------- P | L |
> * yes-v4 no-v6 ----------------------------------------- G |
> * L | yes ----------------------------------------- L |
> * P | no ----------------------------------------- P | P
> * | yes ----------------------------------------- G | P
> * | yes - May not work -----------------------------------------
> * L | G | no ----------------------------------------- P
> * | G | yes - May not work
> * ----------------------------------------- G | G | yes
> * -----------------------------------------
> */
>
> if (ifa->address.sa.sa_family != fam) {
> /* forget non matching family */
> return (NULL);
> }
> /* Ok the address may be ok */
> if ((dest_is_loop == 0) && (dest_is_priv == 0)) {
> dest_is_global = 1;
> }
> if (fam == AF_INET6) {
> /* ok to use deprecated addresses? */
> if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
> return (NULL);
> }
> if (ifa->src_is_priv) {
> /* Special case, linklocal to loop */
> if (dest_is_loop)
> return (NULL);
> }
> }
> /*
> * Now that we know what is what, implement or table this could in
> * theory be done slicker (it used to be), but this is
> * straightforward and easier to validate :-)
> */
>
> if ((ifa->src_is_loop == 0) && (dest_is_priv)) {
> return (NULL);
> }
> if ((ifa->src_is_loop == 0) && (dest_is_global)) {
> return (NULL);
> }
> /* its an acceptable address */
> return (ifa);
> }
>
> int
> sctp_is_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
> {
> struct sctp_laddr *laddr;
>
> if (stcb == NULL) {
> /* There are no restrictions, no TCB :-) */
> return (0);
> }
> LIST_FOREACH(laddr, &stcb->asoc.sctp_restricted_addrs, sctp_nxt_addr) {
> if (laddr->ifa == NULL) {
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) {
> printf("Help I have fallen and I can't get up!\n");
> }
> #endif
> continue;
> }
> if (laddr->ifa == ifa) {
> /* Yes it is on the list */
> return (1);
> }
> }
> return (0);
> }
>
>
> int
> sctp_is_addr_in_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa)
> {
> struct sctp_laddr *laddr;
>
> if (ifa == NULL)
> return (0);
> LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
> if (laddr->ifa == NULL) {
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) {
> printf("Help I have fallen and I can't get up!\n");
> }
> #endif
> continue;
> }
> if ((laddr->ifa == ifa) && laddr->action == 0)
> /* same pointer */
> return (1);
> }
> return (0);
> }
>
>
>
> static struct sctp_ifa *
> sctp_choose_boundspecific_inp(struct sctp_inpcb *inp,
> struct route *ro,
> uint32_t vrf_id,
> int non_asoc_addr_ok,
> uint8_t dest_is_priv,
> uint8_t dest_is_loop,
> sa_family_t fam)
> {
> struct sctp_laddr *laddr, *starting_point;
> void *ifn;
> int resettotop = 0;
> struct sctp_ifn *sctp_ifn;
> struct sctp_ifa *sctp_ifa, *pass;
> struct sctp_vrf *vrf;
> uint32_t ifn_index;
>
> vrf = sctp_find_vrf(vrf_id);
> if (vrf == NULL)
> return (NULL);
>
> ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro);
> ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro);
> sctp_ifn = sctp_find_ifn(vrf, ifn, ifn_index);
> /*
> * first question, is the ifn we will emit on in our list, if so, we
> * want such an address. Note that we first looked for a prefered
> * address.
> */
> if (sctp_ifn) {
> /* is a prefered one on the interface we route out? */
> LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
> if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
> continue;
> pass = sctp_is_ifa_addr_prefered(sctp_ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if (sctp_is_addr_in_ep(inp, pass)) {
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
> }
> }
> /*
> * ok, now we now need to find one on the list of the addresses. We
> * can't get one on the emitting interface so lets find first a
> * prefered one. If not that a acceptable one otherwise... we return
> * NULL.
> */
> starting_point = inp->next_addr_touse;
> once_again:
> if (inp->next_addr_touse == NULL) {
> inp->next_addr_touse = LIST_FIRST(&inp->sctp_addr_list);
> resettotop = 1;
> }
> for (laddr = inp->next_addr_touse; laddr; laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
> if (laddr->ifa == NULL) {
> /* address has been removed */
> continue;
> }
> pass = sctp_is_ifa_addr_prefered(laddr->ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
> if (resettotop == 0) {
> inp->next_addr_touse = NULL;
> goto once_again;
> }
> inp->next_addr_touse = starting_point;
> resettotop = 0;
> once_again_too:
> if (inp->next_addr_touse == NULL) {
> inp->next_addr_touse = LIST_FIRST(&inp->sctp_addr_list);
> resettotop = 1;
> }
> /* ok, what about an acceptable address in the inp */
> for (laddr = inp->next_addr_touse; laddr; laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
> if (laddr->ifa == NULL) {
> /* address has been removed */
> continue;
> }
> pass = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
> if (resettotop == 0) {
> inp->next_addr_touse = NULL;
> goto once_again_too;
> }
> /*
> * no address bound can be a source for the destination we are in
> * trouble
> */
> return (NULL);
> }
>
>
>
> static struct sctp_ifa *
> sctp_choose_boundspecific_stcb(struct sctp_inpcb *inp,
> struct sctp_tcb *stcb,
> struct sctp_nets *net,
> struct route *ro,
> uint32_t vrf_id,
> uint8_t dest_is_priv,
> uint8_t dest_is_loop,
> int non_asoc_addr_ok,
> sa_family_t fam)
> {
> struct sctp_laddr *laddr, *starting_point;
> void *ifn;
> struct sctp_ifn *sctp_ifn;
> struct sctp_ifa *sctp_ifa, *pass;
> uint8_t start_at_beginning = 0;
> struct sctp_vrf *vrf;
> uint32_t ifn_index;
>
> /*
> * first question, is the ifn we will emit on in our list, if so, we
> * want that one.
> */
> vrf = sctp_find_vrf(vrf_id);
> if (vrf == NULL)
> return (NULL);
>
> ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro);
> ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro);
> sctp_ifn = sctp_find_ifn(vrf, ifn, ifn_index);
>
> /*
> * first question, is the ifn we will emit on in our list, if so, we
> * want that one.. First we look for a prefered. Second we go for an
> * acceptable.
> */
> if (sctp_ifn) {
> /* first try for an prefered address on the ep */
> LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
> if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
> continue;
> if (sctp_is_addr_in_ep(inp, sctp_ifa)) {
> pass = sctp_is_ifa_addr_prefered(sctp_ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if ((non_asoc_addr_ok == 0) &&
> (sctp_is_addr_restricted(stcb, pass))) {
> /* on the no-no list */
> continue;
> }
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
> }
> /* next try for an acceptable address on the ep */
> LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
> if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
> continue;
> if (sctp_is_addr_in_ep(inp, sctp_ifa)) {
> pass = sctp_is_ifa_addr_acceptable(sctp_ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if ((non_asoc_addr_ok == 0) &&
> (sctp_is_addr_restricted(stcb, pass))) {
> /* on the no-no list */
> continue;
> }
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
> }
>
> }
> /*
> * if we can't find one like that then we must look at all addresses
> * bound to pick one at first prefereable then secondly acceptable.
> */
> starting_point = stcb->asoc.last_used_address;
> sctp_from_the_top:
> if (stcb->asoc.last_used_address == NULL) {
> start_at_beginning = 1;
> stcb->asoc.last_used_address = LIST_FIRST(&inp->sctp_addr_list);
> }
> /* search beginning with the last used address */
> for (laddr = stcb->asoc.last_used_address; laddr;
> laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
> if (laddr->ifa == NULL) {
> /* address has been removed */
> continue;
> }
> pass = sctp_is_ifa_addr_prefered(laddr->ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if ((non_asoc_addr_ok == 0) &&
> (sctp_is_addr_restricted(stcb, pass))) {
> /* on the no-no list */
> continue;
> }
> stcb->asoc.last_used_address = laddr;
> atomic_add_int(&pass->refcount, 1);
> return (pass);
>
> }
> if (start_at_beginning == 0) {
> stcb->asoc.last_used_address = NULL;
> goto sctp_from_the_top;
> }
> /* now try for any higher scope than the destination */
> stcb->asoc.last_used_address = starting_point;
> start_at_beginning = 0;
> sctp_from_the_top2:
> if (stcb->asoc.last_used_address == NULL) {
> start_at_beginning = 1;
> stcb->asoc.last_used_address = LIST_FIRST(&inp->sctp_addr_list);
> }
> /* search beginning with the last used address */
> for (laddr = stcb->asoc.last_used_address; laddr;
> laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
> if (laddr->ifa == NULL) {
> /* address has been removed */
> continue;
> }
> pass = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if ((non_asoc_addr_ok == 0) &&
> (sctp_is_addr_restricted(stcb, pass))) {
> /* on the no-no list */
> continue;
> }
> stcb->asoc.last_used_address = laddr;
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
> if (start_at_beginning == 0) {
> stcb->asoc.last_used_address = NULL;
> goto sctp_from_the_top2;
> }
> return (NULL);
> }
>
> static struct sctp_ifa *
> sctp_select_nth_prefered_addr_from_ifn_boundall(struct sctp_ifn *ifn,
> struct sctp_tcb *stcb,
> int non_asoc_addr_ok,
> uint8_t dest_is_loop,
> uint8_t dest_is_priv,
> int addr_wanted,
> sa_family_t fam)
> {
> struct sctp_ifa *ifa, *pass;
> int num_eligible_addr = 0;
>
> LIST_FOREACH(ifa, &ifn->ifalist, next_ifa) {
> if ((ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
> continue;
> pass = sctp_is_ifa_addr_prefered(ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if (stcb) {
> if ((non_asoc_addr_ok == 0) && sctp_is_addr_restricted(stcb, pass)) {
> /*
> * It is restricted for some reason..
> * probably not yet added.
> */
> continue;
> }
> }
> if (num_eligible_addr >= addr_wanted) {
> return (pass);
> }
> num_eligible_addr++;
> }
> return (NULL);
> }
>
>
1867a2626,3042
> sctp_count_num_prefered_boundall(struct sctp_ifn *ifn,
> struct sctp_tcb *stcb,
> int non_asoc_addr_ok,
> uint8_t dest_is_loop,
> uint8_t dest_is_priv,
> sa_family_t fam)
> {
> struct sctp_ifa *ifa, *pass;
> int num_eligible_addr = 0;
>
> LIST_FOREACH(ifa, &ifn->ifalist, next_ifa) {
> if ((ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0)) {
> continue;
> }
> pass = sctp_is_ifa_addr_prefered(ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL) {
> continue;
> }
> if (stcb) {
> if ((non_asoc_addr_ok == 0) && sctp_is_addr_restricted(stcb, pass)) {
> /*
> * It is restricted for some reason..
> * probably not yet added.
> */
> continue;
> }
> }
> num_eligible_addr++;
> }
> return (num_eligible_addr);
> }
>
> static struct sctp_ifa *
> sctp_choose_boundall(struct sctp_inpcb *inp,
> struct sctp_tcb *stcb,
> struct sctp_nets *net,
> struct route *ro,
> uint32_t vrf_id,
> uint8_t dest_is_priv,
> uint8_t dest_is_loop,
> int non_asoc_addr_ok,
> sa_family_t fam)
> {
> int cur_addr_num = 0, num_prefered = 0;
> void *ifn;
> struct sctp_ifn *sctp_ifn, *looked_at = NULL, *emit_ifn;
> struct sctp_ifa *sctp_ifa, *pass;
> uint32_t ifn_index;
> struct sctp_vrf *vrf;
>
> /*
> * For boundall we can use any address in the association. If
> * non_asoc_addr_ok is set we can use any address (at least in
> * theory). So we look for prefered addresses first. If we find one,
> * we use it. Otherwise we next try to get an address on the
> * interface, which we should be able to do (unless non_asoc_addr_ok
> * is false and we are routed out that way). In these cases where we
> * can't use the address of the interface we go through all the
> * ifn's looking for an address we can use and fill that in. Punting
> * means we send back address 0, which will probably cause problems
> * actually since then IP will fill in the address of the route ifn,
> * which means we probably already rejected it.. i.e. here comes an
> * abort :-<.
> */
> vrf = sctp_find_vrf(vrf_id);
> if (vrf == NULL)
> return (NULL);
>
> ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro);
> ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro);
>
> emit_ifn = looked_at = sctp_ifn = sctp_find_ifn(vrf, ifn, ifn_index);
> if (sctp_ifn == NULL) {
> /* ?? We don't have this guy ?? */
> goto bound_all_plan_b;
> }
> if (net) {
> cur_addr_num = net->indx_of_eligible_next_to_use;
> }
> num_prefered = sctp_count_num_prefered_boundall(sctp_ifn,
> stcb,
> non_asoc_addr_ok,
> dest_is_loop,
> dest_is_priv, fam);
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) {
> printf("Found %d prefered source addresses\n", num_prefered);
> }
> #endif
> if (num_prefered == 0) {
> /*
> * no eligible addresses, we must use some other interface
> * address if we can find one.
> */
> goto bound_all_plan_b;
> }
> /*
> * Ok we have num_eligible_addr set with how many we can use, this
> * may vary from call to call due to addresses being deprecated
> * etc..
> */
> if (cur_addr_num >= num_prefered) {
> cur_addr_num = 0;
> }
> /*
> * select the nth address from the list (where cur_addr_num is the
> * nth) and 0 is the first one, 1 is the second one etc...
> */
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) {
> printf("cur_addr_num:%d\n", cur_addr_num);
> }
> #endif
> sctp_ifa = sctp_select_nth_prefered_addr_from_ifn_boundall(sctp_ifn, stcb, non_asoc_addr_ok, dest_is_loop,
> dest_is_priv, cur_addr_num, fam);
>
> /* if sctp_ifa is NULL something changed??, fall to plan b. */
> if (sctp_ifa) {
> atomic_add_int(&sctp_ifa->refcount, 1);
> if (net) {
> /* save off where the next one we will want */
> net->indx_of_eligible_next_to_use = cur_addr_num + 1;
> }
> return (sctp_ifa);
> }
> /*
> * plan_b: Look at all interfaces and find a prefered address. If no
> * prefered fall through to plan_c.
> */
> bound_all_plan_b:
> LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
> if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
> /* wrong base scope */
> continue;
> }
> if ((sctp_ifn == looked_at) && looked_at)
> /* already looked at this guy */
> continue;
> num_prefered = sctp_count_num_prefered_boundall(sctp_ifn, stcb, non_asoc_addr_ok,
> dest_is_loop, dest_is_priv, fam);
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) {
> printf("Found ifn:%p %d prefered source addresses\n", ifn, num_prefered);
> }
> #endif
> if (num_prefered == 0) {
> /*
> * None on this interface.
> */
> continue;
> }
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT2) {
> printf("num prefered:%d on interface:%p cur_addr_num:%d\n",
> num_prefered,
> sctp_ifn,
> cur_addr_num);
> }
> #endif
>
> /*
> * Ok we have num_eligible_addr set with how many we can
> * use, this may vary from call to call due to addresses
> * being deprecated etc..
> */
> if (cur_addr_num >= num_prefered) {
> cur_addr_num = 0;
> }
> pass = sctp_select_nth_prefered_addr_from_ifn_boundall(sctp_ifn, stcb, non_asoc_addr_ok, dest_is_loop,
> dest_is_priv, cur_addr_num, fam);
> if (pass == NULL)
> continue;
> if (net) {
> net->indx_of_eligible_next_to_use = cur_addr_num + 1;
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT2) {
> printf("we selected %d\n", cur_addr_num);
> printf("Source:");
> sctp_print_address(&pass->address.sa);
> printf("Dest:");
> sctp_print_address(&net->ro._l_addr.sa);
> }
> #endif
> }
> atomic_add_int(&pass->refcount, 1);
> return (pass);
>
> }
>
> /*
> * plan_c: See if we have an acceptable address on the emit
> * interface
> */
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT2) {
> if (net) {
> printf("Plan C no prefered for Dest:");
> sctp_print_address(&net->ro._l_addr.sa);
> }
> }
> #endif
>
> LIST_FOREACH(sctp_ifa, &emit_ifn->ifalist, next_ifa) {
> if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
> continue;
> pass = sctp_is_ifa_addr_acceptable(sctp_ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if (stcb) {
> if ((non_asoc_addr_ok == 0) && sctp_is_addr_restricted(stcb, pass)) {
> /*
> * It is restricted for some reason..
> * probably not yet added.
> */
> continue;
> }
> }
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
>
> /*
> * plan_d: We are in trouble. No prefered address on the emit
> * interface. And not even a perfered address on all interfaces. Go
> * out and see if we can find an acceptable address somewhere
> * amongst all interfaces.
> */
> LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
> if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
> /* wrong base scope */
> continue;
> }
> if ((sctp_ifn == looked_at) && looked_at)
> /* already looked at this guy */
> continue;
>
> LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
> if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
> continue;
> pass = sctp_is_ifa_addr_acceptable(sctp_ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if (stcb) {
> if ((non_asoc_addr_ok == 0) && sctp_is_addr_restricted(stcb, pass)) {
> /*
> * It is restricted for some
> * reason.. probably not yet added.
> */
> continue;
> }
> }
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
> }
> /*
> * Ok we can find NO address to source from that is not on our
> * negative list and non_asoc_address is NOT ok, or its on our
> * negative list. We cant source to it :-(
> */
> return (NULL);
> }
>
>
>
> /* tcb may be NULL */
> struct sctp_ifa *
> sctp_source_address_selection(struct sctp_inpcb *inp,
> struct sctp_tcb *stcb,
> struct route *ro,
> struct sctp_nets *net,
> int non_asoc_addr_ok, uint32_t vrf_id)
> {
>
> struct sockaddr_in *to = (struct sockaddr_in *)&ro->ro_dst;
> struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)&ro->ro_dst;
> struct sctp_ifa *answer;
> uint8_t dest_is_priv, dest_is_loop;
> int did_rtalloc = 0;
> sa_family_t fam;
>
> /*
> * Rules: - Find the route if needed, cache if I can. - Look at
> * interface address in route, Is it in the bound list. If so we
> * have the best source. - If not we must rotate amongst the
> * addresses.
> *
> * Cavets and issues
> *
> * Do we need to pay attention to scope. We can have a private address
> * or a global address we are sourcing or sending to. So if we draw
> * it out zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
> * For V4 ------------------------------------------ source *
> * dest * result ----------------------------------------- <a>
> * Private * Global * NAT
> * ----------------------------------------- <b> Private *
> * Private * No problem -----------------------------------------
> * <c> Global * Private * Huh, How will this work?
> * ----------------------------------------- <d> Global *
> * Global * No Problem ------------------------------------------
> * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz For V6
> * ------------------------------------------ source * dest *
> * result ----------------------------------------- <a> Linklocal *
> * Global * ----------------------------------------- <b>
> * Linklocal * Linklocal * No problem
> * ----------------------------------------- <c> Global *
> * Linklocal * Huh, How will this work?
> * ----------------------------------------- <d> Global *
> * Global * No Problem ------------------------------------------
> * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
> *
> * And then we add to that what happens if there are multiple addresses
> * assigned to an interface. Remember the ifa on a ifn is a linked
> * list of addresses. So one interface can have more than one IP
> * address. What happens if we have both a private and a global
> * address? Do we then use context of destination to sort out which
> * one is best? And what about NAT's sending P->G may get you a NAT
> * translation, or should you select the G thats on the interface in
> * preference.
> *
> * Decisions:
> *
> * - count the number of addresses on the interface. - if its one, no
> * problem except case <c>. For <a> we will assume a NAT out there.
> * - if there are more than one, then we need to worry about scope P
> * or G. We should prefer G -> G and P -> P if possible. Then as a
> * secondary fall back to mixed types G->P being a last ditch one. -
> * The above all works for bound all, but bound specific we need to
> * use the same concept but instead only consider the bound
> * addresses. If the bound set is NOT assigned to the interface then
> * we must use rotation amongst the bound addresses..
> *
> */
> if (ro->ro_rt == NULL) {
> /*
> * Need a route to cache.
> *
> */
> rtalloc_ign(ro, 0UL);
> did_rtalloc = 1;
> }
> if (ro->ro_rt == NULL) {
> return (NULL);
> }
> fam = to->sin_family;
> dest_is_priv = dest_is_loop = 0;
> /* Setup our scopes for the destination */
> if (fam == AF_INET) {
> /* Scope based on outbound address */
> if ((IN4_ISPRIVATE_ADDRESS(&to->sin_addr))) {
> dest_is_priv = 1;
> } else if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) {
> dest_is_loop = 1;
> if (net != NULL) {
> /* mark it as local */
> net->addr_is_local = 1;
> }
> }
> } else if (fam == AF_INET6) {
> /* Scope based on outbound address */
> if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) {
> /*
> * If the route goes to the loopback address OR the
> * address is a loopback address, we are loopback
> * scope. But we don't use dest_is_priv (link local
> * addresses).
> */
> dest_is_loop = 1;
> if (net != NULL) {
> /* mark it as local */
> net->addr_is_local = 1;
> }
> } else if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) {
> dest_is_priv = 1;
> }
> }
> if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
> /*
> * When bound to all if the address list is set it is a
> * negative list. Addresses being added by asconf.
> */
> answer = sctp_choose_boundall(inp, stcb, net, ro, vrf_id,
> dest_is_priv,
> dest_is_loop,
> non_asoc_addr_ok,
> fam);
> return (answer);
> }
> /*
> * Three possiblities here:
> *
> * a) stcb is NULL, which means we operate only from the list of
> * addresses (ifa's) bound to the endpoint and we care not about the
> * list. b) stcb is NOT-NULL, which means we have an assoc structure
> * and auto-asconf is on. This means that the list of addresses is a
> * NOT list. We use the list from the inp, but any listed address in
> * our list is NOT yet added. However if the non_asoc_addr_ok is set
> * we CAN use an address NOT available (i.e. being added). Its a
> * negative list. c) stcb is NOT-NULL, which means we have an assoc
> * structure and auto-asconf is off. This means that the list of
> * addresses is the ONLY addresses I can use.. its positive.
> *
> * Note we collapse b & c into the same function just like in the v6
> * address selection.
> */
> if (stcb) {
> answer = sctp_choose_boundspecific_stcb(inp, stcb, net, ro, vrf_id,
> dest_is_priv, dest_is_loop, non_asoc_addr_ok, fam);
>
> } else {
> answer = sctp_choose_boundspecific_inp(inp, ro, vrf_id, non_asoc_addr_ok, dest_is_priv, dest_is_loop, fam);
>
> }
> return (answer);
> }
>
> static int
1917,1920c3092
< extern int sctp_mbuf_threshold_count;
<
<
< __inline struct mbuf *
---
> struct mbuf *
2124,2125d3295
< extern int sctp_no_csum_on_loopback;
<
2158a3329
> uint32_t vrf_id;
2160a3332
>
2164a3337,3342
> if (stcb == NULL) {
> vrf_id = SCTP_DEFAULT_VRFID;
> } else {
> vrf_id = stcb->asoc.vrf_id;
> }
>
2189c3367
< struct ip *ip;
---
> struct ip *ip = NULL;
2253,2257c3431,3437
< ((struct sockaddr_in *)&net->ro._s_addr)->sin_addr = sctp_ipv4_source_address_selection(inp,
< stcb,
< ro, net, out_of_asoc_ok);
< if (ro->ro_rt)
< net->src_addr_selected = 1;
---
> net->ro._s_addr = sctp_source_address_selection(inp, stcb,
> ro, net, out_of_asoc_ok, vrf_id);
> if (net->ro._s_addr == NULL) {
> /* No route to host */
> goto no_route;
> }
> net->src_addr_selected = 1;
2259c3439
< ip->ip_src = ((struct sockaddr_in *)&net->ro._s_addr)->sin_addr;
---
> ip->ip_src = net->ro._s_addr->address.sin.sin_addr;
2261,2262c3441,3449
< ip->ip_src = sctp_ipv4_source_address_selection(inp,
< stcb, ro, net, out_of_asoc_ok);
---
> struct sctp_ifa *_lsrc;
>
> _lsrc = sctp_source_address_selection(inp,
> stcb, ro, net, out_of_asoc_ok, vrf_id);
> if (_lsrc == NULL) {
> goto no_route;
> }
> ip->ip_src = _lsrc->address.sin.sin_addr;
> sctp_free_ifa(_lsrc);
2276c3463
< * here!
---
> * here (yet)!
2277a3465
> no_route:
2280,2281c3468,3472
< printf("low_level_output: dropped v4 packet- no valid source addr\n");
< printf("Destination was %x\n", (uint32_t) (ntohl(ip->ip_dst.s_addr)));
---
> printf("low_level_output: dropped packet - no valid source addr\n");
> if (net) {
> printf("Destination was ");
> sctp_print_address(&net->ro._l_addr.sa);
> }
2285,2291c3476,3486
< if ((net->dest_state & SCTP_ADDR_REACHABLE) && stcb)
< sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
< stcb,
< SCTP_FAILED_THRESHOLD,
< (void *)net);
< net->dest_state &= ~SCTP_ADDR_REACHABLE;
< net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
---
> if (net->dest_state & SCTP_ADDR_CONFIRMED) {
> if ((net->dest_state & SCTP_ADDR_REACHABLE) && stcb) {
> printf("no route takes interface %p down\n", net);
> sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
> stcb,
> SCTP_FAILED_THRESHOLD,
> (void *)net);
> net->dest_state &= ~SCTP_ADDR_REACHABLE;
> net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
> }
> }
2302a3498,3501
> if (net->ro._s_addr) {
> sctp_free_ifa(net->ro._s_addr);
> net->ro._s_addr = NULL;
> }
2352c3551
< if (ro->ro_rt)
---
> if (ro->ro_rt) {
2353a3553,3554
> ro->ro_rt = NULL;
> }
2363a3565,3569
> if (net->ro._s_addr &&
> net->src_addr_selected) {
> sctp_free_ifa(net->ro._s_addr);
> net->ro._s_addr = NULL;
> }
2451,2455c3657,3669
< ((struct sockaddr_in6 *)&net->ro._s_addr)->sin6_addr = sctp_ipv6_source_address_selection(inp,
< stcb, ro, net, out_of_asoc_ok);
<
< if (ro->ro_rt)
< net->src_addr_selected = 1;
---
> net->ro._s_addr = sctp_source_address_selection(inp,
> stcb,
> ro,
> net,
> out_of_asoc_ok,
> vrf_id);
> if (net->ro._s_addr == NULL) {
> #ifdef SCTP_DEBUG
> printf("V6:No route to host\n");
> #endif
> goto no_route;
> }
> net->src_addr_selected = 1;
2457c3671
< lsa6->sin6_addr = ((struct sockaddr_in6 *)&net->ro._s_addr)->sin6_addr;
---
> lsa6->sin6_addr = net->ro._s_addr->address.sin6.sin6_addr;
2459,2460c3673,3680
< lsa6->sin6_addr = sctp_ipv6_source_address_selection(
< inp, stcb, ro, net, out_of_asoc_ok);
---
> struct sctp_ifa *_lsrc;
>
> _lsrc = sctp_source_address_selection(inp, stcb, ro, net, out_of_asoc_ok, vrf_id);
> if (_lsrc == NULL) {
> goto no_route;
> }
> lsa6->sin6_addr = _lsrc->address.sin6.sin6_addr;
> sctp_free_ifa(_lsrc);
2470,2501c3690
< #ifdef SCTP_DEBUG
< if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) {
< printf("low_level_output: dropped v6 pkt- no valid source addr\n");
< }
< #endif
< sctp_m_freem(o_pak);
< if (net) {
< if ((net->dest_state & SCTP_ADDR_REACHABLE) && stcb)
< sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
< stcb,
< SCTP_FAILED_THRESHOLD,
< (void *)net);
< net->dest_state &= ~SCTP_ADDR_REACHABLE;
< net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
< if (stcb) {
< if (net == stcb->asoc.primary_destination) {
< /* need a new primary */
< struct sctp_nets *alt;
<
< 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;
< net->src_addr_selected = 0;
< }
< }
< }
< }
< }
< return (EHOSTUNREACH);
---
> goto no_route;
2568c3757
< if (ret)
---
> if (ret) {
2569a3759
> }
2578a3769,3774
>
> if (net->ro._s_addr &&
> net->src_addr_selected) {
> sctp_free_ifa(net->ro._s_addr);
> net->ro._s_addr = NULL;
> }
3266a4463
> uint32_t vrf_id;
3267a4465
> vrf_id = SCTP_DEFAULT_VRFID;
3361c4559
< struct in_addr addr;
---
> struct sctp_ifa *addr;
3378,3379c4576,4580
< addr = sctp_ipv4_source_address_selection(inp, NULL,
< ro, NULL, 0);
---
> addr = sctp_source_address_selection(inp, NULL,
> ro, NULL, 0, vrf_id);
> if (addr == NULL)
> return;
>
3381a4583
> ro->ro_rt = NULL;
3383c4585
< stc.laddress[0] = addr.s_addr;
---
> stc.laddress[0] = addr->address.sin.sin_addr.s_addr;
3398c4600
< if (sctp_is_address_on_local_host((struct sockaddr *)sin)) {
---
> if (sctp_is_address_on_local_host((struct sockaddr *)sin, vrf_id)) {
3402c4604
< stc.local_scope = 1;
---
> stc.local_scope = 0;
3405c4607
< struct in6_addr addr;
---
> struct sctp_ifa *addr;
3420c4622
< if (sctp_is_address_on_local_host((struct sockaddr *)sin6)) {
---
> if (sctp_is_address_on_local_host((struct sockaddr *)sin6, vrf_id)) {
3422c4624
< stc.local_scope = 1;
---
> stc.local_scope = 0;
3462,3463c4664,4668
< addr = sctp_ipv6_source_address_selection(inp, NULL,
< ro, NULL, 0);
---
> addr = sctp_source_address_selection(inp, NULL,
> ro, NULL, 0, vrf_id);
> if (addr == NULL)
> return;
>
3465a4671
> ro->ro_rt = NULL;
3467c4673
< memcpy(&stc.laddress, &addr, sizeof(struct in6_addr));
---
> memcpy(&stc.laddress, &addr->address.sin6.sin6_addr, sizeof(struct in6_addr));
3504,3506c4710,4715
< net->ro._s_addr.sin.sin_addr =
< sctp_ipv4_source_address_selection(inp,
< stcb, (struct route *)&net->ro, net, 0);
---
> net->ro._s_addr = sctp_source_address_selection(inp,
> stcb, (struct route *)&net->ro,
> net, 0, vrf_id);
> if (net->ro._s_addr == NULL)
> return;
>
3510c4719
< stc.laddress[0] = net->ro._s_addr.sin.sin_addr.s_addr;
---
> stc.laddress[0] = net->ro._s_addr->address.sin.sin_addr.s_addr;
3525,3527c4734,4739
< net->ro._s_addr.sin6.sin6_addr =
< sctp_ipv6_source_address_selection(inp,
< stcb, (struct route *)&net->ro, net, 0);
---
> net->ro._s_addr = sctp_source_address_selection(inp,
> stcb, (struct route *)&net->ro,
> net, 0, vrf_id);
> if (net->ro._s_addr == NULL)
> return;
>
3530c4742
< memcpy(&stc.laddress, &net->ro._l_addr.sin6.sin6_addr,
---
> memcpy(&stc.laddress, &net->ro._s_addr->address.sin6.sin6_addr,
3673c4885
< random_len = sctp_auth_random_len;
---
> random_len = SCTP_AUTH_RANDOM_SIZE_DEFAULT;
4014d5225
< extern unsigned int sctp_max_chunks_on_queue;
4615c5826
< ret = sctp_initiate_iterator(NULL, sctp_sendall_iterator,
---
> ret = sctp_initiate_iterator(NULL, sctp_sendall_iterator, NULL,
4810d6020
< extern int sctp_min_split_point;
5197c6407
< struct sctp_stream_out *strq, *strqn;
---
> struct sctp_stream_out *strq, *strqn, *strqt;
5204c6414
< #ifdef AF_INET6
---
> #ifdef INET6
5270a6481
> strqt = sctp_select_a_stream(stcb, asoc);
5277c6488
< strq = sctp_select_a_stream(stcb, asoc);
---
> strq = strqt;
5339,5340d6549
< extern int sctp_early_fr;
<
5367c6576
< int one_chunk, hbflag;
---
> int one_chunk, hbflag, skip_data_for_this_net;
5518c6727,6731
<
---
> if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
> skip_data_for_this_net = 1;
> } else {
> skip_data_for_this_net = 0;
> }
5744d6956
< sctp_clean_up_ctl(stcb, asoc);
5746c6958
< return (error);
---
> continue;
5807c7019
< if (((asoc->state & SCTP_STATE_OPEN) == SCTP_STATE_OPEN) ||
---
> if ((((asoc->state & SCTP_STATE_OPEN) == SCTP_STATE_OPEN) && (skip_data_for_this_net == 0)) ||
6012d7223
< sctp_clean_up_ctl(stcb, asoc);
6014c7225
< return (error);
---
> continue;
6910c8121,8125
< data_list[i]->rec.data.chunk_was_revoked = 0;
---
> if (data_list[i]->rec.data.chunk_was_revoked) {
> /* Deflate the cwnd */
> data_list[i]->whoTo->cwnd -= data_list[i]->book_size;
> data_list[i]->rec.data.chunk_was_revoked = 0;
> }
7529,7532c8744,8751
< sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
< stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_5);
< sctp_timer_start(SCTP_TIMER_TYPE_RECV,
< stcb->sctp_ep, stcb, NULL);
---
> if (stcb->asoc.delayed_ack) {
> sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
> stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_5);
> sctp_timer_start(SCTP_TIMER_TYPE_RECV,
> stcb->sctp_ep, stcb, NULL);
> } else {
> stcb->asoc.send_sack = 1;
> }
7539a8759,8761
> /* Clear our pkt counts */
> asoc->data_pkts_seen = 0;
>
7598,7601c8820,8827
< sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
< stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6);
< sctp_timer_start(SCTP_TIMER_TYPE_RECV,
< stcb->sctp_ep, stcb, NULL);
---
> if (stcb->asoc.delayed_ack) {
> sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
> stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6);
> sctp_timer_start(SCTP_TIMER_TYPE_RECV,
> stcb->sctp_ep, stcb, NULL);
> } else {
> stcb->asoc.send_sack = 1;
> }
7739a8966
> asoc->send_sack = 0;
9217d10443
< extern unsigned int sctp_add_more_threshold;
9383a10610,10611
> uint32_t vrf;
>
9396c10624,10625
< stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0);
---
> vrf = SCTP_DEFAULT_VRFID;
> stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0, vrf);
9525c10754
< if (((so->so_state & SS_NBIO)
---
> if ((SCTP_SO_IS_NBIO(so)
< __FBSDID("$FreeBSD: head/sys/netinet/sctp_output.c 166675 2007-02-12 23:24:31Z rrs $");
---
> __FBSDID("$FreeBSD: head/sys/netinet/sctp_output.c 167598 2007-03-15 11:27:14Z rrs $");
38a39
> #include <netinet/sctp_sysctl.h>
51,52d51
< #ifdef SCTP_DEBUG
< extern uint32_t sctp_debug_on;
54d52
< #endif
56,57d53
<
<
1862a1859,1877
> int
> sctp_is_address_in_scope(struct sctp_ifa *ifa,
> int ipv4_addr_legal,
> int ipv6_addr_legal,
> int loopback_scope,
> int ipv4_local_scope,
> int local_scope,
> int site_scope,
> int do_update)
> {
> if ((loopback_scope == 0) &&
> (ifa->ifn_p) && SCTP_IFN_IS_IFT_LOOP(ifa->ifn_p)) {
> /*
> * skip loopback if not in scope *
> */
> return (0);
> }
> if ((ifa->address.sa.sa_family == AF_INET) && ipv4_addr_legal) {
> struct sockaddr_in *sin;
1863a1879,1890
> sin = (struct sockaddr_in *)&ifa->address.sin;
> if (sin->sin_addr.s_addr == 0) {
> /* not in scope , unspecified */
> return (0);
> }
> if ((ipv4_local_scope == 0) &&
> (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
> /* private address not in scope */
> return (0);
> }
> } else if ((ifa->address.sa.sa_family == AF_INET6) && ipv6_addr_legal) {
> struct sockaddr_in6 *sin6;
1865c1892,1920
< extern int sctp_peer_chunk_oh;
---
> /*
> * Must update the flags, bummer, which means any IFA locks
> * must now be applied HERE <->
> */
> if (do_update) {
> sctp_gather_internal_ifa_flags(ifa);
> }
> if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
> return (0);
> }
> /* ok to use deprecated addresses? */
> sin6 = (struct sockaddr_in6 *)&ifa->address.sin6;
> if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
> /* skip unspecifed addresses */
> return (0);
> }
> if ( /* (local_scope == 0) && */
> (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
> return (0);
> }
> if ((site_scope == 0) &&
> (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
> return (0);
> }
> } else {
> return (0);
> }
> return (1);
> }
1866a1922,2624
> static struct mbuf *
> sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa)
> {
> struct sctp_paramhdr *parmh;
> struct mbuf *mret;
> int len;
>
> if (ifa->address.sa.sa_family == AF_INET) {
> len = sizeof(struct sctp_ipv4addr_param);
> } else if (ifa->address.sa.sa_family == AF_INET6) {
> len = sizeof(struct sctp_ipv6addr_param);
> } else {
> /* unknown type */
> return (m);
> }
> if (M_TRAILINGSPACE(m) >= len) {
> /* easy side we just drop it on the end */
> parmh = (struct sctp_paramhdr *)(SCTP_BUF_AT(m, SCTP_BUF_LEN(m)));
> mret = m;
> } else {
> /* Need more space */
> mret = m;
> while (SCTP_BUF_NEXT(mret) != NULL) {
> mret = SCTP_BUF_NEXT(mret);
> }
> SCTP_BUF_NEXT(mret) = sctp_get_mbuf_for_msg(len, 0, M_DONTWAIT, 1, MT_DATA);
> if (SCTP_BUF_NEXT(mret) == NULL) {
> /* We are hosed, can't add more addresses */
> return (m);
> }
> mret = SCTP_BUF_NEXT(mret);
> parmh = mtod(mret, struct sctp_paramhdr *);
> }
> /* now add the parameter */
> if (ifa->address.sa.sa_family == AF_INET) {
> struct sctp_ipv4addr_param *ipv4p;
> struct sockaddr_in *sin;
>
> sin = (struct sockaddr_in *)&ifa->address.sin;
> ipv4p = (struct sctp_ipv4addr_param *)parmh;
> parmh->param_type = htons(SCTP_IPV4_ADDRESS);
> parmh->param_length = htons(len);
> ipv4p->addr = sin->sin_addr.s_addr;
> SCTP_BUF_LEN(mret) += len;
> } else if (ifa->address.sa.sa_family == AF_INET6) {
> struct sctp_ipv6addr_param *ipv6p;
> struct sockaddr_in6 *sin6;
>
> sin6 = (struct sockaddr_in6 *)&ifa->address.sin6;
> ipv6p = (struct sctp_ipv6addr_param *)parmh;
> parmh->param_type = htons(SCTP_IPV6_ADDRESS);
> parmh->param_length = htons(len);
> memcpy(ipv6p->addr, &sin6->sin6_addr,
> sizeof(ipv6p->addr));
> /* clear embedded scope in the address */
> in6_clearscope((struct in6_addr *)ipv6p->addr);
> SCTP_BUF_LEN(mret) += len;
> } else {
> return (m);
> }
> return (mret);
> }
>
>
> struct mbuf *
> sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, struct sctp_scoping *scope,
> struct mbuf *m_at, int cnt_inits_to)
> {
> struct sctp_vrf *vrf = NULL;
> int cnt, limit_out = 0, total_count;
> uint32_t vrf_id;
>
> vrf_id = SCTP_DEFAULT_VRFID;
> SCTP_IPI_ADDR_LOCK();
> vrf = sctp_find_vrf(vrf_id);
> if (vrf == NULL) {
> SCTP_IPI_ADDR_UNLOCK();
> return (m_at);
> }
> if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
> struct sctp_ifa *sctp_ifap;
> struct sctp_ifn *sctp_ifnp;
>
> cnt = cnt_inits_to;
> if (vrf->total_ifa_count > SCTP_COUNT_LIMIT) {
> limit_out = 1;
> cnt = SCTP_ADDRESS_LIMIT;
> goto skip_count;
> }
> LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
> if ((scope->loopback_scope == 0) &&
> SCTP_IFN_IS_IFT_LOOP(sctp_ifnp)) {
> /*
> * Skip loopback devices if loopback_scope
> * not set
> */
> continue;
> }
> LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
> if (sctp_is_address_in_scope(sctp_ifap,
> scope->ipv4_addr_legal,
> scope->ipv6_addr_legal,
> scope->loopback_scope,
> scope->ipv4_local_scope,
> scope->local_scope,
> scope->site_scope, 1) == 0) {
> continue;
> }
> cnt++;
> if (cnt > SCTP_ADDRESS_LIMIT) {
> break;
> }
> }
> if (cnt > SCTP_ADDRESS_LIMIT) {
> break;
> }
> }
> skip_count:
> if (cnt > 1) {
> total_count = 0;
> LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
> cnt = 0;
> if ((scope->loopback_scope == 0) &&
> SCTP_IFN_IS_IFT_LOOP(sctp_ifnp)) {
> /*
> * Skip loopback devices if
> * loopback_scope not set
> */
> continue;
> }
> LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
> if (sctp_is_address_in_scope(sctp_ifap,
> scope->ipv4_addr_legal,
> scope->ipv6_addr_legal,
> scope->loopback_scope,
> scope->ipv4_local_scope,
> scope->local_scope,
> scope->site_scope, 0) == 0) {
> continue;
> }
> m_at = sctp_add_addr_to_mbuf(m_at, sctp_ifap);
> if (limit_out) {
> cnt++;
> total_count++;
> if (cnt >= 2) {
> /*
> * two from each
> * address
> */
> break;
> }
> if (total_count > SCTP_ADDRESS_LIMIT) {
> /* No more addresses */
> break;
> }
> }
> }
> }
> }
> } else {
> struct sctp_laddr *laddr;
>
> cnt = cnt_inits_to;
> /* First, how many ? */
> LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
> if (laddr->ifa == NULL) {
> continue;
> }
> if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED)
> /*
> * Address being deleted by the system, dont
> * list.
> */
> continue;
> if (laddr->action == SCTP_DEL_IP_ADDRESS) {
> /*
> * Address being deleted on this ep don't
> * list.
> */
> continue;
> }
> if (sctp_is_address_in_scope(laddr->ifa,
> scope->ipv4_addr_legal,
> scope->ipv6_addr_legal,
> scope->loopback_scope,
> scope->ipv4_local_scope,
> scope->local_scope,
> scope->site_scope, 1) == 0) {
> continue;
> }
> cnt++;
> }
> if (cnt > SCTP_ADDRESS_LIMIT) {
> limit_out = 1;
> }
> /*
> * To get through a NAT we only list addresses if we have
> * more than one. That way if you just bind a single address
> * we let the source of the init dictate our address.
> */
> if (cnt > 1) {
> LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
> cnt = 0;
> if (laddr->ifa == NULL) {
> continue;
> }
> if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED)
> continue;
>
> if (sctp_is_address_in_scope(laddr->ifa,
> scope->ipv4_addr_legal,
> scope->ipv6_addr_legal,
> scope->loopback_scope,
> scope->ipv4_local_scope,
> scope->local_scope,
> scope->site_scope, 0) == 0) {
> continue;
> }
> m_at = sctp_add_addr_to_mbuf(m_at, laddr->ifa);
> cnt++;
> if (cnt >= SCTP_ADDRESS_LIMIT) {
> break;
> }
> }
> }
> }
> SCTP_IPI_ADDR_UNLOCK();
> return (m_at);
> }
>
> static struct sctp_ifa *
> sctp_is_ifa_addr_prefered(struct sctp_ifa *ifa,
> uint8_t dest_is_loop,
> uint8_t dest_is_priv,
> sa_family_t fam)
> {
> uint8_t dest_is_global = 0;
>
> /*
> * is_scope -> dest_is_priv is true if destination is a private
> * address
> */
> /* dest_is_loop is true if destination is a loopback addresses */
>
> /*
> * Here we determine if its a prefered address. A prefered address
> * means it is the same scope or higher scope then the destination.
> * L = loopback, P = private, G = global
> * ----------------------------------------- src | dest | result
> * ---------------------------------------- L | L | yes
> * ----------------------------------------- P | L |
> * yes-v4 no-v6 ----------------------------------------- G |
> * L | yes-v4 no-v6 ----------------------------------------- L
> * | P | no ----------------------------------------- P |
> * P | yes ----------------------------------------- G |
> * P | no ----------------------------------------- L | G
> * | no ----------------------------------------- P | G |
> * no ----------------------------------------- G | G |
> * yes -----------------------------------------
> */
>
> if (ifa->address.sa.sa_family != fam) {
> /* forget mis-matched family */
> return (NULL);
> }
> if ((dest_is_priv == 0) && (dest_is_loop == 0)) {
> dest_is_global = 1;
> }
> /* Ok the address may be ok */
> if (fam == AF_INET6) {
> /* ok to use deprecated addresses? */
> if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
> return (NULL);
> }
> if (ifa->src_is_priv) {
> if (dest_is_loop) {
> return (NULL);
> }
> }
> if (ifa->src_is_glob) {
>
> if (dest_is_loop) {
> return (NULL);
> }
> }
> }
> /*
> * Now that we know what is what, implement or table this could in
> * theory be done slicker (it used to be), but this is
> * straightforward and easier to validate :-)
> */
> if ((ifa->src_is_loop) && (dest_is_priv)) {
> return (NULL);
> }
> if ((ifa->src_is_glob) && (dest_is_priv)) {
> return (NULL);
> }
> if ((ifa->src_is_loop) && (dest_is_global)) {
> return (NULL);
> }
> if ((ifa->src_is_priv) && (dest_is_global)) {
> return (NULL);
> }
> /* its a prefered address */
> return (ifa);
> }
>
> static struct sctp_ifa *
> sctp_is_ifa_addr_acceptable(struct sctp_ifa *ifa,
> uint8_t dest_is_loop,
> uint8_t dest_is_priv,
> sa_family_t fam)
> {
> uint8_t dest_is_global = 0;
>
>
> /*
> * Here we determine if its a acceptable address. A acceptable
> * address means it is the same scope or higher scope but we can
> * allow for NAT which means its ok to have a global dest and a
> * private src.
> *
> * L = loopback, P = private, G = global
> * ----------------------------------------- src | dest | result
> * ----------------------------------------- L | L | yes
> * ----------------------------------------- P | L |
> * yes-v4 no-v6 ----------------------------------------- G |
> * L | yes ----------------------------------------- L |
> * P | no ----------------------------------------- P | P
> * | yes ----------------------------------------- G | P
> * | yes - May not work -----------------------------------------
> * L | G | no ----------------------------------------- P
> * | G | yes - May not work
> * ----------------------------------------- G | G | yes
> * -----------------------------------------
> */
>
> if (ifa->address.sa.sa_family != fam) {
> /* forget non matching family */
> return (NULL);
> }
> /* Ok the address may be ok */
> if ((dest_is_loop == 0) && (dest_is_priv == 0)) {
> dest_is_global = 1;
> }
> if (fam == AF_INET6) {
> /* ok to use deprecated addresses? */
> if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
> return (NULL);
> }
> if (ifa->src_is_priv) {
> /* Special case, linklocal to loop */
> if (dest_is_loop)
> return (NULL);
> }
> }
> /*
> * Now that we know what is what, implement or table this could in
> * theory be done slicker (it used to be), but this is
> * straightforward and easier to validate :-)
> */
>
> if ((ifa->src_is_loop == 0) && (dest_is_priv)) {
> return (NULL);
> }
> if ((ifa->src_is_loop == 0) && (dest_is_global)) {
> return (NULL);
> }
> /* its an acceptable address */
> return (ifa);
> }
>
> int
> sctp_is_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
> {
> struct sctp_laddr *laddr;
>
> if (stcb == NULL) {
> /* There are no restrictions, no TCB :-) */
> return (0);
> }
> LIST_FOREACH(laddr, &stcb->asoc.sctp_restricted_addrs, sctp_nxt_addr) {
> if (laddr->ifa == NULL) {
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) {
> printf("Help I have fallen and I can't get up!\n");
> }
> #endif
> continue;
> }
> if (laddr->ifa == ifa) {
> /* Yes it is on the list */
> return (1);
> }
> }
> return (0);
> }
>
>
> int
> sctp_is_addr_in_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa)
> {
> struct sctp_laddr *laddr;
>
> if (ifa == NULL)
> return (0);
> LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
> if (laddr->ifa == NULL) {
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) {
> printf("Help I have fallen and I can't get up!\n");
> }
> #endif
> continue;
> }
> if ((laddr->ifa == ifa) && laddr->action == 0)
> /* same pointer */
> return (1);
> }
> return (0);
> }
>
>
>
> static struct sctp_ifa *
> sctp_choose_boundspecific_inp(struct sctp_inpcb *inp,
> struct route *ro,
> uint32_t vrf_id,
> int non_asoc_addr_ok,
> uint8_t dest_is_priv,
> uint8_t dest_is_loop,
> sa_family_t fam)
> {
> struct sctp_laddr *laddr, *starting_point;
> void *ifn;
> int resettotop = 0;
> struct sctp_ifn *sctp_ifn;
> struct sctp_ifa *sctp_ifa, *pass;
> struct sctp_vrf *vrf;
> uint32_t ifn_index;
>
> vrf = sctp_find_vrf(vrf_id);
> if (vrf == NULL)
> return (NULL);
>
> ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro);
> ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro);
> sctp_ifn = sctp_find_ifn(vrf, ifn, ifn_index);
> /*
> * first question, is the ifn we will emit on in our list, if so, we
> * want such an address. Note that we first looked for a prefered
> * address.
> */
> if (sctp_ifn) {
> /* is a prefered one on the interface we route out? */
> LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
> if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
> continue;
> pass = sctp_is_ifa_addr_prefered(sctp_ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if (sctp_is_addr_in_ep(inp, pass)) {
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
> }
> }
> /*
> * ok, now we now need to find one on the list of the addresses. We
> * can't get one on the emitting interface so lets find first a
> * prefered one. If not that a acceptable one otherwise... we return
> * NULL.
> */
> starting_point = inp->next_addr_touse;
> once_again:
> if (inp->next_addr_touse == NULL) {
> inp->next_addr_touse = LIST_FIRST(&inp->sctp_addr_list);
> resettotop = 1;
> }
> for (laddr = inp->next_addr_touse; laddr; laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
> if (laddr->ifa == NULL) {
> /* address has been removed */
> continue;
> }
> pass = sctp_is_ifa_addr_prefered(laddr->ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
> if (resettotop == 0) {
> inp->next_addr_touse = NULL;
> goto once_again;
> }
> inp->next_addr_touse = starting_point;
> resettotop = 0;
> once_again_too:
> if (inp->next_addr_touse == NULL) {
> inp->next_addr_touse = LIST_FIRST(&inp->sctp_addr_list);
> resettotop = 1;
> }
> /* ok, what about an acceptable address in the inp */
> for (laddr = inp->next_addr_touse; laddr; laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
> if (laddr->ifa == NULL) {
> /* address has been removed */
> continue;
> }
> pass = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
> if (resettotop == 0) {
> inp->next_addr_touse = NULL;
> goto once_again_too;
> }
> /*
> * no address bound can be a source for the destination we are in
> * trouble
> */
> return (NULL);
> }
>
>
>
> static struct sctp_ifa *
> sctp_choose_boundspecific_stcb(struct sctp_inpcb *inp,
> struct sctp_tcb *stcb,
> struct sctp_nets *net,
> struct route *ro,
> uint32_t vrf_id,
> uint8_t dest_is_priv,
> uint8_t dest_is_loop,
> int non_asoc_addr_ok,
> sa_family_t fam)
> {
> struct sctp_laddr *laddr, *starting_point;
> void *ifn;
> struct sctp_ifn *sctp_ifn;
> struct sctp_ifa *sctp_ifa, *pass;
> uint8_t start_at_beginning = 0;
> struct sctp_vrf *vrf;
> uint32_t ifn_index;
>
> /*
> * first question, is the ifn we will emit on in our list, if so, we
> * want that one.
> */
> vrf = sctp_find_vrf(vrf_id);
> if (vrf == NULL)
> return (NULL);
>
> ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro);
> ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro);
> sctp_ifn = sctp_find_ifn(vrf, ifn, ifn_index);
>
> /*
> * first question, is the ifn we will emit on in our list, if so, we
> * want that one.. First we look for a prefered. Second we go for an
> * acceptable.
> */
> if (sctp_ifn) {
> /* first try for an prefered address on the ep */
> LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
> if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
> continue;
> if (sctp_is_addr_in_ep(inp, sctp_ifa)) {
> pass = sctp_is_ifa_addr_prefered(sctp_ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if ((non_asoc_addr_ok == 0) &&
> (sctp_is_addr_restricted(stcb, pass))) {
> /* on the no-no list */
> continue;
> }
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
> }
> /* next try for an acceptable address on the ep */
> LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
> if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
> continue;
> if (sctp_is_addr_in_ep(inp, sctp_ifa)) {
> pass = sctp_is_ifa_addr_acceptable(sctp_ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if ((non_asoc_addr_ok == 0) &&
> (sctp_is_addr_restricted(stcb, pass))) {
> /* on the no-no list */
> continue;
> }
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
> }
>
> }
> /*
> * if we can't find one like that then we must look at all addresses
> * bound to pick one at first prefereable then secondly acceptable.
> */
> starting_point = stcb->asoc.last_used_address;
> sctp_from_the_top:
> if (stcb->asoc.last_used_address == NULL) {
> start_at_beginning = 1;
> stcb->asoc.last_used_address = LIST_FIRST(&inp->sctp_addr_list);
> }
> /* search beginning with the last used address */
> for (laddr = stcb->asoc.last_used_address; laddr;
> laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
> if (laddr->ifa == NULL) {
> /* address has been removed */
> continue;
> }
> pass = sctp_is_ifa_addr_prefered(laddr->ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if ((non_asoc_addr_ok == 0) &&
> (sctp_is_addr_restricted(stcb, pass))) {
> /* on the no-no list */
> continue;
> }
> stcb->asoc.last_used_address = laddr;
> atomic_add_int(&pass->refcount, 1);
> return (pass);
>
> }
> if (start_at_beginning == 0) {
> stcb->asoc.last_used_address = NULL;
> goto sctp_from_the_top;
> }
> /* now try for any higher scope than the destination */
> stcb->asoc.last_used_address = starting_point;
> start_at_beginning = 0;
> sctp_from_the_top2:
> if (stcb->asoc.last_used_address == NULL) {
> start_at_beginning = 1;
> stcb->asoc.last_used_address = LIST_FIRST(&inp->sctp_addr_list);
> }
> /* search beginning with the last used address */
> for (laddr = stcb->asoc.last_used_address; laddr;
> laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
> if (laddr->ifa == NULL) {
> /* address has been removed */
> continue;
> }
> pass = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if ((non_asoc_addr_ok == 0) &&
> (sctp_is_addr_restricted(stcb, pass))) {
> /* on the no-no list */
> continue;
> }
> stcb->asoc.last_used_address = laddr;
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
> if (start_at_beginning == 0) {
> stcb->asoc.last_used_address = NULL;
> goto sctp_from_the_top2;
> }
> return (NULL);
> }
>
> static struct sctp_ifa *
> sctp_select_nth_prefered_addr_from_ifn_boundall(struct sctp_ifn *ifn,
> struct sctp_tcb *stcb,
> int non_asoc_addr_ok,
> uint8_t dest_is_loop,
> uint8_t dest_is_priv,
> int addr_wanted,
> sa_family_t fam)
> {
> struct sctp_ifa *ifa, *pass;
> int num_eligible_addr = 0;
>
> LIST_FOREACH(ifa, &ifn->ifalist, next_ifa) {
> if ((ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
> continue;
> pass = sctp_is_ifa_addr_prefered(ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if (stcb) {
> if ((non_asoc_addr_ok == 0) && sctp_is_addr_restricted(stcb, pass)) {
> /*
> * It is restricted for some reason..
> * probably not yet added.
> */
> continue;
> }
> }
> if (num_eligible_addr >= addr_wanted) {
> return (pass);
> }
> num_eligible_addr++;
> }
> return (NULL);
> }
>
>
1867a2626,3042
> sctp_count_num_prefered_boundall(struct sctp_ifn *ifn,
> struct sctp_tcb *stcb,
> int non_asoc_addr_ok,
> uint8_t dest_is_loop,
> uint8_t dest_is_priv,
> sa_family_t fam)
> {
> struct sctp_ifa *ifa, *pass;
> int num_eligible_addr = 0;
>
> LIST_FOREACH(ifa, &ifn->ifalist, next_ifa) {
> if ((ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0)) {
> continue;
> }
> pass = sctp_is_ifa_addr_prefered(ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL) {
> continue;
> }
> if (stcb) {
> if ((non_asoc_addr_ok == 0) && sctp_is_addr_restricted(stcb, pass)) {
> /*
> * It is restricted for some reason..
> * probably not yet added.
> */
> continue;
> }
> }
> num_eligible_addr++;
> }
> return (num_eligible_addr);
> }
>
> static struct sctp_ifa *
> sctp_choose_boundall(struct sctp_inpcb *inp,
> struct sctp_tcb *stcb,
> struct sctp_nets *net,
> struct route *ro,
> uint32_t vrf_id,
> uint8_t dest_is_priv,
> uint8_t dest_is_loop,
> int non_asoc_addr_ok,
> sa_family_t fam)
> {
> int cur_addr_num = 0, num_prefered = 0;
> void *ifn;
> struct sctp_ifn *sctp_ifn, *looked_at = NULL, *emit_ifn;
> struct sctp_ifa *sctp_ifa, *pass;
> uint32_t ifn_index;
> struct sctp_vrf *vrf;
>
> /*
> * For boundall we can use any address in the association. If
> * non_asoc_addr_ok is set we can use any address (at least in
> * theory). So we look for prefered addresses first. If we find one,
> * we use it. Otherwise we next try to get an address on the
> * interface, which we should be able to do (unless non_asoc_addr_ok
> * is false and we are routed out that way). In these cases where we
> * can't use the address of the interface we go through all the
> * ifn's looking for an address we can use and fill that in. Punting
> * means we send back address 0, which will probably cause problems
> * actually since then IP will fill in the address of the route ifn,
> * which means we probably already rejected it.. i.e. here comes an
> * abort :-<.
> */
> vrf = sctp_find_vrf(vrf_id);
> if (vrf == NULL)
> return (NULL);
>
> ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro);
> ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro);
>
> emit_ifn = looked_at = sctp_ifn = sctp_find_ifn(vrf, ifn, ifn_index);
> if (sctp_ifn == NULL) {
> /* ?? We don't have this guy ?? */
> goto bound_all_plan_b;
> }
> if (net) {
> cur_addr_num = net->indx_of_eligible_next_to_use;
> }
> num_prefered = sctp_count_num_prefered_boundall(sctp_ifn,
> stcb,
> non_asoc_addr_ok,
> dest_is_loop,
> dest_is_priv, fam);
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) {
> printf("Found %d prefered source addresses\n", num_prefered);
> }
> #endif
> if (num_prefered == 0) {
> /*
> * no eligible addresses, we must use some other interface
> * address if we can find one.
> */
> goto bound_all_plan_b;
> }
> /*
> * Ok we have num_eligible_addr set with how many we can use, this
> * may vary from call to call due to addresses being deprecated
> * etc..
> */
> if (cur_addr_num >= num_prefered) {
> cur_addr_num = 0;
> }
> /*
> * select the nth address from the list (where cur_addr_num is the
> * nth) and 0 is the first one, 1 is the second one etc...
> */
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) {
> printf("cur_addr_num:%d\n", cur_addr_num);
> }
> #endif
> sctp_ifa = sctp_select_nth_prefered_addr_from_ifn_boundall(sctp_ifn, stcb, non_asoc_addr_ok, dest_is_loop,
> dest_is_priv, cur_addr_num, fam);
>
> /* if sctp_ifa is NULL something changed??, fall to plan b. */
> if (sctp_ifa) {
> atomic_add_int(&sctp_ifa->refcount, 1);
> if (net) {
> /* save off where the next one we will want */
> net->indx_of_eligible_next_to_use = cur_addr_num + 1;
> }
> return (sctp_ifa);
> }
> /*
> * plan_b: Look at all interfaces and find a prefered address. If no
> * prefered fall through to plan_c.
> */
> bound_all_plan_b:
> LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
> if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
> /* wrong base scope */
> continue;
> }
> if ((sctp_ifn == looked_at) && looked_at)
> /* already looked at this guy */
> continue;
> num_prefered = sctp_count_num_prefered_boundall(sctp_ifn, stcb, non_asoc_addr_ok,
> dest_is_loop, dest_is_priv, fam);
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) {
> printf("Found ifn:%p %d prefered source addresses\n", ifn, num_prefered);
> }
> #endif
> if (num_prefered == 0) {
> /*
> * None on this interface.
> */
> continue;
> }
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT2) {
> printf("num prefered:%d on interface:%p cur_addr_num:%d\n",
> num_prefered,
> sctp_ifn,
> cur_addr_num);
> }
> #endif
>
> /*
> * Ok we have num_eligible_addr set with how many we can
> * use, this may vary from call to call due to addresses
> * being deprecated etc..
> */
> if (cur_addr_num >= num_prefered) {
> cur_addr_num = 0;
> }
> pass = sctp_select_nth_prefered_addr_from_ifn_boundall(sctp_ifn, stcb, non_asoc_addr_ok, dest_is_loop,
> dest_is_priv, cur_addr_num, fam);
> if (pass == NULL)
> continue;
> if (net) {
> net->indx_of_eligible_next_to_use = cur_addr_num + 1;
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT2) {
> printf("we selected %d\n", cur_addr_num);
> printf("Source:");
> sctp_print_address(&pass->address.sa);
> printf("Dest:");
> sctp_print_address(&net->ro._l_addr.sa);
> }
> #endif
> }
> atomic_add_int(&pass->refcount, 1);
> return (pass);
>
> }
>
> /*
> * plan_c: See if we have an acceptable address on the emit
> * interface
> */
> #ifdef SCTP_DEBUG
> if (sctp_debug_on & SCTP_DEBUG_OUTPUT2) {
> if (net) {
> printf("Plan C no prefered for Dest:");
> sctp_print_address(&net->ro._l_addr.sa);
> }
> }
> #endif
>
> LIST_FOREACH(sctp_ifa, &emit_ifn->ifalist, next_ifa) {
> if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
> continue;
> pass = sctp_is_ifa_addr_acceptable(sctp_ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if (stcb) {
> if ((non_asoc_addr_ok == 0) && sctp_is_addr_restricted(stcb, pass)) {
> /*
> * It is restricted for some reason..
> * probably not yet added.
> */
> continue;
> }
> }
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
>
> /*
> * plan_d: We are in trouble. No prefered address on the emit
> * interface. And not even a perfered address on all interfaces. Go
> * out and see if we can find an acceptable address somewhere
> * amongst all interfaces.
> */
> LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
> if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
> /* wrong base scope */
> continue;
> }
> if ((sctp_ifn == looked_at) && looked_at)
> /* already looked at this guy */
> continue;
>
> LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
> if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
> continue;
> pass = sctp_is_ifa_addr_acceptable(sctp_ifa, dest_is_loop, dest_is_priv, fam);
> if (pass == NULL)
> continue;
> if (stcb) {
> if ((non_asoc_addr_ok == 0) && sctp_is_addr_restricted(stcb, pass)) {
> /*
> * It is restricted for some
> * reason.. probably not yet added.
> */
> continue;
> }
> }
> atomic_add_int(&pass->refcount, 1);
> return (pass);
> }
> }
> /*
> * Ok we can find NO address to source from that is not on our
> * negative list and non_asoc_address is NOT ok, or its on our
> * negative list. We cant source to it :-(
> */
> return (NULL);
> }
>
>
>
> /* tcb may be NULL */
> struct sctp_ifa *
> sctp_source_address_selection(struct sctp_inpcb *inp,
> struct sctp_tcb *stcb,
> struct route *ro,
> struct sctp_nets *net,
> int non_asoc_addr_ok, uint32_t vrf_id)
> {
>
> struct sockaddr_in *to = (struct sockaddr_in *)&ro->ro_dst;
> struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)&ro->ro_dst;
> struct sctp_ifa *answer;
> uint8_t dest_is_priv, dest_is_loop;
> int did_rtalloc = 0;
> sa_family_t fam;
>
> /*
> * Rules: - Find the route if needed, cache if I can. - Look at
> * interface address in route, Is it in the bound list. If so we
> * have the best source. - If not we must rotate amongst the
> * addresses.
> *
> * Cavets and issues
> *
> * Do we need to pay attention to scope. We can have a private address
> * or a global address we are sourcing or sending to. So if we draw
> * it out zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
> * For V4 ------------------------------------------ source *
> * dest * result ----------------------------------------- <a>
> * Private * Global * NAT
> * ----------------------------------------- <b> Private *
> * Private * No problem -----------------------------------------
> * <c> Global * Private * Huh, How will this work?
> * ----------------------------------------- <d> Global *
> * Global * No Problem ------------------------------------------
> * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz For V6
> * ------------------------------------------ source * dest *
> * result ----------------------------------------- <a> Linklocal *
> * Global * ----------------------------------------- <b>
> * Linklocal * Linklocal * No problem
> * ----------------------------------------- <c> Global *
> * Linklocal * Huh, How will this work?
> * ----------------------------------------- <d> Global *
> * Global * No Problem ------------------------------------------
> * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
> *
> * And then we add to that what happens if there are multiple addresses
> * assigned to an interface. Remember the ifa on a ifn is a linked
> * list of addresses. So one interface can have more than one IP
> * address. What happens if we have both a private and a global
> * address? Do we then use context of destination to sort out which
> * one is best? And what about NAT's sending P->G may get you a NAT
> * translation, or should you select the G thats on the interface in
> * preference.
> *
> * Decisions:
> *
> * - count the number of addresses on the interface. - if its one, no
> * problem except case <c>. For <a> we will assume a NAT out there.
> * - if there are more than one, then we need to worry about scope P
> * or G. We should prefer G -> G and P -> P if possible. Then as a
> * secondary fall back to mixed types G->P being a last ditch one. -
> * The above all works for bound all, but bound specific we need to
> * use the same concept but instead only consider the bound
> * addresses. If the bound set is NOT assigned to the interface then
> * we must use rotation amongst the bound addresses..
> *
> */
> if (ro->ro_rt == NULL) {
> /*
> * Need a route to cache.
> *
> */
> rtalloc_ign(ro, 0UL);
> did_rtalloc = 1;
> }
> if (ro->ro_rt == NULL) {
> return (NULL);
> }
> fam = to->sin_family;
> dest_is_priv = dest_is_loop = 0;
> /* Setup our scopes for the destination */
> if (fam == AF_INET) {
> /* Scope based on outbound address */
> if ((IN4_ISPRIVATE_ADDRESS(&to->sin_addr))) {
> dest_is_priv = 1;
> } else if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) {
> dest_is_loop = 1;
> if (net != NULL) {
> /* mark it as local */
> net->addr_is_local = 1;
> }
> }
> } else if (fam == AF_INET6) {
> /* Scope based on outbound address */
> if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) {
> /*
> * If the route goes to the loopback address OR the
> * address is a loopback address, we are loopback
> * scope. But we don't use dest_is_priv (link local
> * addresses).
> */
> dest_is_loop = 1;
> if (net != NULL) {
> /* mark it as local */
> net->addr_is_local = 1;
> }
> } else if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) {
> dest_is_priv = 1;
> }
> }
> if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
> /*
> * When bound to all if the address list is set it is a
> * negative list. Addresses being added by asconf.
> */
> answer = sctp_choose_boundall(inp, stcb, net, ro, vrf_id,
> dest_is_priv,
> dest_is_loop,
> non_asoc_addr_ok,
> fam);
> return (answer);
> }
> /*
> * Three possiblities here:
> *
> * a) stcb is NULL, which means we operate only from the list of
> * addresses (ifa's) bound to the endpoint and we care not about the
> * list. b) stcb is NOT-NULL, which means we have an assoc structure
> * and auto-asconf is on. This means that the list of addresses is a
> * NOT list. We use the list from the inp, but any listed address in
> * our list is NOT yet added. However if the non_asoc_addr_ok is set
> * we CAN use an address NOT available (i.e. being added). Its a
> * negative list. c) stcb is NOT-NULL, which means we have an assoc
> * structure and auto-asconf is off. This means that the list of
> * addresses is the ONLY addresses I can use.. its positive.
> *
> * Note we collapse b & c into the same function just like in the v6
> * address selection.
> */
> if (stcb) {
> answer = sctp_choose_boundspecific_stcb(inp, stcb, net, ro, vrf_id,
> dest_is_priv, dest_is_loop, non_asoc_addr_ok, fam);
>
> } else {
> answer = sctp_choose_boundspecific_inp(inp, ro, vrf_id, non_asoc_addr_ok, dest_is_priv, dest_is_loop, fam);
>
> }
> return (answer);
> }
>
> static int
1917,1920c3092
< extern int sctp_mbuf_threshold_count;
<
<
< __inline struct mbuf *
---
> struct mbuf *
2124,2125d3295
< extern int sctp_no_csum_on_loopback;
<
2158a3329
> uint32_t vrf_id;
2160a3332
>
2164a3337,3342
> if (stcb == NULL) {
> vrf_id = SCTP_DEFAULT_VRFID;
> } else {
> vrf_id = stcb->asoc.vrf_id;
> }
>
2189c3367
< struct ip *ip;
---
> struct ip *ip = NULL;
2253,2257c3431,3437
< ((struct sockaddr_in *)&net->ro._s_addr)->sin_addr = sctp_ipv4_source_address_selection(inp,
< stcb,
< ro, net, out_of_asoc_ok);
< if (ro->ro_rt)
< net->src_addr_selected = 1;
---
> net->ro._s_addr = sctp_source_address_selection(inp, stcb,
> ro, net, out_of_asoc_ok, vrf_id);
> if (net->ro._s_addr == NULL) {
> /* No route to host */
> goto no_route;
> }
> net->src_addr_selected = 1;
2259c3439
< ip->ip_src = ((struct sockaddr_in *)&net->ro._s_addr)->sin_addr;
---
> ip->ip_src = net->ro._s_addr->address.sin.sin_addr;
2261,2262c3441,3449
< ip->ip_src = sctp_ipv4_source_address_selection(inp,
< stcb, ro, net, out_of_asoc_ok);
---
> struct sctp_ifa *_lsrc;
>
> _lsrc = sctp_source_address_selection(inp,
> stcb, ro, net, out_of_asoc_ok, vrf_id);
> if (_lsrc == NULL) {
> goto no_route;
> }
> ip->ip_src = _lsrc->address.sin.sin_addr;
> sctp_free_ifa(_lsrc);
2276c3463
< * here!
---
> * here (yet)!
2277a3465
> no_route:
2280,2281c3468,3472
< printf("low_level_output: dropped v4 packet- no valid source addr\n");
< printf("Destination was %x\n", (uint32_t) (ntohl(ip->ip_dst.s_addr)));
---
> printf("low_level_output: dropped packet - no valid source addr\n");
> if (net) {
> printf("Destination was ");
> sctp_print_address(&net->ro._l_addr.sa);
> }
2285,2291c3476,3486
< if ((net->dest_state & SCTP_ADDR_REACHABLE) && stcb)
< sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
< stcb,
< SCTP_FAILED_THRESHOLD,
< (void *)net);
< net->dest_state &= ~SCTP_ADDR_REACHABLE;
< net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
---
> if (net->dest_state & SCTP_ADDR_CONFIRMED) {
> if ((net->dest_state & SCTP_ADDR_REACHABLE) && stcb) {
> printf("no route takes interface %p down\n", net);
> sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
> stcb,
> SCTP_FAILED_THRESHOLD,
> (void *)net);
> net->dest_state &= ~SCTP_ADDR_REACHABLE;
> net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
> }
> }
2302a3498,3501
> if (net->ro._s_addr) {
> sctp_free_ifa(net->ro._s_addr);
> net->ro._s_addr = NULL;
> }
2352c3551
< if (ro->ro_rt)
---
> if (ro->ro_rt) {
2353a3553,3554
> ro->ro_rt = NULL;
> }
2363a3565,3569
> if (net->ro._s_addr &&
> net->src_addr_selected) {
> sctp_free_ifa(net->ro._s_addr);
> net->ro._s_addr = NULL;
> }
2451,2455c3657,3669
< ((struct sockaddr_in6 *)&net->ro._s_addr)->sin6_addr = sctp_ipv6_source_address_selection(inp,
< stcb, ro, net, out_of_asoc_ok);
<
< if (ro->ro_rt)
< net->src_addr_selected = 1;
---
> net->ro._s_addr = sctp_source_address_selection(inp,
> stcb,
> ro,
> net,
> out_of_asoc_ok,
> vrf_id);
> if (net->ro._s_addr == NULL) {
> #ifdef SCTP_DEBUG
> printf("V6:No route to host\n");
> #endif
> goto no_route;
> }
> net->src_addr_selected = 1;
2457c3671
< lsa6->sin6_addr = ((struct sockaddr_in6 *)&net->ro._s_addr)->sin6_addr;
---
> lsa6->sin6_addr = net->ro._s_addr->address.sin6.sin6_addr;
2459,2460c3673,3680
< lsa6->sin6_addr = sctp_ipv6_source_address_selection(
< inp, stcb, ro, net, out_of_asoc_ok);
---
> struct sctp_ifa *_lsrc;
>
> _lsrc = sctp_source_address_selection(inp, stcb, ro, net, out_of_asoc_ok, vrf_id);
> if (_lsrc == NULL) {
> goto no_route;
> }
> lsa6->sin6_addr = _lsrc->address.sin6.sin6_addr;
> sctp_free_ifa(_lsrc);
2470,2501c3690
< #ifdef SCTP_DEBUG
< if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) {
< printf("low_level_output: dropped v6 pkt- no valid source addr\n");
< }
< #endif
< sctp_m_freem(o_pak);
< if (net) {
< if ((net->dest_state & SCTP_ADDR_REACHABLE) && stcb)
< sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
< stcb,
< SCTP_FAILED_THRESHOLD,
< (void *)net);
< net->dest_state &= ~SCTP_ADDR_REACHABLE;
< net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
< if (stcb) {
< if (net == stcb->asoc.primary_destination) {
< /* need a new primary */
< struct sctp_nets *alt;
<
< 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;
< net->src_addr_selected = 0;
< }
< }
< }
< }
< }
< return (EHOSTUNREACH);
---
> goto no_route;
2568c3757
< if (ret)
---
> if (ret) {
2569a3759
> }
2578a3769,3774
>
> if (net->ro._s_addr &&
> net->src_addr_selected) {
> sctp_free_ifa(net->ro._s_addr);
> net->ro._s_addr = NULL;
> }
3266a4463
> uint32_t vrf_id;
3267a4465
> vrf_id = SCTP_DEFAULT_VRFID;
3361c4559
< struct in_addr addr;
---
> struct sctp_ifa *addr;
3378,3379c4576,4580
< addr = sctp_ipv4_source_address_selection(inp, NULL,
< ro, NULL, 0);
---
> addr = sctp_source_address_selection(inp, NULL,
> ro, NULL, 0, vrf_id);
> if (addr == NULL)
> return;
>
3381a4583
> ro->ro_rt = NULL;
3383c4585
< stc.laddress[0] = addr.s_addr;
---
> stc.laddress[0] = addr->address.sin.sin_addr.s_addr;
3398c4600
< if (sctp_is_address_on_local_host((struct sockaddr *)sin)) {
---
> if (sctp_is_address_on_local_host((struct sockaddr *)sin, vrf_id)) {
3402c4604
< stc.local_scope = 1;
---
> stc.local_scope = 0;
3405c4607
< struct in6_addr addr;
---
> struct sctp_ifa *addr;
3420c4622
< if (sctp_is_address_on_local_host((struct sockaddr *)sin6)) {
---
> if (sctp_is_address_on_local_host((struct sockaddr *)sin6, vrf_id)) {
3422c4624
< stc.local_scope = 1;
---
> stc.local_scope = 0;
3462,3463c4664,4668
< addr = sctp_ipv6_source_address_selection(inp, NULL,
< ro, NULL, 0);
---
> addr = sctp_source_address_selection(inp, NULL,
> ro, NULL, 0, vrf_id);
> if (addr == NULL)
> return;
>
3465a4671
> ro->ro_rt = NULL;
3467c4673
< memcpy(&stc.laddress, &addr, sizeof(struct in6_addr));
---
> memcpy(&stc.laddress, &addr->address.sin6.sin6_addr, sizeof(struct in6_addr));
3504,3506c4710,4715
< net->ro._s_addr.sin.sin_addr =
< sctp_ipv4_source_address_selection(inp,
< stcb, (struct route *)&net->ro, net, 0);
---
> net->ro._s_addr = sctp_source_address_selection(inp,
> stcb, (struct route *)&net->ro,
> net, 0, vrf_id);
> if (net->ro._s_addr == NULL)
> return;
>
3510c4719
< stc.laddress[0] = net->ro._s_addr.sin.sin_addr.s_addr;
---
> stc.laddress[0] = net->ro._s_addr->address.sin.sin_addr.s_addr;
3525,3527c4734,4739
< net->ro._s_addr.sin6.sin6_addr =
< sctp_ipv6_source_address_selection(inp,
< stcb, (struct route *)&net->ro, net, 0);
---
> net->ro._s_addr = sctp_source_address_selection(inp,
> stcb, (struct route *)&net->ro,
> net, 0, vrf_id);
> if (net->ro._s_addr == NULL)
> return;
>
3530c4742
< memcpy(&stc.laddress, &net->ro._l_addr.sin6.sin6_addr,
---
> memcpy(&stc.laddress, &net->ro._s_addr->address.sin6.sin6_addr,
3673c4885
< random_len = sctp_auth_random_len;
---
> random_len = SCTP_AUTH_RANDOM_SIZE_DEFAULT;
4014d5225
< extern unsigned int sctp_max_chunks_on_queue;
4615c5826
< ret = sctp_initiate_iterator(NULL, sctp_sendall_iterator,
---
> ret = sctp_initiate_iterator(NULL, sctp_sendall_iterator, NULL,
4810d6020
< extern int sctp_min_split_point;
5197c6407
< struct sctp_stream_out *strq, *strqn;
---
> struct sctp_stream_out *strq, *strqn, *strqt;
5204c6414
< #ifdef AF_INET6
---
> #ifdef INET6
5270a6481
> strqt = sctp_select_a_stream(stcb, asoc);
5277c6488
< strq = sctp_select_a_stream(stcb, asoc);
---
> strq = strqt;
5339,5340d6549
< extern int sctp_early_fr;
<
5367c6576
< int one_chunk, hbflag;
---
> int one_chunk, hbflag, skip_data_for_this_net;
5518c6727,6731
<
---
> if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
> skip_data_for_this_net = 1;
> } else {
> skip_data_for_this_net = 0;
> }
5744d6956
< sctp_clean_up_ctl(stcb, asoc);
5746c6958
< return (error);
---
> continue;
5807c7019
< if (((asoc->state & SCTP_STATE_OPEN) == SCTP_STATE_OPEN) ||
---
> if ((((asoc->state & SCTP_STATE_OPEN) == SCTP_STATE_OPEN) && (skip_data_for_this_net == 0)) ||
6012d7223
< sctp_clean_up_ctl(stcb, asoc);
6014c7225
< return (error);
---
> continue;
6910c8121,8125
< data_list[i]->rec.data.chunk_was_revoked = 0;
---
> if (data_list[i]->rec.data.chunk_was_revoked) {
> /* Deflate the cwnd */
> data_list[i]->whoTo->cwnd -= data_list[i]->book_size;
> data_list[i]->rec.data.chunk_was_revoked = 0;
> }
7529,7532c8744,8751
< sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
< stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_5);
< sctp_timer_start(SCTP_TIMER_TYPE_RECV,
< stcb->sctp_ep, stcb, NULL);
---
> if (stcb->asoc.delayed_ack) {
> sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
> stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_5);
> sctp_timer_start(SCTP_TIMER_TYPE_RECV,
> stcb->sctp_ep, stcb, NULL);
> } else {
> stcb->asoc.send_sack = 1;
> }
7539a8759,8761
> /* Clear our pkt counts */
> asoc->data_pkts_seen = 0;
>
7598,7601c8820,8827
< sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
< stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6);
< sctp_timer_start(SCTP_TIMER_TYPE_RECV,
< stcb->sctp_ep, stcb, NULL);
---
> if (stcb->asoc.delayed_ack) {
> sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
> stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6);
> sctp_timer_start(SCTP_TIMER_TYPE_RECV,
> stcb->sctp_ep, stcb, NULL);
> } else {
> stcb->asoc.send_sack = 1;
> }
7739a8966
> asoc->send_sack = 0;
9217d10443
< extern unsigned int sctp_add_more_threshold;
9383a10610,10611
> uint32_t vrf;
>
9396c10624,10625
< stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0);
---
> vrf = SCTP_DEFAULT_VRFID;
> stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0, vrf);
9525c10754
< if (((so->so_state & SS_NBIO)
---
> if ((SCTP_SO_IS_NBIO(so)