diff options
Diffstat (limited to 'sys/netinet/sctp_pcb.c')
-rw-r--r-- | sys/netinet/sctp_pcb.c | 76 |
1 files changed, 56 insertions, 20 deletions
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index ce71edc..0160aea 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -155,6 +155,7 @@ sctp_allocate_vrf(int vrf_id) vrf->vrf_id = vrf_id; LIST_INIT(&vrf->ifnlist); vrf->total_ifa_count = 0; + vrf->refcount = 0; /* now also setup table ids */ SCTP_INIT_VRF_TABLEID(vrf); /* Init the HASH of addresses */ @@ -215,6 +216,19 @@ sctp_find_vrf(uint32_t vrf_id) return (NULL); } +void +sctp_free_vrf(struct sctp_vrf *vrf) +{ + int ret; + + ret = atomic_fetchadd_int(&vrf->refcount, -1); + if (ret == 1) { + /* We zero'd the count */ + LIST_REMOVE(vrf, next_vrf); + SCTP_FREE(vrf, SCTP_M_VRF); + atomic_subtract_int(&sctppcbinfo.ipi_count_vrfs, 1); + } +} void sctp_free_ifn(struct sctp_ifn *sctp_ifnp) @@ -224,6 +238,9 @@ sctp_free_ifn(struct sctp_ifn *sctp_ifnp) ret = atomic_fetchadd_int(&sctp_ifnp->refcount, -1); if (ret == 1) { /* We zero'd the count */ + if (sctp_ifnp->vrf) { + sctp_free_vrf(sctp_ifnp->vrf); + } SCTP_FREE(sctp_ifnp, SCTP_M_IFN); atomic_subtract_int(&sctppcbinfo.ipi_count_ifns, 1); } @@ -249,6 +266,9 @@ sctp_free_ifa(struct sctp_ifa *sctp_ifap) ret = atomic_fetchadd_int(&sctp_ifap->refcount, -1); if (ret == 1) { /* We zero'd the count */ + if (sctp_ifap->ifn_p) { + sctp_free_ifn(sctp_ifap->ifn_p); + } SCTP_FREE(sctp_ifap, SCTP_M_IFA); atomic_subtract_int(&sctppcbinfo.ipi_count_ifas, 1); } @@ -293,15 +313,19 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, /* How granular do we need the locks to be here? */ SCTP_IPI_ADDR_LOCK(); - vrf = sctp_find_vrf(vrf_id); - if (vrf == NULL) { - vrf = sctp_allocate_vrf(vrf_id); + sctp_ifnp = sctp_find_ifn(ifn, ifn_index); + if (sctp_ifnp) { + vrf = sctp_ifnp->vrf; + } else { + vrf = sctp_find_vrf(vrf_id); if (vrf == NULL) { - SCTP_IPI_ADDR_UNLOCK(); - return (NULL); + vrf = sctp_allocate_vrf(vrf_id); + if (vrf == NULL) { + SCTP_IPI_ADDR_UNLOCK(); + return (NULL); + } } } - sctp_ifnp = sctp_find_ifn(ifn, ifn_index); if (sctp_ifnp == NULL) { /* * build one and add it, can't hold lock until after malloc @@ -321,6 +345,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, sctp_ifnp->ifa_count = 0; sctp_ifnp->refcount = 1; sctp_ifnp->vrf = vrf; + atomic_add_int(&vrf->refcount, 1); sctp_ifnp->ifn_mtu = SCTP_GATHER_MTU_FROM_IFN_INFO(ifn, ifn_index, addr->sa_family); if (if_name != NULL) { memcpy(sctp_ifnp->ifn_name, if_name, SCTP_IFNAMSIZ); @@ -340,10 +365,15 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, /* Hmm, it already exists? */ if ((sctp_ifap->ifn_p) && (sctp_ifap->ifn_p->ifn_index == ifn_index)) { + if (new_ifn_af) { + /* Remove the created one that we don't want */ + sctp_delete_ifn(sctp_ifap->ifn_p, 1); + } 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; + atomic_add_int(&sctp_ifap->ifn_p->refcount, 1); exit_stage_left: SCTP_IPI_ADDR_UNLOCK(); return (sctp_ifap); @@ -356,6 +386,13 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, * The first IFN gets the address, * duplicates are ignored. */ + if (new_ifn_af) { + /* + * Remove the created one that we + * don't want + */ + sctp_delete_ifn(sctp_ifap->ifn_p, 1); + } goto exit_stage_left; } else { /* repair ifnp which was NULL ? */ @@ -2078,7 +2115,8 @@ sctp_isport_inuse(struct sctp_inpcb *inp, uint16_t lport, uint32_t vrf_id) int -sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, struct thread *p) +sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, + struct sctp_ifa *sctp_ifap, struct thread *p) { /* bind a ep to a socket address */ struct sctppcbhead *head; @@ -2328,8 +2366,11 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, struct thread *p) * zero out the port to find the address! yuck! can't do * this earlier since need port for sctp_pcb_findep() */ - ifa = sctp_find_ifa_by_addr((struct sockaddr *)&store_sa, - vrf_id, 0); + if (sctp_ifap) + ifa = sctp_ifap; + else + ifa = sctp_find_ifa_by_addr((struct sockaddr *)&store_sa, + vrf_id, 0); if (ifa == NULL) { /* Can't find an interface with that address */ SCTP_INP_WUNLOCK(inp); @@ -2349,12 +2390,8 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, struct thread *p) inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUNDALL; /* allow bindx() to send ASCONF's for binding changes */ sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF); - /* set the automatic addr changes from kernel flag */ - if (sctp_auto_asconf == 0) { - sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); - } else { - sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); - } + /* clear automatic addr changes from kernel flag */ + sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); /* add this address to the endpoint list */ error = sctp_insert_laddr(&inp->sctp_addr_list, ifa, 0); @@ -3168,10 +3205,9 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, sctp_set_initial_cc_param(stcb, net); -#if defined(SCTP_CWND_MONITOR) || defined(SCTP_CWND_LOGGING) - sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); -#endif - + if (sctp_logging_level & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { + sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); + } /* * CMT: CUC algo - set find_pseudo_cumack to TRUE (1) at beginning * of assoc (2005/06/27, iyengar@cis.udel.edu) @@ -3343,7 +3379,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, * ephemerial bind for you. */ if ((err = sctp_inpcb_bind(inp->sctp_socket, - (struct sockaddr *)NULL, + (struct sockaddr *)NULL, (struct sctp_ifa *)NULL, (struct thread *)NULL ))) { /* bind error, probably perm */ |