|
|
@@ -121,6 +121,14 @@ static const struct proto_ops msg_ops;
|
|
|
static struct proto tipc_proto;
|
|
|
static struct proto tipc_proto_kern;
|
|
|
|
|
|
+static const struct nla_policy tipc_nl_sock_policy[TIPC_NLA_SOCK_MAX + 1] = {
|
|
|
+ [TIPC_NLA_SOCK_UNSPEC] = { .type = NLA_UNSPEC },
|
|
|
+ [TIPC_NLA_SOCK_ADDR] = { .type = NLA_U32 },
|
|
|
+ [TIPC_NLA_SOCK_REF] = { .type = NLA_U32 },
|
|
|
+ [TIPC_NLA_SOCK_CON] = { .type = NLA_NESTED },
|
|
|
+ [TIPC_NLA_SOCK_HAS_PUBL] = { .type = NLA_FLAG }
|
|
|
+};
|
|
|
+
|
|
|
/*
|
|
|
* Revised TIPC socket locking policy:
|
|
|
*
|
|
|
@@ -2902,3 +2910,130 @@ int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
|
|
|
return skb->len;
|
|
|
}
|
|
|
+
|
|
|
+/* Caller should hold socket lock for the passed tipc socket. */
|
|
|
+int __tipc_nl_add_sk_publ(struct sk_buff *skb, struct netlink_callback *cb,
|
|
|
+ struct publication *publ)
|
|
|
+{
|
|
|
+ void *hdr;
|
|
|
+ struct nlattr *attrs;
|
|
|
+
|
|
|
+ hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
|
|
|
+ &tipc_genl_v2_family, NLM_F_MULTI, TIPC_NL_PUBL_GET);
|
|
|
+ if (!hdr)
|
|
|
+ goto msg_cancel;
|
|
|
+
|
|
|
+ attrs = nla_nest_start(skb, TIPC_NLA_PUBL);
|
|
|
+ if (!attrs)
|
|
|
+ goto genlmsg_cancel;
|
|
|
+
|
|
|
+ if (nla_put_u32(skb, TIPC_NLA_PUBL_KEY, publ->key))
|
|
|
+ goto attr_msg_cancel;
|
|
|
+ if (nla_put_u32(skb, TIPC_NLA_PUBL_TYPE, publ->type))
|
|
|
+ goto attr_msg_cancel;
|
|
|
+ if (nla_put_u32(skb, TIPC_NLA_PUBL_LOWER, publ->lower))
|
|
|
+ goto attr_msg_cancel;
|
|
|
+ if (nla_put_u32(skb, TIPC_NLA_PUBL_UPPER, publ->upper))
|
|
|
+ goto attr_msg_cancel;
|
|
|
+
|
|
|
+ nla_nest_end(skb, attrs);
|
|
|
+ genlmsg_end(skb, hdr);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+attr_msg_cancel:
|
|
|
+ nla_nest_cancel(skb, attrs);
|
|
|
+genlmsg_cancel:
|
|
|
+ genlmsg_cancel(skb, hdr);
|
|
|
+msg_cancel:
|
|
|
+ return -EMSGSIZE;
|
|
|
+}
|
|
|
+
|
|
|
+/* Caller should hold socket lock for the passed tipc socket. */
|
|
|
+int __tipc_nl_list_sk_publ(struct sk_buff *skb, struct netlink_callback *cb,
|
|
|
+ struct tipc_sock *tsk, u32 *last_publ)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+ struct publication *p;
|
|
|
+
|
|
|
+ if (*last_publ) {
|
|
|
+ list_for_each_entry(p, &tsk->publications, pport_list) {
|
|
|
+ if (p->key == *last_publ)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (p->key != *last_publ) {
|
|
|
+ /* We never set seq or call nl_dump_check_consistent()
|
|
|
+ * this means that setting prev_seq here will cause the
|
|
|
+ * consistence check to fail in the netlink callback
|
|
|
+ * handler. Resulting in the last NLMSG_DONE message
|
|
|
+ * having the NLM_F_DUMP_INTR flag set.
|
|
|
+ */
|
|
|
+ cb->prev_seq = 1;
|
|
|
+ *last_publ = 0;
|
|
|
+ return -EPIPE;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ p = list_first_entry(&tsk->publications, struct publication,
|
|
|
+ pport_list);
|
|
|
+ }
|
|
|
+
|
|
|
+ list_for_each_entry_from(p, &tsk->publications, pport_list) {
|
|
|
+ err = __tipc_nl_add_sk_publ(skb, cb, p);
|
|
|
+ if (err) {
|
|
|
+ *last_publ = p->key;
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ *last_publ = 0;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int tipc_nl_publ_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+ u32 tsk_ref = cb->args[0];
|
|
|
+ u32 last_publ = cb->args[1];
|
|
|
+ u32 done = cb->args[2];
|
|
|
+ struct tipc_sock *tsk;
|
|
|
+
|
|
|
+ if (!tsk_ref) {
|
|
|
+ struct nlattr **attrs;
|
|
|
+ struct nlattr *sock[TIPC_NLA_SOCK_MAX + 1];
|
|
|
+
|
|
|
+ err = tipc_nlmsg_parse(cb->nlh, &attrs);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ err = nla_parse_nested(sock, TIPC_NLA_SOCK_MAX,
|
|
|
+ attrs[TIPC_NLA_SOCK],
|
|
|
+ tipc_nl_sock_policy);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ if (!sock[TIPC_NLA_SOCK_REF])
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ tsk_ref = nla_get_u32(sock[TIPC_NLA_SOCK_REF]);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (done)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ tsk = tipc_sk_get(tsk_ref);
|
|
|
+ if (!tsk)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ lock_sock(&tsk->sk);
|
|
|
+ err = __tipc_nl_list_sk_publ(skb, cb, tsk, &last_publ);
|
|
|
+ if (!err)
|
|
|
+ done = 1;
|
|
|
+ release_sock(&tsk->sk);
|
|
|
+ tipc_sk_put(tsk);
|
|
|
+
|
|
|
+ cb->args[0] = tsk_ref;
|
|
|
+ cb->args[1] = last_publ;
|
|
|
+ cb->args[2] = done;
|
|
|
+
|
|
|
+ return skb->len;
|
|
|
+}
|