diff options
-rw-r--r-- | include/uapi/linux/tipc_netlink.h | 12 | ||||
-rw-r--r-- | net/tipc/netlink.c | 7 | ||||
-rw-r--r-- | net/tipc/node.c | 96 | ||||
-rw-r--r-- | net/tipc/node.h | 4 |
4 files changed, 118 insertions, 1 deletions
diff --git a/include/uapi/linux/tipc_netlink.h b/include/uapi/linux/tipc_netlink.h index 43beef28d67f..08a793374e8c 100644 --- a/include/uapi/linux/tipc_netlink.h +++ b/include/uapi/linux/tipc_netlink.h | |||
@@ -52,6 +52,7 @@ enum { | |||
52 | TIPC_NL_LINK_RESET_STATS, | 52 | TIPC_NL_LINK_RESET_STATS, |
53 | TIPC_NL_MEDIA_GET, | 53 | TIPC_NL_MEDIA_GET, |
54 | TIPC_NL_MEDIA_SET, | 54 | TIPC_NL_MEDIA_SET, |
55 | TIPC_NL_NODE_GET, | ||
55 | 56 | ||
56 | __TIPC_NL_CMD_MAX, | 57 | __TIPC_NL_CMD_MAX, |
57 | TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1 | 58 | TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1 |
@@ -65,6 +66,7 @@ enum { | |||
65 | TIPC_NLA_PUBL, /* nest */ | 66 | TIPC_NLA_PUBL, /* nest */ |
66 | TIPC_NLA_LINK, /* nest */ | 67 | TIPC_NLA_LINK, /* nest */ |
67 | TIPC_NLA_MEDIA, /* nest */ | 68 | TIPC_NLA_MEDIA, /* nest */ |
69 | TIPC_NLA_NODE, /* nest */ | ||
68 | 70 | ||
69 | __TIPC_NLA_MAX, | 71 | __TIPC_NLA_MAX, |
70 | TIPC_NLA_MAX = __TIPC_NLA_MAX - 1 | 72 | TIPC_NLA_MAX = __TIPC_NLA_MAX - 1 |
@@ -121,6 +123,16 @@ enum { | |||
121 | TIPC_NLA_MEDIA_MAX = __TIPC_NLA_MEDIA_MAX - 1 | 123 | TIPC_NLA_MEDIA_MAX = __TIPC_NLA_MEDIA_MAX - 1 |
122 | }; | 124 | }; |
123 | 125 | ||
126 | /* Node info */ | ||
127 | enum { | ||
128 | TIPC_NLA_NODE_UNSPEC, | ||
129 | TIPC_NLA_NODE_ADDR, /* u32 */ | ||
130 | TIPC_NLA_NODE_UP, /* flag */ | ||
131 | |||
132 | __TIPC_NLA_NODE_MAX, | ||
133 | TIPC_NLA_NODE_MAX = __TIPC_NLA_NODE_MAX - 1 | ||
134 | }; | ||
135 | |||
124 | /* Publication info */ | 136 | /* Publication info */ |
125 | enum { | 137 | enum { |
126 | TIPC_NLA_PUBL_UNSPEC, | 138 | TIPC_NLA_PUBL_UNSPEC, |
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 8673e370b7ed..5b0e3c8457d2 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "socket.h" | 39 | #include "socket.h" |
40 | #include "bearer.h" | 40 | #include "bearer.h" |
41 | #include "link.h" | 41 | #include "link.h" |
42 | #include "node.h" | ||
42 | #include <net/genetlink.h> | 43 | #include <net/genetlink.h> |
43 | 44 | ||
44 | static int handle_cmd(struct sk_buff *skb, struct genl_info *info) | 45 | static int handle_cmd(struct sk_buff *skb, struct genl_info *info) |
@@ -78,6 +79,7 @@ static const struct nla_policy tipc_nl_policy[TIPC_NLA_MAX + 1] = { | |||
78 | [TIPC_NLA_PUBL] = { .type = NLA_NESTED, }, | 79 | [TIPC_NLA_PUBL] = { .type = NLA_NESTED, }, |
79 | [TIPC_NLA_LINK] = { .type = NLA_NESTED, }, | 80 | [TIPC_NLA_LINK] = { .type = NLA_NESTED, }, |
80 | [TIPC_NLA_MEDIA] = { .type = NLA_NESTED, }, | 81 | [TIPC_NLA_MEDIA] = { .type = NLA_NESTED, }, |
82 | [TIPC_NLA_NODE] = { .type = NLA_NESTED, } | ||
81 | }; | 83 | }; |
82 | 84 | ||
83 | /* Legacy ASCII API */ | 85 | /* Legacy ASCII API */ |
@@ -166,6 +168,11 @@ static const struct genl_ops tipc_genl_v2_ops[] = { | |||
166 | .cmd = TIPC_NL_MEDIA_SET, | 168 | .cmd = TIPC_NL_MEDIA_SET, |
167 | .doit = tipc_nl_media_set, | 169 | .doit = tipc_nl_media_set, |
168 | .policy = tipc_nl_policy, | 170 | .policy = tipc_nl_policy, |
171 | }, | ||
172 | { | ||
173 | .cmd = TIPC_NL_NODE_GET, | ||
174 | .dumpit = tipc_nl_node_dump, | ||
175 | .policy = tipc_nl_policy, | ||
169 | } | 176 | } |
170 | }; | 177 | }; |
171 | 178 | ||
diff --git a/net/tipc/node.c b/net/tipc/node.c index 5781634e957d..72a75d4838b2 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c | |||
@@ -58,6 +58,12 @@ struct tipc_sock_conn { | |||
58 | struct list_head list; | 58 | struct list_head list; |
59 | }; | 59 | }; |
60 | 60 | ||
61 | static const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = { | ||
62 | [TIPC_NLA_NODE_UNSPEC] = { .type = NLA_UNSPEC }, | ||
63 | [TIPC_NLA_NODE_ADDR] = { .type = NLA_U32 }, | ||
64 | [TIPC_NLA_NODE_UP] = { .type = NLA_FLAG } | ||
65 | }; | ||
66 | |||
61 | /* | 67 | /* |
62 | * A trivial power-of-two bitmask technique is used for speed, since this | 68 | * A trivial power-of-two bitmask technique is used for speed, since this |
63 | * operation is done for every incoming TIPC packet. The number of hash table | 69 | * operation is done for every incoming TIPC packet. The number of hash table |
@@ -601,3 +607,93 @@ void tipc_node_unlock(struct tipc_node *node) | |||
601 | tipc_nametbl_withdraw(TIPC_LINK_STATE, addr, | 607 | tipc_nametbl_withdraw(TIPC_LINK_STATE, addr, |
602 | link_id, addr); | 608 | link_id, addr); |
603 | } | 609 | } |
610 | |||
611 | /* Caller should hold node lock for the passed node */ | ||
612 | int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node) | ||
613 | { | ||
614 | void *hdr; | ||
615 | struct nlattr *attrs; | ||
616 | |||
617 | hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family, | ||
618 | NLM_F_MULTI, TIPC_NL_NODE_GET); | ||
619 | if (!hdr) | ||
620 | return -EMSGSIZE; | ||
621 | |||
622 | attrs = nla_nest_start(msg->skb, TIPC_NLA_NODE); | ||
623 | if (!attrs) | ||
624 | goto msg_full; | ||
625 | |||
626 | if (nla_put_u32(msg->skb, TIPC_NLA_NODE_ADDR, node->addr)) | ||
627 | goto attr_msg_full; | ||
628 | if (tipc_node_is_up(node)) | ||
629 | if (nla_put_flag(msg->skb, TIPC_NLA_NODE_UP)) | ||
630 | goto attr_msg_full; | ||
631 | |||
632 | nla_nest_end(msg->skb, attrs); | ||
633 | genlmsg_end(msg->skb, hdr); | ||
634 | |||
635 | return 0; | ||
636 | |||
637 | attr_msg_full: | ||
638 | nla_nest_cancel(msg->skb, attrs); | ||
639 | msg_full: | ||
640 | genlmsg_cancel(msg->skb, hdr); | ||
641 | |||
642 | return -EMSGSIZE; | ||
643 | } | ||
644 | |||
645 | int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
646 | { | ||
647 | int err; | ||
648 | int done = cb->args[0]; | ||
649 | int last_addr = cb->args[1]; | ||
650 | struct tipc_node *node; | ||
651 | struct tipc_nl_msg msg; | ||
652 | |||
653 | if (done) | ||
654 | return 0; | ||
655 | |||
656 | msg.skb = skb; | ||
657 | msg.portid = NETLINK_CB(cb->skb).portid; | ||
658 | msg.seq = cb->nlh->nlmsg_seq; | ||
659 | |||
660 | rcu_read_lock(); | ||
661 | |||
662 | if (last_addr && !tipc_node_find(last_addr)) { | ||
663 | rcu_read_unlock(); | ||
664 | /* We never set seq or call nl_dump_check_consistent() this | ||
665 | * means that setting prev_seq here will cause the consistence | ||
666 | * check to fail in the netlink callback handler. Resulting in | ||
667 | * the NLMSG_DONE message having the NLM_F_DUMP_INTR flag set if | ||
668 | * the node state changed while we released the lock. | ||
669 | */ | ||
670 | cb->prev_seq = 1; | ||
671 | return -EPIPE; | ||
672 | } | ||
673 | |||
674 | list_for_each_entry_rcu(node, &tipc_node_list, list) { | ||
675 | if (last_addr) { | ||
676 | if (node->addr == last_addr) | ||
677 | last_addr = 0; | ||
678 | else | ||
679 | continue; | ||
680 | } | ||
681 | |||
682 | tipc_node_lock(node); | ||
683 | err = __tipc_nl_add_node(&msg, node); | ||
684 | if (err) { | ||
685 | last_addr = node->addr; | ||
686 | tipc_node_unlock(node); | ||
687 | goto out; | ||
688 | } | ||
689 | |||
690 | tipc_node_unlock(node); | ||
691 | } | ||
692 | done = 1; | ||
693 | out: | ||
694 | cb->args[0] = done; | ||
695 | cb->args[1] = last_addr; | ||
696 | rcu_read_unlock(); | ||
697 | |||
698 | return skb->len; | ||
699 | } | ||
diff --git a/net/tipc/node.h b/net/tipc/node.h index 04e91458bb29..005fbcef3212 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * net/tipc/node.h: Include file for TIPC node management routines | 2 | * net/tipc/node.h: Include file for TIPC node management routines |
3 | * | 3 | * |
4 | * Copyright (c) 2000-2006, Ericsson AB | 4 | * Copyright (c) 2000-2006, 2014, Ericsson AB |
5 | * Copyright (c) 2005, 2010-2014, Wind River Systems | 5 | * Copyright (c) 2005, 2010-2014, Wind River Systems |
6 | * All rights reserved. | 6 | * All rights reserved. |
7 | * | 7 | * |
@@ -145,6 +145,8 @@ void tipc_node_unlock(struct tipc_node *node); | |||
145 | int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port); | 145 | int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port); |
146 | void tipc_node_remove_conn(u32 dnode, u32 port); | 146 | void tipc_node_remove_conn(u32 dnode, u32 port); |
147 | 147 | ||
148 | int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb); | ||
149 | |||
148 | static inline void tipc_node_lock(struct tipc_node *node) | 150 | static inline void tipc_node_lock(struct tipc_node *node) |
149 | { | 151 | { |
150 | spin_lock_bh(&node->lock); | 152 | spin_lock_bh(&node->lock); |