summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_pcb.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/sctp_pcb.c')
-rw-r--r--sys/netinet/sctp_pcb.c76
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 */
OpenPOWER on IntegriCloud