diff options
Diffstat (limited to 'net/sctp/socket.c')
| -rw-r--r-- | net/sctp/socket.c | 56 | 
1 files changed, 33 insertions, 23 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 33391254fa82..3e1a9600be5e 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5068,12 +5068,9 @@ static int sctp_init_sock(struct sock *sk)  	SCTP_DBG_OBJCNT_INC(sock); -	local_bh_disable();  	sk_sockets_allocated_inc(sk);  	sock_prot_inuse_add(net, sk->sk_prot, 1); -	local_bh_enable(); -  	return 0;  } @@ -5099,10 +5096,8 @@ static void sctp_destroy_sock(struct sock *sk)  		list_del(&sp->auto_asconf_list);  	}  	sctp_endpoint_free(sp->ep); -	local_bh_disable();  	sk_sockets_allocated_dec(sk);  	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); -	local_bh_enable();  }  /* Triggered when there are no references on the socket anymore */ @@ -5299,14 +5294,14 @@ int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *),  			   void *p) {  	int err = 0;  	int hash = 0; -	struct sctp_ep_common *epb; +	struct sctp_endpoint *ep;  	struct sctp_hashbucket *head;  	for (head = sctp_ep_hashtable; hash < sctp_ep_hashsize;  	     hash++, head++) {  		read_lock_bh(&head->lock); -		sctp_for_each_hentry(epb, &head->chain) { -			err = cb(sctp_ep(epb), p); +		sctp_for_each_hentry(ep, &head->chain) { +			err = cb(ep, p);  			if (err)  				break;  		} @@ -5317,32 +5312,41 @@ int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *),  }  EXPORT_SYMBOL_GPL(sctp_for_each_endpoint); -int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *), -				  struct net *net, +int sctp_transport_lookup_process(sctp_callback_t cb, struct net *net,  				  const union sctp_addr *laddr,  				  const union sctp_addr *paddr, void *p)  {  	struct sctp_transport *transport; -	int err; +	struct sctp_endpoint *ep; +	int err = -ENOENT;  	rcu_read_lock();  	transport = sctp_addrs_lookup_transport(net, laddr, paddr); +	if (!transport) { +		rcu_read_unlock(); +		return err; +	} +	ep = transport->asoc->ep; +	if (!sctp_endpoint_hold(ep)) { /* asoc can be peeled off */ +		sctp_transport_put(transport); +		rcu_read_unlock(); +		return err; +	}  	rcu_read_unlock(); -	if (!transport) -		return -ENOENT; -	err = cb(transport, p); +	err = cb(ep, transport, p); +	sctp_endpoint_put(ep);  	sctp_transport_put(transport); -  	return err;  }  EXPORT_SYMBOL_GPL(sctp_transport_lookup_process); -int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *), -			    int (*cb_done)(struct sctp_transport *, void *), -			    struct net *net, int *pos, void *p) { +int sctp_transport_traverse_process(sctp_callback_t cb, sctp_callback_t cb_done, +				    struct net *net, int *pos, void *p) +{  	struct rhashtable_iter hti;  	struct sctp_transport *tsp; +	struct sctp_endpoint *ep;  	int ret;  again: @@ -5351,26 +5355,32 @@ again:  	tsp = sctp_transport_get_idx(net, &hti, *pos + 1);  	for (; !IS_ERR_OR_NULL(tsp); tsp = sctp_transport_get_next(net, &hti)) { -		ret = cb(tsp, p); -		if (ret) -			break; +		ep = tsp->asoc->ep; +		if (sctp_endpoint_hold(ep)) { /* asoc can be peeled off */ +			ret = cb(ep, tsp, p); +			if (ret) +				break; +			sctp_endpoint_put(ep); +		}  		(*pos)++;  		sctp_transport_put(tsp);  	}  	sctp_transport_walk_stop(&hti);  	if (ret) { -		if (cb_done && !cb_done(tsp, p)) { +		if (cb_done && !cb_done(ep, tsp, p)) {  			(*pos)++; +			sctp_endpoint_put(ep);  			sctp_transport_put(tsp);  			goto again;  		} +		sctp_endpoint_put(ep);  		sctp_transport_put(tsp);  	}  	return ret;  } -EXPORT_SYMBOL_GPL(sctp_for_each_transport); +EXPORT_SYMBOL_GPL(sctp_transport_traverse_process);  /* 7.2.1 Association Status (SCTP_STATUS)  |