aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-02-09 16:20:53 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-09 16:20:53 -0500
commit9dce285b70c157754d753203112cfef22770b1f9 (patch)
tree4859799a8311ecd637e2a582600af1057a78e08b /net/tipc
parentc8ac18f2006b2926ce375c01646b2f487d1c33b2 (diff)
parent941787b82982b3f33ac398c8c00035ddd0f8c514 (diff)
Merge branch 'tipc-next'
Richard Alpe says: ==================== tipc: new compat layer for the legacy NL API This is a compatibility / transcoding layer for the old netlink API. It relies on the new netlink API to collect data or perform actions (dumpit / doit). The main benefit of this compat layer is that it removes a lot of complex code from the tipc core as only the new API needs to be able harness data or perform actions. I.e. the compat layer isn't concerned with locking or how the internal data-structures look. As long as the new API stays relatively intact the compat layer should be fine. The main challenge in this compat layer is the randomness of the legacy API. Some commands send binary data and some send ASCII data, some are very picky in optimizing there buffer sizes and some just don't care. Most legacy commands put there data in a single TLV (data container) but some segment the data into multiple TLV's. This list of randomness goes on and on.. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/Makefile6
-rw-r--r--net/tipc/bcast.c45
-rw-r--r--net/tipc/bcast.h1
-rw-r--r--net/tipc/bearer.c86
-rw-r--r--net/tipc/bearer.h5
-rw-r--r--net/tipc/config.c332
-rw-r--r--net/tipc/config.h67
-rw-r--r--net/tipc/core.c10
-rw-r--r--net/tipc/core.h3
-rw-r--r--net/tipc/link.c325
-rw-r--r--net/tipc/link.h8
-rw-r--r--net/tipc/log.c55
-rw-r--r--net/tipc/name_table.c190
-rw-r--r--net/tipc/name_table.h2
-rw-r--r--net/tipc/net.c6
-rw-r--r--net/tipc/netlink.c67
-rw-r--r--net/tipc/netlink.h4
-rw-r--r--net/tipc/netlink_compat.c1084
-rw-r--r--net/tipc/node.c131
-rw-r--r--net/tipc/node.h4
-rw-r--r--net/tipc/socket.c90
-rw-r--r--net/tipc/socket.h1
22 files changed, 1127 insertions, 1395 deletions
diff --git a/net/tipc/Makefile b/net/tipc/Makefile
index 333e4592772c..599b1a540d2b 100644
--- a/net/tipc/Makefile
+++ b/net/tipc/Makefile
@@ -4,11 +4,11 @@
4 4
5obj-$(CONFIG_TIPC) := tipc.o 5obj-$(CONFIG_TIPC) := tipc.o
6 6
7tipc-y += addr.o bcast.o bearer.o config.o \ 7tipc-y += addr.o bcast.o bearer.o \
8 core.o link.o discover.o msg.o \ 8 core.o link.o discover.o msg.o \
9 name_distr.o subscr.o name_table.o net.o \ 9 name_distr.o subscr.o name_table.o net.o \
10 netlink.o node.o socket.o log.o eth_media.o \ 10 netlink.o netlink_compat.o node.o socket.o eth_media.o \
11 server.o 11 server.o socket.o
12 12
13tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_media.o 13tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_media.o
14tipc-$(CONFIG_SYSCTL) += sysctl.o 14tipc-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index 81b1fef1f5e0..3e41704832de 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -810,7 +810,7 @@ int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg)
810 810
811 tipc_bclink_lock(net); 811 tipc_bclink_lock(net);
812 812
813 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family, 813 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
814 NLM_F_MULTI, TIPC_NL_LINK_GET); 814 NLM_F_MULTI, TIPC_NL_LINK_GET);
815 if (!hdr) 815 if (!hdr)
816 return -EMSGSIZE; 816 return -EMSGSIZE;
@@ -860,49 +860,6 @@ msg_full:
860 return -EMSGSIZE; 860 return -EMSGSIZE;
861} 861}
862 862
863int tipc_bclink_stats(struct net *net, char *buf, const u32 buf_size)
864{
865 int ret;
866 struct tipc_stats *s;
867 struct tipc_net *tn = net_generic(net, tipc_net_id);
868 struct tipc_link *bcl = tn->bcl;
869
870 if (!bcl)
871 return 0;
872
873 tipc_bclink_lock(net);
874
875 s = &bcl->stats;
876
877 ret = tipc_snprintf(buf, buf_size, "Link <%s>\n"
878 " Window:%u packets\n",
879 bcl->name, bcl->queue_limit[0]);
880 ret += tipc_snprintf(buf + ret, buf_size - ret,
881 " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
882 s->recv_info, s->recv_fragments,
883 s->recv_fragmented, s->recv_bundles,
884 s->recv_bundled);
885 ret += tipc_snprintf(buf + ret, buf_size - ret,
886 " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
887 s->sent_info, s->sent_fragments,
888 s->sent_fragmented, s->sent_bundles,
889 s->sent_bundled);
890 ret += tipc_snprintf(buf + ret, buf_size - ret,
891 " RX naks:%u defs:%u dups:%u\n",
892 s->recv_nacks, s->deferred_recv, s->duplicates);
893 ret += tipc_snprintf(buf + ret, buf_size - ret,
894 " TX naks:%u acks:%u dups:%u\n",
895 s->sent_nacks, s->sent_acks, s->retransmitted);
896 ret += tipc_snprintf(buf + ret, buf_size - ret,
897 " Congestion link:%u Send queue max:%u avg:%u\n",
898 s->link_congs, s->max_queue_sz,
899 s->queue_sz_counts ?
900 (s->accu_queue_sz / s->queue_sz_counts) : 0);
901
902 tipc_bclink_unlock(net);
903 return ret;
904}
905
906int tipc_bclink_reset_stats(struct net *net) 863int tipc_bclink_reset_stats(struct net *net)
907{ 864{
908 struct tipc_net *tn = net_generic(net, tipc_net_id); 865 struct tipc_net *tn = net_generic(net, tipc_net_id);
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h
index a910c0b9f249..43f397fbac55 100644
--- a/net/tipc/bcast.h
+++ b/net/tipc/bcast.h
@@ -127,7 +127,6 @@ u32 tipc_bclink_get_last_sent(struct net *net);
127u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr); 127u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr);
128void tipc_bclink_update_link_state(struct tipc_node *node, 128void tipc_bclink_update_link_state(struct tipc_node *node,
129 u32 last_sent); 129 u32 last_sent);
130int tipc_bclink_stats(struct net *net, char *stats_buf, const u32 buf_size);
131int tipc_bclink_reset_stats(struct net *net); 130int tipc_bclink_reset_stats(struct net *net);
132int tipc_bclink_set_queue_limits(struct net *net, u32 limit); 131int tipc_bclink_set_queue_limits(struct net *net, u32 limit);
133void tipc_bcbearer_sort(struct net *net, struct tipc_node_map *nm_ptr, 132void tipc_bcbearer_sort(struct net *net, struct tipc_node_map *nm_ptr,
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 33dc3486d16c..48852c2dcc03 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -36,7 +36,6 @@
36 36
37#include <net/sock.h> 37#include <net/sock.h>
38#include "core.h" 38#include "core.h"
39#include "config.h"
40#include "bearer.h" 39#include "bearer.h"
41#include "link.h" 40#include "link.h"
42#include "discover.h" 41#include "discover.h"
@@ -112,38 +111,18 @@ void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a)
112 m_ptr = media_find_id(a->media_id); 111 m_ptr = media_find_id(a->media_id);
113 112
114 if (m_ptr && !m_ptr->addr2str(a, addr_str, sizeof(addr_str))) 113 if (m_ptr && !m_ptr->addr2str(a, addr_str, sizeof(addr_str)))
115 ret = tipc_snprintf(buf, len, "%s(%s)", m_ptr->name, addr_str); 114 ret = scnprintf(buf, len, "%s(%s)", m_ptr->name, addr_str);
116 else { 115 else {
117 u32 i; 116 u32 i;
118 117
119 ret = tipc_snprintf(buf, len, "UNKNOWN(%u)", a->media_id); 118 ret = scnprintf(buf, len, "UNKNOWN(%u)", a->media_id);
120 for (i = 0; i < sizeof(a->value); i++) 119 for (i = 0; i < sizeof(a->value); i++)
121 ret += tipc_snprintf(buf - ret, len + ret, 120 ret += scnprintf(buf - ret, len + ret,
122 "-%02x", a->value[i]); 121 "-%02x", a->value[i]);
123 } 122 }
124} 123}
125 124
126/** 125/**
127 * tipc_media_get_names - record names of registered media in buffer
128 */
129struct sk_buff *tipc_media_get_names(void)
130{
131 struct sk_buff *buf;
132 int i;
133
134 buf = tipc_cfg_reply_alloc(MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME));
135 if (!buf)
136 return NULL;
137
138 for (i = 0; media_info_array[i] != NULL; i++) {
139 tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME,
140 media_info_array[i]->name,
141 strlen(media_info_array[i]->name) + 1);
142 }
143 return buf;
144}
145
146/**
147 * bearer_name_validate - validate & (optionally) deconstruct bearer name 126 * bearer_name_validate - validate & (optionally) deconstruct bearer name
148 * @name: ptr to bearer name string 127 * @name: ptr to bearer name string
149 * @name_parts: ptr to area for bearer name components (or NULL if not needed) 128 * @name_parts: ptr to area for bearer name components (or NULL if not needed)
@@ -205,35 +184,6 @@ struct tipc_bearer *tipc_bearer_find(struct net *net, const char *name)
205 return NULL; 184 return NULL;
206} 185}
207 186
208/**
209 * tipc_bearer_get_names - record names of bearers in buffer
210 */
211struct sk_buff *tipc_bearer_get_names(struct net *net)
212{
213 struct tipc_net *tn = net_generic(net, tipc_net_id);
214 struct sk_buff *buf;
215 struct tipc_bearer *b;
216 int i, j;
217
218 buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
219 if (!buf)
220 return NULL;
221
222 for (i = 0; media_info_array[i] != NULL; i++) {
223 for (j = 0; j < MAX_BEARERS; j++) {
224 b = rtnl_dereference(tn->bearer_list[j]);
225 if (!b)
226 continue;
227 if (b->media == media_info_array[i]) {
228 tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
229 b->name,
230 strlen(b->name) + 1);
231 }
232 }
233 }
234 return buf;
235}
236
237void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest) 187void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest)
238{ 188{
239 struct tipc_net *tn = net_generic(net, tipc_net_id); 189 struct tipc_net *tn = net_generic(net, tipc_net_id);
@@ -265,8 +215,8 @@ void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest)
265/** 215/**
266 * tipc_enable_bearer - enable bearer with the given name 216 * tipc_enable_bearer - enable bearer with the given name
267 */ 217 */
268int tipc_enable_bearer(struct net *net, const char *name, u32 disc_domain, 218static int tipc_enable_bearer(struct net *net, const char *name,
269 u32 priority) 219 u32 disc_domain, u32 priority)
270{ 220{
271 struct tipc_net *tn = net_generic(net, tipc_net_id); 221 struct tipc_net *tn = net_generic(net, tipc_net_id);
272 struct tipc_bearer *b_ptr; 222 struct tipc_bearer *b_ptr;
@@ -422,22 +372,6 @@ static void bearer_disable(struct net *net, struct tipc_bearer *b_ptr,
422 kfree_rcu(b_ptr, rcu); 372 kfree_rcu(b_ptr, rcu);
423} 373}
424 374
425int tipc_disable_bearer(struct net *net, const char *name)
426{
427 struct tipc_bearer *b_ptr;
428 int res;
429
430 b_ptr = tipc_bearer_find(net, name);
431 if (b_ptr == NULL) {
432 pr_warn("Attempt to disable unknown bearer <%s>\n", name);
433 res = -EINVAL;
434 } else {
435 bearer_disable(net, b_ptr, false);
436 res = 0;
437 }
438 return res;
439}
440
441int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b) 375int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b)
442{ 376{
443 struct net_device *dev; 377 struct net_device *dev;
@@ -658,7 +592,7 @@ static int __tipc_nl_add_bearer(struct tipc_nl_msg *msg,
658 struct nlattr *attrs; 592 struct nlattr *attrs;
659 struct nlattr *prop; 593 struct nlattr *prop;
660 594
661 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family, 595 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
662 NLM_F_MULTI, TIPC_NL_BEARER_GET); 596 NLM_F_MULTI, TIPC_NL_BEARER_GET);
663 if (!hdr) 597 if (!hdr)
664 return -EMSGSIZE; 598 return -EMSGSIZE;
@@ -785,7 +719,7 @@ int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
785 char *name; 719 char *name;
786 struct tipc_bearer *bearer; 720 struct tipc_bearer *bearer;
787 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; 721 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
788 struct net *net = genl_info_net(info); 722 struct net *net = sock_net(skb->sk);
789 723
790 if (!info->attrs[TIPC_NLA_BEARER]) 724 if (!info->attrs[TIPC_NLA_BEARER])
791 return -EINVAL; 725 return -EINVAL;
@@ -816,11 +750,11 @@ int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
816 750
817int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info) 751int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
818{ 752{
819 struct net *net = genl_info_net(info);
820 struct tipc_net *tn = net_generic(net, tipc_net_id);
821 int err; 753 int err;
822 char *bearer; 754 char *bearer;
823 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; 755 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
756 struct net *net = sock_net(skb->sk);
757 struct tipc_net *tn = net_generic(net, tipc_net_id);
824 u32 domain; 758 u32 domain;
825 u32 prio; 759 u32 prio;
826 760
@@ -924,7 +858,7 @@ static int __tipc_nl_add_media(struct tipc_nl_msg *msg,
924 struct nlattr *attrs; 858 struct nlattr *attrs;
925 struct nlattr *prop; 859 struct nlattr *prop;
926 860
927 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family, 861 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
928 NLM_F_MULTI, TIPC_NL_MEDIA_GET); 862 NLM_F_MULTI, TIPC_NL_MEDIA_GET);
929 if (!hdr) 863 if (!hdr)
930 return -EMSGSIZE; 864 return -EMSGSIZE;
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index c035e3e24764..6b17795ff8bc 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -173,9 +173,6 @@ struct tipc_bearer_names {
173 */ 173 */
174 174
175void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr); 175void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr);
176int tipc_enable_bearer(struct net *net, const char *bearer_name,
177 u32 disc_domain, u32 priority);
178int tipc_disable_bearer(struct net *net, const char *name);
179 176
180/* 177/*
181 * Routines made available to TIPC by supported media types 178 * Routines made available to TIPC by supported media types
@@ -199,13 +196,11 @@ int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info);
199int tipc_media_set_priority(const char *name, u32 new_value); 196int tipc_media_set_priority(const char *name, u32 new_value);
200int tipc_media_set_window(const char *name, u32 new_value); 197int tipc_media_set_window(const char *name, u32 new_value);
201void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a); 198void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a);
202struct sk_buff *tipc_media_get_names(void);
203int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b); 199int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b);
204void tipc_disable_l2_media(struct tipc_bearer *b); 200void tipc_disable_l2_media(struct tipc_bearer *b);
205int tipc_l2_send_msg(struct net *net, struct sk_buff *buf, 201int tipc_l2_send_msg(struct net *net, struct sk_buff *buf,
206 struct tipc_bearer *b, struct tipc_media_addr *dest); 202 struct tipc_bearer *b, struct tipc_media_addr *dest);
207 203
208struct sk_buff *tipc_bearer_get_names(struct net *net);
209void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest); 204void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest);
210void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest); 205void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest);
211struct tipc_bearer *tipc_bearer_find(struct net *net, const char *name); 206struct tipc_bearer *tipc_bearer_find(struct net *net, const char *name);
diff --git a/net/tipc/config.c b/net/tipc/config.c
deleted file mode 100644
index 6873360cda53..000000000000
--- a/net/tipc/config.c
+++ /dev/null
@@ -1,332 +0,0 @@
1/*
2 * net/tipc/config.c: TIPC configuration management code
3 *
4 * Copyright (c) 2002-2006, Ericsson AB
5 * Copyright (c) 2004-2007, 2010-2013, Wind River Systems
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the names of the copyright holders nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * Alternatively, this software may be distributed under the terms of the
21 * GNU General Public License ("GPL") version 2 as published by the Free
22 * Software Foundation.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#include "core.h"
38#include "socket.h"
39#include "name_table.h"
40#include "config.h"
41#include "server.h"
42
43#define REPLY_TRUNCATED "<truncated>\n"
44
45static const void *req_tlv_area; /* request message TLV area */
46static int req_tlv_space; /* request message TLV area size */
47static int rep_headroom; /* reply message headroom to use */
48
49struct sk_buff *tipc_cfg_reply_alloc(int payload_size)
50{
51 struct sk_buff *buf;
52
53 buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC);
54 if (buf)
55 skb_reserve(buf, rep_headroom);
56 return buf;
57}
58
59int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
60 void *tlv_data, int tlv_data_size)
61{
62 struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(buf);
63 int new_tlv_space = TLV_SPACE(tlv_data_size);
64
65 if (skb_tailroom(buf) < new_tlv_space)
66 return 0;
67 skb_put(buf, new_tlv_space);
68 tlv->tlv_type = htons(tlv_type);
69 tlv->tlv_len = htons(TLV_LENGTH(tlv_data_size));
70 if (tlv_data_size && tlv_data)
71 memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size);
72 return 1;
73}
74
75static struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value)
76{
77 struct sk_buff *buf;
78 __be32 value_net;
79
80 buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value)));
81 if (buf) {
82 value_net = htonl(value);
83 tipc_cfg_append_tlv(buf, tlv_type, &value_net,
84 sizeof(value_net));
85 }
86 return buf;
87}
88
89static struct sk_buff *tipc_cfg_reply_unsigned(u32 value)
90{
91 return tipc_cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value);
92}
93
94struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string)
95{
96 struct sk_buff *buf;
97 int string_len = strlen(string) + 1;
98
99 buf = tipc_cfg_reply_alloc(TLV_SPACE(string_len));
100 if (buf)
101 tipc_cfg_append_tlv(buf, tlv_type, string, string_len);
102 return buf;
103}
104
105static struct sk_buff *tipc_show_stats(void)
106{
107 struct sk_buff *buf;
108 struct tlv_desc *rep_tlv;
109 char *pb;
110 int pb_len;
111 int str_len;
112 u32 value;
113
114 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
115 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
116
117 value = ntohl(*(u32 *)TLV_DATA(req_tlv_area));
118 if (value != 0)
119 return tipc_cfg_reply_error_string("unsupported argument");
120
121 buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
122 if (buf == NULL)
123 return NULL;
124
125 rep_tlv = (struct tlv_desc *)buf->data;
126 pb = TLV_DATA(rep_tlv);
127 pb_len = ULTRA_STRING_MAX_LEN;
128
129 str_len = tipc_snprintf(pb, pb_len, "TIPC version " TIPC_MOD_VER "\n");
130 str_len += 1; /* for "\0" */
131 skb_put(buf, TLV_SPACE(str_len));
132 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
133
134 return buf;
135}
136
137static struct sk_buff *cfg_enable_bearer(struct net *net)
138{
139 struct tipc_bearer_config *args;
140
141 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG))
142 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
143
144 args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area);
145 if (tipc_enable_bearer(net, args->name,
146 ntohl(args->disc_domain),
147 ntohl(args->priority)))
148 return tipc_cfg_reply_error_string("unable to enable bearer");
149
150 return tipc_cfg_reply_none();
151}
152
153static struct sk_buff *cfg_disable_bearer(struct net *net)
154{
155 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME))
156 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
157
158 if (tipc_disable_bearer(net, (char *)TLV_DATA(req_tlv_area)))
159 return tipc_cfg_reply_error_string("unable to disable bearer");
160
161 return tipc_cfg_reply_none();
162}
163
164static struct sk_buff *cfg_set_own_addr(struct net *net)
165{
166 struct tipc_net *tn = net_generic(net, tipc_net_id);
167 u32 addr;
168
169 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
170 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
171
172 addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
173 if (addr == tn->own_addr)
174 return tipc_cfg_reply_none();
175 if (!tipc_addr_node_valid(addr))
176 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
177 " (node address)");
178 if (tn->own_addr)
179 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
180 " (cannot change node address once assigned)");
181 if (!tipc_net_start(net, addr))
182 return tipc_cfg_reply_none();
183
184 return tipc_cfg_reply_error_string("cannot change to network mode");
185}
186
187static struct sk_buff *cfg_set_netid(struct net *net)
188{
189 struct tipc_net *tn = net_generic(net, tipc_net_id);
190 u32 value;
191
192 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
193 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
194 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
195 if (value == tn->net_id)
196 return tipc_cfg_reply_none();
197 if (value < 1 || value > 9999)
198 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
199 " (network id must be 1-9999)");
200 if (tn->own_addr)
201 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
202 " (cannot change network id once TIPC has joined a network)");
203 tn->net_id = value;
204 return tipc_cfg_reply_none();
205}
206
207struct sk_buff *tipc_cfg_do_cmd(struct net *net, u32 orig_node, u16 cmd,
208 const void *request_area, int request_space,
209 int reply_headroom)
210{
211 struct sk_buff *rep_tlv_buf;
212 struct tipc_net *tn = net_generic(net, tipc_net_id);
213
214 rtnl_lock();
215
216 /* Save request and reply details in a well-known location */
217 req_tlv_area = request_area;
218 req_tlv_space = request_space;
219 rep_headroom = reply_headroom;
220
221 /* Check command authorization */
222 if (likely(in_own_node(net, orig_node))) {
223 /* command is permitted */
224 } else {
225 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
226 " (cannot be done remotely)");
227 goto exit;
228 }
229
230 /* Call appropriate processing routine */
231 switch (cmd) {
232 case TIPC_CMD_NOOP:
233 rep_tlv_buf = tipc_cfg_reply_none();
234 break;
235 case TIPC_CMD_GET_NODES:
236 rep_tlv_buf = tipc_node_get_nodes(net, req_tlv_area,
237 req_tlv_space);
238 break;
239 case TIPC_CMD_GET_LINKS:
240 rep_tlv_buf = tipc_node_get_links(net, req_tlv_area,
241 req_tlv_space);
242 break;
243 case TIPC_CMD_SHOW_LINK_STATS:
244 rep_tlv_buf = tipc_link_cmd_show_stats(net, req_tlv_area,
245 req_tlv_space);
246 break;
247 case TIPC_CMD_RESET_LINK_STATS:
248 rep_tlv_buf = tipc_link_cmd_reset_stats(net, req_tlv_area,
249 req_tlv_space);
250 break;
251 case TIPC_CMD_SHOW_NAME_TABLE:
252 rep_tlv_buf = tipc_nametbl_get(net, req_tlv_area,
253 req_tlv_space);
254 break;
255 case TIPC_CMD_GET_BEARER_NAMES:
256 rep_tlv_buf = tipc_bearer_get_names(net);
257 break;
258 case TIPC_CMD_GET_MEDIA_NAMES:
259 rep_tlv_buf = tipc_media_get_names();
260 break;
261 case TIPC_CMD_SHOW_PORTS:
262 rep_tlv_buf = tipc_sk_socks_show(net);
263 break;
264 case TIPC_CMD_SHOW_STATS:
265 rep_tlv_buf = tipc_show_stats();
266 break;
267 case TIPC_CMD_SET_LINK_TOL:
268 case TIPC_CMD_SET_LINK_PRI:
269 case TIPC_CMD_SET_LINK_WINDOW:
270 rep_tlv_buf = tipc_link_cmd_config(net, req_tlv_area,
271 req_tlv_space, cmd);
272 break;
273 case TIPC_CMD_ENABLE_BEARER:
274 rep_tlv_buf = cfg_enable_bearer(net);
275 break;
276 case TIPC_CMD_DISABLE_BEARER:
277 rep_tlv_buf = cfg_disable_bearer(net);
278 break;
279 case TIPC_CMD_SET_NODE_ADDR:
280 rep_tlv_buf = cfg_set_own_addr(net);
281 break;
282 case TIPC_CMD_SET_NETID:
283 rep_tlv_buf = cfg_set_netid(net);
284 break;
285 case TIPC_CMD_GET_NETID:
286 rep_tlv_buf = tipc_cfg_reply_unsigned(tn->net_id);
287 break;
288 case TIPC_CMD_NOT_NET_ADMIN:
289 rep_tlv_buf =
290 tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
291 break;
292 case TIPC_CMD_SET_MAX_ZONES:
293 case TIPC_CMD_GET_MAX_ZONES:
294 case TIPC_CMD_SET_MAX_SLAVES:
295 case TIPC_CMD_GET_MAX_SLAVES:
296 case TIPC_CMD_SET_MAX_CLUSTERS:
297 case TIPC_CMD_GET_MAX_CLUSTERS:
298 case TIPC_CMD_SET_MAX_NODES:
299 case TIPC_CMD_GET_MAX_NODES:
300 case TIPC_CMD_SET_MAX_SUBSCR:
301 case TIPC_CMD_GET_MAX_SUBSCR:
302 case TIPC_CMD_SET_MAX_PUBL:
303 case TIPC_CMD_GET_MAX_PUBL:
304 case TIPC_CMD_SET_LOG_SIZE:
305 case TIPC_CMD_SET_REMOTE_MNG:
306 case TIPC_CMD_GET_REMOTE_MNG:
307 case TIPC_CMD_DUMP_LOG:
308 case TIPC_CMD_SET_MAX_PORTS:
309 case TIPC_CMD_GET_MAX_PORTS:
310 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
311 " (obsolete command)");
312 break;
313 default:
314 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
315 " (unknown command)");
316 break;
317 }
318
319 WARN_ON(rep_tlv_buf->len > TLV_SPACE(ULTRA_STRING_MAX_LEN));
320
321 /* Append an error message if we cannot return all requested data */
322 if (rep_tlv_buf->len == TLV_SPACE(ULTRA_STRING_MAX_LEN)) {
323 if (*(rep_tlv_buf->data + ULTRA_STRING_MAX_LEN) != '\0')
324 sprintf(rep_tlv_buf->data + rep_tlv_buf->len -
325 sizeof(REPLY_TRUNCATED) - 1, REPLY_TRUNCATED);
326 }
327
328 /* Return reply buffer */
329exit:
330 rtnl_unlock();
331 return rep_tlv_buf;
332}
diff --git a/net/tipc/config.h b/net/tipc/config.h
deleted file mode 100644
index 9e9b575fc429..000000000000
--- a/net/tipc/config.h
+++ /dev/null
@@ -1,67 +0,0 @@
1/*
2 * net/tipc/config.h: Include file for TIPC configuration service code
3 *
4 * Copyright (c) 2003-2006, Ericsson AB
5 * Copyright (c) 2005, Wind River Systems
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the names of the copyright holders nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * Alternatively, this software may be distributed under the terms of the
21 * GNU General Public License ("GPL") version 2 as published by the Free
22 * Software Foundation.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#ifndef _TIPC_CONFIG_H
38#define _TIPC_CONFIG_H
39
40#include "link.h"
41
42#define ULTRA_STRING_MAX_LEN 32768
43
44struct sk_buff *tipc_cfg_reply_alloc(int payload_size);
45int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
46 void *tlv_data, int tlv_data_size);
47struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string);
48
49static inline struct sk_buff *tipc_cfg_reply_none(void)
50{
51 return tipc_cfg_reply_alloc(0);
52}
53
54static inline struct sk_buff *tipc_cfg_reply_error_string(char *string)
55{
56 return tipc_cfg_reply_string_type(TIPC_TLV_ERROR_STRING, string);
57}
58
59static inline struct sk_buff *tipc_cfg_reply_ultra_string(char *string)
60{
61 return tipc_cfg_reply_string_type(TIPC_TLV_ULTRA_STRING, string);
62}
63
64struct sk_buff *tipc_cfg_do_cmd(struct net *net, u32 orig_node, u16 cmd,
65 const void *req_tlv_area, int req_tlv_space,
66 int headroom);
67#endif
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 674bd2698528..935205e6bcfe 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -39,7 +39,8 @@
39#include "core.h" 39#include "core.h"
40#include "name_table.h" 40#include "name_table.h"
41#include "subscr.h" 41#include "subscr.h"
42#include "config.h" 42#include "bearer.h"
43#include "net.h"
43#include "socket.h" 44#include "socket.h"
44 45
45#include <linux/module.h> 46#include <linux/module.h>
@@ -111,6 +112,10 @@ static int __init tipc_init(void)
111 if (err) 112 if (err)
112 goto out_netlink; 113 goto out_netlink;
113 114
115 err = tipc_netlink_compat_start();
116 if (err)
117 goto out_netlink_compat;
118
114 err = tipc_socket_init(); 119 err = tipc_socket_init();
115 if (err) 120 if (err)
116 goto out_socket; 121 goto out_socket;
@@ -136,6 +141,8 @@ out_pernet:
136out_sysctl: 141out_sysctl:
137 tipc_socket_stop(); 142 tipc_socket_stop();
138out_socket: 143out_socket:
144 tipc_netlink_compat_stop();
145out_netlink_compat:
139 tipc_netlink_stop(); 146 tipc_netlink_stop();
140out_netlink: 147out_netlink:
141 pr_err("Unable to start in single node mode\n"); 148 pr_err("Unable to start in single node mode\n");
@@ -146,6 +153,7 @@ static void __exit tipc_exit(void)
146{ 153{
147 tipc_bearer_cleanup(); 154 tipc_bearer_cleanup();
148 tipc_netlink_stop(); 155 tipc_netlink_stop();
156 tipc_netlink_compat_stop();
149 tipc_socket_stop(); 157 tipc_socket_stop();
150 tipc_unregister_sysctl(); 158 tipc_unregister_sysctl();
151 unregister_pernet_subsys(&tipc_net_ops); 159 unregister_pernet_subsys(&tipc_net_ops);
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 817b2e9d4227..3dc68c7a966d 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -70,8 +70,6 @@
70 70
71#define TIPC_MOD_VER "2.0.0" 71#define TIPC_MOD_VER "2.0.0"
72 72
73int tipc_snprintf(char *buf, int len, const char *fmt, ...);
74
75extern int tipc_net_id __read_mostly; 73extern int tipc_net_id __read_mostly;
76extern int sysctl_tipc_rmem[3] __read_mostly; 74extern int sysctl_tipc_rmem[3] __read_mostly;
77extern int sysctl_tipc_named_timeout __read_mostly; 75extern int sysctl_tipc_named_timeout __read_mostly;
@@ -115,5 +113,4 @@ void tipc_unregister_sysctl(void);
115#define tipc_register_sysctl() 0 113#define tipc_register_sysctl() 0
116#define tipc_unregister_sysctl() 114#define tipc_unregister_sysctl()
117#endif 115#endif
118
119#endif 116#endif
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 942491234099..a4cf364316de 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -40,7 +40,6 @@
40#include "socket.h" 40#include "socket.h"
41#include "name_distr.h" 41#include "name_distr.h"
42#include "discover.h" 42#include "discover.h"
43#include "config.h"
44#include "netlink.h" 43#include "netlink.h"
45 44
46#include <linux/pkt_sched.h> 45#include <linux/pkt_sched.h>
@@ -1959,150 +1958,6 @@ static struct tipc_node *tipc_link_find_owner(struct net *net,
1959} 1958}
1960 1959
1961/** 1960/**
1962 * link_value_is_valid -- validate proposed link tolerance/priority/window
1963 *
1964 * @cmd: value type (TIPC_CMD_SET_LINK_*)
1965 * @new_value: the new value
1966 *
1967 * Returns 1 if value is within range, 0 if not.
1968 */
1969static int link_value_is_valid(u16 cmd, u32 new_value)
1970{
1971 switch (cmd) {
1972 case TIPC_CMD_SET_LINK_TOL:
1973 return (new_value >= TIPC_MIN_LINK_TOL) &&
1974 (new_value <= TIPC_MAX_LINK_TOL);
1975 case TIPC_CMD_SET_LINK_PRI:
1976 return (new_value <= TIPC_MAX_LINK_PRI);
1977 case TIPC_CMD_SET_LINK_WINDOW:
1978 return (new_value >= TIPC_MIN_LINK_WIN) &&
1979 (new_value <= TIPC_MAX_LINK_WIN);
1980 }
1981 return 0;
1982}
1983
1984/**
1985 * link_cmd_set_value - change priority/tolerance/window for link/bearer/media
1986 * @net: the applicable net namespace
1987 * @name: ptr to link, bearer, or media name
1988 * @new_value: new value of link, bearer, or media setting
1989 * @cmd: which link, bearer, or media attribute to set (TIPC_CMD_SET_LINK_*)
1990 *
1991 * Caller must hold RTNL lock to ensure link/bearer/media is not deleted.
1992 *
1993 * Returns 0 if value updated and negative value on error.
1994 */
1995static int link_cmd_set_value(struct net *net, const char *name, u32 new_value,
1996 u16 cmd)
1997{
1998 struct tipc_node *node;
1999 struct tipc_link *l_ptr;
2000 struct tipc_bearer *b_ptr;
2001 struct tipc_media *m_ptr;
2002 int bearer_id;
2003 int res = 0;
2004
2005 node = tipc_link_find_owner(net, name, &bearer_id);
2006 if (node) {
2007 tipc_node_lock(node);
2008 l_ptr = node->links[bearer_id];
2009
2010 if (l_ptr) {
2011 switch (cmd) {
2012 case TIPC_CMD_SET_LINK_TOL:
2013 link_set_supervision_props(l_ptr, new_value);
2014 tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0,
2015 new_value, 0, 0);
2016 break;
2017 case TIPC_CMD_SET_LINK_PRI:
2018 l_ptr->priority = new_value;
2019 tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0,
2020 0, new_value, 0);
2021 break;
2022 case TIPC_CMD_SET_LINK_WINDOW:
2023 tipc_link_set_queue_limits(l_ptr, new_value);
2024 break;
2025 default:
2026 res = -EINVAL;
2027 break;
2028 }
2029 }
2030 tipc_node_unlock(node);
2031 return res;
2032 }
2033
2034 b_ptr = tipc_bearer_find(net, name);
2035 if (b_ptr) {
2036 switch (cmd) {
2037 case TIPC_CMD_SET_LINK_TOL:
2038 b_ptr->tolerance = new_value;
2039 break;
2040 case TIPC_CMD_SET_LINK_PRI:
2041 b_ptr->priority = new_value;
2042 break;
2043 case TIPC_CMD_SET_LINK_WINDOW:
2044 b_ptr->window = new_value;
2045 break;
2046 default:
2047 res = -EINVAL;
2048 break;
2049 }
2050 return res;
2051 }
2052
2053 m_ptr = tipc_media_find(name);
2054 if (!m_ptr)
2055 return -ENODEV;
2056 switch (cmd) {
2057 case TIPC_CMD_SET_LINK_TOL:
2058 m_ptr->tolerance = new_value;
2059 break;
2060 case TIPC_CMD_SET_LINK_PRI:
2061 m_ptr->priority = new_value;
2062 break;
2063 case TIPC_CMD_SET_LINK_WINDOW:
2064 m_ptr->window = new_value;
2065 break;
2066 default:
2067 res = -EINVAL;
2068 break;
2069 }
2070 return res;
2071}
2072
2073struct sk_buff *tipc_link_cmd_config(struct net *net, const void *req_tlv_area,
2074 int req_tlv_space, u16 cmd)
2075{
2076 struct tipc_link_config *args;
2077 u32 new_value;
2078 int res;
2079
2080 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_CONFIG))
2081 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
2082
2083 args = (struct tipc_link_config *)TLV_DATA(req_tlv_area);
2084 new_value = ntohl(args->value);
2085
2086 if (!link_value_is_valid(cmd, new_value))
2087 return tipc_cfg_reply_error_string(
2088 "cannot change, value invalid");
2089
2090 if (!strcmp(args->name, tipc_bclink_name)) {
2091 if ((cmd == TIPC_CMD_SET_LINK_WINDOW) &&
2092 (tipc_bclink_set_queue_limits(net, new_value) == 0))
2093 return tipc_cfg_reply_none();
2094 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
2095 " (cannot change setting on broadcast link)");
2096 }
2097
2098 res = link_cmd_set_value(net, args->name, new_value, cmd);
2099 if (res)
2100 return tipc_cfg_reply_error_string("cannot change link setting");
2101
2102 return tipc_cfg_reply_none();
2103}
2104
2105/**
2106 * link_reset_statistics - reset link statistics 1961 * link_reset_statistics - reset link statistics
2107 * @l_ptr: pointer to link 1962 * @l_ptr: pointer to link
2108 */ 1963 */
@@ -2113,180 +1968,6 @@ static void link_reset_statistics(struct tipc_link *l_ptr)
2113 l_ptr->stats.recv_info = l_ptr->next_in_no; 1968 l_ptr->stats.recv_info = l_ptr->next_in_no;
2114} 1969}
2115 1970
2116struct sk_buff *tipc_link_cmd_reset_stats(struct net *net,
2117 const void *req_tlv_area,
2118 int req_tlv_space)
2119{
2120 char *link_name;
2121 struct tipc_link *l_ptr;
2122 struct tipc_node *node;
2123 unsigned int bearer_id;
2124
2125 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
2126 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
2127
2128 link_name = (char *)TLV_DATA(req_tlv_area);
2129 if (!strcmp(link_name, tipc_bclink_name)) {
2130 if (tipc_bclink_reset_stats(net))
2131 return tipc_cfg_reply_error_string("link not found");
2132 return tipc_cfg_reply_none();
2133 }
2134 node = tipc_link_find_owner(net, link_name, &bearer_id);
2135 if (!node)
2136 return tipc_cfg_reply_error_string("link not found");
2137
2138 tipc_node_lock(node);
2139 l_ptr = node->links[bearer_id];
2140 if (!l_ptr) {
2141 tipc_node_unlock(node);
2142 return tipc_cfg_reply_error_string("link not found");
2143 }
2144 link_reset_statistics(l_ptr);
2145 tipc_node_unlock(node);
2146 return tipc_cfg_reply_none();
2147}
2148
2149/**
2150 * percent - convert count to a percentage of total (rounding up or down)
2151 */
2152static u32 percent(u32 count, u32 total)
2153{
2154 return (count * 100 + (total / 2)) / total;
2155}
2156
2157/**
2158 * tipc_link_stats - print link statistics
2159 * @net: the applicable net namespace
2160 * @name: link name
2161 * @buf: print buffer area
2162 * @buf_size: size of print buffer area
2163 *
2164 * Returns length of print buffer data string (or 0 if error)
2165 */
2166static int tipc_link_stats(struct net *net, const char *name, char *buf,
2167 const u32 buf_size)
2168{
2169 struct tipc_link *l;
2170 struct tipc_stats *s;
2171 struct tipc_node *node;
2172 char *status;
2173 u32 profile_total = 0;
2174 unsigned int bearer_id;
2175 int ret;
2176
2177 if (!strcmp(name, tipc_bclink_name))
2178 return tipc_bclink_stats(net, buf, buf_size);
2179
2180 node = tipc_link_find_owner(net, name, &bearer_id);
2181 if (!node)
2182 return 0;
2183
2184 tipc_node_lock(node);
2185
2186 l = node->links[bearer_id];
2187 if (!l) {
2188 tipc_node_unlock(node);
2189 return 0;
2190 }
2191
2192 s = &l->stats;
2193
2194 if (tipc_link_is_active(l))
2195 status = "ACTIVE";
2196 else if (tipc_link_is_up(l))
2197 status = "STANDBY";
2198 else
2199 status = "DEFUNCT";
2200
2201 ret = tipc_snprintf(buf, buf_size, "Link <%s>\n"
2202 " %s MTU:%u Priority:%u Tolerance:%u ms"
2203 " Window:%u packets\n",
2204 l->name, status, l->max_pkt, l->priority,
2205 l->tolerance, l->queue_limit[0]);
2206
2207 ret += tipc_snprintf(buf + ret, buf_size - ret,
2208 " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
2209 l->next_in_no - s->recv_info, s->recv_fragments,
2210 s->recv_fragmented, s->recv_bundles,
2211 s->recv_bundled);
2212
2213 ret += tipc_snprintf(buf + ret, buf_size - ret,
2214 " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
2215 l->next_out_no - s->sent_info, s->sent_fragments,
2216 s->sent_fragmented, s->sent_bundles,
2217 s->sent_bundled);
2218
2219 profile_total = s->msg_length_counts;
2220 if (!profile_total)
2221 profile_total = 1;
2222
2223 ret += tipc_snprintf(buf + ret, buf_size - ret,
2224 " TX profile sample:%u packets average:%u octets\n"
2225 " 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% "
2226 "-16384:%u%% -32768:%u%% -66000:%u%%\n",
2227 s->msg_length_counts,
2228 s->msg_lengths_total / profile_total,
2229 percent(s->msg_length_profile[0], profile_total),
2230 percent(s->msg_length_profile[1], profile_total),
2231 percent(s->msg_length_profile[2], profile_total),
2232 percent(s->msg_length_profile[3], profile_total),
2233 percent(s->msg_length_profile[4], profile_total),
2234 percent(s->msg_length_profile[5], profile_total),
2235 percent(s->msg_length_profile[6], profile_total));
2236
2237 ret += tipc_snprintf(buf + ret, buf_size - ret,
2238 " RX states:%u probes:%u naks:%u defs:%u"
2239 " dups:%u\n", s->recv_states, s->recv_probes,
2240 s->recv_nacks, s->deferred_recv, s->duplicates);
2241
2242 ret += tipc_snprintf(buf + ret, buf_size - ret,
2243 " TX states:%u probes:%u naks:%u acks:%u"
2244 " dups:%u\n", s->sent_states, s->sent_probes,
2245 s->sent_nacks, s->sent_acks, s->retransmitted);
2246
2247 ret += tipc_snprintf(buf + ret, buf_size - ret,
2248 " Congestion link:%u Send queue"
2249 " max:%u avg:%u\n", s->link_congs,
2250 s->max_queue_sz, s->queue_sz_counts ?
2251 (s->accu_queue_sz / s->queue_sz_counts) : 0);
2252
2253 tipc_node_unlock(node);
2254 return ret;
2255}
2256
2257struct sk_buff *tipc_link_cmd_show_stats(struct net *net,
2258 const void *req_tlv_area,
2259 int req_tlv_space)
2260{
2261 struct sk_buff *buf;
2262 struct tlv_desc *rep_tlv;
2263 int str_len;
2264 int pb_len;
2265 char *pb;
2266
2267 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
2268 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
2269
2270 buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
2271 if (!buf)
2272 return NULL;
2273
2274 rep_tlv = (struct tlv_desc *)buf->data;
2275 pb = TLV_DATA(rep_tlv);
2276 pb_len = ULTRA_STRING_MAX_LEN;
2277 str_len = tipc_link_stats(net, (char *)TLV_DATA(req_tlv_area),
2278 pb, pb_len);
2279 if (!str_len) {
2280 kfree_skb(buf);
2281 return tipc_cfg_reply_error_string("link not found");
2282 }
2283 str_len += 1; /* for "\0" */
2284 skb_put(buf, TLV_SPACE(str_len));
2285 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
2286
2287 return buf;
2288}
2289
2290static void link_print(struct tipc_link *l_ptr, const char *str) 1971static void link_print(struct tipc_link *l_ptr, const char *str)
2291{ 1972{
2292 struct tipc_net *tn = net_generic(l_ptr->owner->net, tipc_net_id); 1973 struct tipc_net *tn = net_generic(l_ptr->owner->net, tipc_net_id);
@@ -2357,7 +2038,7 @@ int tipc_nl_link_set(struct sk_buff *skb, struct genl_info *info)
2357 struct tipc_link *link; 2038 struct tipc_link *link;
2358 struct tipc_node *node; 2039 struct tipc_node *node;
2359 struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; 2040 struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1];
2360 struct net *net = genl_info_net(info); 2041 struct net *net = sock_net(skb->sk);
2361 2042
2362 if (!info->attrs[TIPC_NLA_LINK]) 2043 if (!info->attrs[TIPC_NLA_LINK])
2363 return -EINVAL; 2044 return -EINVAL;
@@ -2498,7 +2179,7 @@ static int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg,
2498 struct nlattr *prop; 2179 struct nlattr *prop;
2499 struct tipc_net *tn = net_generic(net, tipc_net_id); 2180 struct tipc_net *tn = net_generic(net, tipc_net_id);
2500 2181
2501 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family, 2182 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
2502 NLM_F_MULTI, TIPC_NL_LINK_GET); 2183 NLM_F_MULTI, TIPC_NL_LINK_GET);
2503 if (!hdr) 2184 if (!hdr)
2504 return -EMSGSIZE; 2185 return -EMSGSIZE;
@@ -2709,7 +2390,7 @@ int tipc_nl_link_reset_stats(struct sk_buff *skb, struct genl_info *info)
2709 struct tipc_link *link; 2390 struct tipc_link *link;
2710 struct tipc_node *node; 2391 struct tipc_node *node;
2711 struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; 2392 struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1];
2712 struct net *net = genl_info_net(info); 2393 struct net *net = sock_net(skb->sk);
2713 2394
2714 if (!info->attrs[TIPC_NLA_LINK]) 2395 if (!info->attrs[TIPC_NLA_LINK])
2715 return -EINVAL; 2396 return -EINVAL;
diff --git a/net/tipc/link.h b/net/tipc/link.h
index 34d3f55c4cea..7aeb52092bf3 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -215,14 +215,6 @@ void tipc_link_reset_fragments(struct tipc_link *l_ptr);
215int tipc_link_is_up(struct tipc_link *l_ptr); 215int tipc_link_is_up(struct tipc_link *l_ptr);
216int tipc_link_is_active(struct tipc_link *l_ptr); 216int tipc_link_is_active(struct tipc_link *l_ptr);
217void tipc_link_purge_queues(struct tipc_link *l_ptr); 217void tipc_link_purge_queues(struct tipc_link *l_ptr);
218struct sk_buff *tipc_link_cmd_config(struct net *net, const void *req_tlv_area,
219 int req_tlv_space, u16 cmd);
220struct sk_buff *tipc_link_cmd_show_stats(struct net *net,
221 const void *req_tlv_area,
222 int req_tlv_space);
223struct sk_buff *tipc_link_cmd_reset_stats(struct net *net,
224 const void *req_tlv_area,
225 int req_tlv_space);
226void tipc_link_reset_all(struct tipc_node *node); 218void tipc_link_reset_all(struct tipc_node *node);
227void tipc_link_reset(struct tipc_link *l_ptr); 219void tipc_link_reset(struct tipc_link *l_ptr);
228void tipc_link_reset_list(struct net *net, unsigned int bearer_id); 220void tipc_link_reset_list(struct net *net, unsigned int bearer_id);
diff --git a/net/tipc/log.c b/net/tipc/log.c
deleted file mode 100644
index abef644f27d8..000000000000
--- a/net/tipc/log.c
+++ /dev/null
@@ -1,55 +0,0 @@
1/*
2 * net/tipc/log.c: TIPC print buffer routines for debugging
3 *
4 * Copyright (c) 1996-2006, Ericsson AB
5 * Copyright (c) 2005-2007, Wind River Systems
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the names of the copyright holders nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * Alternatively, this software may be distributed under the terms of the
21 * GNU General Public License ("GPL") version 2 as published by the Free
22 * Software Foundation.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#include "core.h"
38#include "config.h"
39
40/**
41 * tipc_snprintf - append formatted output to print buffer
42 * @buf: pointer to print buffer
43 * @len: buffer length
44 * @fmt: formatted info to be printed
45 */
46int tipc_snprintf(char *buf, int len, const char *fmt, ...)
47{
48 int i;
49 va_list args;
50
51 va_start(args, fmt);
52 i = vscnprintf(buf, len, fmt, args);
53 va_end(args);
54 return i;
55}
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index 18a3d44238bc..105ba7adf06f 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -36,11 +36,13 @@
36 36
37#include <net/sock.h> 37#include <net/sock.h>
38#include "core.h" 38#include "core.h"
39#include "config.h" 39#include "netlink.h"
40#include "name_table.h" 40#include "name_table.h"
41#include "name_distr.h" 41#include "name_distr.h"
42#include "subscr.h" 42#include "subscr.h"
43#include "bcast.h" 43#include "bcast.h"
44#include "addr.h"
45#include <net/genetlink.h>
44 46
45#define TIPC_NAMETBL_SIZE 1024 /* must be a power of 2 */ 47#define TIPC_NAMETBL_SIZE 1024 /* must be a power of 2 */
46 48
@@ -773,190 +775,6 @@ void tipc_nametbl_unsubscribe(struct tipc_subscription *s)
773 spin_unlock_bh(&tn->nametbl_lock); 775 spin_unlock_bh(&tn->nametbl_lock);
774} 776}
775 777
776/**
777 * subseq_list - print specified sub-sequence contents into the given buffer
778 */
779static int subseq_list(struct sub_seq *sseq, char *buf, int len, u32 depth,
780 u32 index)
781{
782 char portIdStr[27];
783 const char *scope_str[] = {"", " zone", " cluster", " node"};
784 struct publication *publ;
785 struct name_info *info;
786 int ret;
787
788 ret = tipc_snprintf(buf, len, "%-10u %-10u ", sseq->lower, sseq->upper);
789
790 if (depth == 2) {
791 ret += tipc_snprintf(buf - ret, len + ret, "\n");
792 return ret;
793 }
794
795 info = sseq->info;
796
797 list_for_each_entry(publ, &info->zone_list, zone_list) {
798 sprintf(portIdStr, "<%u.%u.%u:%u>",
799 tipc_zone(publ->node), tipc_cluster(publ->node),
800 tipc_node(publ->node), publ->ref);
801 ret += tipc_snprintf(buf + ret, len - ret, "%-26s ", portIdStr);
802 if (depth > 3) {
803 ret += tipc_snprintf(buf + ret, len - ret, "%-10u %s",
804 publ->key, scope_str[publ->scope]);
805 }
806 if (!list_is_last(&publ->zone_list, &info->zone_list))
807 ret += tipc_snprintf(buf + ret, len - ret,
808 "\n%33s", " ");
809 }
810
811 ret += tipc_snprintf(buf + ret, len - ret, "\n");
812 return ret;
813}
814
815/**
816 * nameseq_list - print specified name sequence contents into the given buffer
817 */
818static int nameseq_list(struct name_seq *seq, char *buf, int len, u32 depth,
819 u32 type, u32 lowbound, u32 upbound, u32 index)
820{
821 struct sub_seq *sseq;
822 char typearea[11];
823 int ret = 0;
824
825 if (seq->first_free == 0)
826 return 0;
827
828 sprintf(typearea, "%-10u", seq->type);
829
830 if (depth == 1) {
831 ret += tipc_snprintf(buf, len, "%s\n", typearea);
832 return ret;
833 }
834
835 for (sseq = seq->sseqs; sseq != &seq->sseqs[seq->first_free]; sseq++) {
836 if ((lowbound <= sseq->upper) && (upbound >= sseq->lower)) {
837 ret += tipc_snprintf(buf + ret, len - ret, "%s ",
838 typearea);
839 spin_lock_bh(&seq->lock);
840 ret += subseq_list(sseq, buf + ret, len - ret,
841 depth, index);
842 spin_unlock_bh(&seq->lock);
843 sprintf(typearea, "%10s", " ");
844 }
845 }
846 return ret;
847}
848
849/**
850 * nametbl_header - print name table header into the given buffer
851 */
852static int nametbl_header(char *buf, int len, u32 depth)
853{
854 const char *header[] = {
855 "Type ",
856 "Lower Upper ",
857 "Port Identity ",
858 "Publication Scope"
859 };
860
861 int i;
862 int ret = 0;
863
864 if (depth > 4)
865 depth = 4;
866 for (i = 0; i < depth; i++)
867 ret += tipc_snprintf(buf + ret, len - ret, header[i]);
868 ret += tipc_snprintf(buf + ret, len - ret, "\n");
869 return ret;
870}
871
872/**
873 * nametbl_list - print specified name table contents into the given buffer
874 */
875static int nametbl_list(struct net *net, char *buf, int len, u32 depth_info,
876 u32 type, u32 lowbound, u32 upbound)
877{
878 struct tipc_net *tn = net_generic(net, tipc_net_id);
879 struct hlist_head *seq_head;
880 struct name_seq *seq;
881 int all_types;
882 int ret = 0;
883 u32 depth;
884 u32 i;
885
886 all_types = (depth_info & TIPC_NTQ_ALLTYPES);
887 depth = (depth_info & ~TIPC_NTQ_ALLTYPES);
888
889 if (depth == 0)
890 return 0;
891
892 if (all_types) {
893 /* display all entries in name table to specified depth */
894 ret += nametbl_header(buf, len, depth);
895 lowbound = 0;
896 upbound = ~0;
897 for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
898 seq_head = &tn->nametbl->seq_hlist[i];
899 hlist_for_each_entry_rcu(seq, seq_head, ns_list) {
900 ret += nameseq_list(seq, buf + ret, len - ret,
901 depth, seq->type,
902 lowbound, upbound, i);
903 }
904 }
905 } else {
906 /* display only the sequence that matches the specified type */
907 if (upbound < lowbound) {
908 ret += tipc_snprintf(buf + ret, len - ret,
909 "invalid name sequence specified\n");
910 return ret;
911 }
912 ret += nametbl_header(buf + ret, len - ret, depth);
913 i = hash(type);
914 seq_head = &tn->nametbl->seq_hlist[i];
915 hlist_for_each_entry_rcu(seq, seq_head, ns_list) {
916 if (seq->type == type) {
917 ret += nameseq_list(seq, buf + ret, len - ret,
918 depth, type,
919 lowbound, upbound, i);
920 break;
921 }
922 }
923 }
924 return ret;
925}
926
927struct sk_buff *tipc_nametbl_get(struct net *net, const void *req_tlv_area,
928 int req_tlv_space)
929{
930 struct sk_buff *buf;
931 struct tipc_name_table_query *argv;
932 struct tlv_desc *rep_tlv;
933 char *pb;
934 int pb_len;
935 int str_len;
936
937 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NAME_TBL_QUERY))
938 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
939
940 buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
941 if (!buf)
942 return NULL;
943
944 rep_tlv = (struct tlv_desc *)buf->data;
945 pb = TLV_DATA(rep_tlv);
946 pb_len = ULTRA_STRING_MAX_LEN;
947 argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area);
948 rcu_read_lock();
949 str_len = nametbl_list(net, pb, pb_len, ntohl(argv->depth),
950 ntohl(argv->type),
951 ntohl(argv->lowbound), ntohl(argv->upbound));
952 rcu_read_unlock();
953 str_len += 1; /* for "\0" */
954 skb_put(buf, TLV_SPACE(str_len));
955 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
956
957 return buf;
958}
959
960int tipc_nametbl_init(struct net *net) 778int tipc_nametbl_init(struct net *net)
961{ 779{
962 struct tipc_net *tn = net_generic(net, tipc_net_id); 780 struct tipc_net *tn = net_generic(net, tipc_net_id);
@@ -1055,7 +873,7 @@ static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg,
1055 *last_publ = p->key; 873 *last_publ = p->key;
1056 874
1057 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, 875 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq,
1058 &tipc_genl_v2_family, NLM_F_MULTI, 876 &tipc_genl_family, NLM_F_MULTI,
1059 TIPC_NL_NAME_TABLE_GET); 877 TIPC_NL_NAME_TABLE_GET);
1060 if (!hdr) 878 if (!hdr)
1061 return -EMSGSIZE; 879 return -EMSGSIZE;
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h
index 0304ddc6b101..1524a73830f7 100644
--- a/net/tipc/name_table.h
+++ b/net/tipc/name_table.h
@@ -97,8 +97,6 @@ struct name_table {
97 97
98int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb); 98int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb);
99 99
100struct sk_buff *tipc_nametbl_get(struct net *net, const void *req_tlv_area,
101 int req_tlv_space);
102u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance, u32 *node); 100u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance, u32 *node);
103int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper, 101int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
104 u32 limit, struct tipc_plist *dports); 102 u32 limit, struct tipc_plist *dports);
diff --git a/net/tipc/net.c b/net/tipc/net.c
index 263267e0e7fe..a54f3cbe2246 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -40,8 +40,6 @@
40#include "subscr.h" 40#include "subscr.h"
41#include "socket.h" 41#include "socket.h"
42#include "node.h" 42#include "node.h"
43#include "config.h"
44#include "bcast.h"
45 43
46static const struct nla_policy tipc_nl_net_policy[TIPC_NLA_NET_MAX + 1] = { 44static const struct nla_policy tipc_nl_net_policy[TIPC_NLA_NET_MAX + 1] = {
47 [TIPC_NLA_NET_UNSPEC] = { .type = NLA_UNSPEC }, 45 [TIPC_NLA_NET_UNSPEC] = { .type = NLA_UNSPEC },
@@ -156,7 +154,7 @@ static int __tipc_nl_add_net(struct net *net, struct tipc_nl_msg *msg)
156 void *hdr; 154 void *hdr;
157 struct nlattr *attrs; 155 struct nlattr *attrs;
158 156
159 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family, 157 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
160 NLM_F_MULTI, TIPC_NL_NET_GET); 158 NLM_F_MULTI, TIPC_NL_NET_GET);
161 if (!hdr) 159 if (!hdr)
162 return -EMSGSIZE; 160 return -EMSGSIZE;
@@ -208,7 +206,7 @@ out:
208 206
209int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info) 207int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
210{ 208{
211 struct net *net = genl_info_net(info); 209 struct net *net = sock_net(skb->sk);
212 struct tipc_net *tn = net_generic(net, tipc_net_id); 210 struct tipc_net *tn = net_generic(net, tipc_net_id);
213 struct nlattr *attrs[TIPC_NLA_NET_MAX + 1]; 211 struct nlattr *attrs[TIPC_NLA_NET_MAX + 1];
214 int err; 212 int err;
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
index fe0f5134ce15..7f6475efc984 100644
--- a/net/tipc/netlink.c
+++ b/net/tipc/netlink.c
@@ -35,7 +35,6 @@
35 */ 35 */
36 36
37#include "core.h" 37#include "core.h"
38#include "config.h"
39#include "socket.h" 38#include "socket.h"
40#include "name_table.h" 39#include "name_table.h"
41#include "bearer.h" 40#include "bearer.h"
@@ -44,39 +43,6 @@
44#include "net.h" 43#include "net.h"
45#include <net/genetlink.h> 44#include <net/genetlink.h>
46 45
47static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
48{
49 struct net *net = genl_info_net(info);
50 struct sk_buff *rep_buf;
51 struct nlmsghdr *rep_nlh;
52 struct nlmsghdr *req_nlh = info->nlhdr;
53 struct tipc_genlmsghdr *req_userhdr = info->userhdr;
54 int hdr_space = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
55 u16 cmd;
56
57 if ((req_userhdr->cmd & 0xC000) &&
58 (!netlink_net_capable(skb, CAP_NET_ADMIN)))
59 cmd = TIPC_CMD_NOT_NET_ADMIN;
60 else
61 cmd = req_userhdr->cmd;
62
63 rep_buf = tipc_cfg_do_cmd(net, req_userhdr->dest, cmd,
64 nlmsg_data(req_nlh) + GENL_HDRLEN +
65 TIPC_GENL_HDRLEN,
66 nlmsg_attrlen(req_nlh, GENL_HDRLEN +
67 TIPC_GENL_HDRLEN), hdr_space);
68
69 if (rep_buf) {
70 skb_push(rep_buf, hdr_space);
71 rep_nlh = nlmsg_hdr(rep_buf);
72 memcpy(rep_nlh, req_nlh, hdr_space);
73 rep_nlh->nlmsg_len = rep_buf->len;
74 genlmsg_unicast(net, rep_buf, NETLINK_CB(skb).portid);
75 }
76
77 return 0;
78}
79
80static const struct nla_policy tipc_nl_policy[TIPC_NLA_MAX + 1] = { 46static const struct nla_policy tipc_nl_policy[TIPC_NLA_MAX + 1] = {
81 [TIPC_NLA_UNSPEC] = { .type = NLA_UNSPEC, }, 47 [TIPC_NLA_UNSPEC] = { .type = NLA_UNSPEC, },
82 [TIPC_NLA_BEARER] = { .type = NLA_NESTED, }, 48 [TIPC_NLA_BEARER] = { .type = NLA_NESTED, },
@@ -89,28 +55,10 @@ static const struct nla_policy tipc_nl_policy[TIPC_NLA_MAX + 1] = {
89 [TIPC_NLA_NAME_TABLE] = { .type = NLA_NESTED, } 55 [TIPC_NLA_NAME_TABLE] = { .type = NLA_NESTED, }
90}; 56};
91 57
92/* Legacy ASCII API */
93static struct genl_family tipc_genl_family = {
94 .id = GENL_ID_GENERATE,
95 .name = TIPC_GENL_NAME,
96 .version = TIPC_GENL_VERSION,
97 .hdrsize = TIPC_GENL_HDRLEN,
98 .maxattr = 0,
99 .netnsok = true,
100};
101
102/* Legacy ASCII API */
103static struct genl_ops tipc_genl_ops[] = {
104 {
105 .cmd = TIPC_GENL_CMD,
106 .doit = handle_cmd,
107 },
108};
109
110/* Users of the legacy API (tipc-config) can't handle that we add operations, 58/* Users of the legacy API (tipc-config) can't handle that we add operations,
111 * so we have a separate genl handling for the new API. 59 * so we have a separate genl handling for the new API.
112 */ 60 */
113struct genl_family tipc_genl_v2_family = { 61struct genl_family tipc_genl_family = {
114 .id = GENL_ID_GENERATE, 62 .id = GENL_ID_GENERATE,
115 .name = TIPC_GENL_V2_NAME, 63 .name = TIPC_GENL_V2_NAME,
116 .version = TIPC_GENL_V2_VERSION, 64 .version = TIPC_GENL_V2_VERSION,
@@ -202,9 +150,9 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
202 150
203int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***attr) 151int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***attr)
204{ 152{
205 u32 maxattr = tipc_genl_v2_family.maxattr; 153 u32 maxattr = tipc_genl_family.maxattr;
206 154
207 *attr = tipc_genl_v2_family.attrbuf; 155 *attr = tipc_genl_family.attrbuf;
208 if (!*attr) 156 if (!*attr)
209 return -EOPNOTSUPP; 157 return -EOPNOTSUPP;
210 158
@@ -215,13 +163,7 @@ int tipc_netlink_start(void)
215{ 163{
216 int res; 164 int res;
217 165
218 res = genl_register_family_with_ops(&tipc_genl_family, tipc_genl_ops); 166 res = genl_register_family_with_ops(&tipc_genl_family,
219 if (res) {
220 pr_err("Failed to register legacy interface\n");
221 return res;
222 }
223
224 res = genl_register_family_with_ops(&tipc_genl_v2_family,
225 tipc_genl_v2_ops); 167 tipc_genl_v2_ops);
226 if (res) { 168 if (res) {
227 pr_err("Failed to register netlink interface\n"); 169 pr_err("Failed to register netlink interface\n");
@@ -233,5 +175,4 @@ int tipc_netlink_start(void)
233void tipc_netlink_stop(void) 175void tipc_netlink_stop(void)
234{ 176{
235 genl_unregister_family(&tipc_genl_family); 177 genl_unregister_family(&tipc_genl_family);
236 genl_unregister_family(&tipc_genl_v2_family);
237} 178}
diff --git a/net/tipc/netlink.h b/net/tipc/netlink.h
index ae2f2d923a15..08a1db67b927 100644
--- a/net/tipc/netlink.h
+++ b/net/tipc/netlink.h
@@ -36,7 +36,7 @@
36#ifndef _TIPC_NETLINK_H 36#ifndef _TIPC_NETLINK_H
37#define _TIPC_NETLINK_H 37#define _TIPC_NETLINK_H
38 38
39extern struct genl_family tipc_genl_v2_family; 39extern struct genl_family tipc_genl_family;
40int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***buf); 40int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***buf);
41 41
42struct tipc_nl_msg { 42struct tipc_nl_msg {
@@ -46,6 +46,8 @@ struct tipc_nl_msg {
46}; 46};
47 47
48int tipc_netlink_start(void); 48int tipc_netlink_start(void);
49int tipc_netlink_compat_start(void);
49void tipc_netlink_stop(void); 50void tipc_netlink_stop(void);
51void tipc_netlink_compat_stop(void);
50 52
51#endif 53#endif
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c
new file mode 100644
index 000000000000..ce9121e8e990
--- /dev/null
+++ b/net/tipc/netlink_compat.c
@@ -0,0 +1,1084 @@
1/*
2 * Copyright (c) 2014, Ericsson AB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the names of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * Alternatively, this software may be distributed under the terms of the
18 * GNU General Public License ("GPL") version 2 as published by the Free
19 * Software Foundation.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "bearer.h"
36#include "link.h"
37#include "name_table.h"
38#include "socket.h"
39#include "node.h"
40#include "net.h"
41#include <net/genetlink.h>
42#include <linux/tipc_config.h>
43
44/* The legacy API had an artificial message length limit called
45 * ULTRA_STRING_MAX_LEN.
46 */
47#define ULTRA_STRING_MAX_LEN 32768
48
49#define TIPC_SKB_MAX TLV_SPACE(ULTRA_STRING_MAX_LEN)
50
51#define REPLY_TRUNCATED "<truncated>\n"
52
53struct tipc_nl_compat_msg {
54 u16 cmd;
55 int rep_type;
56 int rep_size;
57 int req_type;
58 struct sk_buff *rep;
59 struct tlv_desc *req;
60 struct sock *dst_sk;
61};
62
63struct tipc_nl_compat_cmd_dump {
64 int (*header)(struct tipc_nl_compat_msg *);
65 int (*dumpit)(struct sk_buff *, struct netlink_callback *);
66 int (*format)(struct tipc_nl_compat_msg *msg, struct nlattr **attrs);
67};
68
69struct tipc_nl_compat_cmd_doit {
70 int (*doit)(struct sk_buff *skb, struct genl_info *info);
71 int (*transcode)(struct sk_buff *skb, struct tipc_nl_compat_msg *msg);
72};
73
74static int tipc_skb_tailroom(struct sk_buff *skb)
75{
76 int tailroom;
77 int limit;
78
79 tailroom = skb_tailroom(skb);
80 limit = TIPC_SKB_MAX - skb->len;
81
82 if (tailroom < limit)
83 return tailroom;
84
85 return limit;
86}
87
88static int tipc_add_tlv(struct sk_buff *skb, u16 type, void *data, u16 len)
89{
90 struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(skb);
91
92 if (tipc_skb_tailroom(skb) < TLV_SPACE(len))
93 return -EMSGSIZE;
94
95 skb_put(skb, TLV_SPACE(len));
96 tlv->tlv_type = htons(type);
97 tlv->tlv_len = htons(TLV_LENGTH(len));
98 if (len && data)
99 memcpy(TLV_DATA(tlv), data, len);
100
101 return 0;
102}
103
104static void tipc_tlv_init(struct sk_buff *skb, u16 type)
105{
106 struct tlv_desc *tlv = (struct tlv_desc *)skb->data;
107
108 TLV_SET_LEN(tlv, 0);
109 TLV_SET_TYPE(tlv, type);
110 skb_put(skb, sizeof(struct tlv_desc));
111}
112
113static int tipc_tlv_sprintf(struct sk_buff *skb, const char *fmt, ...)
114{
115 int n;
116 u16 len;
117 u32 rem;
118 char *buf;
119 struct tlv_desc *tlv;
120 va_list args;
121
122 rem = tipc_skb_tailroom(skb);
123
124 tlv = (struct tlv_desc *)skb->data;
125 len = TLV_GET_LEN(tlv);
126 buf = TLV_DATA(tlv) + len;
127
128 va_start(args, fmt);
129 n = vscnprintf(buf, rem, fmt, args);
130 va_end(args);
131
132 TLV_SET_LEN(tlv, n + len);
133 skb_put(skb, n);
134
135 return n;
136}
137
138static struct sk_buff *tipc_tlv_alloc(int size)
139{
140 int hdr_len;
141 struct sk_buff *buf;
142
143 size = TLV_SPACE(size);
144 hdr_len = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
145
146 buf = alloc_skb(hdr_len + size, GFP_KERNEL);
147 if (!buf)
148 return NULL;
149
150 skb_reserve(buf, hdr_len);
151
152 return buf;
153}
154
155static struct sk_buff *tipc_get_err_tlv(char *str)
156{
157 int str_len = strlen(str) + 1;
158 struct sk_buff *buf;
159
160 buf = tipc_tlv_alloc(TLV_SPACE(str_len));
161 if (buf)
162 tipc_add_tlv(buf, TIPC_TLV_ERROR_STRING, str, str_len);
163
164 return buf;
165}
166
167static int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
168 struct tipc_nl_compat_msg *msg,
169 struct sk_buff *arg)
170{
171 int len = 0;
172 int err;
173 struct sk_buff *buf;
174 struct nlmsghdr *nlmsg;
175 struct netlink_callback cb;
176
177 memset(&cb, 0, sizeof(cb));
178 cb.nlh = (struct nlmsghdr *)arg->data;
179 cb.skb = arg;
180
181 buf = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
182 if (!buf)
183 return -ENOMEM;
184
185 buf->sk = msg->dst_sk;
186
187 do {
188 int rem;
189
190 len = (*cmd->dumpit)(buf, &cb);
191
192 nlmsg_for_each_msg(nlmsg, nlmsg_hdr(buf), len, rem) {
193 struct nlattr **attrs;
194
195 err = tipc_nlmsg_parse(nlmsg, &attrs);
196 if (err)
197 goto err_out;
198
199 err = (*cmd->format)(msg, attrs);
200 if (err)
201 goto err_out;
202
203 if (tipc_skb_tailroom(msg->rep) <= 1) {
204 err = -EMSGSIZE;
205 goto err_out;
206 }
207 }
208
209 skb_reset_tail_pointer(buf);
210 buf->len = 0;
211
212 } while (len);
213
214 err = 0;
215
216err_out:
217 kfree_skb(buf);
218
219 if (err == -EMSGSIZE) {
220 /* The legacy API only considered messages filling
221 * "ULTRA_STRING_MAX_LEN" to be truncated.
222 */
223 if ((TIPC_SKB_MAX - msg->rep->len) <= 1) {
224 char *tail = skb_tail_pointer(msg->rep);
225
226 if (*tail != '\0')
227 sprintf(tail - sizeof(REPLY_TRUNCATED) - 1,
228 REPLY_TRUNCATED);
229 }
230
231 return 0;
232 }
233
234 return err;
235}
236
237static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
238 struct tipc_nl_compat_msg *msg)
239{
240 int err;
241 struct sk_buff *arg;
242
243 if (msg->req_type && !TLV_CHECK_TYPE(msg->req, msg->req_type))
244 return -EINVAL;
245
246 msg->rep = tipc_tlv_alloc(msg->rep_size);
247 if (!msg->rep)
248 return -ENOMEM;
249
250 if (msg->rep_type)
251 tipc_tlv_init(msg->rep, msg->rep_type);
252
253 if (cmd->header)
254 (*cmd->header)(msg);
255
256 arg = nlmsg_new(0, GFP_KERNEL);
257 if (!arg) {
258 kfree_skb(msg->rep);
259 return -ENOMEM;
260 }
261
262 err = __tipc_nl_compat_dumpit(cmd, msg, arg);
263 if (err)
264 kfree_skb(msg->rep);
265
266 kfree_skb(arg);
267
268 return err;
269}
270
271static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
272 struct tipc_nl_compat_msg *msg)
273{
274 int err;
275 struct sk_buff *doit_buf;
276 struct sk_buff *trans_buf;
277 struct nlattr **attrbuf;
278 struct genl_info info;
279
280 trans_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
281 if (!trans_buf)
282 return -ENOMEM;
283
284 err = (*cmd->transcode)(trans_buf, msg);
285 if (err)
286 goto trans_out;
287
288 attrbuf = kmalloc((tipc_genl_family.maxattr + 1) *
289 sizeof(struct nlattr *), GFP_KERNEL);
290 if (!attrbuf) {
291 err = -ENOMEM;
292 goto trans_out;
293 }
294
295 err = nla_parse(attrbuf, tipc_genl_family.maxattr,
296 (const struct nlattr *)trans_buf->data,
297 trans_buf->len, NULL);
298 if (err)
299 goto parse_out;
300
301 doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
302 if (!doit_buf) {
303 err = -ENOMEM;
304 goto parse_out;
305 }
306
307 doit_buf->sk = msg->dst_sk;
308
309 memset(&info, 0, sizeof(info));
310 info.attrs = attrbuf;
311
312 err = (*cmd->doit)(doit_buf, &info);
313
314 kfree_skb(doit_buf);
315parse_out:
316 kfree(attrbuf);
317trans_out:
318 kfree_skb(trans_buf);
319
320 return err;
321}
322
323static int tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
324 struct tipc_nl_compat_msg *msg)
325{
326 int err;
327
328 if (msg->req_type && !TLV_CHECK_TYPE(msg->req, msg->req_type))
329 return -EINVAL;
330
331 err = __tipc_nl_compat_doit(cmd, msg);
332 if (err)
333 return err;
334
335 /* The legacy API considered an empty message a success message */
336 msg->rep = tipc_tlv_alloc(0);
337 if (!msg->rep)
338 return -ENOMEM;
339
340 return 0;
341}
342
343static int tipc_nl_compat_bearer_dump(struct tipc_nl_compat_msg *msg,
344 struct nlattr **attrs)
345{
346 struct nlattr *bearer[TIPC_NLA_BEARER_MAX + 1];
347
348 nla_parse_nested(bearer, TIPC_NLA_BEARER_MAX, attrs[TIPC_NLA_BEARER],
349 NULL);
350
351 return tipc_add_tlv(msg->rep, TIPC_TLV_BEARER_NAME,
352 nla_data(bearer[TIPC_NLA_BEARER_NAME]),
353 nla_len(bearer[TIPC_NLA_BEARER_NAME]));
354}
355
356static int tipc_nl_compat_bearer_enable(struct sk_buff *skb,
357 struct tipc_nl_compat_msg *msg)
358{
359 struct nlattr *prop;
360 struct nlattr *bearer;
361 struct tipc_bearer_config *b;
362
363 b = (struct tipc_bearer_config *)TLV_DATA(msg->req);
364
365 bearer = nla_nest_start(skb, TIPC_NLA_BEARER);
366 if (!bearer)
367 return -EMSGSIZE;
368
369 if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, b->name))
370 return -EMSGSIZE;
371
372 if (nla_put_u32(skb, TIPC_NLA_BEARER_DOMAIN, ntohl(b->disc_domain)))
373 return -EMSGSIZE;
374
375 if (ntohl(b->priority) <= TIPC_MAX_LINK_PRI) {
376 prop = nla_nest_start(skb, TIPC_NLA_BEARER_PROP);
377 if (!prop)
378 return -EMSGSIZE;
379 if (nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(b->priority)))
380 return -EMSGSIZE;
381 nla_nest_end(skb, prop);
382 }
383 nla_nest_end(skb, bearer);
384
385 return 0;
386}
387
388static int tipc_nl_compat_bearer_disable(struct sk_buff *skb,
389 struct tipc_nl_compat_msg *msg)
390{
391 char *name;
392 struct nlattr *bearer;
393
394 name = (char *)TLV_DATA(msg->req);
395
396 bearer = nla_nest_start(skb, TIPC_NLA_BEARER);
397 if (!bearer)
398 return -EMSGSIZE;
399
400 if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, name))
401 return -EMSGSIZE;
402
403 nla_nest_end(skb, bearer);
404
405 return 0;
406}
407
408static inline u32 perc(u32 count, u32 total)
409{
410 return (count * 100 + (total / 2)) / total;
411}
412
413static void __fill_bc_link_stat(struct tipc_nl_compat_msg *msg,
414 struct nlattr *prop[], struct nlattr *stats[])
415{
416 tipc_tlv_sprintf(msg->rep, " Window:%u packets\n",
417 nla_get_u32(prop[TIPC_NLA_PROP_WIN]));
418
419 tipc_tlv_sprintf(msg->rep,
420 " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
421 nla_get_u32(stats[TIPC_NLA_STATS_RX_INFO]),
422 nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]),
423 nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]),
424 nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]),
425 nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED]));
426
427 tipc_tlv_sprintf(msg->rep,
428 " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
429 nla_get_u32(stats[TIPC_NLA_STATS_TX_INFO]),
430 nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]),
431 nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]),
432 nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]),
433 nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED]));
434
435 tipc_tlv_sprintf(msg->rep, " RX naks:%u defs:%u dups:%u\n",
436 nla_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]),
437 nla_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]),
438 nla_get_u32(stats[TIPC_NLA_STATS_DUPLICATES]));
439
440 tipc_tlv_sprintf(msg->rep, " TX naks:%u acks:%u dups:%u\n",
441 nla_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]),
442 nla_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]),
443 nla_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED]));
444
445 tipc_tlv_sprintf(msg->rep,
446 " Congestion link:%u Send queue max:%u avg:%u",
447 nla_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]),
448 nla_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]),
449 nla_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE]));
450}
451
452static int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg,
453 struct nlattr **attrs)
454{
455 char *name;
456 struct nlattr *link[TIPC_NLA_LINK_MAX + 1];
457 struct nlattr *prop[TIPC_NLA_PROP_MAX + 1];
458 struct nlattr *stats[TIPC_NLA_STATS_MAX + 1];
459
460 nla_parse_nested(link, TIPC_NLA_LINK_MAX, attrs[TIPC_NLA_LINK], NULL);
461
462 nla_parse_nested(prop, TIPC_NLA_PROP_MAX, link[TIPC_NLA_LINK_PROP],
463 NULL);
464
465 nla_parse_nested(stats, TIPC_NLA_STATS_MAX, link[TIPC_NLA_LINK_STATS],
466 NULL);
467
468 name = (char *)TLV_DATA(msg->req);
469 if (strcmp(name, nla_data(link[TIPC_NLA_LINK_NAME])) != 0)
470 return 0;
471
472 tipc_tlv_sprintf(msg->rep, "\nLink <%s>\n",
473 nla_data(link[TIPC_NLA_LINK_NAME]));
474
475 if (link[TIPC_NLA_LINK_BROADCAST]) {
476 __fill_bc_link_stat(msg, prop, stats);
477 return 0;
478 }
479
480 if (link[TIPC_NLA_LINK_ACTIVE])
481 tipc_tlv_sprintf(msg->rep, " ACTIVE");
482 else if (link[TIPC_NLA_LINK_UP])
483 tipc_tlv_sprintf(msg->rep, " STANDBY");
484 else
485 tipc_tlv_sprintf(msg->rep, " DEFUNCT");
486
487 tipc_tlv_sprintf(msg->rep, " MTU:%u Priority:%u",
488 nla_get_u32(link[TIPC_NLA_LINK_MTU]),
489 nla_get_u32(prop[TIPC_NLA_PROP_PRIO]));
490
491 tipc_tlv_sprintf(msg->rep, " Tolerance:%u ms Window:%u packets\n",
492 nla_get_u32(prop[TIPC_NLA_PROP_TOL]),
493 nla_get_u32(prop[TIPC_NLA_PROP_WIN]));
494
495 tipc_tlv_sprintf(msg->rep,
496 " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
497 nla_get_u32(link[TIPC_NLA_LINK_RX]) -
498 nla_get_u32(stats[TIPC_NLA_STATS_RX_INFO]),
499 nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]),
500 nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]),
501 nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]),
502 nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED]));
503
504 tipc_tlv_sprintf(msg->rep,
505 " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
506 nla_get_u32(link[TIPC_NLA_LINK_TX]) -
507 nla_get_u32(stats[TIPC_NLA_STATS_TX_INFO]),
508 nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]),
509 nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]),
510 nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]),
511 nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED]));
512
513 tipc_tlv_sprintf(msg->rep,
514 " TX profile sample:%u packets average:%u octets\n",
515 nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_CNT]),
516 nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_TOT]) /
517 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT]));
518
519 tipc_tlv_sprintf(msg->rep,
520 " 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% ",
521 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P0]),
522 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
523 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P1]),
524 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
525 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P2]),
526 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
527 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P3]),
528 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])));
529
530 tipc_tlv_sprintf(msg->rep, "-16384:%u%% -32768:%u%% -66000:%u%%\n",
531 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P4]),
532 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
533 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P5]),
534 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
535 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P6]),
536 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])));
537
538 tipc_tlv_sprintf(msg->rep,
539 " RX states:%u probes:%u naks:%u defs:%u dups:%u\n",
540 nla_get_u32(stats[TIPC_NLA_STATS_RX_STATES]),
541 nla_get_u32(stats[TIPC_NLA_STATS_RX_PROBES]),
542 nla_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]),
543 nla_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]),
544 nla_get_u32(stats[TIPC_NLA_STATS_DUPLICATES]));
545
546 tipc_tlv_sprintf(msg->rep,
547 " TX states:%u probes:%u naks:%u acks:%u dups:%u\n",
548 nla_get_u32(stats[TIPC_NLA_STATS_TX_STATES]),
549 nla_get_u32(stats[TIPC_NLA_STATS_TX_PROBES]),
550 nla_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]),
551 nla_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]),
552 nla_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED]));
553
554 tipc_tlv_sprintf(msg->rep,
555 " Congestion link:%u Send queue max:%u avg:%u",
556 nla_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]),
557 nla_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]),
558 nla_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE]));
559
560 return 0;
561}
562
563static int tipc_nl_compat_link_dump(struct tipc_nl_compat_msg *msg,
564 struct nlattr **attrs)
565{
566 struct nlattr *link[TIPC_NLA_LINK_MAX + 1];
567 struct tipc_link_info link_info;
568
569 nla_parse_nested(link, TIPC_NLA_LINK_MAX, attrs[TIPC_NLA_LINK], NULL);
570
571 link_info.dest = nla_get_flag(link[TIPC_NLA_LINK_DEST]);
572 link_info.up = htonl(nla_get_flag(link[TIPC_NLA_LINK_UP]));
573 strcpy(link_info.str, nla_data(link[TIPC_NLA_LINK_NAME]));
574
575 return tipc_add_tlv(msg->rep, TIPC_TLV_LINK_INFO,
576 &link_info, sizeof(link_info));
577}
578
579static int tipc_nl_compat_link_set(struct sk_buff *skb,
580 struct tipc_nl_compat_msg *msg)
581{
582 struct nlattr *link;
583 struct nlattr *prop;
584 struct tipc_link_config *lc;
585
586 lc = (struct tipc_link_config *)TLV_DATA(msg->req);
587
588 link = nla_nest_start(skb, TIPC_NLA_LINK);
589 if (!link)
590 return -EMSGSIZE;
591
592 if (nla_put_string(skb, TIPC_NLA_LINK_NAME, lc->name))
593 return -EMSGSIZE;
594
595 prop = nla_nest_start(skb, TIPC_NLA_LINK_PROP);
596 if (!prop)
597 return -EMSGSIZE;
598
599 if (msg->cmd == TIPC_CMD_SET_LINK_PRI) {
600 if (nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(lc->value)))
601 return -EMSGSIZE;
602 } else if (msg->cmd == TIPC_CMD_SET_LINK_TOL) {
603 if (nla_put_u32(skb, TIPC_NLA_PROP_TOL, ntohl(lc->value)))
604 return -EMSGSIZE;
605 } else if (msg->cmd == TIPC_CMD_SET_LINK_WINDOW) {
606 if (nla_put_u32(skb, TIPC_NLA_PROP_WIN, ntohl(lc->value)))
607 return -EMSGSIZE;
608 }
609
610 nla_nest_end(skb, prop);
611 nla_nest_end(skb, link);
612
613 return 0;
614}
615
616static int tipc_nl_compat_link_reset_stats(struct sk_buff *skb,
617 struct tipc_nl_compat_msg *msg)
618{
619 char *name;
620 struct nlattr *link;
621
622 name = (char *)TLV_DATA(msg->req);
623
624 link = nla_nest_start(skb, TIPC_NLA_LINK);
625 if (!link)
626 return -EMSGSIZE;
627
628 if (nla_put_string(skb, TIPC_NLA_LINK_NAME, name))
629 return -EMSGSIZE;
630
631 nla_nest_end(skb, link);
632
633 return 0;
634}
635
636static int tipc_nl_compat_name_table_dump_header(struct tipc_nl_compat_msg *msg)
637{
638 int i;
639 u32 depth;
640 struct tipc_name_table_query *ntq;
641 static const char * const header[] = {
642 "Type ",
643 "Lower Upper ",
644 "Port Identity ",
645 "Publication Scope"
646 };
647
648 ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req);
649
650 depth = ntohl(ntq->depth);
651
652 if (depth > 4)
653 depth = 4;
654 for (i = 0; i < depth; i++)
655 tipc_tlv_sprintf(msg->rep, header[i]);
656 tipc_tlv_sprintf(msg->rep, "\n");
657
658 return 0;
659}
660
661static int tipc_nl_compat_name_table_dump(struct tipc_nl_compat_msg *msg,
662 struct nlattr **attrs)
663{
664 char port_str[27];
665 struct tipc_name_table_query *ntq;
666 struct nlattr *nt[TIPC_NLA_NAME_TABLE_MAX + 1];
667 struct nlattr *publ[TIPC_NLA_PUBL_MAX + 1];
668 u32 node, depth, type, lowbound, upbound;
669 static const char * const scope_str[] = {"", " zone", " cluster",
670 " node"};
671
672 nla_parse_nested(nt, TIPC_NLA_NAME_TABLE_MAX,
673 attrs[TIPC_NLA_NAME_TABLE], NULL);
674
675 nla_parse_nested(publ, TIPC_NLA_PUBL_MAX, nt[TIPC_NLA_NAME_TABLE_PUBL],
676 NULL);
677
678 ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req);
679
680 depth = ntohl(ntq->depth);
681 type = ntohl(ntq->type);
682 lowbound = ntohl(ntq->lowbound);
683 upbound = ntohl(ntq->upbound);
684
685 if (!(depth & TIPC_NTQ_ALLTYPES) &&
686 (type != nla_get_u32(publ[TIPC_NLA_PUBL_TYPE])))
687 return 0;
688 if (lowbound && (lowbound > nla_get_u32(publ[TIPC_NLA_PUBL_UPPER])))
689 return 0;
690 if (upbound && (upbound < nla_get_u32(publ[TIPC_NLA_PUBL_LOWER])))
691 return 0;
692
693 tipc_tlv_sprintf(msg->rep, "%-10u ",
694 nla_get_u32(publ[TIPC_NLA_PUBL_TYPE]));
695
696 if (depth == 1)
697 goto out;
698
699 tipc_tlv_sprintf(msg->rep, "%-10u %-10u ",
700 nla_get_u32(publ[TIPC_NLA_PUBL_LOWER]),
701 nla_get_u32(publ[TIPC_NLA_PUBL_UPPER]));
702
703 if (depth == 2)
704 goto out;
705
706 node = nla_get_u32(publ[TIPC_NLA_PUBL_NODE]);
707 sprintf(port_str, "<%u.%u.%u:%u>", tipc_zone(node), tipc_cluster(node),
708 tipc_node(node), nla_get_u32(publ[TIPC_NLA_PUBL_REF]));
709 tipc_tlv_sprintf(msg->rep, "%-26s ", port_str);
710
711 if (depth == 3)
712 goto out;
713
714 tipc_tlv_sprintf(msg->rep, "%-10u %s",
715 nla_get_u32(publ[TIPC_NLA_PUBL_REF]),
716 scope_str[nla_get_u32(publ[TIPC_NLA_PUBL_SCOPE])]);
717out:
718 tipc_tlv_sprintf(msg->rep, "\n");
719
720 return 0;
721}
722
723static int __tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg *msg,
724 struct nlattr **attrs)
725{
726 u32 type, lower, upper;
727 struct nlattr *publ[TIPC_NLA_PUBL_MAX + 1];
728
729 nla_parse_nested(publ, TIPC_NLA_PUBL_MAX, attrs[TIPC_NLA_PUBL], NULL);
730
731 type = nla_get_u32(publ[TIPC_NLA_PUBL_TYPE]);
732 lower = nla_get_u32(publ[TIPC_NLA_PUBL_LOWER]);
733 upper = nla_get_u32(publ[TIPC_NLA_PUBL_UPPER]);
734
735 if (lower == upper)
736 tipc_tlv_sprintf(msg->rep, " {%u,%u}", type, lower);
737 else
738 tipc_tlv_sprintf(msg->rep, " {%u,%u,%u}", type, lower, upper);
739
740 return 0;
741}
742
743static int tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg *msg, u32 sock)
744{
745 int err;
746 void *hdr;
747 struct nlattr *nest;
748 struct sk_buff *args;
749 struct tipc_nl_compat_cmd_dump dump;
750
751 args = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
752 if (!args)
753 return -ENOMEM;
754
755 hdr = genlmsg_put(args, 0, 0, &tipc_genl_family, NLM_F_MULTI,
756 TIPC_NL_PUBL_GET);
757
758 nest = nla_nest_start(args, TIPC_NLA_SOCK);
759 if (!nest) {
760 kfree_skb(args);
761 return -EMSGSIZE;
762 }
763
764 if (nla_put_u32(args, TIPC_NLA_SOCK_REF, sock)) {
765 kfree_skb(args);
766 return -EMSGSIZE;
767 }
768
769 nla_nest_end(args, nest);
770 genlmsg_end(args, hdr);
771
772 dump.dumpit = tipc_nl_publ_dump;
773 dump.format = __tipc_nl_compat_publ_dump;
774
775 err = __tipc_nl_compat_dumpit(&dump, msg, args);
776
777 kfree_skb(args);
778
779 return err;
780}
781
782static int tipc_nl_compat_sk_dump(struct tipc_nl_compat_msg *msg,
783 struct nlattr **attrs)
784{
785 int err;
786 u32 sock_ref;
787 struct nlattr *sock[TIPC_NLA_SOCK_MAX + 1];
788
789 nla_parse_nested(sock, TIPC_NLA_SOCK_MAX, attrs[TIPC_NLA_SOCK], NULL);
790
791 sock_ref = nla_get_u32(sock[TIPC_NLA_SOCK_REF]);
792 tipc_tlv_sprintf(msg->rep, "%u:", sock_ref);
793
794 if (sock[TIPC_NLA_SOCK_CON]) {
795 u32 node;
796 struct nlattr *con[TIPC_NLA_CON_MAX + 1];
797
798 nla_parse_nested(con, TIPC_NLA_CON_MAX, sock[TIPC_NLA_SOCK_CON],
799 NULL);
800
801 node = nla_get_u32(con[TIPC_NLA_CON_NODE]);
802 tipc_tlv_sprintf(msg->rep, " connected to <%u.%u.%u:%u>",
803 tipc_zone(node),
804 tipc_cluster(node),
805 tipc_node(node),
806 nla_get_u32(con[TIPC_NLA_CON_SOCK]));
807
808 if (con[TIPC_NLA_CON_FLAG])
809 tipc_tlv_sprintf(msg->rep, " via {%u,%u}\n",
810 nla_get_u32(con[TIPC_NLA_CON_TYPE]),
811 nla_get_u32(con[TIPC_NLA_CON_INST]));
812 else
813 tipc_tlv_sprintf(msg->rep, "\n");
814 } else if (sock[TIPC_NLA_SOCK_HAS_PUBL]) {
815 tipc_tlv_sprintf(msg->rep, " bound to");
816
817 err = tipc_nl_compat_publ_dump(msg, sock_ref);
818 if (err)
819 return err;
820 }
821 tipc_tlv_sprintf(msg->rep, "\n");
822
823 return 0;
824}
825
826static int tipc_nl_compat_media_dump(struct tipc_nl_compat_msg *msg,
827 struct nlattr **attrs)
828{
829 struct nlattr *media[TIPC_NLA_MEDIA_MAX + 1];
830
831 nla_parse_nested(media, TIPC_NLA_MEDIA_MAX, attrs[TIPC_NLA_MEDIA],
832 NULL);
833
834 return tipc_add_tlv(msg->rep, TIPC_TLV_MEDIA_NAME,
835 nla_data(media[TIPC_NLA_MEDIA_NAME]),
836 nla_len(media[TIPC_NLA_MEDIA_NAME]));
837}
838
839static int tipc_nl_compat_node_dump(struct tipc_nl_compat_msg *msg,
840 struct nlattr **attrs)
841{
842 struct tipc_node_info node_info;
843 struct nlattr *node[TIPC_NLA_NODE_MAX + 1];
844
845 nla_parse_nested(node, TIPC_NLA_NODE_MAX, attrs[TIPC_NLA_NODE], NULL);
846
847 node_info.addr = htonl(nla_get_u32(node[TIPC_NLA_NODE_ADDR]));
848 node_info.up = htonl(nla_get_flag(node[TIPC_NLA_NODE_UP]));
849
850 return tipc_add_tlv(msg->rep, TIPC_TLV_NODE_INFO, &node_info,
851 sizeof(node_info));
852}
853
854static int tipc_nl_compat_net_set(struct sk_buff *skb,
855 struct tipc_nl_compat_msg *msg)
856{
857 u32 val;
858 struct nlattr *net;
859
860 val = ntohl(*(__be32 *)TLV_DATA(msg->req));
861
862 net = nla_nest_start(skb, TIPC_NLA_NET);
863 if (!net)
864 return -EMSGSIZE;
865
866 if (msg->cmd == TIPC_CMD_SET_NODE_ADDR) {
867 if (nla_put_u32(skb, TIPC_NLA_NET_ADDR, val))
868 return -EMSGSIZE;
869 } else if (msg->cmd == TIPC_CMD_SET_NETID) {
870 if (nla_put_u32(skb, TIPC_NLA_NET_ID, val))
871 return -EMSGSIZE;
872 }
873 nla_nest_end(skb, net);
874
875 return 0;
876}
877
878static int tipc_nl_compat_net_dump(struct tipc_nl_compat_msg *msg,
879 struct nlattr **attrs)
880{
881 __be32 id;
882 struct nlattr *net[TIPC_NLA_NET_MAX + 1];
883
884 nla_parse_nested(net, TIPC_NLA_NET_MAX, attrs[TIPC_NLA_NET], NULL);
885 id = htonl(nla_get_u32(net[TIPC_NLA_NET_ID]));
886
887 return tipc_add_tlv(msg->rep, TIPC_TLV_UNSIGNED, &id, sizeof(id));
888}
889
890static int tipc_cmd_show_stats_compat(struct tipc_nl_compat_msg *msg)
891{
892 msg->rep = tipc_tlv_alloc(ULTRA_STRING_MAX_LEN);
893 if (!msg->rep)
894 return -ENOMEM;
895
896 tipc_tlv_init(msg->rep, TIPC_TLV_ULTRA_STRING);
897 tipc_tlv_sprintf(msg->rep, "TIPC version " TIPC_MOD_VER "\n");
898
899 return 0;
900}
901
902static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
903{
904 struct tipc_nl_compat_cmd_dump dump;
905 struct tipc_nl_compat_cmd_doit doit;
906
907 memset(&dump, 0, sizeof(dump));
908 memset(&doit, 0, sizeof(doit));
909
910 switch (msg->cmd) {
911 case TIPC_CMD_NOOP:
912 msg->rep = tipc_tlv_alloc(0);
913 if (!msg->rep)
914 return -ENOMEM;
915 return 0;
916 case TIPC_CMD_GET_BEARER_NAMES:
917 msg->rep_size = MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME);
918 dump.dumpit = tipc_nl_bearer_dump;
919 dump.format = tipc_nl_compat_bearer_dump;
920 return tipc_nl_compat_dumpit(&dump, msg);
921 case TIPC_CMD_ENABLE_BEARER:
922 msg->req_type = TIPC_TLV_BEARER_CONFIG;
923 doit.doit = tipc_nl_bearer_enable;
924 doit.transcode = tipc_nl_compat_bearer_enable;
925 return tipc_nl_compat_doit(&doit, msg);
926 case TIPC_CMD_DISABLE_BEARER:
927 msg->req_type = TIPC_TLV_BEARER_NAME;
928 doit.doit = tipc_nl_bearer_disable;
929 doit.transcode = tipc_nl_compat_bearer_disable;
930 return tipc_nl_compat_doit(&doit, msg);
931 case TIPC_CMD_SHOW_LINK_STATS:
932 msg->req_type = TIPC_TLV_LINK_NAME;
933 msg->rep_size = ULTRA_STRING_MAX_LEN;
934 msg->rep_type = TIPC_TLV_ULTRA_STRING;
935 dump.dumpit = tipc_nl_link_dump;
936 dump.format = tipc_nl_compat_link_stat_dump;
937 return tipc_nl_compat_dumpit(&dump, msg);
938 case TIPC_CMD_GET_LINKS:
939 msg->req_type = TIPC_TLV_NET_ADDR;
940 msg->rep_size = ULTRA_STRING_MAX_LEN;
941 dump.dumpit = tipc_nl_link_dump;
942 dump.format = tipc_nl_compat_link_dump;
943 return tipc_nl_compat_dumpit(&dump, msg);
944 case TIPC_CMD_SET_LINK_TOL:
945 case TIPC_CMD_SET_LINK_PRI:
946 case TIPC_CMD_SET_LINK_WINDOW:
947 msg->req_type = TIPC_TLV_LINK_CONFIG;
948 doit.doit = tipc_nl_link_set;
949 doit.transcode = tipc_nl_compat_link_set;
950 return tipc_nl_compat_doit(&doit, msg);
951 case TIPC_CMD_RESET_LINK_STATS:
952 msg->req_type = TIPC_TLV_LINK_NAME;
953 doit.doit = tipc_nl_link_reset_stats;
954 doit.transcode = tipc_nl_compat_link_reset_stats;
955 return tipc_nl_compat_doit(&doit, msg);
956 case TIPC_CMD_SHOW_NAME_TABLE:
957 msg->req_type = TIPC_TLV_NAME_TBL_QUERY;
958 msg->rep_size = ULTRA_STRING_MAX_LEN;
959 msg->rep_type = TIPC_TLV_ULTRA_STRING;
960 dump.header = tipc_nl_compat_name_table_dump_header;
961 dump.dumpit = tipc_nl_name_table_dump;
962 dump.format = tipc_nl_compat_name_table_dump;
963 return tipc_nl_compat_dumpit(&dump, msg);
964 case TIPC_CMD_SHOW_PORTS:
965 msg->rep_size = ULTRA_STRING_MAX_LEN;
966 msg->rep_type = TIPC_TLV_ULTRA_STRING;
967 dump.dumpit = tipc_nl_sk_dump;
968 dump.format = tipc_nl_compat_sk_dump;
969 return tipc_nl_compat_dumpit(&dump, msg);
970 case TIPC_CMD_GET_MEDIA_NAMES:
971 msg->rep_size = MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME);
972 dump.dumpit = tipc_nl_media_dump;
973 dump.format = tipc_nl_compat_media_dump;
974 return tipc_nl_compat_dumpit(&dump, msg);
975 case TIPC_CMD_GET_NODES:
976 msg->rep_size = ULTRA_STRING_MAX_LEN;
977 dump.dumpit = tipc_nl_node_dump;
978 dump.format = tipc_nl_compat_node_dump;
979 return tipc_nl_compat_dumpit(&dump, msg);
980 case TIPC_CMD_SET_NODE_ADDR:
981 msg->req_type = TIPC_TLV_NET_ADDR;
982 doit.doit = tipc_nl_net_set;
983 doit.transcode = tipc_nl_compat_net_set;
984 return tipc_nl_compat_doit(&doit, msg);
985 case TIPC_CMD_SET_NETID:
986 msg->req_type = TIPC_TLV_UNSIGNED;
987 doit.doit = tipc_nl_net_set;
988 doit.transcode = tipc_nl_compat_net_set;
989 return tipc_nl_compat_doit(&doit, msg);
990 case TIPC_CMD_GET_NETID:
991 msg->rep_size = sizeof(u32);
992 dump.dumpit = tipc_nl_net_dump;
993 dump.format = tipc_nl_compat_net_dump;
994 return tipc_nl_compat_dumpit(&dump, msg);
995 case TIPC_CMD_SHOW_STATS:
996 return tipc_cmd_show_stats_compat(msg);
997 }
998
999 return -EOPNOTSUPP;
1000}
1001
1002static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info)
1003{
1004 int err;
1005 int len;
1006 struct tipc_nl_compat_msg msg;
1007 struct nlmsghdr *req_nlh;
1008 struct nlmsghdr *rep_nlh;
1009 struct tipc_genlmsghdr *req_userhdr = info->userhdr;
1010 struct net *net = genl_info_net(info);
1011
1012 memset(&msg, 0, sizeof(msg));
1013
1014 req_nlh = (struct nlmsghdr *)skb->data;
1015 msg.req = nlmsg_data(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN;
1016 msg.cmd = req_userhdr->cmd;
1017 msg.dst_sk = info->dst_sk;
1018
1019 if ((msg.cmd & 0xC000) && (!netlink_net_capable(skb, CAP_NET_ADMIN))) {
1020 msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_NET_ADMIN);
1021 err = -EACCES;
1022 goto send;
1023 }
1024
1025 len = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN);
1026 if (TLV_GET_LEN(msg.req) && !TLV_OK(msg.req, len)) {
1027 msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED);
1028 err = -EOPNOTSUPP;
1029 goto send;
1030 }
1031
1032 err = tipc_nl_compat_handle(&msg);
1033 if (err == -EOPNOTSUPP)
1034 msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED);
1035 else if (err == -EINVAL)
1036 msg.rep = tipc_get_err_tlv(TIPC_CFG_TLV_ERROR);
1037send:
1038 if (!msg.rep)
1039 return err;
1040
1041 len = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
1042 skb_push(msg.rep, len);
1043 rep_nlh = nlmsg_hdr(msg.rep);
1044 memcpy(rep_nlh, info->nlhdr, len);
1045 rep_nlh->nlmsg_len = msg.rep->len;
1046 genlmsg_unicast(net, msg.rep, NETLINK_CB(skb).portid);
1047
1048 return err;
1049}
1050
1051static struct genl_family tipc_genl_compat_family = {
1052 .id = GENL_ID_GENERATE,
1053 .name = TIPC_GENL_NAME,
1054 .version = TIPC_GENL_VERSION,
1055 .hdrsize = TIPC_GENL_HDRLEN,
1056 .maxattr = 0,
1057 .netnsok = true,
1058};
1059
1060static struct genl_ops tipc_genl_compat_ops[] = {
1061 {
1062 .cmd = TIPC_GENL_CMD,
1063 .doit = tipc_nl_compat_recv,
1064 },
1065};
1066
1067int tipc_netlink_compat_start(void)
1068{
1069 int res;
1070
1071 res = genl_register_family_with_ops(&tipc_genl_compat_family,
1072 tipc_genl_compat_ops);
1073 if (res) {
1074 pr_err("Failed to register legacy compat interface\n");
1075 return res;
1076 }
1077
1078 return 0;
1079}
1080
1081void tipc_netlink_compat_stop(void)
1082{
1083 genl_unregister_family(&tipc_genl_compat_family);
1084}
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 52308498f208..86152de8248d 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -35,7 +35,7 @@
35 */ 35 */
36 36
37#include "core.h" 37#include "core.h"
38#include "config.h" 38#include "link.h"
39#include "node.h" 39#include "node.h"
40#include "name_distr.h" 40#include "name_distr.h"
41#include "socket.h" 41#include "socket.h"
@@ -120,7 +120,6 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr)
120 list_add_tail_rcu(&n_ptr->list, &temp_node->list); 120 list_add_tail_rcu(&n_ptr->list, &temp_node->list);
121 n_ptr->action_flags = TIPC_WAIT_PEER_LINKS_DOWN; 121 n_ptr->action_flags = TIPC_WAIT_PEER_LINKS_DOWN;
122 n_ptr->signature = INVALID_NODE_SIG; 122 n_ptr->signature = INVALID_NODE_SIG;
123 tn->num_nodes++;
124exit: 123exit:
125 spin_unlock_bh(&tn->node_list_lock); 124 spin_unlock_bh(&tn->node_list_lock);
126 return n_ptr; 125 return n_ptr;
@@ -131,8 +130,6 @@ static void tipc_node_delete(struct tipc_net *tn, struct tipc_node *n_ptr)
131 list_del_rcu(&n_ptr->list); 130 list_del_rcu(&n_ptr->list);
132 hlist_del_rcu(&n_ptr->hash); 131 hlist_del_rcu(&n_ptr->hash);
133 kfree_rcu(n_ptr, rcu); 132 kfree_rcu(n_ptr, rcu);
134
135 tn->num_nodes--;
136} 133}
137 134
138void tipc_node_stop(struct net *net) 135void tipc_node_stop(struct net *net)
@@ -319,27 +316,18 @@ int tipc_node_is_up(struct tipc_node *n_ptr)
319 316
320void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) 317void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
321{ 318{
322 struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
323
324 n_ptr->links[l_ptr->bearer_id] = l_ptr; 319 n_ptr->links[l_ptr->bearer_id] = l_ptr;
325 spin_lock_bh(&tn->node_list_lock);
326 tn->num_links++;
327 spin_unlock_bh(&tn->node_list_lock);
328 n_ptr->link_cnt++; 320 n_ptr->link_cnt++;
329} 321}
330 322
331void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) 323void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
332{ 324{
333 struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
334 int i; 325 int i;
335 326
336 for (i = 0; i < MAX_BEARERS; i++) { 327 for (i = 0; i < MAX_BEARERS; i++) {
337 if (l_ptr != n_ptr->links[i]) 328 if (l_ptr != n_ptr->links[i])
338 continue; 329 continue;
339 n_ptr->links[i] = NULL; 330 n_ptr->links[i] = NULL;
340 spin_lock_bh(&tn->node_list_lock);
341 tn->num_links--;
342 spin_unlock_bh(&tn->node_list_lock);
343 n_ptr->link_cnt--; 331 n_ptr->link_cnt--;
344 } 332 }
345} 333}
@@ -416,121 +404,6 @@ static void node_lost_contact(struct tipc_node *n_ptr)
416 } 404 }
417} 405}
418 406
419struct sk_buff *tipc_node_get_nodes(struct net *net, const void *req_tlv_area,
420 int req_tlv_space)
421{
422 struct tipc_net *tn = net_generic(net, tipc_net_id);
423 u32 domain;
424 struct sk_buff *buf;
425 struct tipc_node *n_ptr;
426 struct tipc_node_info node_info;
427 u32 payload_size;
428
429 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
430 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
431
432 domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
433 if (!tipc_addr_domain_valid(domain))
434 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
435 " (network address)");
436
437 spin_lock_bh(&tn->node_list_lock);
438 if (!tn->num_nodes) {
439 spin_unlock_bh(&tn->node_list_lock);
440 return tipc_cfg_reply_none();
441 }
442
443 /* For now, get space for all other nodes */
444 payload_size = TLV_SPACE(sizeof(node_info)) * tn->num_nodes;
445 if (payload_size > 32768u) {
446 spin_unlock_bh(&tn->node_list_lock);
447 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
448 " (too many nodes)");
449 }
450 spin_unlock_bh(&tn->node_list_lock);
451
452 buf = tipc_cfg_reply_alloc(payload_size);
453 if (!buf)
454 return NULL;
455
456 /* Add TLVs for all nodes in scope */
457 rcu_read_lock();
458 list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {
459 if (!tipc_in_scope(domain, n_ptr->addr))
460 continue;
461 node_info.addr = htonl(n_ptr->addr);
462 node_info.up = htonl(tipc_node_is_up(n_ptr));
463 tipc_cfg_append_tlv(buf, TIPC_TLV_NODE_INFO,
464 &node_info, sizeof(node_info));
465 }
466 rcu_read_unlock();
467 return buf;
468}
469
470struct sk_buff *tipc_node_get_links(struct net *net, const void *req_tlv_area,
471 int req_tlv_space)
472{
473 struct tipc_net *tn = net_generic(net, tipc_net_id);
474 u32 domain;
475 struct sk_buff *buf;
476 struct tipc_node *n_ptr;
477 struct tipc_link_info link_info;
478 u32 payload_size;
479
480 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
481 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
482
483 domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
484 if (!tipc_addr_domain_valid(domain))
485 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
486 " (network address)");
487
488 if (!tn->own_addr)
489 return tipc_cfg_reply_none();
490
491 spin_lock_bh(&tn->node_list_lock);
492 /* Get space for all unicast links + broadcast link */
493 payload_size = TLV_SPACE((sizeof(link_info)) * (tn->num_links + 1));
494 if (payload_size > 32768u) {
495 spin_unlock_bh(&tn->node_list_lock);
496 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
497 " (too many links)");
498 }
499 spin_unlock_bh(&tn->node_list_lock);
500
501 buf = tipc_cfg_reply_alloc(payload_size);
502 if (!buf)
503 return NULL;
504
505 /* Add TLV for broadcast link */
506 link_info.dest = htonl(tipc_cluster_mask(tn->own_addr));
507 link_info.up = htonl(1);
508 strlcpy(link_info.str, tipc_bclink_name, TIPC_MAX_LINK_NAME);
509 tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
510
511 /* Add TLVs for any other links in scope */
512 rcu_read_lock();
513 list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {
514 u32 i;
515
516 if (!tipc_in_scope(domain, n_ptr->addr))
517 continue;
518 tipc_node_lock(n_ptr);
519 for (i = 0; i < MAX_BEARERS; i++) {
520 if (!n_ptr->links[i])
521 continue;
522 link_info.dest = htonl(n_ptr->addr);
523 link_info.up = htonl(tipc_link_is_up(n_ptr->links[i]));
524 strcpy(link_info.str, n_ptr->links[i]->name);
525 tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO,
526 &link_info, sizeof(link_info));
527 }
528 tipc_node_unlock(n_ptr);
529 }
530 rcu_read_unlock();
531 return buf;
532}
533
534/** 407/**
535 * tipc_node_get_linkname - get the name of a link 408 * tipc_node_get_linkname - get the name of a link
536 * 409 *
@@ -623,7 +496,7 @@ static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node)
623 void *hdr; 496 void *hdr;
624 struct nlattr *attrs; 497 struct nlattr *attrs;
625 498
626 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family, 499 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
627 NLM_F_MULTI, TIPC_NL_NODE_GET); 500 NLM_F_MULTI, TIPC_NL_NODE_GET);
628 if (!hdr) 501 if (!hdr)
629 return -EMSGSIZE; 502 return -EMSGSIZE;
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 20ec13f9bede..3d18c66b7f78 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -142,10 +142,6 @@ void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr);
142void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr); 142void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr);
143int tipc_node_active_links(struct tipc_node *n_ptr); 143int tipc_node_active_links(struct tipc_node *n_ptr);
144int tipc_node_is_up(struct tipc_node *n_ptr); 144int tipc_node_is_up(struct tipc_node *n_ptr);
145struct sk_buff *tipc_node_get_links(struct net *net, const void *req_tlv_area,
146 int req_tlv_space);
147struct sk_buff *tipc_node_get_nodes(struct net *net, const void *req_tlv_area,
148 int req_tlv_space);
149int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node, 145int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node,
150 char *linkname, size_t len); 146 char *linkname, size_t len);
151void tipc_node_unlock(struct tipc_node *node); 147void tipc_node_unlock(struct tipc_node *node);
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 4a98d15a1323..f73e975af80b 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -40,7 +40,6 @@
40#include "name_table.h" 40#include "name_table.h"
41#include "node.h" 41#include "node.h"
42#include "link.h" 42#include "link.h"
43#include "config.h"
44#include "name_distr.h" 43#include "name_distr.h"
45#include "socket.h" 44#include "socket.h"
46 45
@@ -2281,91 +2280,6 @@ static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope,
2281 return rc; 2280 return rc;
2282} 2281}
2283 2282
2284static int tipc_sk_show(struct tipc_sock *tsk, char *buf,
2285 int len, int full_id)
2286{
2287 struct net *net = sock_net(&tsk->sk);
2288 struct tipc_net *tn = net_generic(net, tipc_net_id);
2289 struct publication *publ;
2290 int ret;
2291
2292 if (full_id)
2293 ret = tipc_snprintf(buf, len, "<%u.%u.%u:%u>:",
2294 tipc_zone(tn->own_addr),
2295 tipc_cluster(tn->own_addr),
2296 tipc_node(tn->own_addr), tsk->portid);
2297 else
2298 ret = tipc_snprintf(buf, len, "%-10u:", tsk->portid);
2299
2300 if (tsk->connected) {
2301 u32 dport = tsk_peer_port(tsk);
2302 u32 destnode = tsk_peer_node(tsk);
2303
2304 ret += tipc_snprintf(buf + ret, len - ret,
2305 " connected to <%u.%u.%u:%u>",
2306 tipc_zone(destnode),
2307 tipc_cluster(destnode),
2308 tipc_node(destnode), dport);
2309 if (tsk->conn_type != 0)
2310 ret += tipc_snprintf(buf + ret, len - ret,
2311 " via {%u,%u}", tsk->conn_type,
2312 tsk->conn_instance);
2313 } else if (tsk->published) {
2314 ret += tipc_snprintf(buf + ret, len - ret, " bound to");
2315 list_for_each_entry(publ, &tsk->publications, pport_list) {
2316 if (publ->lower == publ->upper)
2317 ret += tipc_snprintf(buf + ret, len - ret,
2318 " {%u,%u}", publ->type,
2319 publ->lower);
2320 else
2321 ret += tipc_snprintf(buf + ret, len - ret,
2322 " {%u,%u,%u}", publ->type,
2323 publ->lower, publ->upper);
2324 }
2325 }
2326 ret += tipc_snprintf(buf + ret, len - ret, "\n");
2327 return ret;
2328}
2329
2330struct sk_buff *tipc_sk_socks_show(struct net *net)
2331{
2332 struct tipc_net *tn = net_generic(net, tipc_net_id);
2333 const struct bucket_table *tbl;
2334 struct rhash_head *pos;
2335 struct sk_buff *buf;
2336 struct tlv_desc *rep_tlv;
2337 char *pb;
2338 int pb_len;
2339 struct tipc_sock *tsk;
2340 int str_len = 0;
2341 int i;
2342
2343 buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
2344 if (!buf)
2345 return NULL;
2346 rep_tlv = (struct tlv_desc *)buf->data;
2347 pb = TLV_DATA(rep_tlv);
2348 pb_len = ULTRA_STRING_MAX_LEN;
2349
2350 rcu_read_lock();
2351 tbl = rht_dereference_rcu((&tn->sk_rht)->tbl, &tn->sk_rht);
2352 for (i = 0; i < tbl->size; i++) {
2353 rht_for_each_entry_rcu(tsk, pos, tbl, i, node) {
2354 spin_lock_bh(&tsk->sk.sk_lock.slock);
2355 str_len += tipc_sk_show(tsk, pb + str_len,
2356 pb_len - str_len, 0);
2357 spin_unlock_bh(&tsk->sk.sk_lock.slock);
2358 }
2359 }
2360 rcu_read_unlock();
2361
2362 str_len += 1; /* for "\0" */
2363 skb_put(buf, TLV_SPACE(str_len));
2364 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
2365
2366 return buf;
2367}
2368
2369/* tipc_sk_reinit: set non-zero address in all existing sockets 2283/* tipc_sk_reinit: set non-zero address in all existing sockets
2370 * when we go from standalone to network mode. 2284 * when we go from standalone to network mode.
2371 */ 2285 */
@@ -2783,7 +2697,7 @@ static int __tipc_nl_add_sk(struct sk_buff *skb, struct netlink_callback *cb,
2783 struct tipc_net *tn = net_generic(net, tipc_net_id); 2697 struct tipc_net *tn = net_generic(net, tipc_net_id);
2784 2698
2785 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 2699 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
2786 &tipc_genl_v2_family, NLM_F_MULTI, TIPC_NL_SOCK_GET); 2700 &tipc_genl_family, NLM_F_MULTI, TIPC_NL_SOCK_GET);
2787 if (!hdr) 2701 if (!hdr)
2788 goto msg_cancel; 2702 goto msg_cancel;
2789 2703
@@ -2864,7 +2778,7 @@ static int __tipc_nl_add_sk_publ(struct sk_buff *skb,
2864 struct nlattr *attrs; 2778 struct nlattr *attrs;
2865 2779
2866 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 2780 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
2867 &tipc_genl_v2_family, NLM_F_MULTI, TIPC_NL_PUBL_GET); 2781 &tipc_genl_family, NLM_F_MULTI, TIPC_NL_PUBL_GET);
2868 if (!hdr) 2782 if (!hdr)
2869 goto msg_cancel; 2783 goto msg_cancel;
2870 2784
diff --git a/net/tipc/socket.h b/net/tipc/socket.h
index 8be0da7df8fc..238f1b7bd9bd 100644
--- a/net/tipc/socket.h
+++ b/net/tipc/socket.h
@@ -49,7 +49,6 @@ void tipc_sock_release_local(struct socket *sock);
49int tipc_sock_accept_local(struct socket *sock, struct socket **newsock, 49int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,
50 int flags); 50 int flags);
51int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq); 51int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq);
52struct sk_buff *tipc_sk_socks_show(struct net *net);
53void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq, 52void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq,
54 struct sk_buff_head *inputq); 53 struct sk_buff_head *inputq);
55void tipc_sk_reinit(struct net *net); 54void tipc_sk_reinit(struct net *net);