sctp: export some apis or variables for sctp_diag and reuse some for proc

For some main variables in sctp.ko, we couldn't export it to other modules,
so we have to define some api to access them.

It will include sctp transport and endpoint's traversal.

There are some transport traversal functions for sctp_diag, we can also
use it for sctp_proc. cause they have the similar situation to traversal
transport.

v2->v3:
- rhashtable_walk_init need the parameter gfp, because of recent upstrem
  update

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Xin Long
2016-04-14 15:35:31 +08:00
committed by David S. Miller
parent 52c52a61a3
commit 626d16f50f
3 changed files with 156 additions and 63 deletions

View File

@@ -4288,6 +4288,131 @@ int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc,
}
EXPORT_SYMBOL_GPL(sctp_get_sctp_info);
/* use callback to avoid exporting the core structure */
int sctp_transport_walk_start(struct rhashtable_iter *iter)
{
int err;
err = rhashtable_walk_init(&sctp_transport_hashtable, iter,
GFP_KERNEL);
if (err)
return err;
err = rhashtable_walk_start(iter);
return err == -EAGAIN ? 0 : err;
}
void sctp_transport_walk_stop(struct rhashtable_iter *iter)
{
rhashtable_walk_stop(iter);
rhashtable_walk_exit(iter);
}
struct sctp_transport *sctp_transport_get_next(struct net *net,
struct rhashtable_iter *iter)
{
struct sctp_transport *t;
t = rhashtable_walk_next(iter);
for (; t; t = rhashtable_walk_next(iter)) {
if (IS_ERR(t)) {
if (PTR_ERR(t) == -EAGAIN)
continue;
break;
}
if (net_eq(sock_net(t->asoc->base.sk), net) &&
t->asoc->peer.primary_path == t)
break;
}
return t;
}
struct sctp_transport *sctp_transport_get_idx(struct net *net,
struct rhashtable_iter *iter,
int pos)
{
void *obj = SEQ_START_TOKEN;
while (pos && (obj = sctp_transport_get_next(net, iter)) &&
!IS_ERR(obj))
pos--;
return obj;
}
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_hashbucket *head;
for (head = sctp_ep_hashtable; hash < sctp_ep_hashsize;
hash++, head++) {
read_lock(&head->lock);
sctp_for_each_hentry(epb, &head->chain) {
err = cb(sctp_ep(epb), p);
if (err)
break;
}
read_unlock(&head->lock);
}
return err;
}
EXPORT_SYMBOL_GPL(sctp_for_each_endpoint);
int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *),
struct net *net,
const union sctp_addr *laddr,
const union sctp_addr *paddr, void *p)
{
struct sctp_transport *transport;
int err = 0;
rcu_read_lock();
transport = sctp_addrs_lookup_transport(net, laddr, paddr);
if (!transport || !sctp_transport_hold(transport))
goto out;
err = cb(transport, p);
sctp_transport_put(transport);
out:
rcu_read_unlock();
return err;
}
EXPORT_SYMBOL_GPL(sctp_transport_lookup_process);
int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *),
struct net *net, int pos, void *p) {
struct rhashtable_iter hti;
int err = 0;
void *obj;
if (sctp_transport_walk_start(&hti))
goto out;
sctp_transport_get_idx(net, &hti, pos);
obj = sctp_transport_get_next(net, &hti);
for (; obj && !IS_ERR(obj); obj = sctp_transport_get_next(net, &hti)) {
struct sctp_transport *transport = obj;
if (!sctp_transport_hold(transport))
continue;
err = cb(transport, p);
sctp_transport_put(transport);
if (err)
break;
}
out:
sctp_transport_walk_stop(&hti);
return err;
}
EXPORT_SYMBOL_GPL(sctp_for_each_transport);
/* 7.2.1 Association Status (SCTP_STATUS)
* Applications can retrieve current status information about an