|
@@ -2801,3 +2801,104 @@ void tipc_socket_stop(void)
|
|
|
sock_unregister(tipc_family_ops.family);
|
|
|
proto_unregister(&tipc_proto);
|
|
|
}
|
|
|
+
|
|
|
+/* Caller should hold socket lock for the passed tipc socket. */
|
|
|
+int __tipc_nl_add_sk_con(struct sk_buff *skb, struct tipc_sock *tsk)
|
|
|
+{
|
|
|
+ u32 peer_node;
|
|
|
+ u32 peer_port;
|
|
|
+ struct nlattr *nest;
|
|
|
+
|
|
|
+ peer_node = tsk_peer_node(tsk);
|
|
|
+ peer_port = tsk_peer_port(tsk);
|
|
|
+
|
|
|
+ nest = nla_nest_start(skb, TIPC_NLA_SOCK_CON);
|
|
|
+
|
|
|
+ if (nla_put_u32(skb, TIPC_NLA_CON_NODE, peer_node))
|
|
|
+ goto msg_full;
|
|
|
+ if (nla_put_u32(skb, TIPC_NLA_CON_SOCK, peer_port))
|
|
|
+ goto msg_full;
|
|
|
+
|
|
|
+ if (tsk->conn_type != 0) {
|
|
|
+ if (nla_put_flag(skb, TIPC_NLA_CON_FLAG))
|
|
|
+ goto msg_full;
|
|
|
+ if (nla_put_u32(skb, TIPC_NLA_CON_TYPE, tsk->conn_type))
|
|
|
+ goto msg_full;
|
|
|
+ if (nla_put_u32(skb, TIPC_NLA_CON_INST, tsk->conn_instance))
|
|
|
+ goto msg_full;
|
|
|
+ }
|
|
|
+ nla_nest_end(skb, nest);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+msg_full:
|
|
|
+ nla_nest_cancel(skb, nest);
|
|
|
+
|
|
|
+ return -EMSGSIZE;
|
|
|
+}
|
|
|
+
|
|
|
+/* Caller should hold socket lock for the passed tipc socket. */
|
|
|
+int __tipc_nl_add_sk(struct sk_buff *skb, struct netlink_callback *cb,
|
|
|
+ struct tipc_sock *tsk)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+ 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_SOCK_GET);
|
|
|
+ if (!hdr)
|
|
|
+ goto msg_cancel;
|
|
|
+
|
|
|
+ attrs = nla_nest_start(skb, TIPC_NLA_SOCK);
|
|
|
+ if (!attrs)
|
|
|
+ goto genlmsg_cancel;
|
|
|
+ if (nla_put_u32(skb, TIPC_NLA_SOCK_REF, tsk->ref))
|
|
|
+ goto attr_msg_cancel;
|
|
|
+ if (nla_put_u32(skb, TIPC_NLA_SOCK_ADDR, tipc_own_addr))
|
|
|
+ goto attr_msg_cancel;
|
|
|
+
|
|
|
+ if (tsk->connected) {
|
|
|
+ err = __tipc_nl_add_sk_con(skb, tsk);
|
|
|
+ if (err)
|
|
|
+ goto attr_msg_cancel;
|
|
|
+ } else if (!list_empty(&tsk->publications)) {
|
|
|
+ if (nla_put_flag(skb, TIPC_NLA_SOCK_HAS_PUBL))
|
|
|
+ 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;
|
|
|
+}
|
|
|
+
|
|
|
+int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+ struct tipc_sock *tsk;
|
|
|
+ u32 prev_ref = cb->args[0];
|
|
|
+ u32 ref = prev_ref;
|
|
|
+
|
|
|
+ tsk = tipc_sk_get_next(&ref);
|
|
|
+ for (; tsk; tsk = tipc_sk_get_next(&ref)) {
|
|
|
+ lock_sock(&tsk->sk);
|
|
|
+ err = __tipc_nl_add_sk(skb, cb, tsk);
|
|
|
+ release_sock(&tsk->sk);
|
|
|
+ tipc_sk_put(tsk);
|
|
|
+ if (err)
|
|
|
+ break;
|
|
|
+
|
|
|
+ prev_ref = ref;
|
|
|
+ }
|
|
|
+
|
|
|
+ cb->args[0] = prev_ref;
|
|
|
+
|
|
|
+ return skb->len;
|
|
|
+}
|