sctp: export some apis or variables for sctp_diag and reuse some for proc
authorXin Long <lucien.xin@gmail.com>
Thu, 14 Apr 2016 07:35:31 +0000 (15:35 +0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 15 Apr 2016 21:29:36 +0000 (17:29 -0400)
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>
include/net/sctp/sctp.h
net/sctp/proc.c
net/sctp/socket.c

index 268b10058ef5b0e2398d8c3945a042f9710505da..3f1c0ff7d4b6c3714c79fec87c90b4dbf1c99cf2 100644 (file)
@@ -116,6 +116,19 @@ extern struct percpu_counter sctp_sockets_allocated;
 int sctp_asconf_mgmt(struct sctp_sock *, struct sctp_sockaddr_entry *);
 struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
 
+int sctp_transport_walk_start(struct rhashtable_iter *iter);
+void sctp_transport_walk_stop(struct rhashtable_iter *iter);
+struct sctp_transport *sctp_transport_get_next(struct net *net,
+                       struct rhashtable_iter *iter);
+struct sctp_transport *sctp_transport_get_idx(struct net *net,
+                       struct rhashtable_iter *iter, int pos);
+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);
+int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *),
+                           struct net *net, int pos, void *p);
+int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *), void *p);
 int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc,
                       struct sctp_info *info);
 
index 6d45d53321e6bf2559233e321eea19c0d6c2ba19..dd8492f0037db9e4be6428f888bad328e0257b85 100644 (file)
@@ -282,81 +282,31 @@ struct sctp_ht_iter {
        struct rhashtable_iter hti;
 };
 
-static struct sctp_transport *sctp_transport_get_next(struct seq_file *seq)
-{
-       struct sctp_ht_iter *iter = seq->private;
-       struct sctp_transport *t;
-
-       t = rhashtable_walk_next(&iter->hti);
-       for (; t; t = rhashtable_walk_next(&iter->hti)) {
-               if (IS_ERR(t)) {
-                       if (PTR_ERR(t) == -EAGAIN)
-                               continue;
-                       break;
-               }
-
-               if (net_eq(sock_net(t->asoc->base.sk), seq_file_net(seq)) &&
-                   t->asoc->peer.primary_path == t)
-                       break;
-       }
-
-       return t;
-}
-
-static struct sctp_transport *sctp_transport_get_idx(struct seq_file *seq,
-                                                    loff_t pos)
-{
-       void *obj = SEQ_START_TOKEN;
-
-       while (pos && (obj = sctp_transport_get_next(seq)) && !IS_ERR(obj))
-               pos--;
-
-       return obj;
-}
-
-static int sctp_transport_walk_start(struct seq_file *seq)
-{
-       struct sctp_ht_iter *iter = seq->private;
-       int err;
-
-       err = rhashtable_walk_init(&sctp_transport_hashtable, &iter->hti,
-                                  GFP_KERNEL);
-       if (err)
-               return err;
-
-       err = rhashtable_walk_start(&iter->hti);
-
-       return err == -EAGAIN ? 0 : err;
-}
-
-static void sctp_transport_walk_stop(struct seq_file *seq)
-{
-       struct sctp_ht_iter *iter = seq->private;
-
-       rhashtable_walk_stop(&iter->hti);
-       rhashtable_walk_exit(&iter->hti);
-}
-
 static void *sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
 {
-       int err = sctp_transport_walk_start(seq);
+       struct sctp_ht_iter *iter = seq->private;
+       int err = sctp_transport_walk_start(&iter->hti);
 
        if (err)
                return ERR_PTR(err);
 
-       return sctp_transport_get_idx(seq, *pos);
+       return sctp_transport_get_idx(seq_file_net(seq), &iter->hti, *pos);
 }
 
 static void sctp_assocs_seq_stop(struct seq_file *seq, void *v)
 {
-       sctp_transport_walk_stop(seq);
+       struct sctp_ht_iter *iter = seq->private;
+
+       sctp_transport_walk_stop(&iter->hti);
 }
 
 static void *sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
+       struct sctp_ht_iter *iter = seq->private;
+
        ++*pos;
 
-       return sctp_transport_get_next(seq);
+       return sctp_transport_get_next(seq_file_net(seq), &iter->hti);
 }
 
 /* Display sctp associations (/proc/net/sctp/assocs). */
@@ -458,24 +408,29 @@ void sctp_assocs_proc_exit(struct net *net)
 
 static void *sctp_remaddr_seq_start(struct seq_file *seq, loff_t *pos)
 {
-       int err = sctp_transport_walk_start(seq);
+       struct sctp_ht_iter *iter = seq->private;
+       int err = sctp_transport_walk_start(&iter->hti);
 
        if (err)
                return ERR_PTR(err);
 
-       return sctp_transport_get_idx(seq, *pos);
+       return sctp_transport_get_idx(seq_file_net(seq), &iter->hti, *pos);
 }
 
 static void *sctp_remaddr_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
+       struct sctp_ht_iter *iter = seq->private;
+
        ++*pos;
 
-       return sctp_transport_get_next(seq);
+       return sctp_transport_get_next(seq_file_net(seq), &iter->hti);
 }
 
 static void sctp_remaddr_seq_stop(struct seq_file *seq, void *v)
 {
-       sctp_transport_walk_stop(seq);
+       struct sctp_ht_iter *iter = seq->private;
+
+       sctp_transport_walk_stop(&iter->hti);
 }
 
 static int sctp_remaddr_seq_show(struct seq_file *seq, void *v)
index cd0fb3bb493cd581c946320d4f0df72208df4bf4..5e5bc08d2b25f30d5c84d0b358f26c9e425f4af5 100644 (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