34c34
< __FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 166675 2007-02-12 23:24:31Z rrs $");
---
> __FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 167598 2007-03-15 11:27:14Z rrs $");
38a39
> #include <netinet/sctp_sysctl.h>
45a47
> #include <netinet/sctp_bsd_addr.h>
48,57d49
< #ifdef SCTP_DEBUG
< uint32_t sctp_debug_on = 0;
<
< #endif /* SCTP_DEBUG */
<
<
< extern int sctp_pcbtblsize;
< extern int sctp_hashtblsize;
< extern int sctp_chunkscale;
<
75d66
<
95a87,130
> /*
> * Addresses are added to VRF's (Virtual Router's). For BSD we
> * have only the default VRF 0. We maintain a hash list of
> * VRF's. Each VRF has its own list of sctp_ifn's. Each of
> * these has a list of addresses. When we add a new address
> * to a VRF we lookup the ifn/ifn_index, if the ifn does
> * not exist we create it and add it to the list of IFN's
> * within the VRF. Once we have the sctp_ifn, we add the
> * address to the list. So we look something like:
> *
> * hash-vrf-table
> * vrf-> ifn-> ifn -> ifn
> * vrf |
> * ... +--ifa-> ifa -> ifa
> * vrf
> *
> * We keep these seperate lists since the SCTP subsystem will
> * point to these from its source address selection nets structure.
> * When an address is deleted it does not happen right away on
> * the SCTP side, it gets scheduled. What we do when a
> * delete happens is immediately remove the address from
> * the master list and decrement the refcount. As our
> * addip iterator works through and frees the src address
> * selection pointing to the sctp_ifa, eventually the refcount
> * will reach 0 and we will delete it. Note that it is assumed
> * that any locking on system level ifn/ifa is done at the
> * caller of these functions and these routines will only
> * lock the SCTP structures as they add or delete things.
> *
> * Other notes on VRF concepts.
> * - An endpoint can be in multiple VRF's
> * - An association lives within a VRF and only one VRF.
> * - Any incoming packet we can deduce the VRF for by
> * looking at the mbuf/pak inbound (for BSD its VRF=0 :D)
> * - Any downward send call or connect call must supply the
> * VRF via ancillary data or via some sort of set default
> * VRF socket option call (again for BSD no brainer since
> * the VRF is always 0).
> * - An endpoint may add multiple VRF's to it.
> * - Listening sockets can accept associations in any
> * of the VRF's they are in but the assoc will end up
> * in only one VRF (gotten from the packet or connect/send).
> *
> */
96a132,379
> struct sctp_vrf *
> sctp_allocate_vrf(int vrfid)
> {
> struct sctp_vrf *vrf = NULL;
> struct sctp_vrflist *bucket;
>
> /* First allocate the VRF structure */
> vrf = sctp_find_vrf(vrfid);
> if (vrf) {
> /* Already allocated */
> return (vrf);
> }
> SCTP_MALLOC(vrf, struct sctp_vrf *, sizeof(struct sctp_vrf),
> "SCTP_VRF");
> if (vrf == NULL) {
> /* No memory */
> #ifdef INVARIANTS
> panic("No memory for VRF:%d", vrfid);
> #endif
> return (NULL);
> }
> /* setup the VRF */
> memset(vrf, 0, sizeof(struct sctp_vrf));
> vrf->vrf_id = vrfid;
> LIST_INIT(&vrf->ifnlist);
> vrf->total_ifa_count = 0;
> /* Add it to the hash table */
> bucket = &sctppcbinfo.sctp_vrfhash[(vrfid & sctppcbinfo.hashvrfmark)];
> LIST_INSERT_HEAD(bucket, vrf, next_vrf);
> return (vrf);
> }
>
>
> struct sctp_ifn *
> sctp_find_ifn(struct sctp_vrf *vrf, void *ifn, uint32_t ifn_index)
> {
> struct sctp_ifn *sctp_ifnp;
>
> /*
> * We assume the lock is held for the addresses if thats wrong
> * problems could occur :-)
> */
> LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
> if (sctp_ifnp->ifn_index == ifn_index) {
> return (sctp_ifnp);
> }
> if (sctp_ifnp->ifn_p && ifn && (sctp_ifnp->ifn_p == ifn)) {
> return (sctp_ifnp);
> }
> }
> return (NULL);
> }
>
> struct sctp_vrf *
> sctp_find_vrf(uint32_t vrfid)
> {
> struct sctp_vrflist *bucket;
> struct sctp_vrf *liste;
>
> bucket = &sctppcbinfo.sctp_vrfhash[(vrfid & sctppcbinfo.hashvrfmark)];
> LIST_FOREACH(liste, bucket, next_vrf) {
> if (vrfid == liste->vrf_id) {
> return (liste);
> }
> }
> return (NULL);
> }
>
> void
> sctp_free_ifa(struct sctp_ifa *sctp_ifap)
> {
> int ret;
>
> ret = atomic_fetchadd_int(&sctp_ifap->refcount, -1);
> if (ret == 1) {
> /* We zero'd the count */
> SCTP_FREE(sctp_ifap);
> }
> }
>
> struct sctp_ifa *
> sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index,
> uint32_t ifn_type, const char *if_name,
> void *ifa, struct sockaddr *addr, uint32_t ifa_flags)
> {
> struct sctp_vrf *vrf;
> struct sctp_ifn *sctp_ifnp = NULL;
> struct sctp_ifa *sctp_ifap = NULL;
>
> /* How granular do we need the locks to be here? */
> SCTP_IPI_ADDR_LOCK();
> vrf = sctp_find_vrf(vrfid);
> if (vrf == NULL) {
> vrf = sctp_allocate_vrf(vrfid);
> if (vrf == NULL) {
> SCTP_IPI_ADDR_UNLOCK();
> return (NULL);
> }
> }
> sctp_ifnp = sctp_find_ifn(vrf, ifn, ifn_index);
> if (sctp_ifnp == NULL) {
> /*
> * build one and add it, can't hold lock until after malloc
> * done though.
> */
> SCTP_IPI_ADDR_UNLOCK();
> SCTP_MALLOC(sctp_ifnp, struct sctp_ifn *, sizeof(struct sctp_ifn), "SCTP_IFN");
> if (sctp_ifnp == NULL) {
> #ifdef INVARIANTS
> panic("No memory for IFN:%u", sctp_ifnp->ifn_index);
> #endif
> return (NULL);
> }
> sctp_ifnp->ifn_index = ifn_index;
> sctp_ifnp->ifn_p = ifn;
> sctp_ifnp->ifn_type = ifn_type;
> sctp_ifnp->ifa_count = 0;
> sctp_ifnp->refcount = 0;
> sctp_ifnp->vrf = vrf;
> memcpy(sctp_ifnp->ifn_name, if_name, SCTP_IFNAMSIZ);
> LIST_INIT(&sctp_ifnp->ifalist);
> SCTP_IPI_ADDR_LOCK();
> LIST_INSERT_HEAD(&vrf->ifnlist, sctp_ifnp, next_ifn);
> }
> sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1);
> if (sctp_ifap) {
> /* Hmm, it already exists? */
> if ((sctp_ifap->ifn_p) &&
> (sctp_ifap->ifn_p->ifn_index == ifn_index)) {
> if (sctp_ifap->localifa_flags & SCTP_BEING_DELETED) {
> /* easy to solve, just switch back to active */
> sctp_ifap->localifa_flags = SCTP_ADDR_VALID;
> sctp_ifap->ifn_p = sctp_ifnp;
> exit_stage_left:
> SCTP_IPI_ADDR_UNLOCK();
> return (sctp_ifap);
> } else {
> goto exit_stage_left;
> }
> } else {
> if (sctp_ifap->ifn_p) {
> /*
> * The first IFN gets the address,
> * duplicates are ignored.
> */
> goto exit_stage_left;
> } else {
> /* repair ifnp which was NULL ? */
> sctp_ifap->localifa_flags = SCTP_ADDR_VALID;
> sctp_ifap->ifn_p = sctp_ifnp;
> atomic_add_int(&sctp_ifnp->refcount, 1);
> }
> goto exit_stage_left;
> }
> }
> SCTP_IPI_ADDR_UNLOCK();
> SCTP_MALLOC(sctp_ifap, struct sctp_ifa *, sizeof(struct sctp_ifa), "SCTP_IFA");
> if (sctp_ifap == NULL) {
> #ifdef INVARIANTS
> panic("No memory for IFA");
> #endif
> return (NULL);
> }
> memset(sctp_ifap, 0, sizeof(sctp_ifap));
> sctp_ifap->ifn_p = sctp_ifnp;
> atomic_add_int(&sctp_ifnp->refcount, 1);
>
> sctp_ifap->ifa = ifa;
> memcpy(&sctp_ifap->address, addr, addr->sa_len);
> sctp_ifap->localifa_flags = SCTP_ADDR_VALID | SCTP_ADDR_DEFER_USE;
> sctp_ifap->flags = ifa_flags;
> /* Set scope */
> if (sctp_ifap->address.sa.sa_family == AF_INET) {
> struct sockaddr_in *sin;
>
> sin = (struct sockaddr_in *)&sctp_ifap->address.sin;
> if (SCTP_IFN_IS_IFT_LOOP(sctp_ifap->ifn_p) ||
> (IN4_ISLOOPBACK_ADDRESS(&sin->sin_addr))) {
> sctp_ifap->src_is_loop = 1;
> }
> if ((IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
> sctp_ifap->src_is_priv = 1;
> }
> } else if (sctp_ifap->address.sa.sa_family == AF_INET6) {
> /* ok to use deprecated addresses? */
> struct sockaddr_in6 *sin6;
>
> sin6 = (struct sockaddr_in6 *)&sctp_ifap->address.sin6;
> if (SCTP_IFN_IS_IFT_LOOP(sctp_ifap->ifn_p) ||
> (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))) {
> sctp_ifap->src_is_loop = 1;
> }
> if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
> sctp_ifap->src_is_priv = 1;
> }
> }
> if ((sctp_ifap->src_is_priv == 0) &&
> (sctp_ifap->src_is_loop == 0)) {
> sctp_ifap->src_is_glob = 1;
> }
> SCTP_IPI_ADDR_LOCK();
> sctp_ifap->refcount = 1;
> LIST_INSERT_HEAD(&sctp_ifnp->ifalist, sctp_ifap, next_ifa);
> sctp_ifnp->ifa_count++;
> vrf->total_ifa_count++;
> SCTP_IPI_ADDR_UNLOCK();
> return (sctp_ifap);
> }
>
> struct sctp_ifa *
> sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
> uint32_t ifn_index)
> {
> struct sctp_vrf *vrf;
> struct sctp_ifa *sctp_ifap = NULL;
> struct sctp_ifn *sctp_ifnp = NULL;
>
> SCTP_IPI_ADDR_LOCK();
>
> vrf = sctp_find_vrf(vrfid);
> if (vrf == NULL) {
> printf("Can't find vrfid:%d\n", vrfid);
> goto out_now;
> }
> sctp_ifnp = sctp_find_ifn(vrf, (void *)NULL, ifn_index);
> if (sctp_ifnp == NULL) {
> sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1);
> } else {
> sctp_ifap = sctp_find_ifa_in_ifn(sctp_ifnp, addr, 1);
> }
>
> if (sctp_ifap) {
> sctp_ifap->localifa_flags &= SCTP_ADDR_VALID;
> sctp_ifap->localifa_flags |= SCTP_BEING_DELETED;
> sctp_ifnp->ifa_count--;
> vrf->total_ifa_count--;
> LIST_REMOVE(sctp_ifap, next_ifa);
> atomic_add_int(&sctp_ifnp->refcount, -1);
> } else {
> printf("Del Addr-ifn:%d Could not find address:",
> ifn_index);
> sctp_print_address(addr);
> }
> out_now:
> SCTP_IPI_ADDR_UNLOCK();
> return (sctp_ifap);
> }
>
180c463
< if (laddr->ifa->ifa_addr == NULL) {
---
> if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) {
183c466
< printf("ifa with a NULL address\n");
---
> printf("ifa being deleted\n");
188c471
< if (laddr->ifa->ifa_addr->sa_family ==
---
> if (laddr->ifa->address.sa.sa_family ==
193,194c476
< intf_addr = (struct sockaddr_in *)
< laddr->ifa->ifa_addr;
---
> intf_addr = &laddr->ifa->address.sin;
208,209c490
< intf_addr6 = (struct sockaddr_in6 *)
< laddr->ifa->ifa_addr;
---
> intf_addr6 = &laddr->ifa->address.sin6;
598c879
< uint16_t lport)
---
> uint16_t lport, uint32_t vrf_id)
603a885
> int fnd;
641a924,928
> /* does a VRF id match? */
> fnd = 0;
> if (inp->def_vrf_id == vrf_id)
> fnd = 1;
>
642a930,931
> if (!fnd)
> continue;
678a968,976
> /* does a VRF id match? */
> fnd = 0;
> if (inp->def_vrf_id == vrf_id)
> fnd = 1;
>
> if (!fnd) {
> SCTP_INP_RUNLOCK(inp);
> continue;
> }
694c992
< if (laddr->ifa->ifa_addr == NULL) {
---
> if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) {
697c995
< printf("Huh IFA as an ifa_addr=NULL, ");
---
> printf("Huh IFA being deleted\n");
702c1000
< if (laddr->ifa->ifa_addr->sa_family == nam->sa_family) {
---
> if (laddr->ifa->address.sa.sa_family == nam->sa_family) {
706,707c1004
< intf_addr = (struct sockaddr_in *)
< laddr->ifa->ifa_addr;
---
> intf_addr = &laddr->ifa->address.sin;
717,718c1014
< intf_addr6 = (struct sockaddr_in6 *)
< laddr->ifa->ifa_addr;
---
> intf_addr6 = &laddr->ifa->address.sin6;
734c1030
< sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool, int have_lock)
---
> sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool, int have_lock, uint32_t vrf_id)
768c1064
< inp = sctp_endpoint_probe(nam, head, lport);
---
> inp = sctp_endpoint_probe(nam, head, lport, vrf_id);
789c1085
< inp = sctp_endpoint_probe(nam, head, lport);
---
> inp = sctp_endpoint_probe(nam, head, lport, vrf_id);
813c1109
< struct sctp_inpcb **inp_p, struct sctp_nets **netp, int find_tcp_pool)
---
> struct sctp_inpcb **inp_p, struct sctp_nets **netp, int find_tcp_pool, uint32_t vrf_id)
830c1126
< inp = sctp_pcb_findep(to, 0, 1);
---
> inp = sctp_pcb_findep(to, 0, 1, vrf_id);
1029a1326
> uint32_t vrf_id;
1031c1328
<
---
> vrf_id = SCTP_DEFAULT_VRFID;
1114c1411
< find_tcp_pool);
---
> find_tcp_pool, vrf_id);
1118c1415
< find_tcp_pool);
---
> find_tcp_pool, vrf_id);
1285,1302d1581
< extern int sctp_max_burst_default;
<
< extern unsigned int sctp_delayed_sack_time_default;
< extern unsigned int sctp_heartbeat_interval_default;
< extern unsigned int sctp_pmtu_raise_time_default;
< extern unsigned int sctp_shutdown_guard_time_default;
< extern unsigned int sctp_secret_lifetime_default;
<
< extern unsigned int sctp_rto_max_default;
< extern unsigned int sctp_rto_min_default;
< extern unsigned int sctp_rto_initial_default;
< extern unsigned int sctp_init_rto_max_default;
< extern unsigned int sctp_valid_cookie_life_default;
< extern unsigned int sctp_init_rtx_max_default;
< extern unsigned int sctp_assoc_rtx_max_default;
< extern unsigned int sctp_path_rtx_max_default;
< extern unsigned int sctp_nr_outgoing_streams_default;
<
1367,1368c1646,1647
< if ((so->so_type == SOCK_DGRAM) ||
< (so->so_type == SOCK_SEQPACKET)) {
---
> if ((SCTP_SO_TYPE(so) == SOCK_DGRAM) ||
> (SCTP_SO_TYPE(so) == SOCK_SEQPACKET)) {
1374,1375c1653,1654
< /* so->so_state |= SS_NBIO; */
< } else if (so->so_type == SOCK_STREAM) {
---
> /* SCTP_SET_SO_NBIO(so); */
> } else if (SCTP_SO_TYPE(so) == SOCK_STREAM) {
1381c1660
< so->so_state &= ~SS_NBIO;
---
> SCTP_CLEAR_SO_NBIO(so);
1396a1676,1677
> inp->def_vrf_id = SCTP_DEFAULT_VRFID;
>
1409a1691
>
1435a1718
> m->sctp_sack_freq = sctp_sack_freq_default;
1473d1755
<
1604c1886
< sctp_isport_inuse(struct sctp_inpcb *inp, uint16_t lport)
---
> sctp_isport_inuse(struct sctp_inpcb *inp, uint16_t lport, uint32_t vrf_id)
1607a1890
> int fnd;
1615a1899,1905
> /* is it in the VRF in question */
> fnd = 0;
> if (t_inp->def_vrf_id == vrf_id)
> fnd = 1;
> if (!fnd)
> continue;
>
1655a1946
> uint32_t vrf_id;
1714a2006,2010
> /*
> * Setup a vrf_id to be the default for the non-bind-all case.
> */
> vrf_id = inp->def_vrf_id;
>
1727,1728c2023,2026
< priv_check(p,
< PRIV_NETINET_RESERVEDPORT)
---
> priv_check_cred(p->td_ucred,
> PRIV_NETINET_RESERVEDPORT,
> SUSER_ALLOWJAIL
> )
1743,1755c2041,2073
< inp_tmp = sctp_pcb_findep(addr, 0, 1);
< if (inp_tmp != NULL) {
< /*
< * lock guy returned and lower count note that we
< * are not bound so inp_tmp should NEVER be inp. And
< * it is this inp (inp_tmp) that gets the reference
< * bump, so we must lower it.
< */
< SCTP_INP_DECR_REF(inp_tmp);
< SCTP_INP_DECR_REF(inp);
< /* unlock info */
< SCTP_INP_INFO_WUNLOCK();
< return (EADDRNOTAVAIL);
---
> if (bindall) {
> vrf_id = inp->def_vrf_id;
> inp_tmp = sctp_pcb_findep(addr, 0, 1, vrf_id);
> if (inp_tmp != NULL) {
> /*
> * lock guy returned and lower count note
> * that we are not bound so inp_tmp should
> * NEVER be inp. And it is this inp
> * (inp_tmp) that gets the reference bump,
> * so we must lower it.
> */
> SCTP_INP_DECR_REF(inp_tmp);
> SCTP_INP_DECR_REF(inp);
> /* unlock info */
> SCTP_INP_INFO_WUNLOCK();
> return (EADDRNOTAVAIL);
> }
> } else {
> inp_tmp = sctp_pcb_findep(addr, 0, 1, vrf_id);
> if (inp_tmp != NULL) {
> /*
> * lock guy returned and lower count note
> * that we are not bound so inp_tmp should
> * NEVER be inp. And it is this inp
> * (inp_tmp) that gets the reference bump,
> * so we must lower it.
> */
> SCTP_INP_DECR_REF(inp_tmp);
> SCTP_INP_DECR_REF(inp);
> /* unlock info */
> SCTP_INP_INFO_WUNLOCK();
> return (EADDRNOTAVAIL);
> }
1760c2078
< if (sctp_isport_inuse(inp, lport)) {
---
> if (sctp_isport_inuse(inp, lport, vrf_id)) {
1780a2099
> int not_found = 1;
1791c2110,2111
< if (sctp_isport_inuse(inp, htons(port_attempt)) == 0) {
---
> vrf_id = inp->def_vrf_id;
> if (sctp_isport_inuse(inp, htons(port_attempt), vrf_id) == 1) {
1792a2113,2117
> not_found = 0;
> break;
> }
> if (not_found == 1) {
> /* We can use this port */
1805c2130,2131
< if (sctp_isport_inuse(inp, htons(port_attempt)) == 0) {
---
> vrf_id = inp->def_vrf_id;
> if (sctp_isport_inuse(inp, htons(port_attempt), vrf_id) == 1) {
1806a2133,2137
> not_found = 0;
> break;
> }
> if (not_found == 1) {
> /* We can use this port */
1821c2152,2153
< if (sctp_isport_inuse(inp, htons(port_attempt)) == 0) {
---
> vrf_id = inp->def_vrf_id;
> if (sctp_isport_inuse(inp, htons(port_attempt), vrf_id) == 1) {
1822a2155,2159
> not_found = 0;
> break;
> }
> if (not_found == 1) {
> /* We can use this port */
1863c2200
< struct ifaddr *ifa;
---
> struct sctp_ifa *ifa;
1885c2222
< ifa = sctp_find_ifa_by_addr((struct sockaddr *)&store_sa);
---
> ifa = sctp_find_ifa_by_addr((struct sockaddr *)&store_sa, vrf_id, 0);
1893,1902c2230,2231
< struct in6_ifaddr *ifa6;
<
< ifa6 = (struct in6_ifaddr *)ifa;
< /*
< * allow binding of deprecated addresses as per RFC
< * 2462 and ipng discussion
< */
< if (ifa6->ia6_flags & (IN6_IFF_DETACHED |
< IN6_IFF_ANYCAST |
< IN6_IFF_NOTREADY)) {
---
> /* GAK, more FIXME IFA lock? */
> if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
1911a2241
> sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF);
1914a2245,2248
> /*
> * allow bindx() to send ASCONF's for binding
> * changes
> */
1917,1918c2251
< /* allow bindx() to send ASCONF's for binding changes */
< sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF);
---
>
1920c2253
< error = sctp_insert_laddr(&inp->sctp_addr_list, ifa);
---
> error = sctp_insert_laddr(&inp->sctp_addr_list, ifa, 0);
1967c2300
< LIST_FOREACH(it, &sctppcbinfo.iteratorhead, sctp_nxt_itr) {
---
> TAILQ_FOREACH(it, &sctppcbinfo.iteratorhead, sctp_nxt_itr) {
2396,2398c2729
< LIST_REMOVE(laddr, sctp_nxt_addr);
< SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_laddr, laddr);
< SCTP_DECR_LADDR_COUNT();
---
> sctp_remove_laddr(laddr);
2451c2782
< sctp_is_address_on_local_host(struct sockaddr *addr)
---
> sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id)
2453,2454c2784
< struct ifnet *ifn;
< struct ifaddr *ifa;
---
> struct sctp_ifa *sctp_ifa;
2456,2461c2786,2792
< TAILQ_FOREACH(ifn, &ifnet, if_list) {
< TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
< if (addr->sa_family == ifa->ifa_addr->sa_family) {
< /* same family */
< if (addr->sa_family == AF_INET) {
< struct sockaddr_in *sin, *sin_c;
---
> sctp_ifa = sctp_find_ifa_by_addr(addr, vrf_id, 0);
> if (sctp_ifa) {
> return (1);
> } else {
> return (0);
> }
> }
2463,2490c2794,2800
< sin = (struct sockaddr_in *)addr;
< sin_c = (struct sockaddr_in *)
< ifa->ifa_addr;
< if (sin->sin_addr.s_addr ==
< sin_c->sin_addr.s_addr) {
< /*
< * we are on the same
< * machine
< */
< return (1);
< }
< } else if (addr->sa_family == AF_INET6) {
< struct sockaddr_in6 *sin6, *sin_c6;
<
< sin6 = (struct sockaddr_in6 *)addr;
< sin_c6 = (struct sockaddr_in6 *)
< ifa->ifa_addr;
< if (SCTP6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
< &sin_c6->sin6_addr)) {
< /*
< * we are on the same
< * machine
< */
< return (1);
< }
< }
< }
< }
---
> void
> sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
> {
> net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
> /* we always get at LEAST 2 MTU's */
> if (net->cwnd < (2 * net->mtu)) {
> net->cwnd = 2 * net->mtu;
2492c2802
< return (0);
---
> net->ssthresh = stcb->asoc.peers_rwnd;
2557,2563d2866
<
< if (sctp_is_address_on_local_host(newaddr)) {
< stcb->asoc.loopback_scope = 1;
< stcb->asoc.ipv4_local_scope = 1;
< stcb->asoc.local_scope = 1;
< stcb->asoc.site_scope = 1;
< }
2565,2573d2867
< if (from == SCTP_ADDR_IS_CONFIRMED) {
< /* From connectx */
< if (sctp_is_address_on_local_host(newaddr)) {
< stcb->asoc.loopback_scope = 1;
< stcb->asoc.ipv4_local_scope = 1;
< stcb->asoc.local_scope = 1;
< stcb->asoc.site_scope = 1;
< }
< }
2591c2885
< if (sctp_is_address_on_local_host(newaddr)) {
---
> if (sctp_is_address_on_local_host(newaddr, stcb->asoc.vrf_id)) {
2593c2887
< stcb->asoc.local_scope = 1;
---
> stcb->asoc.local_scope = 0;
2615,2623d2908
< if (from == SCTP_ADDR_IS_CONFIRMED) {
< /* From connectx so we check for localhost. */
< if (sctp_is_address_on_local_host(newaddr)) {
< stcb->asoc.loopback_scope = 1;
< stcb->asoc.ipv4_local_scope = 1;
< stcb->asoc.local_scope = 1;
< stcb->asoc.site_scope = 1;
< }
< }
2653c2938,2945
< net->addr_is_local = sctp_is_address_on_local_host(newaddr);
---
> net->addr_is_local = sctp_is_address_on_local_host(newaddr, stcb->asoc.vrf_id);
> if (net->addr_is_local && ((set_scope || (from == SCTP_ADDR_IS_CONFIRMED)))) {
> stcb->asoc.loopback_scope = 1;
> stcb->asoc.ipv4_local_scope = 1;
> stcb->asoc.local_scope = 0;
> stcb->asoc.site_scope = 1;
> addr_inscope = 1;
> }
2670c2962
< #ifdef AF_INET
---
> #ifdef INET
2674c2966
< #ifdef AF_INET6
---
> #ifdef INET6
2718c3010
< net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
---
> sctp_set_initial_cc_param(stcb, net);
2720,2724d3011
< /* we always get at LEAST 2 MTU's */
< if (net->cwnd < (2 * net->mtu)) {
< net->cwnd = 2 * net->mtu;
< }
< net->ssthresh = stcb->asoc.peers_rwnd;
2823c3110
< int for_a_init, int *error, uint32_t override_tag)
---
> int for_a_init, int *error, uint32_t override_tag, uint32_t vrf)
2923c3210
< if ((err = sctp_init_asoc(inp, asoc, for_a_init, override_tag))) {
---
> if ((err = sctp_init_asoc(inp, asoc, for_a_init, override_tag, vrf))) {
3004d3290
< sctp_free_remote_addr(net);
3011,3012c3297
< asoc->primary_destination = sctp_find_alternate_net(stcb, lnet,
< 0);
---
> asoc->primary_destination = sctp_find_alternate_net(stcb, lnet, 0);
3022,3025c3307
< /* if (net == asoc->asconf_last_sent_to) {*/
< /* Reset primary */
< /* asoc->asconf_last_sent_to = TAILQ_FIRST(&asoc->nets);*/
< /* }*/
---
> sctp_free_remote_addr(net);
3634,3639c3916,3918
< /* local addresses, if any */
< while (!SCTP_LIST_EMPTY(&asoc->sctp_local_addr_list)) {
< laddr = LIST_FIRST(&asoc->sctp_local_addr_list);
< LIST_REMOVE(laddr, sctp_nxt_addr);
< SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_laddr, laddr);
< SCTP_DECR_LADDR_COUNT();
---
> while (!SCTP_LIST_EMPTY(&asoc->sctp_restricted_addrs)) {
> laddr = LIST_FIRST(&asoc->sctp_restricted_addrs);
> sctp_remove_laddr(laddr);
3640a3920
>
3794c4074
< if (laddr->ifa->ifa_addr) {
---
> if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) {
3797c4077
< if (laddr->ifa->ifa_addr->sa_family == AF_INET6) {
---
> if (laddr->ifa->address.sa.sa_family == AF_INET6) {
3799c4079
< } else if (laddr->ifa->ifa_addr->sa_family == AF_INET) {
---
> } else if (laddr->ifa->address.sa.sa_family == AF_INET) {
3810c4090
< sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct ifaddr *ifa)
---
> sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa, uint32_t action)
3821,3827c4101,4103
< if (ifa->ifa_addr->sa_family == AF_INET6) {
< struct in6_ifaddr *ifa6;
<
< ifa6 = (struct in6_ifaddr *)ifa;
< if (ifa6->ia6_flags & (IN6_IFF_DETACHED |
< IN6_IFF_DEPRECATED | IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))
< /* Can't bind a non-existent addr. */
---
> if (ifa->address.sa.sa_family == AF_INET6) {
> if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
> /* Can't bind a non-useable addr. */
3828a4105
> }
3838,3840c4115,4117
< if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) && (fnd == 0)) {
< /* Not bound to all */
< error = sctp_insert_laddr(&inp->sctp_addr_list, ifa);
---
> if (fnd == 0) {
> /* Not in the ep list */
> error = sctp_insert_laddr(&inp->sctp_addr_list, ifa, action);
3845c4122
< if (ifa->ifa_addr->sa_family == AF_INET6) {
---
> if (ifa->address.sa.sa_family == AF_INET6) {
3847c4124
< } else if (ifa->ifa_addr->sa_family == AF_INET) {
---
> } else if (ifa->address.sa.sa_family == AF_INET) {
3884c4161
< sctp_del_local_addr_ep(struct sctp_inpcb *inp, struct ifaddr *ifa)
---
> sctp_del_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa)
3904c4181
< if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) && (fnd)) {
---
> if (fnd) {
3919a4197,4199
> struct sctp_nets *net;
>
> SCTP_TCB_LOCK(stcb);
3923c4203,4211
< } /* for each tcb */
---
> /*
> * Now spin through all the nets and purge any ref
> * to laddr
> */
> TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
> if (net->ro._s_addr &&
> (net->ro._s_addr->ifa == laddr->ifa)) {
> /* Yep, purge src address selected */
> struct rtentry *rt;
3924a4213,4225
> /* delete this address if cached */
> rt = net->ro.ro_rt;
> if (rt != NULL) {
> RTFREE(rt);
> net->ro.ro_rt = NULL;
> }
> sctp_free_ifa(net->ro._s_addr);
> net->ro._s_addr = NULL;
> net->src_addr_selected = 0;
> }
> }
> SCTP_TCB_UNLOCK(stcb);
> } /* for each tcb */
3930,3942d4230
< /* select a new primary destination if needed */
< LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
< /*
< * presume caller (sctp_asconf.c) already owns INP
< * lock
< */
< SCTP_TCB_LOCK(stcb);
< if (sctp_destination_is_reachable(stcb,
< (struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr) == 0) {
< sctp_select_primary_destination(stcb);
< }
< SCTP_TCB_UNLOCK(stcb);
< } /* for each tcb */
3954c4242
< sctp_add_local_addr_assoc(struct sctp_tcb *stcb, struct ifaddr *ifa)
---
> sctp_add_local_addr_assoc(struct sctp_tcb *stcb, struct sctp_ifa *ifa, int restricted_list)
3957a4246
> struct sctpladdr *list;
3961c4250
< * Assumes TCP is locked.. and possiblye the INP. May need to
---
> * Assumes TCB is locked.. and possibly the INP. May need to
3964,3966c4253
< inp = stcb->sctp_ep;
< if (ifa->ifa_addr->sa_family == AF_INET6) {
< struct in6_ifaddr *ifa6;
---
> list = &stcb->asoc.sctp_restricted_addrs;
3968,3972c4255,4257
< ifa6 = (struct in6_ifaddr *)ifa;
< if (ifa6->ia6_flags & (IN6_IFF_DETACHED |
< /* IN6_IFF_DEPRECATED | */
< IN6_IFF_ANYCAST |
< IN6_IFF_NOTREADY))
---
> inp = stcb->sctp_ep;
> if (ifa->address.sa.sa_family == AF_INET6) {
> if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
3974a4260
> }
3977c4263
< LIST_FOREACH(laddr, &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) {
---
> LIST_FOREACH(laddr, list, sctp_nxt_addr) {
3984c4270
< error = sctp_insert_laddr(&stcb->asoc.sctp_local_addr_list, ifa);
---
> error = sctp_insert_laddr(list, ifa, 0);
3994c4280
< sctp_insert_laddr(struct sctpladdr *list, struct ifaddr *ifa)
---
> sctp_insert_laddr(struct sctpladdr *list, struct sctp_ifa *ifa, uint32_t act)
4005a4292,4293
> laddr->action = act;
> atomic_add_int(&ifa->refcount, 1);
4020a4309
> sctp_free_ifa(laddr->ifa);
4029c4318
< sctp_del_local_addr_assoc(struct sctp_tcb *stcb, struct ifaddr *ifa)
---
> sctp_del_local_addr_assoc(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
4053c4342
< LIST_FOREACH(laddr, &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) {
---
> LIST_FOREACH(laddr, &stcb->asoc.sctp_restricted_addrs, sctp_nxt_addr) {
4067,4131d4355
< /*
< * Remove an address from the TCB local address list lookup using a sockaddr
< * addr
< */
< int
< sctp_del_local_addr_assoc_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
< {
< struct sctp_inpcb *inp;
< struct sctp_laddr *laddr;
< struct sockaddr *l_sa;
<
< /*
< * This function I find does not seem to have a caller. As such we
< * NEED TO DELETE this code. If we do find a caller, the caller MUST
< * have locked the TCB at the least and probably the INP as well.
< */
< inp = stcb->sctp_ep;
< /* if subset bound and don't allow ASCONF's, can't delete last */
< if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) &&
< (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF) == 0)) {
< if (stcb->asoc.numnets < 2) {
< /* can't delete last address */
< return (-1);
< }
< }
< LIST_FOREACH(laddr, &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) {
< /* make sure the address exists */
< if (laddr->ifa == NULL)
< continue;
< if (laddr->ifa->ifa_addr == NULL)
< continue;
<
< l_sa = laddr->ifa->ifa_addr;
< if (l_sa->sa_family == AF_INET6) {
< /* IPv6 address */
< struct sockaddr_in6 *sin1, *sin2;
<
< sin1 = (struct sockaddr_in6 *)l_sa;
< sin2 = (struct sockaddr_in6 *)sa;
< if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
< sizeof(struct in6_addr)) == 0) {
< /* matched */
< sctp_remove_laddr(laddr);
< return (0);
< }
< } else if (l_sa->sa_family == AF_INET) {
< /* IPv4 address */
< struct sockaddr_in *sin1, *sin2;
<
< sin1 = (struct sockaddr_in *)l_sa;
< sin2 = (struct sockaddr_in *)sa;
< if (sin1->sin_addr.s_addr == sin2->sin_addr.s_addr) {
< /* matched */
< sctp_remove_laddr(laddr);
< return (0);
< }
< } else {
< /* invalid family */
< return (-1);
< }
< } /* end foreach */
< /* address not found! */
< return (-1);
< }
<
4162c4386
< LIST_INIT(&sctppcbinfo.iteratorhead);
---
> TAILQ_INIT(&sctppcbinfo.iteratorhead);
4179a4404,4407
>
> sctppcbinfo.sctp_vrfhash = SCTP_HASH_INIT(SCTP_SIZE_OF_VRF_HASH,
> &sctppcbinfo.hashvrfmark);
>
4217a4446,4447
> SCTP_IPI_ITERATOR_WQ_INIT();
>
4246a4477,4488
> #if defined(SCTP_USE_THREAD_BASED_ITERATOR)
> sctppcbinfo.iterator_running = 0;
> sctp_startup_iterator();
> #endif
>
> /*
> * INIT the default VRF which for BSD is the only one, other O/S's
> * may have more. But initially they must start with one and then
> * add the VRF's as addresses are added.
> */
> sctp_init_vrf_list(SCTP_DEFAULT_VRF);
>
4817,4818c5059,5061
< /* Must be confirmed */
< return (-1);
---
> /* Must be confirmed, so queue to set */
> net->dest_state |= SCTP_ADDR_REQ_PRIMARY;
> return (0);
4925,5003d5167
< /*
< * Delete the address from the endpoint local address list Lookup using a
< * sockaddr address (ie. not an ifaddr)
< */
< int
< sctp_del_local_addr_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa)
< {
< struct sctp_laddr *laddr;
< struct sockaddr *l_sa;
< int found = 0;
<
< /*
< * Here is another function I cannot find a caller for. As such we
< * SHOULD delete it if we have no users. If we find a user that user
< * MUST have the INP locked.
< *
< */
<
< if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
< /* You are already bound to all. You have it already */
< return (EINVAL);
< }
< LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
< /* make sure the address exists */
< if (laddr->ifa == NULL)
< continue;
< if (laddr->ifa->ifa_addr == NULL)
< continue;
<
< l_sa = laddr->ifa->ifa_addr;
< if (l_sa->sa_family == AF_INET6) {
< /* IPv6 address */
< struct sockaddr_in6 *sin1, *sin2;
<
< sin1 = (struct sockaddr_in6 *)l_sa;
< sin2 = (struct sockaddr_in6 *)sa;
< if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
< sizeof(struct in6_addr)) == 0) {
< /* matched */
< found = 1;
< break;
< }
< } else if (l_sa->sa_family == AF_INET) {
< /* IPv4 address */
< struct sockaddr_in *sin1, *sin2;
<
< sin1 = (struct sockaddr_in *)l_sa;
< sin2 = (struct sockaddr_in *)sa;
< if (sin1->sin_addr.s_addr == sin2->sin_addr.s_addr) {
< /* matched */
< found = 1;
< break;
< }
< } else {
< /* invalid family */
< return (-1);
< }
< }
<
< if (found && inp->laddr_count < 2) {
< /* can't delete unless there are at LEAST 2 addresses */
< return (-1);
< }
< if (found && (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
< /*
< * remove it from the ep list, this should NOT be done until
< * its really gone from the interface list and we won't be
< * receiving more of these. Probably right away. If we do
< * allow a removal of an address from an association
< * (sub-set bind) than this should NOT be called until the
< * all ASCONF come back from this association.
< */
< sctp_remove_laddr(laddr);
< return (0);
< } else {
< return (-1);
< }
< }
<
5007d5170
< extern int sctp_do_drain;
5162a5326
> sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_DRAIN);
5212,5214c5376,5386
< sctp_initiate_iterator(inp_func inpf, asoc_func af, uint32_t pcb_state,
< uint32_t pcb_features, uint32_t asoc_state, void *argp, uint32_t argi,
< end_func ef, struct sctp_inpcb *s_inp, uint8_t chunk_output_off)
---
> sctp_initiate_iterator(inp_func inpf,
> asoc_func af,
> inp_func inpe,
> uint32_t pcb_state,
> uint32_t pcb_features,
> uint32_t asoc_state,
> void *argp,
> uint32_t argi,
> end_func ef,
> struct sctp_inpcb *s_inp,
> uint8_t chunk_output_off)
5228a5401,5404
> if (inpf)
> it->done_current_ep = 0;
> else
> it->done_current_ep = 1;
5234a5411
> it->function_inp_end = inpe;
5241a5419
>
5245a5424,5436
> SCTP_IPI_ITERATOR_WQ_LOCK();
> if (it->inp)
> SCTP_INP_INCR_REF(it->inp);
> TAILQ_INSERT_TAIL(&sctppcbinfo.iteratorhead, it, sctp_nxt_itr);
> #if defined(SCTP_USE_THREAD_BASED_ITERATOR)
> if (sctppcbinfo.iterator_running == 0) {
> sctp_wakeup_iterator();
> }
> SCTP_IPI_ITERATOR_WQ_UNLOCK();
> #else
> if (it->inp)
> SCTP_INP_DECR_REF(it->inp);
> SCTP_IPI_ITERATOR_WQ_UNLOCK();
5249,5251d5439
< SCTP_INP_INFO_WLOCK();
< LIST_INSERT_HEAD(&sctppcbinfo.iteratorhead, it, sctp_nxt_itr);
< SCTP_INP_INFO_WUNLOCK();
5253a5442
> #endif
< __FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 166675 2007-02-12 23:24:31Z rrs $");
---
> __FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 167598 2007-03-15 11:27:14Z rrs $");
38a39
> #include <netinet/sctp_sysctl.h>
45a47
> #include <netinet/sctp_bsd_addr.h>
48,57d49
< #ifdef SCTP_DEBUG
< uint32_t sctp_debug_on = 0;
<
< #endif /* SCTP_DEBUG */
<
<
< extern int sctp_pcbtblsize;
< extern int sctp_hashtblsize;
< extern int sctp_chunkscale;
<
75d66
<
95a87,130
> /*
> * Addresses are added to VRF's (Virtual Router's). For BSD we
> * have only the default VRF 0. We maintain a hash list of
> * VRF's. Each VRF has its own list of sctp_ifn's. Each of
> * these has a list of addresses. When we add a new address
> * to a VRF we lookup the ifn/ifn_index, if the ifn does
> * not exist we create it and add it to the list of IFN's
> * within the VRF. Once we have the sctp_ifn, we add the
> * address to the list. So we look something like:
> *
> * hash-vrf-table
> * vrf-> ifn-> ifn -> ifn
> * vrf |
> * ... +--ifa-> ifa -> ifa
> * vrf
> *
> * We keep these seperate lists since the SCTP subsystem will
> * point to these from its source address selection nets structure.
> * When an address is deleted it does not happen right away on
> * the SCTP side, it gets scheduled. What we do when a
> * delete happens is immediately remove the address from
> * the master list and decrement the refcount. As our
> * addip iterator works through and frees the src address
> * selection pointing to the sctp_ifa, eventually the refcount
> * will reach 0 and we will delete it. Note that it is assumed
> * that any locking on system level ifn/ifa is done at the
> * caller of these functions and these routines will only
> * lock the SCTP structures as they add or delete things.
> *
> * Other notes on VRF concepts.
> * - An endpoint can be in multiple VRF's
> * - An association lives within a VRF and only one VRF.
> * - Any incoming packet we can deduce the VRF for by
> * looking at the mbuf/pak inbound (for BSD its VRF=0 :D)
> * - Any downward send call or connect call must supply the
> * VRF via ancillary data or via some sort of set default
> * VRF socket option call (again for BSD no brainer since
> * the VRF is always 0).
> * - An endpoint may add multiple VRF's to it.
> * - Listening sockets can accept associations in any
> * of the VRF's they are in but the assoc will end up
> * in only one VRF (gotten from the packet or connect/send).
> *
> */
96a132,379
> struct sctp_vrf *
> sctp_allocate_vrf(int vrfid)
> {
> struct sctp_vrf *vrf = NULL;
> struct sctp_vrflist *bucket;
>
> /* First allocate the VRF structure */
> vrf = sctp_find_vrf(vrfid);
> if (vrf) {
> /* Already allocated */
> return (vrf);
> }
> SCTP_MALLOC(vrf, struct sctp_vrf *, sizeof(struct sctp_vrf),
> "SCTP_VRF");
> if (vrf == NULL) {
> /* No memory */
> #ifdef INVARIANTS
> panic("No memory for VRF:%d", vrfid);
> #endif
> return (NULL);
> }
> /* setup the VRF */
> memset(vrf, 0, sizeof(struct sctp_vrf));
> vrf->vrf_id = vrfid;
> LIST_INIT(&vrf->ifnlist);
> vrf->total_ifa_count = 0;
> /* Add it to the hash table */
> bucket = &sctppcbinfo.sctp_vrfhash[(vrfid & sctppcbinfo.hashvrfmark)];
> LIST_INSERT_HEAD(bucket, vrf, next_vrf);
> return (vrf);
> }
>
>
> struct sctp_ifn *
> sctp_find_ifn(struct sctp_vrf *vrf, void *ifn, uint32_t ifn_index)
> {
> struct sctp_ifn *sctp_ifnp;
>
> /*
> * We assume the lock is held for the addresses if thats wrong
> * problems could occur :-)
> */
> LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
> if (sctp_ifnp->ifn_index == ifn_index) {
> return (sctp_ifnp);
> }
> if (sctp_ifnp->ifn_p && ifn && (sctp_ifnp->ifn_p == ifn)) {
> return (sctp_ifnp);
> }
> }
> return (NULL);
> }
>
> struct sctp_vrf *
> sctp_find_vrf(uint32_t vrfid)
> {
> struct sctp_vrflist *bucket;
> struct sctp_vrf *liste;
>
> bucket = &sctppcbinfo.sctp_vrfhash[(vrfid & sctppcbinfo.hashvrfmark)];
> LIST_FOREACH(liste, bucket, next_vrf) {
> if (vrfid == liste->vrf_id) {
> return (liste);
> }
> }
> return (NULL);
> }
>
> void
> sctp_free_ifa(struct sctp_ifa *sctp_ifap)
> {
> int ret;
>
> ret = atomic_fetchadd_int(&sctp_ifap->refcount, -1);
> if (ret == 1) {
> /* We zero'd the count */
> SCTP_FREE(sctp_ifap);
> }
> }
>
> struct sctp_ifa *
> sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index,
> uint32_t ifn_type, const char *if_name,
> void *ifa, struct sockaddr *addr, uint32_t ifa_flags)
> {
> struct sctp_vrf *vrf;
> struct sctp_ifn *sctp_ifnp = NULL;
> struct sctp_ifa *sctp_ifap = NULL;
>
> /* How granular do we need the locks to be here? */
> SCTP_IPI_ADDR_LOCK();
> vrf = sctp_find_vrf(vrfid);
> if (vrf == NULL) {
> vrf = sctp_allocate_vrf(vrfid);
> if (vrf == NULL) {
> SCTP_IPI_ADDR_UNLOCK();
> return (NULL);
> }
> }
> sctp_ifnp = sctp_find_ifn(vrf, ifn, ifn_index);
> if (sctp_ifnp == NULL) {
> /*
> * build one and add it, can't hold lock until after malloc
> * done though.
> */
> SCTP_IPI_ADDR_UNLOCK();
> SCTP_MALLOC(sctp_ifnp, struct sctp_ifn *, sizeof(struct sctp_ifn), "SCTP_IFN");
> if (sctp_ifnp == NULL) {
> #ifdef INVARIANTS
> panic("No memory for IFN:%u", sctp_ifnp->ifn_index);
> #endif
> return (NULL);
> }
> sctp_ifnp->ifn_index = ifn_index;
> sctp_ifnp->ifn_p = ifn;
> sctp_ifnp->ifn_type = ifn_type;
> sctp_ifnp->ifa_count = 0;
> sctp_ifnp->refcount = 0;
> sctp_ifnp->vrf = vrf;
> memcpy(sctp_ifnp->ifn_name, if_name, SCTP_IFNAMSIZ);
> LIST_INIT(&sctp_ifnp->ifalist);
> SCTP_IPI_ADDR_LOCK();
> LIST_INSERT_HEAD(&vrf->ifnlist, sctp_ifnp, next_ifn);
> }
> sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1);
> if (sctp_ifap) {
> /* Hmm, it already exists? */
> if ((sctp_ifap->ifn_p) &&
> (sctp_ifap->ifn_p->ifn_index == ifn_index)) {
> if (sctp_ifap->localifa_flags & SCTP_BEING_DELETED) {
> /* easy to solve, just switch back to active */
> sctp_ifap->localifa_flags = SCTP_ADDR_VALID;
> sctp_ifap->ifn_p = sctp_ifnp;
> exit_stage_left:
> SCTP_IPI_ADDR_UNLOCK();
> return (sctp_ifap);
> } else {
> goto exit_stage_left;
> }
> } else {
> if (sctp_ifap->ifn_p) {
> /*
> * The first IFN gets the address,
> * duplicates are ignored.
> */
> goto exit_stage_left;
> } else {
> /* repair ifnp which was NULL ? */
> sctp_ifap->localifa_flags = SCTP_ADDR_VALID;
> sctp_ifap->ifn_p = sctp_ifnp;
> atomic_add_int(&sctp_ifnp->refcount, 1);
> }
> goto exit_stage_left;
> }
> }
> SCTP_IPI_ADDR_UNLOCK();
> SCTP_MALLOC(sctp_ifap, struct sctp_ifa *, sizeof(struct sctp_ifa), "SCTP_IFA");
> if (sctp_ifap == NULL) {
> #ifdef INVARIANTS
> panic("No memory for IFA");
> #endif
> return (NULL);
> }
> memset(sctp_ifap, 0, sizeof(sctp_ifap));
> sctp_ifap->ifn_p = sctp_ifnp;
> atomic_add_int(&sctp_ifnp->refcount, 1);
>
> sctp_ifap->ifa = ifa;
> memcpy(&sctp_ifap->address, addr, addr->sa_len);
> sctp_ifap->localifa_flags = SCTP_ADDR_VALID | SCTP_ADDR_DEFER_USE;
> sctp_ifap->flags = ifa_flags;
> /* Set scope */
> if (sctp_ifap->address.sa.sa_family == AF_INET) {
> struct sockaddr_in *sin;
>
> sin = (struct sockaddr_in *)&sctp_ifap->address.sin;
> if (SCTP_IFN_IS_IFT_LOOP(sctp_ifap->ifn_p) ||
> (IN4_ISLOOPBACK_ADDRESS(&sin->sin_addr))) {
> sctp_ifap->src_is_loop = 1;
> }
> if ((IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
> sctp_ifap->src_is_priv = 1;
> }
> } else if (sctp_ifap->address.sa.sa_family == AF_INET6) {
> /* ok to use deprecated addresses? */
> struct sockaddr_in6 *sin6;
>
> sin6 = (struct sockaddr_in6 *)&sctp_ifap->address.sin6;
> if (SCTP_IFN_IS_IFT_LOOP(sctp_ifap->ifn_p) ||
> (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))) {
> sctp_ifap->src_is_loop = 1;
> }
> if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
> sctp_ifap->src_is_priv = 1;
> }
> }
> if ((sctp_ifap->src_is_priv == 0) &&
> (sctp_ifap->src_is_loop == 0)) {
> sctp_ifap->src_is_glob = 1;
> }
> SCTP_IPI_ADDR_LOCK();
> sctp_ifap->refcount = 1;
> LIST_INSERT_HEAD(&sctp_ifnp->ifalist, sctp_ifap, next_ifa);
> sctp_ifnp->ifa_count++;
> vrf->total_ifa_count++;
> SCTP_IPI_ADDR_UNLOCK();
> return (sctp_ifap);
> }
>
> struct sctp_ifa *
> sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
> uint32_t ifn_index)
> {
> struct sctp_vrf *vrf;
> struct sctp_ifa *sctp_ifap = NULL;
> struct sctp_ifn *sctp_ifnp = NULL;
>
> SCTP_IPI_ADDR_LOCK();
>
> vrf = sctp_find_vrf(vrfid);
> if (vrf == NULL) {
> printf("Can't find vrfid:%d\n", vrfid);
> goto out_now;
> }
> sctp_ifnp = sctp_find_ifn(vrf, (void *)NULL, ifn_index);
> if (sctp_ifnp == NULL) {
> sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1);
> } else {
> sctp_ifap = sctp_find_ifa_in_ifn(sctp_ifnp, addr, 1);
> }
>
> if (sctp_ifap) {
> sctp_ifap->localifa_flags &= SCTP_ADDR_VALID;
> sctp_ifap->localifa_flags |= SCTP_BEING_DELETED;
> sctp_ifnp->ifa_count--;
> vrf->total_ifa_count--;
> LIST_REMOVE(sctp_ifap, next_ifa);
> atomic_add_int(&sctp_ifnp->refcount, -1);
> } else {
> printf("Del Addr-ifn:%d Could not find address:",
> ifn_index);
> sctp_print_address(addr);
> }
> out_now:
> SCTP_IPI_ADDR_UNLOCK();
> return (sctp_ifap);
> }
>
180c463
< if (laddr->ifa->ifa_addr == NULL) {
---
> if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) {
183c466
< printf("ifa with a NULL address\n");
---
> printf("ifa being deleted\n");
188c471
< if (laddr->ifa->ifa_addr->sa_family ==
---
> if (laddr->ifa->address.sa.sa_family ==
193,194c476
< intf_addr = (struct sockaddr_in *)
< laddr->ifa->ifa_addr;
---
> intf_addr = &laddr->ifa->address.sin;
208,209c490
< intf_addr6 = (struct sockaddr_in6 *)
< laddr->ifa->ifa_addr;
---
> intf_addr6 = &laddr->ifa->address.sin6;
598c879
< uint16_t lport)
---
> uint16_t lport, uint32_t vrf_id)
603a885
> int fnd;
641a924,928
> /* does a VRF id match? */
> fnd = 0;
> if (inp->def_vrf_id == vrf_id)
> fnd = 1;
>
642a930,931
> if (!fnd)
> continue;
678a968,976
> /* does a VRF id match? */
> fnd = 0;
> if (inp->def_vrf_id == vrf_id)
> fnd = 1;
>
> if (!fnd) {
> SCTP_INP_RUNLOCK(inp);
> continue;
> }
694c992
< if (laddr->ifa->ifa_addr == NULL) {
---
> if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) {
697c995
< printf("Huh IFA as an ifa_addr=NULL, ");
---
> printf("Huh IFA being deleted\n");
702c1000
< if (laddr->ifa->ifa_addr->sa_family == nam->sa_family) {
---
> if (laddr->ifa->address.sa.sa_family == nam->sa_family) {
706,707c1004
< intf_addr = (struct sockaddr_in *)
< laddr->ifa->ifa_addr;
---
> intf_addr = &laddr->ifa->address.sin;
717,718c1014
< intf_addr6 = (struct sockaddr_in6 *)
< laddr->ifa->ifa_addr;
---
> intf_addr6 = &laddr->ifa->address.sin6;
734c1030
< sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool, int have_lock)
---
> sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool, int have_lock, uint32_t vrf_id)
768c1064
< inp = sctp_endpoint_probe(nam, head, lport);
---
> inp = sctp_endpoint_probe(nam, head, lport, vrf_id);
789c1085
< inp = sctp_endpoint_probe(nam, head, lport);
---
> inp = sctp_endpoint_probe(nam, head, lport, vrf_id);
813c1109
< struct sctp_inpcb **inp_p, struct sctp_nets **netp, int find_tcp_pool)
---
> struct sctp_inpcb **inp_p, struct sctp_nets **netp, int find_tcp_pool, uint32_t vrf_id)
830c1126
< inp = sctp_pcb_findep(to, 0, 1);
---
> inp = sctp_pcb_findep(to, 0, 1, vrf_id);
1029a1326
> uint32_t vrf_id;
1031c1328
<
---
> vrf_id = SCTP_DEFAULT_VRFID;
1114c1411
< find_tcp_pool);
---
> find_tcp_pool, vrf_id);
1118c1415
< find_tcp_pool);
---
> find_tcp_pool, vrf_id);
1285,1302d1581
< extern int sctp_max_burst_default;
<
< extern unsigned int sctp_delayed_sack_time_default;
< extern unsigned int sctp_heartbeat_interval_default;
< extern unsigned int sctp_pmtu_raise_time_default;
< extern unsigned int sctp_shutdown_guard_time_default;
< extern unsigned int sctp_secret_lifetime_default;
<
< extern unsigned int sctp_rto_max_default;
< extern unsigned int sctp_rto_min_default;
< extern unsigned int sctp_rto_initial_default;
< extern unsigned int sctp_init_rto_max_default;
< extern unsigned int sctp_valid_cookie_life_default;
< extern unsigned int sctp_init_rtx_max_default;
< extern unsigned int sctp_assoc_rtx_max_default;
< extern unsigned int sctp_path_rtx_max_default;
< extern unsigned int sctp_nr_outgoing_streams_default;
<
1367,1368c1646,1647
< if ((so->so_type == SOCK_DGRAM) ||
< (so->so_type == SOCK_SEQPACKET)) {
---
> if ((SCTP_SO_TYPE(so) == SOCK_DGRAM) ||
> (SCTP_SO_TYPE(so) == SOCK_SEQPACKET)) {
1374,1375c1653,1654
< /* so->so_state |= SS_NBIO; */
< } else if (so->so_type == SOCK_STREAM) {
---
> /* SCTP_SET_SO_NBIO(so); */
> } else if (SCTP_SO_TYPE(so) == SOCK_STREAM) {
1381c1660
< so->so_state &= ~SS_NBIO;
---
> SCTP_CLEAR_SO_NBIO(so);
1396a1676,1677
> inp->def_vrf_id = SCTP_DEFAULT_VRFID;
>
1409a1691
>
1435a1718
> m->sctp_sack_freq = sctp_sack_freq_default;
1473d1755
<
1604c1886
< sctp_isport_inuse(struct sctp_inpcb *inp, uint16_t lport)
---
> sctp_isport_inuse(struct sctp_inpcb *inp, uint16_t lport, uint32_t vrf_id)
1607a1890
> int fnd;
1615a1899,1905
> /* is it in the VRF in question */
> fnd = 0;
> if (t_inp->def_vrf_id == vrf_id)
> fnd = 1;
> if (!fnd)
> continue;
>
1655a1946
> uint32_t vrf_id;
1714a2006,2010
> /*
> * Setup a vrf_id to be the default for the non-bind-all case.
> */
> vrf_id = inp->def_vrf_id;
>
1727,1728c2023,2026
< priv_check(p,
< PRIV_NETINET_RESERVEDPORT)
---
> priv_check_cred(p->td_ucred,
> PRIV_NETINET_RESERVEDPORT,
> SUSER_ALLOWJAIL
> )
1743,1755c2041,2073
< inp_tmp = sctp_pcb_findep(addr, 0, 1);
< if (inp_tmp != NULL) {
< /*
< * lock guy returned and lower count note that we
< * are not bound so inp_tmp should NEVER be inp. And
< * it is this inp (inp_tmp) that gets the reference
< * bump, so we must lower it.
< */
< SCTP_INP_DECR_REF(inp_tmp);
< SCTP_INP_DECR_REF(inp);
< /* unlock info */
< SCTP_INP_INFO_WUNLOCK();
< return (EADDRNOTAVAIL);
---
> if (bindall) {
> vrf_id = inp->def_vrf_id;
> inp_tmp = sctp_pcb_findep(addr, 0, 1, vrf_id);
> if (inp_tmp != NULL) {
> /*
> * lock guy returned and lower count note
> * that we are not bound so inp_tmp should
> * NEVER be inp. And it is this inp
> * (inp_tmp) that gets the reference bump,
> * so we must lower it.
> */
> SCTP_INP_DECR_REF(inp_tmp);
> SCTP_INP_DECR_REF(inp);
> /* unlock info */
> SCTP_INP_INFO_WUNLOCK();
> return (EADDRNOTAVAIL);
> }
> } else {
> inp_tmp = sctp_pcb_findep(addr, 0, 1, vrf_id);
> if (inp_tmp != NULL) {
> /*
> * lock guy returned and lower count note
> * that we are not bound so inp_tmp should
> * NEVER be inp. And it is this inp
> * (inp_tmp) that gets the reference bump,
> * so we must lower it.
> */
> SCTP_INP_DECR_REF(inp_tmp);
> SCTP_INP_DECR_REF(inp);
> /* unlock info */
> SCTP_INP_INFO_WUNLOCK();
> return (EADDRNOTAVAIL);
> }
1760c2078
< if (sctp_isport_inuse(inp, lport)) {
---
> if (sctp_isport_inuse(inp, lport, vrf_id)) {
1780a2099
> int not_found = 1;
1791c2110,2111
< if (sctp_isport_inuse(inp, htons(port_attempt)) == 0) {
---
> vrf_id = inp->def_vrf_id;
> if (sctp_isport_inuse(inp, htons(port_attempt), vrf_id) == 1) {
1792a2113,2117
> not_found = 0;
> break;
> }
> if (not_found == 1) {
> /* We can use this port */
1805c2130,2131
< if (sctp_isport_inuse(inp, htons(port_attempt)) == 0) {
---
> vrf_id = inp->def_vrf_id;
> if (sctp_isport_inuse(inp, htons(port_attempt), vrf_id) == 1) {
1806a2133,2137
> not_found = 0;
> break;
> }
> if (not_found == 1) {
> /* We can use this port */
1821c2152,2153
< if (sctp_isport_inuse(inp, htons(port_attempt)) == 0) {
---
> vrf_id = inp->def_vrf_id;
> if (sctp_isport_inuse(inp, htons(port_attempt), vrf_id) == 1) {
1822a2155,2159
> not_found = 0;
> break;
> }
> if (not_found == 1) {
> /* We can use this port */
1863c2200
< struct ifaddr *ifa;
---
> struct sctp_ifa *ifa;
1885c2222
< ifa = sctp_find_ifa_by_addr((struct sockaddr *)&store_sa);
---
> ifa = sctp_find_ifa_by_addr((struct sockaddr *)&store_sa, vrf_id, 0);
1893,1902c2230,2231
< struct in6_ifaddr *ifa6;
<
< ifa6 = (struct in6_ifaddr *)ifa;
< /*
< * allow binding of deprecated addresses as per RFC
< * 2462 and ipng discussion
< */
< if (ifa6->ia6_flags & (IN6_IFF_DETACHED |
< IN6_IFF_ANYCAST |
< IN6_IFF_NOTREADY)) {
---
> /* GAK, more FIXME IFA lock? */
> if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
1911a2241
> sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF);
1914a2245,2248
> /*
> * allow bindx() to send ASCONF's for binding
> * changes
> */
1917,1918c2251
< /* allow bindx() to send ASCONF's for binding changes */
< sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF);
---
>
1920c2253
< error = sctp_insert_laddr(&inp->sctp_addr_list, ifa);
---
> error = sctp_insert_laddr(&inp->sctp_addr_list, ifa, 0);
1967c2300
< LIST_FOREACH(it, &sctppcbinfo.iteratorhead, sctp_nxt_itr) {
---
> TAILQ_FOREACH(it, &sctppcbinfo.iteratorhead, sctp_nxt_itr) {
2396,2398c2729
< LIST_REMOVE(laddr, sctp_nxt_addr);
< SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_laddr, laddr);
< SCTP_DECR_LADDR_COUNT();
---
> sctp_remove_laddr(laddr);
2451c2782
< sctp_is_address_on_local_host(struct sockaddr *addr)
---
> sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id)
2453,2454c2784
< struct ifnet *ifn;
< struct ifaddr *ifa;
---
> struct sctp_ifa *sctp_ifa;
2456,2461c2786,2792
< TAILQ_FOREACH(ifn, &ifnet, if_list) {
< TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
< if (addr->sa_family == ifa->ifa_addr->sa_family) {
< /* same family */
< if (addr->sa_family == AF_INET) {
< struct sockaddr_in *sin, *sin_c;
---
> sctp_ifa = sctp_find_ifa_by_addr(addr, vrf_id, 0);
> if (sctp_ifa) {
> return (1);
> } else {
> return (0);
> }
> }
2463,2490c2794,2800
< sin = (struct sockaddr_in *)addr;
< sin_c = (struct sockaddr_in *)
< ifa->ifa_addr;
< if (sin->sin_addr.s_addr ==
< sin_c->sin_addr.s_addr) {
< /*
< * we are on the same
< * machine
< */
< return (1);
< }
< } else if (addr->sa_family == AF_INET6) {
< struct sockaddr_in6 *sin6, *sin_c6;
<
< sin6 = (struct sockaddr_in6 *)addr;
< sin_c6 = (struct sockaddr_in6 *)
< ifa->ifa_addr;
< if (SCTP6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
< &sin_c6->sin6_addr)) {
< /*
< * we are on the same
< * machine
< */
< return (1);
< }
< }
< }
< }
---
> void
> sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
> {
> net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
> /* we always get at LEAST 2 MTU's */
> if (net->cwnd < (2 * net->mtu)) {
> net->cwnd = 2 * net->mtu;
2492c2802
< return (0);
---
> net->ssthresh = stcb->asoc.peers_rwnd;
2557,2563d2866
<
< if (sctp_is_address_on_local_host(newaddr)) {
< stcb->asoc.loopback_scope = 1;
< stcb->asoc.ipv4_local_scope = 1;
< stcb->asoc.local_scope = 1;
< stcb->asoc.site_scope = 1;
< }
2565,2573d2867
< if (from == SCTP_ADDR_IS_CONFIRMED) {
< /* From connectx */
< if (sctp_is_address_on_local_host(newaddr)) {
< stcb->asoc.loopback_scope = 1;
< stcb->asoc.ipv4_local_scope = 1;
< stcb->asoc.local_scope = 1;
< stcb->asoc.site_scope = 1;
< }
< }
2591c2885
< if (sctp_is_address_on_local_host(newaddr)) {
---
> if (sctp_is_address_on_local_host(newaddr, stcb->asoc.vrf_id)) {
2593c2887
< stcb->asoc.local_scope = 1;
---
> stcb->asoc.local_scope = 0;
2615,2623d2908
< if (from == SCTP_ADDR_IS_CONFIRMED) {
< /* From connectx so we check for localhost. */
< if (sctp_is_address_on_local_host(newaddr)) {
< stcb->asoc.loopback_scope = 1;
< stcb->asoc.ipv4_local_scope = 1;
< stcb->asoc.local_scope = 1;
< stcb->asoc.site_scope = 1;
< }
< }
2653c2938,2945
< net->addr_is_local = sctp_is_address_on_local_host(newaddr);
---
> net->addr_is_local = sctp_is_address_on_local_host(newaddr, stcb->asoc.vrf_id);
> if (net->addr_is_local && ((set_scope || (from == SCTP_ADDR_IS_CONFIRMED)))) {
> stcb->asoc.loopback_scope = 1;
> stcb->asoc.ipv4_local_scope = 1;
> stcb->asoc.local_scope = 0;
> stcb->asoc.site_scope = 1;
> addr_inscope = 1;
> }
2670c2962
< #ifdef AF_INET
---
> #ifdef INET
2674c2966
< #ifdef AF_INET6
---
> #ifdef INET6
2718c3010
< net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
---
> sctp_set_initial_cc_param(stcb, net);
2720,2724d3011
< /* we always get at LEAST 2 MTU's */
< if (net->cwnd < (2 * net->mtu)) {
< net->cwnd = 2 * net->mtu;
< }
< net->ssthresh = stcb->asoc.peers_rwnd;
2823c3110
< int for_a_init, int *error, uint32_t override_tag)
---
> int for_a_init, int *error, uint32_t override_tag, uint32_t vrf)
2923c3210
< if ((err = sctp_init_asoc(inp, asoc, for_a_init, override_tag))) {
---
> if ((err = sctp_init_asoc(inp, asoc, for_a_init, override_tag, vrf))) {
3004d3290
< sctp_free_remote_addr(net);
3011,3012c3297
< asoc->primary_destination = sctp_find_alternate_net(stcb, lnet,
< 0);
---
> asoc->primary_destination = sctp_find_alternate_net(stcb, lnet, 0);
3022,3025c3307
< /* if (net == asoc->asconf_last_sent_to) {*/
< /* Reset primary */
< /* asoc->asconf_last_sent_to = TAILQ_FIRST(&asoc->nets);*/
< /* }*/
---
> sctp_free_remote_addr(net);
3634,3639c3916,3918
< /* local addresses, if any */
< while (!SCTP_LIST_EMPTY(&asoc->sctp_local_addr_list)) {
< laddr = LIST_FIRST(&asoc->sctp_local_addr_list);
< LIST_REMOVE(laddr, sctp_nxt_addr);
< SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_laddr, laddr);
< SCTP_DECR_LADDR_COUNT();
---
> while (!SCTP_LIST_EMPTY(&asoc->sctp_restricted_addrs)) {
> laddr = LIST_FIRST(&asoc->sctp_restricted_addrs);
> sctp_remove_laddr(laddr);
3640a3920
>
3794c4074
< if (laddr->ifa->ifa_addr) {
---
> if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) {
3797c4077
< if (laddr->ifa->ifa_addr->sa_family == AF_INET6) {
---
> if (laddr->ifa->address.sa.sa_family == AF_INET6) {
3799c4079
< } else if (laddr->ifa->ifa_addr->sa_family == AF_INET) {
---
> } else if (laddr->ifa->address.sa.sa_family == AF_INET) {
3810c4090
< sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct ifaddr *ifa)
---
> sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa, uint32_t action)
3821,3827c4101,4103
< if (ifa->ifa_addr->sa_family == AF_INET6) {
< struct in6_ifaddr *ifa6;
<
< ifa6 = (struct in6_ifaddr *)ifa;
< if (ifa6->ia6_flags & (IN6_IFF_DETACHED |
< IN6_IFF_DEPRECATED | IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))
< /* Can't bind a non-existent addr. */
---
> if (ifa->address.sa.sa_family == AF_INET6) {
> if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
> /* Can't bind a non-useable addr. */
3828a4105
> }
3838,3840c4115,4117
< if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) && (fnd == 0)) {
< /* Not bound to all */
< error = sctp_insert_laddr(&inp->sctp_addr_list, ifa);
---
> if (fnd == 0) {
> /* Not in the ep list */
> error = sctp_insert_laddr(&inp->sctp_addr_list, ifa, action);
3845c4122
< if (ifa->ifa_addr->sa_family == AF_INET6) {
---
> if (ifa->address.sa.sa_family == AF_INET6) {
3847c4124
< } else if (ifa->ifa_addr->sa_family == AF_INET) {
---
> } else if (ifa->address.sa.sa_family == AF_INET) {
3884c4161
< sctp_del_local_addr_ep(struct sctp_inpcb *inp, struct ifaddr *ifa)
---
> sctp_del_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa)
3904c4181
< if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) && (fnd)) {
---
> if (fnd) {
3919a4197,4199
> struct sctp_nets *net;
>
> SCTP_TCB_LOCK(stcb);
3923c4203,4211
< } /* for each tcb */
---
> /*
> * Now spin through all the nets and purge any ref
> * to laddr
> */
> TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
> if (net->ro._s_addr &&
> (net->ro._s_addr->ifa == laddr->ifa)) {
> /* Yep, purge src address selected */
> struct rtentry *rt;
3924a4213,4225
> /* delete this address if cached */
> rt = net->ro.ro_rt;
> if (rt != NULL) {
> RTFREE(rt);
> net->ro.ro_rt = NULL;
> }
> sctp_free_ifa(net->ro._s_addr);
> net->ro._s_addr = NULL;
> net->src_addr_selected = 0;
> }
> }
> SCTP_TCB_UNLOCK(stcb);
> } /* for each tcb */
3930,3942d4230
< /* select a new primary destination if needed */
< LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
< /*
< * presume caller (sctp_asconf.c) already owns INP
< * lock
< */
< SCTP_TCB_LOCK(stcb);
< if (sctp_destination_is_reachable(stcb,
< (struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr) == 0) {
< sctp_select_primary_destination(stcb);
< }
< SCTP_TCB_UNLOCK(stcb);
< } /* for each tcb */
3954c4242
< sctp_add_local_addr_assoc(struct sctp_tcb *stcb, struct ifaddr *ifa)
---
> sctp_add_local_addr_assoc(struct sctp_tcb *stcb, struct sctp_ifa *ifa, int restricted_list)
3957a4246
> struct sctpladdr *list;
3961c4250
< * Assumes TCP is locked.. and possiblye the INP. May need to
---
> * Assumes TCB is locked.. and possibly the INP. May need to
3964,3966c4253
< inp = stcb->sctp_ep;
< if (ifa->ifa_addr->sa_family == AF_INET6) {
< struct in6_ifaddr *ifa6;
---
> list = &stcb->asoc.sctp_restricted_addrs;
3968,3972c4255,4257
< ifa6 = (struct in6_ifaddr *)ifa;
< if (ifa6->ia6_flags & (IN6_IFF_DETACHED |
< /* IN6_IFF_DEPRECATED | */
< IN6_IFF_ANYCAST |
< IN6_IFF_NOTREADY))
---
> inp = stcb->sctp_ep;
> if (ifa->address.sa.sa_family == AF_INET6) {
> if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
3974a4260
> }
3977c4263
< LIST_FOREACH(laddr, &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) {
---
> LIST_FOREACH(laddr, list, sctp_nxt_addr) {
3984c4270
< error = sctp_insert_laddr(&stcb->asoc.sctp_local_addr_list, ifa);
---
> error = sctp_insert_laddr(list, ifa, 0);
3994c4280
< sctp_insert_laddr(struct sctpladdr *list, struct ifaddr *ifa)
---
> sctp_insert_laddr(struct sctpladdr *list, struct sctp_ifa *ifa, uint32_t act)
4005a4292,4293
> laddr->action = act;
> atomic_add_int(&ifa->refcount, 1);
4020a4309
> sctp_free_ifa(laddr->ifa);
4029c4318
< sctp_del_local_addr_assoc(struct sctp_tcb *stcb, struct ifaddr *ifa)
---
> sctp_del_local_addr_assoc(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
4053c4342
< LIST_FOREACH(laddr, &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) {
---
> LIST_FOREACH(laddr, &stcb->asoc.sctp_restricted_addrs, sctp_nxt_addr) {
4067,4131d4355
< /*
< * Remove an address from the TCB local address list lookup using a sockaddr
< * addr
< */
< int
< sctp_del_local_addr_assoc_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
< {
< struct sctp_inpcb *inp;
< struct sctp_laddr *laddr;
< struct sockaddr *l_sa;
<
< /*
< * This function I find does not seem to have a caller. As such we
< * NEED TO DELETE this code. If we do find a caller, the caller MUST
< * have locked the TCB at the least and probably the INP as well.
< */
< inp = stcb->sctp_ep;
< /* if subset bound and don't allow ASCONF's, can't delete last */
< if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) &&
< (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF) == 0)) {
< if (stcb->asoc.numnets < 2) {
< /* can't delete last address */
< return (-1);
< }
< }
< LIST_FOREACH(laddr, &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) {
< /* make sure the address exists */
< if (laddr->ifa == NULL)
< continue;
< if (laddr->ifa->ifa_addr == NULL)
< continue;
<
< l_sa = laddr->ifa->ifa_addr;
< if (l_sa->sa_family == AF_INET6) {
< /* IPv6 address */
< struct sockaddr_in6 *sin1, *sin2;
<
< sin1 = (struct sockaddr_in6 *)l_sa;
< sin2 = (struct sockaddr_in6 *)sa;
< if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
< sizeof(struct in6_addr)) == 0) {
< /* matched */
< sctp_remove_laddr(laddr);
< return (0);
< }
< } else if (l_sa->sa_family == AF_INET) {
< /* IPv4 address */
< struct sockaddr_in *sin1, *sin2;
<
< sin1 = (struct sockaddr_in *)l_sa;
< sin2 = (struct sockaddr_in *)sa;
< if (sin1->sin_addr.s_addr == sin2->sin_addr.s_addr) {
< /* matched */
< sctp_remove_laddr(laddr);
< return (0);
< }
< } else {
< /* invalid family */
< return (-1);
< }
< } /* end foreach */
< /* address not found! */
< return (-1);
< }
<
4162c4386
< LIST_INIT(&sctppcbinfo.iteratorhead);
---
> TAILQ_INIT(&sctppcbinfo.iteratorhead);
4179a4404,4407
>
> sctppcbinfo.sctp_vrfhash = SCTP_HASH_INIT(SCTP_SIZE_OF_VRF_HASH,
> &sctppcbinfo.hashvrfmark);
>
4217a4446,4447
> SCTP_IPI_ITERATOR_WQ_INIT();
>
4246a4477,4488
> #if defined(SCTP_USE_THREAD_BASED_ITERATOR)
> sctppcbinfo.iterator_running = 0;
> sctp_startup_iterator();
> #endif
>
> /*
> * INIT the default VRF which for BSD is the only one, other O/S's
> * may have more. But initially they must start with one and then
> * add the VRF's as addresses are added.
> */
> sctp_init_vrf_list(SCTP_DEFAULT_VRF);
>
4817,4818c5059,5061
< /* Must be confirmed */
< return (-1);
---
> /* Must be confirmed, so queue to set */
> net->dest_state |= SCTP_ADDR_REQ_PRIMARY;
> return (0);
4925,5003d5167
< /*
< * Delete the address from the endpoint local address list Lookup using a
< * sockaddr address (ie. not an ifaddr)
< */
< int
< sctp_del_local_addr_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa)
< {
< struct sctp_laddr *laddr;
< struct sockaddr *l_sa;
< int found = 0;
<
< /*
< * Here is another function I cannot find a caller for. As such we
< * SHOULD delete it if we have no users. If we find a user that user
< * MUST have the INP locked.
< *
< */
<
< if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
< /* You are already bound to all. You have it already */
< return (EINVAL);
< }
< LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
< /* make sure the address exists */
< if (laddr->ifa == NULL)
< continue;
< if (laddr->ifa->ifa_addr == NULL)
< continue;
<
< l_sa = laddr->ifa->ifa_addr;
< if (l_sa->sa_family == AF_INET6) {
< /* IPv6 address */
< struct sockaddr_in6 *sin1, *sin2;
<
< sin1 = (struct sockaddr_in6 *)l_sa;
< sin2 = (struct sockaddr_in6 *)sa;
< if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
< sizeof(struct in6_addr)) == 0) {
< /* matched */
< found = 1;
< break;
< }
< } else if (l_sa->sa_family == AF_INET) {
< /* IPv4 address */
< struct sockaddr_in *sin1, *sin2;
<
< sin1 = (struct sockaddr_in *)l_sa;
< sin2 = (struct sockaddr_in *)sa;
< if (sin1->sin_addr.s_addr == sin2->sin_addr.s_addr) {
< /* matched */
< found = 1;
< break;
< }
< } else {
< /* invalid family */
< return (-1);
< }
< }
<
< if (found && inp->laddr_count < 2) {
< /* can't delete unless there are at LEAST 2 addresses */
< return (-1);
< }
< if (found && (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
< /*
< * remove it from the ep list, this should NOT be done until
< * its really gone from the interface list and we won't be
< * receiving more of these. Probably right away. If we do
< * allow a removal of an address from an association
< * (sub-set bind) than this should NOT be called until the
< * all ASCONF come back from this association.
< */
< sctp_remove_laddr(laddr);
< return (0);
< } else {
< return (-1);
< }
< }
<
5007d5170
< extern int sctp_do_drain;
5162a5326
> sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_DRAIN);
5212,5214c5376,5386
< sctp_initiate_iterator(inp_func inpf, asoc_func af, uint32_t pcb_state,
< uint32_t pcb_features, uint32_t asoc_state, void *argp, uint32_t argi,
< end_func ef, struct sctp_inpcb *s_inp, uint8_t chunk_output_off)
---
> sctp_initiate_iterator(inp_func inpf,
> asoc_func af,
> inp_func inpe,
> uint32_t pcb_state,
> uint32_t pcb_features,
> uint32_t asoc_state,
> void *argp,
> uint32_t argi,
> end_func ef,
> struct sctp_inpcb *s_inp,
> uint8_t chunk_output_off)
5228a5401,5404
> if (inpf)
> it->done_current_ep = 0;
> else
> it->done_current_ep = 1;
5234a5411
> it->function_inp_end = inpe;
5241a5419
>
5245a5424,5436
> SCTP_IPI_ITERATOR_WQ_LOCK();
> if (it->inp)
> SCTP_INP_INCR_REF(it->inp);
> TAILQ_INSERT_TAIL(&sctppcbinfo.iteratorhead, it, sctp_nxt_itr);
> #if defined(SCTP_USE_THREAD_BASED_ITERATOR)
> if (sctppcbinfo.iterator_running == 0) {
> sctp_wakeup_iterator();
> }
> SCTP_IPI_ITERATOR_WQ_UNLOCK();
> #else
> if (it->inp)
> SCTP_INP_DECR_REF(it->inp);
> SCTP_IPI_ITERATOR_WQ_UNLOCK();
5249,5251d5439
< SCTP_INP_INFO_WLOCK();
< LIST_INSERT_HEAD(&sctppcbinfo.iteratorhead, it, sctp_nxt_itr);
< SCTP_INP_INFO_WUNLOCK();
5253a5442
> #endif