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);
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). */
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)
}
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