xref: /linux/net/tipc/netlink_compat.c (revision 32a92f8c89326985e05dce8b22d3f0aa07a3e1bd)
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/string_helpers.h>
43 #include <linux/tipc_config.h>
44 
45 /* The legacy API had an artificial message length limit called
46  * ULTRA_STRING_MAX_LEN.
47  */
48 #define ULTRA_STRING_MAX_LEN 32768
49 
50 #define TIPC_SKB_MAX TLV_SPACE(ULTRA_STRING_MAX_LEN)
51 
52 #define REPLY_TRUNCATED "<truncated>\n"
53 
54 struct tipc_nl_compat_msg {
55 	u16 cmd;
56 	int rep_type;
57 	int rep_size;
58 	int req_type;
59 	int req_size;
60 	struct net *net;
61 	struct sk_buff *rep;
62 	struct tlv_desc *req;
63 	struct sock *dst_sk;
64 };
65 
66 struct tipc_nl_compat_cmd_dump {
67 	int (*header)(struct tipc_nl_compat_msg *);
68 	int (*dumpit)(struct sk_buff *, struct netlink_callback *);
69 	int (*format)(struct tipc_nl_compat_msg *msg, struct nlattr **attrs);
70 };
71 
72 struct tipc_nl_compat_cmd_doit {
73 	int (*doit)(struct sk_buff *skb, struct genl_info *info);
74 	int (*transcode)(struct tipc_nl_compat_cmd_doit *cmd,
75 			 struct sk_buff *skb, struct tipc_nl_compat_msg *msg);
76 };
77 
tipc_skb_tailroom(struct sk_buff * skb)78 static int tipc_skb_tailroom(struct sk_buff *skb)
79 {
80 	int tailroom;
81 	int limit;
82 
83 	tailroom = skb_tailroom(skb);
84 	limit = TIPC_SKB_MAX - skb->len;
85 
86 	if (tailroom < limit)
87 		return tailroom;
88 
89 	return limit;
90 }
91 
TLV_GET_DATA_LEN(struct tlv_desc * tlv)92 static inline int TLV_GET_DATA_LEN(struct tlv_desc *tlv)
93 {
94 	return TLV_GET_LEN(tlv) - TLV_SPACE(0);
95 }
96 
tipc_add_tlv(struct sk_buff * skb,u16 type,void * data,u16 len)97 static int tipc_add_tlv(struct sk_buff *skb, u16 type, void *data, u16 len)
98 {
99 	struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(skb);
100 
101 	if (tipc_skb_tailroom(skb) < TLV_SPACE(len))
102 		return -EMSGSIZE;
103 
104 	skb_put(skb, TLV_SPACE(len));
105 	memset(tlv, 0, TLV_SPACE(len));
106 	tlv->tlv_type = htons(type);
107 	tlv->tlv_len = htons(TLV_LENGTH(len));
108 	if (len && data)
109 		memcpy(TLV_DATA(tlv), data, len);
110 
111 	return 0;
112 }
113 
tipc_tlv_init(struct sk_buff * skb,u16 type)114 static void tipc_tlv_init(struct sk_buff *skb, u16 type)
115 {
116 	struct tlv_desc *tlv = (struct tlv_desc *)skb->data;
117 
118 	TLV_SET_LEN(tlv, 0);
119 	TLV_SET_TYPE(tlv, type);
120 	skb_put(skb, sizeof(struct tlv_desc));
121 }
122 
tipc_tlv_sprintf(struct sk_buff * skb,const char * fmt,...)123 static __printf(2, 3) int tipc_tlv_sprintf(struct sk_buff *skb,
124 					   const char *fmt, ...)
125 {
126 	int n;
127 	u16 len;
128 	u32 rem;
129 	char *buf;
130 	struct tlv_desc *tlv;
131 	va_list args;
132 
133 	rem = tipc_skb_tailroom(skb);
134 
135 	tlv = (struct tlv_desc *)skb->data;
136 	len = TLV_GET_LEN(tlv);
137 	buf = TLV_DATA(tlv) + len;
138 
139 	va_start(args, fmt);
140 	n = vscnprintf(buf, rem, fmt, args);
141 	va_end(args);
142 
143 	TLV_SET_LEN(tlv, n + len);
144 	skb_put(skb, n);
145 
146 	return n;
147 }
148 
tipc_tlv_alloc(int size)149 static struct sk_buff *tipc_tlv_alloc(int size)
150 {
151 	int hdr_len;
152 	struct sk_buff *buf;
153 
154 	size = TLV_SPACE(size);
155 	hdr_len = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
156 
157 	buf = alloc_skb(hdr_len + size, GFP_KERNEL);
158 	if (!buf)
159 		return NULL;
160 
161 	skb_reserve(buf, hdr_len);
162 
163 	return buf;
164 }
165 
tipc_get_err_tlv(char * str)166 static struct sk_buff *tipc_get_err_tlv(char *str)
167 {
168 	int str_len = strlen(str) + 1;
169 	struct sk_buff *buf;
170 
171 	buf = tipc_tlv_alloc(str_len);
172 	if (buf)
173 		tipc_add_tlv(buf, TIPC_TLV_ERROR_STRING, str, str_len);
174 
175 	return buf;
176 }
177 
__tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump * cmd,struct tipc_nl_compat_msg * msg,struct sk_buff * arg)178 static int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
179 				   struct tipc_nl_compat_msg *msg,
180 				   struct sk_buff *arg)
181 {
182 	struct genl_dumpit_info info;
183 	int len = 0;
184 	int err;
185 	struct sk_buff *buf;
186 	struct nlmsghdr *nlmsg;
187 	struct netlink_callback cb;
188 	struct nlattr **attrbuf;
189 
190 	memset(&cb, 0, sizeof(cb));
191 	cb.nlh = (struct nlmsghdr *)arg->data;
192 	cb.skb = arg;
193 	cb.data = &info;
194 
195 	buf = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
196 	if (!buf)
197 		return -ENOMEM;
198 
199 	buf->sk = msg->dst_sk;
200 	if (__tipc_dump_start(&cb, msg->net)) {
201 		kfree_skb(buf);
202 		return -ENOMEM;
203 	}
204 
205 	attrbuf = kzalloc_objs(struct nlattr *, tipc_genl_family.maxattr + 1);
206 	if (!attrbuf) {
207 		err = -ENOMEM;
208 		goto err_out;
209 	}
210 
211 	info.info.attrs = attrbuf;
212 
213 	if (nlmsg_len(cb.nlh) > 0) {
214 		err = nlmsg_parse_deprecated(cb.nlh, GENL_HDRLEN, attrbuf,
215 					     tipc_genl_family.maxattr,
216 					     tipc_genl_family.policy, NULL);
217 		if (err)
218 			goto err_out;
219 	}
220 	do {
221 		int rem;
222 
223 		len = (*cmd->dumpit)(buf, &cb);
224 
225 		nlmsg_for_each_msg(nlmsg, nlmsg_hdr(buf), len, rem) {
226 			err = nlmsg_parse_deprecated(nlmsg, GENL_HDRLEN,
227 						     attrbuf,
228 						     tipc_genl_family.maxattr,
229 						     tipc_genl_family.policy,
230 						     NULL);
231 			if (err)
232 				goto err_out;
233 
234 			err = (*cmd->format)(msg, attrbuf);
235 			if (err)
236 				goto err_out;
237 
238 			if (tipc_skb_tailroom(msg->rep) <= 1) {
239 				err = -EMSGSIZE;
240 				goto err_out;
241 			}
242 		}
243 
244 		skb_reset_tail_pointer(buf);
245 		buf->len = 0;
246 
247 	} while (len);
248 
249 	err = 0;
250 
251 err_out:
252 	kfree(attrbuf);
253 	tipc_dump_done(&cb);
254 	kfree_skb(buf);
255 
256 	if (err == -EMSGSIZE) {
257 		/* The legacy API only considered messages filling
258 		 * "ULTRA_STRING_MAX_LEN" to be truncated.
259 		 */
260 		if ((TIPC_SKB_MAX - msg->rep->len) <= 1) {
261 			char *tail = skb_tail_pointer(msg->rep);
262 
263 			if (*tail != '\0')
264 				sprintf(tail - sizeof(REPLY_TRUNCATED) - 1,
265 					REPLY_TRUNCATED);
266 		}
267 
268 		return 0;
269 	}
270 
271 	return err;
272 }
273 
tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump * cmd,struct tipc_nl_compat_msg * msg)274 static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
275 				 struct tipc_nl_compat_msg *msg)
276 {
277 	struct nlmsghdr *nlh;
278 	struct sk_buff *arg;
279 	int err;
280 
281 	if (msg->req_type && (!msg->req_size ||
282 			      !TLV_CHECK_TYPE(msg->req, msg->req_type)))
283 		return -EINVAL;
284 
285 	msg->rep = tipc_tlv_alloc(msg->rep_size);
286 	if (!msg->rep)
287 		return -ENOMEM;
288 
289 	if (msg->rep_type)
290 		tipc_tlv_init(msg->rep, msg->rep_type);
291 
292 	if (cmd->header) {
293 		err = (*cmd->header)(msg);
294 		if (err) {
295 			kfree_skb(msg->rep);
296 			msg->rep = NULL;
297 			return err;
298 		}
299 	}
300 
301 	arg = nlmsg_new(0, GFP_KERNEL);
302 	if (!arg) {
303 		kfree_skb(msg->rep);
304 		msg->rep = NULL;
305 		return -ENOMEM;
306 	}
307 
308 	nlh = nlmsg_put(arg, 0, 0, tipc_genl_family.id, 0, NLM_F_MULTI);
309 	if (!nlh) {
310 		kfree_skb(arg);
311 		kfree_skb(msg->rep);
312 		msg->rep = NULL;
313 		return -EMSGSIZE;
314 	}
315 	nlmsg_end(arg, nlh);
316 
317 	err = __tipc_nl_compat_dumpit(cmd, msg, arg);
318 	if (err) {
319 		kfree_skb(msg->rep);
320 		msg->rep = NULL;
321 	}
322 	kfree_skb(arg);
323 
324 	return err;
325 }
326 
__tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit * cmd,struct tipc_nl_compat_msg * msg)327 static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
328 				 struct tipc_nl_compat_msg *msg)
329 {
330 	int err;
331 	struct sk_buff *doit_buf;
332 	struct sk_buff *trans_buf;
333 	struct nlattr **attrbuf;
334 	struct genl_info info;
335 
336 	trans_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
337 	if (!trans_buf)
338 		return -ENOMEM;
339 
340 	attrbuf = kmalloc_objs(struct nlattr *, tipc_genl_family.maxattr + 1);
341 	if (!attrbuf) {
342 		err = -ENOMEM;
343 		goto trans_out;
344 	}
345 
346 	doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
347 	if (!doit_buf) {
348 		err = -ENOMEM;
349 		goto attrbuf_out;
350 	}
351 
352 	memset(&info, 0, sizeof(info));
353 	info.attrs = attrbuf;
354 
355 	rtnl_lock();
356 	err = (*cmd->transcode)(cmd, trans_buf, msg);
357 	if (err)
358 		goto doit_out;
359 
360 	err = nla_parse_deprecated(attrbuf, tipc_genl_family.maxattr,
361 				   (const struct nlattr *)trans_buf->data,
362 				   trans_buf->len, NULL, NULL);
363 	if (err)
364 		goto doit_out;
365 
366 	doit_buf->sk = msg->dst_sk;
367 
368 	err = (*cmd->doit)(doit_buf, &info);
369 doit_out:
370 	rtnl_unlock();
371 
372 	kfree_skb(doit_buf);
373 attrbuf_out:
374 	kfree(attrbuf);
375 trans_out:
376 	kfree_skb(trans_buf);
377 
378 	return err;
379 }
380 
tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit * cmd,struct tipc_nl_compat_msg * msg)381 static int tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
382 			       struct tipc_nl_compat_msg *msg)
383 {
384 	int err;
385 
386 	if (msg->req_type && (!msg->req_size ||
387 			      !TLV_CHECK_TYPE(msg->req, msg->req_type)))
388 		return -EINVAL;
389 
390 	err = __tipc_nl_compat_doit(cmd, msg);
391 	if (err)
392 		return err;
393 
394 	/* The legacy API considered an empty message a success message */
395 	msg->rep = tipc_tlv_alloc(0);
396 	if (!msg->rep)
397 		return -ENOMEM;
398 
399 	return 0;
400 }
401 
tipc_nl_compat_bearer_dump(struct tipc_nl_compat_msg * msg,struct nlattr ** attrs)402 static int tipc_nl_compat_bearer_dump(struct tipc_nl_compat_msg *msg,
403 				      struct nlattr **attrs)
404 {
405 	struct nlattr *bearer[TIPC_NLA_BEARER_MAX + 1];
406 	int err;
407 
408 	if (!attrs[TIPC_NLA_BEARER])
409 		return -EINVAL;
410 
411 	err = nla_parse_nested_deprecated(bearer, TIPC_NLA_BEARER_MAX,
412 					  attrs[TIPC_NLA_BEARER], NULL, NULL);
413 	if (err)
414 		return err;
415 
416 	return tipc_add_tlv(msg->rep, TIPC_TLV_BEARER_NAME,
417 			    nla_data(bearer[TIPC_NLA_BEARER_NAME]),
418 			    nla_len(bearer[TIPC_NLA_BEARER_NAME]));
419 }
420 
tipc_nl_compat_bearer_enable(struct tipc_nl_compat_cmd_doit * cmd,struct sk_buff * skb,struct tipc_nl_compat_msg * msg)421 static int tipc_nl_compat_bearer_enable(struct tipc_nl_compat_cmd_doit *cmd,
422 					struct sk_buff *skb,
423 					struct tipc_nl_compat_msg *msg)
424 {
425 	struct nlattr *prop;
426 	struct nlattr *bearer;
427 	struct tipc_bearer_config *b;
428 	int len;
429 
430 	b = (struct tipc_bearer_config *)TLV_DATA(msg->req);
431 
432 	bearer = nla_nest_start_noflag(skb, TIPC_NLA_BEARER);
433 	if (!bearer)
434 		return -EMSGSIZE;
435 
436 	len = TLV_GET_DATA_LEN(msg->req);
437 	len -= offsetof(struct tipc_bearer_config, name);
438 	if (len <= 0)
439 		return -EINVAL;
440 
441 	len = min_t(int, len, TIPC_MAX_BEARER_NAME);
442 	if (!string_is_terminated(b->name, len))
443 		return -EINVAL;
444 
445 	if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, b->name))
446 		return -EMSGSIZE;
447 
448 	if (nla_put_u32(skb, TIPC_NLA_BEARER_DOMAIN, ntohl(b->disc_domain)))
449 		return -EMSGSIZE;
450 
451 	if (ntohl(b->priority) <= TIPC_MAX_LINK_PRI) {
452 		prop = nla_nest_start_noflag(skb, TIPC_NLA_BEARER_PROP);
453 		if (!prop)
454 			return -EMSGSIZE;
455 		if (nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(b->priority)))
456 			return -EMSGSIZE;
457 		nla_nest_end(skb, prop);
458 	}
459 	nla_nest_end(skb, bearer);
460 
461 	return 0;
462 }
463 
tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit * cmd,struct sk_buff * skb,struct tipc_nl_compat_msg * msg)464 static int tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit *cmd,
465 					 struct sk_buff *skb,
466 					 struct tipc_nl_compat_msg *msg)
467 {
468 	char *name;
469 	struct nlattr *bearer;
470 	int len;
471 
472 	name = (char *)TLV_DATA(msg->req);
473 
474 	bearer = nla_nest_start_noflag(skb, TIPC_NLA_BEARER);
475 	if (!bearer)
476 		return -EMSGSIZE;
477 
478 	len = TLV_GET_DATA_LEN(msg->req);
479 	if (len <= 0)
480 		return -EINVAL;
481 
482 	len = min_t(int, len, TIPC_MAX_BEARER_NAME);
483 	if (!string_is_terminated(name, len))
484 		return -EINVAL;
485 
486 	if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, name))
487 		return -EMSGSIZE;
488 
489 	nla_nest_end(skb, bearer);
490 
491 	return 0;
492 }
493 
perc(u32 count,u32 total)494 static inline u32 perc(u32 count, u32 total)
495 {
496 	return (count * 100 + (total / 2)) / total;
497 }
498 
__fill_bc_link_stat(struct tipc_nl_compat_msg * msg,struct nlattr * prop[],struct nlattr * stats[])499 static void __fill_bc_link_stat(struct tipc_nl_compat_msg *msg,
500 				struct nlattr *prop[], struct nlattr *stats[])
501 {
502 	tipc_tlv_sprintf(msg->rep, "  Window:%u packets\n",
503 			 nla_get_u32(prop[TIPC_NLA_PROP_WIN]));
504 
505 	tipc_tlv_sprintf(msg->rep,
506 			 "  RX packets:%u fragments:%u/%u bundles:%u/%u\n",
507 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_INFO]),
508 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]),
509 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]),
510 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]),
511 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED]));
512 
513 	tipc_tlv_sprintf(msg->rep,
514 			 "  TX packets:%u fragments:%u/%u bundles:%u/%u\n",
515 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_INFO]),
516 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]),
517 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]),
518 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]),
519 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED]));
520 
521 	tipc_tlv_sprintf(msg->rep, "  RX naks:%u defs:%u dups:%u\n",
522 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]),
523 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]),
524 			 nla_get_u32(stats[TIPC_NLA_STATS_DUPLICATES]));
525 
526 	tipc_tlv_sprintf(msg->rep, "  TX naks:%u acks:%u dups:%u\n",
527 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]),
528 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]),
529 			 nla_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED]));
530 
531 	tipc_tlv_sprintf(msg->rep,
532 			 "  Congestion link:%u  Send queue max:%u avg:%u",
533 			 nla_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]),
534 			 nla_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]),
535 			 nla_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE]));
536 }
537 
tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg * msg,struct nlattr ** attrs)538 static int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg,
539 					 struct nlattr **attrs)
540 {
541 	char *name;
542 	struct nlattr *link[TIPC_NLA_LINK_MAX + 1];
543 	struct nlattr *prop[TIPC_NLA_PROP_MAX + 1];
544 	struct nlattr *stats[TIPC_NLA_STATS_MAX + 1];
545 	int err;
546 	int len;
547 
548 	if (!attrs[TIPC_NLA_LINK])
549 		return -EINVAL;
550 
551 	err = nla_parse_nested_deprecated(link, TIPC_NLA_LINK_MAX,
552 					  attrs[TIPC_NLA_LINK], NULL, NULL);
553 	if (err)
554 		return err;
555 
556 	if (!link[TIPC_NLA_LINK_PROP])
557 		return -EINVAL;
558 
559 	err = nla_parse_nested_deprecated(prop, TIPC_NLA_PROP_MAX,
560 					  link[TIPC_NLA_LINK_PROP], NULL,
561 					  NULL);
562 	if (err)
563 		return err;
564 
565 	if (!link[TIPC_NLA_LINK_STATS])
566 		return -EINVAL;
567 
568 	err = nla_parse_nested_deprecated(stats, TIPC_NLA_STATS_MAX,
569 					  link[TIPC_NLA_LINK_STATS], NULL,
570 					  NULL);
571 	if (err)
572 		return err;
573 
574 	name = (char *)TLV_DATA(msg->req);
575 
576 	len = TLV_GET_DATA_LEN(msg->req);
577 	if (len <= 0)
578 		return -EINVAL;
579 
580 	len = min_t(int, len, TIPC_MAX_LINK_NAME);
581 	if (!string_is_terminated(name, len))
582 		return -EINVAL;
583 
584 	if (strcmp(name, nla_data(link[TIPC_NLA_LINK_NAME])) != 0)
585 		return 0;
586 
587 	tipc_tlv_sprintf(msg->rep, "\nLink <%s>\n",
588 			 (char *)nla_data(link[TIPC_NLA_LINK_NAME]));
589 
590 	if (link[TIPC_NLA_LINK_BROADCAST]) {
591 		__fill_bc_link_stat(msg, prop, stats);
592 		return 0;
593 	}
594 
595 	if (link[TIPC_NLA_LINK_ACTIVE])
596 		tipc_tlv_sprintf(msg->rep, "  ACTIVE");
597 	else if (link[TIPC_NLA_LINK_UP])
598 		tipc_tlv_sprintf(msg->rep, "  STANDBY");
599 	else
600 		tipc_tlv_sprintf(msg->rep, "  DEFUNCT");
601 
602 	tipc_tlv_sprintf(msg->rep, "  MTU:%u  Priority:%u",
603 			 nla_get_u32(link[TIPC_NLA_LINK_MTU]),
604 			 nla_get_u32(prop[TIPC_NLA_PROP_PRIO]));
605 
606 	tipc_tlv_sprintf(msg->rep, "  Tolerance:%u ms  Window:%u packets\n",
607 			 nla_get_u32(prop[TIPC_NLA_PROP_TOL]),
608 			 nla_get_u32(prop[TIPC_NLA_PROP_WIN]));
609 
610 	tipc_tlv_sprintf(msg->rep,
611 			 "  RX packets:%u fragments:%u/%u bundles:%u/%u\n",
612 			 nla_get_u32(link[TIPC_NLA_LINK_RX]) -
613 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_INFO]),
614 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]),
615 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]),
616 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]),
617 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED]));
618 
619 	tipc_tlv_sprintf(msg->rep,
620 			 "  TX packets:%u fragments:%u/%u bundles:%u/%u\n",
621 			 nla_get_u32(link[TIPC_NLA_LINK_TX]) -
622 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_INFO]),
623 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]),
624 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]),
625 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]),
626 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED]));
627 
628 	tipc_tlv_sprintf(msg->rep,
629 			 "  TX profile sample:%u packets  average:%u octets\n",
630 			 nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_CNT]),
631 			 nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_TOT]) /
632 			 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT]));
633 
634 	tipc_tlv_sprintf(msg->rep,
635 			 "  0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% ",
636 			 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P0]),
637 			      nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
638 			 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P1]),
639 			      nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
640 			 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P2]),
641 			      nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
642 			 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P3]),
643 			      nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])));
644 
645 	tipc_tlv_sprintf(msg->rep, "-16384:%u%% -32768:%u%% -66000:%u%%\n",
646 			 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P4]),
647 			      nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
648 			 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P5]),
649 			      nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
650 			 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P6]),
651 			      nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])));
652 
653 	tipc_tlv_sprintf(msg->rep,
654 			 "  RX states:%u probes:%u naks:%u defs:%u dups:%u\n",
655 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_STATES]),
656 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_PROBES]),
657 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]),
658 			 nla_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]),
659 			 nla_get_u32(stats[TIPC_NLA_STATS_DUPLICATES]));
660 
661 	tipc_tlv_sprintf(msg->rep,
662 			 "  TX states:%u probes:%u naks:%u acks:%u dups:%u\n",
663 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_STATES]),
664 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_PROBES]),
665 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]),
666 			 nla_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]),
667 			 nla_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED]));
668 
669 	tipc_tlv_sprintf(msg->rep,
670 			 "  Congestion link:%u  Send queue max:%u avg:%u",
671 			 nla_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]),
672 			 nla_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]),
673 			 nla_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE]));
674 
675 	return 0;
676 }
677 
tipc_nl_compat_link_dump(struct tipc_nl_compat_msg * msg,struct nlattr ** attrs)678 static int tipc_nl_compat_link_dump(struct tipc_nl_compat_msg *msg,
679 				    struct nlattr **attrs)
680 {
681 	struct nlattr *link[TIPC_NLA_LINK_MAX + 1];
682 	struct tipc_link_info link_info;
683 	int err;
684 
685 	if (!attrs[TIPC_NLA_LINK])
686 		return -EINVAL;
687 
688 	err = nla_parse_nested_deprecated(link, TIPC_NLA_LINK_MAX,
689 					  attrs[TIPC_NLA_LINK], NULL, NULL);
690 	if (err)
691 		return err;
692 
693 	link_info.dest = htonl(nla_get_flag(link[TIPC_NLA_LINK_DEST]));
694 	link_info.up = htonl(nla_get_flag(link[TIPC_NLA_LINK_UP]));
695 	nla_strscpy(link_info.str, link[TIPC_NLA_LINK_NAME],
696 		    TIPC_MAX_LINK_NAME);
697 
698 	return tipc_add_tlv(msg->rep, TIPC_TLV_LINK_INFO,
699 			    &link_info, sizeof(link_info));
700 }
701 
__tipc_add_link_prop(struct sk_buff * skb,struct tipc_nl_compat_msg * msg,struct tipc_link_config * lc)702 static int __tipc_add_link_prop(struct sk_buff *skb,
703 				struct tipc_nl_compat_msg *msg,
704 				struct tipc_link_config *lc)
705 {
706 	switch (msg->cmd) {
707 	case TIPC_CMD_SET_LINK_PRI:
708 		return nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(lc->value));
709 	case TIPC_CMD_SET_LINK_TOL:
710 		return nla_put_u32(skb, TIPC_NLA_PROP_TOL, ntohl(lc->value));
711 	case TIPC_CMD_SET_LINK_WINDOW:
712 		return nla_put_u32(skb, TIPC_NLA_PROP_WIN, ntohl(lc->value));
713 	}
714 
715 	return -EINVAL;
716 }
717 
tipc_nl_compat_media_set(struct sk_buff * skb,struct tipc_nl_compat_msg * msg)718 static int tipc_nl_compat_media_set(struct sk_buff *skb,
719 				    struct tipc_nl_compat_msg *msg)
720 {
721 	struct nlattr *prop;
722 	struct nlattr *media;
723 	struct tipc_link_config *lc;
724 
725 	lc = (struct tipc_link_config *)TLV_DATA(msg->req);
726 
727 	media = nla_nest_start_noflag(skb, TIPC_NLA_MEDIA);
728 	if (!media)
729 		return -EMSGSIZE;
730 
731 	if (nla_put_string(skb, TIPC_NLA_MEDIA_NAME, lc->name))
732 		return -EMSGSIZE;
733 
734 	prop = nla_nest_start_noflag(skb, TIPC_NLA_MEDIA_PROP);
735 	if (!prop)
736 		return -EMSGSIZE;
737 
738 	__tipc_add_link_prop(skb, msg, lc);
739 	nla_nest_end(skb, prop);
740 	nla_nest_end(skb, media);
741 
742 	return 0;
743 }
744 
tipc_nl_compat_bearer_set(struct sk_buff * skb,struct tipc_nl_compat_msg * msg)745 static int tipc_nl_compat_bearer_set(struct sk_buff *skb,
746 				     struct tipc_nl_compat_msg *msg)
747 {
748 	struct nlattr *prop;
749 	struct nlattr *bearer;
750 	struct tipc_link_config *lc;
751 
752 	lc = (struct tipc_link_config *)TLV_DATA(msg->req);
753 
754 	bearer = nla_nest_start_noflag(skb, TIPC_NLA_BEARER);
755 	if (!bearer)
756 		return -EMSGSIZE;
757 
758 	if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, lc->name))
759 		return -EMSGSIZE;
760 
761 	prop = nla_nest_start_noflag(skb, TIPC_NLA_BEARER_PROP);
762 	if (!prop)
763 		return -EMSGSIZE;
764 
765 	__tipc_add_link_prop(skb, msg, lc);
766 	nla_nest_end(skb, prop);
767 	nla_nest_end(skb, bearer);
768 
769 	return 0;
770 }
771 
__tipc_nl_compat_link_set(struct sk_buff * skb,struct tipc_nl_compat_msg * msg)772 static int __tipc_nl_compat_link_set(struct sk_buff *skb,
773 				     struct tipc_nl_compat_msg *msg)
774 {
775 	struct nlattr *prop;
776 	struct nlattr *link;
777 	struct tipc_link_config *lc;
778 
779 	lc = (struct tipc_link_config *)TLV_DATA(msg->req);
780 
781 	link = nla_nest_start_noflag(skb, TIPC_NLA_LINK);
782 	if (!link)
783 		return -EMSGSIZE;
784 
785 	if (nla_put_string(skb, TIPC_NLA_LINK_NAME, lc->name))
786 		return -EMSGSIZE;
787 
788 	prop = nla_nest_start_noflag(skb, TIPC_NLA_LINK_PROP);
789 	if (!prop)
790 		return -EMSGSIZE;
791 
792 	__tipc_add_link_prop(skb, msg, lc);
793 	nla_nest_end(skb, prop);
794 	nla_nest_end(skb, link);
795 
796 	return 0;
797 }
798 
tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit * cmd,struct sk_buff * skb,struct tipc_nl_compat_msg * msg)799 static int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd,
800 				   struct sk_buff *skb,
801 				   struct tipc_nl_compat_msg *msg)
802 {
803 	struct tipc_link_config *lc;
804 	struct tipc_bearer *bearer;
805 	struct tipc_media *media;
806 	int len;
807 
808 	lc = (struct tipc_link_config *)TLV_DATA(msg->req);
809 
810 	len = TLV_GET_DATA_LEN(msg->req);
811 	len -= offsetof(struct tipc_link_config, name);
812 	if (len <= 0)
813 		return -EINVAL;
814 
815 	len = min_t(int, len, TIPC_MAX_LINK_NAME);
816 	if (!string_is_terminated(lc->name, len))
817 		return -EINVAL;
818 
819 	media = tipc_media_find(lc->name);
820 	if (media) {
821 		cmd->doit = &__tipc_nl_media_set;
822 		return tipc_nl_compat_media_set(skb, msg);
823 	}
824 
825 	bearer = tipc_bearer_find(msg->net, lc->name);
826 	if (bearer) {
827 		cmd->doit = &__tipc_nl_bearer_set;
828 		return tipc_nl_compat_bearer_set(skb, msg);
829 	}
830 
831 	return __tipc_nl_compat_link_set(skb, msg);
832 }
833 
tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit * cmd,struct sk_buff * skb,struct tipc_nl_compat_msg * msg)834 static int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd,
835 					   struct sk_buff *skb,
836 					   struct tipc_nl_compat_msg *msg)
837 {
838 	char *name;
839 	struct nlattr *link;
840 	int len;
841 
842 	name = (char *)TLV_DATA(msg->req);
843 
844 	link = nla_nest_start_noflag(skb, TIPC_NLA_LINK);
845 	if (!link)
846 		return -EMSGSIZE;
847 
848 	len = TLV_GET_DATA_LEN(msg->req);
849 	if (len <= 0)
850 		return -EINVAL;
851 
852 	len = min_t(int, len, TIPC_MAX_LINK_NAME);
853 	if (!string_is_terminated(name, len))
854 		return -EINVAL;
855 
856 	if (nla_put_string(skb, TIPC_NLA_LINK_NAME, name))
857 		return -EMSGSIZE;
858 
859 	nla_nest_end(skb, link);
860 
861 	return 0;
862 }
863 
tipc_nl_compat_name_table_dump_header(struct tipc_nl_compat_msg * msg)864 static int tipc_nl_compat_name_table_dump_header(struct tipc_nl_compat_msg *msg)
865 {
866 	int i;
867 	u32 depth;
868 	struct tipc_name_table_query *ntq;
869 	static const char * const header[] = {
870 		"Type       ",
871 		"Lower      Upper      ",
872 		"Port Identity              ",
873 		"Publication Scope"
874 	};
875 
876 	ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req);
877 	if (TLV_GET_DATA_LEN(msg->req) < (int)sizeof(struct tipc_name_table_query))
878 		return -EINVAL;
879 
880 	depth = ntohl(ntq->depth);
881 
882 	if (depth > 4)
883 		depth = 4;
884 	for (i = 0; i < depth; i++)
885 		tipc_tlv_sprintf(msg->rep, header[i]);
886 	tipc_tlv_sprintf(msg->rep, "\n");
887 
888 	return 0;
889 }
890 
tipc_nl_compat_name_table_dump(struct tipc_nl_compat_msg * msg,struct nlattr ** attrs)891 static int tipc_nl_compat_name_table_dump(struct tipc_nl_compat_msg *msg,
892 					  struct nlattr **attrs)
893 {
894 	char port_str[27];
895 	struct tipc_name_table_query *ntq;
896 	struct nlattr *nt[TIPC_NLA_NAME_TABLE_MAX + 1];
897 	struct nlattr *publ[TIPC_NLA_PUBL_MAX + 1];
898 	u32 node, depth, type, lowbound, upbound;
899 	static const char * const scope_str[] = {"", " zone", " cluster",
900 						 " node"};
901 	int err;
902 
903 	if (!attrs[TIPC_NLA_NAME_TABLE])
904 		return -EINVAL;
905 
906 	err = nla_parse_nested_deprecated(nt, TIPC_NLA_NAME_TABLE_MAX,
907 					  attrs[TIPC_NLA_NAME_TABLE], NULL,
908 					  NULL);
909 	if (err)
910 		return err;
911 
912 	if (!nt[TIPC_NLA_NAME_TABLE_PUBL])
913 		return -EINVAL;
914 
915 	err = nla_parse_nested_deprecated(publ, TIPC_NLA_PUBL_MAX,
916 					  nt[TIPC_NLA_NAME_TABLE_PUBL], NULL,
917 					  NULL);
918 	if (err)
919 		return err;
920 
921 	ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req);
922 
923 	depth = ntohl(ntq->depth);
924 	type = ntohl(ntq->type);
925 	lowbound = ntohl(ntq->lowbound);
926 	upbound = ntohl(ntq->upbound);
927 
928 	if (!(depth & TIPC_NTQ_ALLTYPES) &&
929 	    (type != nla_get_u32(publ[TIPC_NLA_PUBL_TYPE])))
930 		return 0;
931 	if (lowbound && (lowbound > nla_get_u32(publ[TIPC_NLA_PUBL_UPPER])))
932 		return 0;
933 	if (upbound && (upbound < nla_get_u32(publ[TIPC_NLA_PUBL_LOWER])))
934 		return 0;
935 
936 	tipc_tlv_sprintf(msg->rep, "%-10u ",
937 			 nla_get_u32(publ[TIPC_NLA_PUBL_TYPE]));
938 
939 	if (depth == 1)
940 		goto out;
941 
942 	tipc_tlv_sprintf(msg->rep, "%-10u %-10u ",
943 			 nla_get_u32(publ[TIPC_NLA_PUBL_LOWER]),
944 			 nla_get_u32(publ[TIPC_NLA_PUBL_UPPER]));
945 
946 	if (depth == 2)
947 		goto out;
948 
949 	node = nla_get_u32(publ[TIPC_NLA_PUBL_NODE]);
950 	sprintf(port_str, "<%u.%u.%u:%u>", tipc_zone(node), tipc_cluster(node),
951 		tipc_node(node), nla_get_u32(publ[TIPC_NLA_PUBL_REF]));
952 	tipc_tlv_sprintf(msg->rep, "%-26s ", port_str);
953 
954 	if (depth == 3)
955 		goto out;
956 
957 	tipc_tlv_sprintf(msg->rep, "%-10u %s",
958 			 nla_get_u32(publ[TIPC_NLA_PUBL_KEY]),
959 			 scope_str[nla_get_u32(publ[TIPC_NLA_PUBL_SCOPE])]);
960 out:
961 	tipc_tlv_sprintf(msg->rep, "\n");
962 
963 	return 0;
964 }
965 
__tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg * msg,struct nlattr ** attrs)966 static int __tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg *msg,
967 				      struct nlattr **attrs)
968 {
969 	u32 type, lower, upper;
970 	struct nlattr *publ[TIPC_NLA_PUBL_MAX + 1];
971 	int err;
972 
973 	if (!attrs[TIPC_NLA_PUBL])
974 		return -EINVAL;
975 
976 	err = nla_parse_nested_deprecated(publ, TIPC_NLA_PUBL_MAX,
977 					  attrs[TIPC_NLA_PUBL], NULL, NULL);
978 	if (err)
979 		return err;
980 
981 	type = nla_get_u32(publ[TIPC_NLA_PUBL_TYPE]);
982 	lower = nla_get_u32(publ[TIPC_NLA_PUBL_LOWER]);
983 	upper = nla_get_u32(publ[TIPC_NLA_PUBL_UPPER]);
984 
985 	if (lower == upper)
986 		tipc_tlv_sprintf(msg->rep, " {%u,%u}", type, lower);
987 	else
988 		tipc_tlv_sprintf(msg->rep, " {%u,%u,%u}", type, lower, upper);
989 
990 	return 0;
991 }
992 
tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg * msg,u32 sock)993 static int tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg *msg, u32 sock)
994 {
995 	int err;
996 	void *hdr;
997 	struct nlattr *nest;
998 	struct sk_buff *args;
999 	struct tipc_nl_compat_cmd_dump dump;
1000 
1001 	args = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1002 	if (!args)
1003 		return -ENOMEM;
1004 
1005 	hdr = genlmsg_put(args, 0, 0, &tipc_genl_family, NLM_F_MULTI,
1006 			  TIPC_NL_PUBL_GET);
1007 	if (!hdr) {
1008 		kfree_skb(args);
1009 		return -EMSGSIZE;
1010 	}
1011 
1012 	nest = nla_nest_start_noflag(args, TIPC_NLA_SOCK);
1013 	if (!nest) {
1014 		kfree_skb(args);
1015 		return -EMSGSIZE;
1016 	}
1017 
1018 	if (nla_put_u32(args, TIPC_NLA_SOCK_REF, sock)) {
1019 		kfree_skb(args);
1020 		return -EMSGSIZE;
1021 	}
1022 
1023 	nla_nest_end(args, nest);
1024 	genlmsg_end(args, hdr);
1025 
1026 	dump.dumpit = tipc_nl_publ_dump;
1027 	dump.format = __tipc_nl_compat_publ_dump;
1028 
1029 	err = __tipc_nl_compat_dumpit(&dump, msg, args);
1030 
1031 	kfree_skb(args);
1032 
1033 	return err;
1034 }
1035 
tipc_nl_compat_sk_dump(struct tipc_nl_compat_msg * msg,struct nlattr ** attrs)1036 static int tipc_nl_compat_sk_dump(struct tipc_nl_compat_msg *msg,
1037 				  struct nlattr **attrs)
1038 {
1039 	int err;
1040 	u32 sock_ref;
1041 	struct nlattr *sock[TIPC_NLA_SOCK_MAX + 1];
1042 
1043 	if (!attrs[TIPC_NLA_SOCK])
1044 		return -EINVAL;
1045 
1046 	err = nla_parse_nested_deprecated(sock, TIPC_NLA_SOCK_MAX,
1047 					  attrs[TIPC_NLA_SOCK], NULL, NULL);
1048 	if (err)
1049 		return err;
1050 
1051 	sock_ref = nla_get_u32(sock[TIPC_NLA_SOCK_REF]);
1052 	tipc_tlv_sprintf(msg->rep, "%u:", sock_ref);
1053 
1054 	if (sock[TIPC_NLA_SOCK_CON]) {
1055 		u32 node;
1056 		struct nlattr *con[TIPC_NLA_CON_MAX + 1];
1057 
1058 		err = nla_parse_nested_deprecated(con, TIPC_NLA_CON_MAX,
1059 						  sock[TIPC_NLA_SOCK_CON],
1060 						  NULL, NULL);
1061 
1062 		if (err)
1063 			return err;
1064 
1065 		node = nla_get_u32(con[TIPC_NLA_CON_NODE]);
1066 		tipc_tlv_sprintf(msg->rep, "  connected to <%u.%u.%u:%u>",
1067 				 tipc_zone(node),
1068 				 tipc_cluster(node),
1069 				 tipc_node(node),
1070 				 nla_get_u32(con[TIPC_NLA_CON_SOCK]));
1071 
1072 		if (con[TIPC_NLA_CON_FLAG])
1073 			tipc_tlv_sprintf(msg->rep, " via {%u,%u}\n",
1074 					 nla_get_u32(con[TIPC_NLA_CON_TYPE]),
1075 					 nla_get_u32(con[TIPC_NLA_CON_INST]));
1076 		else
1077 			tipc_tlv_sprintf(msg->rep, "\n");
1078 	} else if (sock[TIPC_NLA_SOCK_HAS_PUBL]) {
1079 		tipc_tlv_sprintf(msg->rep, " bound to");
1080 
1081 		err = tipc_nl_compat_publ_dump(msg, sock_ref);
1082 		if (err)
1083 			return err;
1084 	}
1085 	tipc_tlv_sprintf(msg->rep, "\n");
1086 
1087 	return 0;
1088 }
1089 
tipc_nl_compat_media_dump(struct tipc_nl_compat_msg * msg,struct nlattr ** attrs)1090 static int tipc_nl_compat_media_dump(struct tipc_nl_compat_msg *msg,
1091 				     struct nlattr **attrs)
1092 {
1093 	struct nlattr *media[TIPC_NLA_MEDIA_MAX + 1];
1094 	int err;
1095 
1096 	if (!attrs[TIPC_NLA_MEDIA])
1097 		return -EINVAL;
1098 
1099 	err = nla_parse_nested_deprecated(media, TIPC_NLA_MEDIA_MAX,
1100 					  attrs[TIPC_NLA_MEDIA], NULL, NULL);
1101 	if (err)
1102 		return err;
1103 
1104 	return tipc_add_tlv(msg->rep, TIPC_TLV_MEDIA_NAME,
1105 			    nla_data(media[TIPC_NLA_MEDIA_NAME]),
1106 			    nla_len(media[TIPC_NLA_MEDIA_NAME]));
1107 }
1108 
tipc_nl_compat_node_dump(struct tipc_nl_compat_msg * msg,struct nlattr ** attrs)1109 static int tipc_nl_compat_node_dump(struct tipc_nl_compat_msg *msg,
1110 				    struct nlattr **attrs)
1111 {
1112 	struct tipc_node_info node_info;
1113 	struct nlattr *node[TIPC_NLA_NODE_MAX + 1];
1114 	int err;
1115 
1116 	if (!attrs[TIPC_NLA_NODE])
1117 		return -EINVAL;
1118 
1119 	err = nla_parse_nested_deprecated(node, TIPC_NLA_NODE_MAX,
1120 					  attrs[TIPC_NLA_NODE], NULL, NULL);
1121 	if (err)
1122 		return err;
1123 
1124 	node_info.addr = htonl(nla_get_u32(node[TIPC_NLA_NODE_ADDR]));
1125 	node_info.up = htonl(nla_get_flag(node[TIPC_NLA_NODE_UP]));
1126 
1127 	return tipc_add_tlv(msg->rep, TIPC_TLV_NODE_INFO, &node_info,
1128 			    sizeof(node_info));
1129 }
1130 
tipc_nl_compat_net_set(struct tipc_nl_compat_cmd_doit * cmd,struct sk_buff * skb,struct tipc_nl_compat_msg * msg)1131 static int tipc_nl_compat_net_set(struct tipc_nl_compat_cmd_doit *cmd,
1132 				  struct sk_buff *skb,
1133 				  struct tipc_nl_compat_msg *msg)
1134 {
1135 	u32 val;
1136 	struct nlattr *net;
1137 
1138 	val = ntohl(*(__be32 *)TLV_DATA(msg->req));
1139 
1140 	net = nla_nest_start_noflag(skb, TIPC_NLA_NET);
1141 	if (!net)
1142 		return -EMSGSIZE;
1143 
1144 	if (msg->cmd == TIPC_CMD_SET_NODE_ADDR) {
1145 		if (nla_put_u32(skb, TIPC_NLA_NET_ADDR, val))
1146 			return -EMSGSIZE;
1147 	} else if (msg->cmd == TIPC_CMD_SET_NETID) {
1148 		if (nla_put_u32(skb, TIPC_NLA_NET_ID, val))
1149 			return -EMSGSIZE;
1150 	}
1151 	nla_nest_end(skb, net);
1152 
1153 	return 0;
1154 }
1155 
tipc_nl_compat_net_dump(struct tipc_nl_compat_msg * msg,struct nlattr ** attrs)1156 static int tipc_nl_compat_net_dump(struct tipc_nl_compat_msg *msg,
1157 				   struct nlattr **attrs)
1158 {
1159 	__be32 id;
1160 	struct nlattr *net[TIPC_NLA_NET_MAX + 1];
1161 	int err;
1162 
1163 	if (!attrs[TIPC_NLA_NET])
1164 		return -EINVAL;
1165 
1166 	err = nla_parse_nested_deprecated(net, TIPC_NLA_NET_MAX,
1167 					  attrs[TIPC_NLA_NET], NULL, NULL);
1168 	if (err)
1169 		return err;
1170 
1171 	id = htonl(nla_get_u32(net[TIPC_NLA_NET_ID]));
1172 
1173 	return tipc_add_tlv(msg->rep, TIPC_TLV_UNSIGNED, &id, sizeof(id));
1174 }
1175 
tipc_cmd_show_stats_compat(struct tipc_nl_compat_msg * msg)1176 static int tipc_cmd_show_stats_compat(struct tipc_nl_compat_msg *msg)
1177 {
1178 	msg->rep = tipc_tlv_alloc(ULTRA_STRING_MAX_LEN);
1179 	if (!msg->rep)
1180 		return -ENOMEM;
1181 
1182 	tipc_tlv_init(msg->rep, TIPC_TLV_ULTRA_STRING);
1183 	tipc_tlv_sprintf(msg->rep, "TIPC version " TIPC_MOD_VER "\n");
1184 
1185 	return 0;
1186 }
1187 
tipc_nl_compat_handle(struct tipc_nl_compat_msg * msg)1188 static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
1189 {
1190 	struct tipc_nl_compat_cmd_dump dump;
1191 	struct tipc_nl_compat_cmd_doit doit;
1192 
1193 	memset(&dump, 0, sizeof(dump));
1194 	memset(&doit, 0, sizeof(doit));
1195 
1196 	switch (msg->cmd) {
1197 	case TIPC_CMD_NOOP:
1198 		msg->rep = tipc_tlv_alloc(0);
1199 		if (!msg->rep)
1200 			return -ENOMEM;
1201 		return 0;
1202 	case TIPC_CMD_GET_BEARER_NAMES:
1203 		msg->rep_size = MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME);
1204 		dump.dumpit = tipc_nl_bearer_dump;
1205 		dump.format = tipc_nl_compat_bearer_dump;
1206 		return tipc_nl_compat_dumpit(&dump, msg);
1207 	case TIPC_CMD_ENABLE_BEARER:
1208 		msg->req_type = TIPC_TLV_BEARER_CONFIG;
1209 		doit.doit = __tipc_nl_bearer_enable;
1210 		doit.transcode = tipc_nl_compat_bearer_enable;
1211 		return tipc_nl_compat_doit(&doit, msg);
1212 	case TIPC_CMD_DISABLE_BEARER:
1213 		msg->req_type = TIPC_TLV_BEARER_NAME;
1214 		doit.doit = __tipc_nl_bearer_disable;
1215 		doit.transcode = tipc_nl_compat_bearer_disable;
1216 		return tipc_nl_compat_doit(&doit, msg);
1217 	case TIPC_CMD_SHOW_LINK_STATS:
1218 		msg->req_type = TIPC_TLV_LINK_NAME;
1219 		msg->rep_size = ULTRA_STRING_MAX_LEN;
1220 		msg->rep_type = TIPC_TLV_ULTRA_STRING;
1221 		dump.dumpit = tipc_nl_node_dump_link;
1222 		dump.format = tipc_nl_compat_link_stat_dump;
1223 		return tipc_nl_compat_dumpit(&dump, msg);
1224 	case TIPC_CMD_GET_LINKS:
1225 		msg->req_type = TIPC_TLV_NET_ADDR;
1226 		msg->rep_size = ULTRA_STRING_MAX_LEN;
1227 		dump.dumpit = tipc_nl_node_dump_link;
1228 		dump.format = tipc_nl_compat_link_dump;
1229 		return tipc_nl_compat_dumpit(&dump, msg);
1230 	case TIPC_CMD_SET_LINK_TOL:
1231 	case TIPC_CMD_SET_LINK_PRI:
1232 	case TIPC_CMD_SET_LINK_WINDOW:
1233 		msg->req_type =  TIPC_TLV_LINK_CONFIG;
1234 		doit.doit = tipc_nl_node_set_link;
1235 		doit.transcode = tipc_nl_compat_link_set;
1236 		return tipc_nl_compat_doit(&doit, msg);
1237 	case TIPC_CMD_RESET_LINK_STATS:
1238 		msg->req_type = TIPC_TLV_LINK_NAME;
1239 		doit.doit = tipc_nl_node_reset_link_stats;
1240 		doit.transcode = tipc_nl_compat_link_reset_stats;
1241 		return tipc_nl_compat_doit(&doit, msg);
1242 	case TIPC_CMD_SHOW_NAME_TABLE:
1243 		msg->req_type = TIPC_TLV_NAME_TBL_QUERY;
1244 		msg->rep_size = ULTRA_STRING_MAX_LEN;
1245 		msg->rep_type = TIPC_TLV_ULTRA_STRING;
1246 		dump.header = tipc_nl_compat_name_table_dump_header;
1247 		dump.dumpit = tipc_nl_name_table_dump;
1248 		dump.format = tipc_nl_compat_name_table_dump;
1249 		return tipc_nl_compat_dumpit(&dump, msg);
1250 	case TIPC_CMD_SHOW_PORTS:
1251 		msg->rep_size = ULTRA_STRING_MAX_LEN;
1252 		msg->rep_type = TIPC_TLV_ULTRA_STRING;
1253 		dump.dumpit = tipc_nl_sk_dump;
1254 		dump.format = tipc_nl_compat_sk_dump;
1255 		return tipc_nl_compat_dumpit(&dump, msg);
1256 	case TIPC_CMD_GET_MEDIA_NAMES:
1257 		msg->rep_size = MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME);
1258 		dump.dumpit = tipc_nl_media_dump;
1259 		dump.format = tipc_nl_compat_media_dump;
1260 		return tipc_nl_compat_dumpit(&dump, msg);
1261 	case TIPC_CMD_GET_NODES:
1262 		msg->rep_size = ULTRA_STRING_MAX_LEN;
1263 		dump.dumpit = tipc_nl_node_dump;
1264 		dump.format = tipc_nl_compat_node_dump;
1265 		return tipc_nl_compat_dumpit(&dump, msg);
1266 	case TIPC_CMD_SET_NODE_ADDR:
1267 		msg->req_type = TIPC_TLV_NET_ADDR;
1268 		doit.doit = __tipc_nl_net_set;
1269 		doit.transcode = tipc_nl_compat_net_set;
1270 		return tipc_nl_compat_doit(&doit, msg);
1271 	case TIPC_CMD_SET_NETID:
1272 		msg->req_type = TIPC_TLV_UNSIGNED;
1273 		doit.doit = __tipc_nl_net_set;
1274 		doit.transcode = tipc_nl_compat_net_set;
1275 		return tipc_nl_compat_doit(&doit, msg);
1276 	case TIPC_CMD_GET_NETID:
1277 		msg->rep_size = sizeof(u32);
1278 		dump.dumpit = tipc_nl_net_dump;
1279 		dump.format = tipc_nl_compat_net_dump;
1280 		return tipc_nl_compat_dumpit(&dump, msg);
1281 	case TIPC_CMD_SHOW_STATS:
1282 		return tipc_cmd_show_stats_compat(msg);
1283 	}
1284 
1285 	return -EOPNOTSUPP;
1286 }
1287 
tipc_nl_compat_recv(struct sk_buff * skb,struct genl_info * info)1288 static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info)
1289 {
1290 	int err;
1291 	int len;
1292 	struct tipc_nl_compat_msg msg;
1293 	struct nlmsghdr *req_nlh;
1294 	struct nlmsghdr *rep_nlh;
1295 	struct tipc_genlmsghdr *req_userhdr = genl_info_userhdr(info);
1296 
1297 	memset(&msg, 0, sizeof(msg));
1298 
1299 	req_nlh = (struct nlmsghdr *)skb->data;
1300 	msg.req = nlmsg_data(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN;
1301 	msg.cmd = req_userhdr->cmd;
1302 	msg.net = genl_info_net(info);
1303 	msg.dst_sk = skb->sk;
1304 
1305 	if ((msg.cmd & 0xC000) && (!netlink_net_capable(skb, CAP_NET_ADMIN))) {
1306 		msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_NET_ADMIN);
1307 		err = -EACCES;
1308 		goto send;
1309 	}
1310 
1311 	msg.req_size = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN);
1312 	if (msg.req_size && !TLV_OK(msg.req, msg.req_size)) {
1313 		msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED);
1314 		err = -EOPNOTSUPP;
1315 		goto send;
1316 	}
1317 
1318 	err = tipc_nl_compat_handle(&msg);
1319 	if ((err == -EOPNOTSUPP) || (err == -EPERM))
1320 		msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED);
1321 	else if (err == -EINVAL)
1322 		msg.rep = tipc_get_err_tlv(TIPC_CFG_TLV_ERROR);
1323 send:
1324 	if (!msg.rep)
1325 		return err;
1326 
1327 	len = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
1328 	skb_push(msg.rep, len);
1329 	rep_nlh = nlmsg_hdr(msg.rep);
1330 	memcpy(rep_nlh, info->nlhdr, len);
1331 	rep_nlh->nlmsg_len = msg.rep->len;
1332 	genlmsg_unicast(msg.net, msg.rep, NETLINK_CB(skb).portid);
1333 
1334 	return err;
1335 }
1336 
1337 static const struct genl_small_ops tipc_genl_compat_ops[] = {
1338 	{
1339 		.cmd		= TIPC_GENL_CMD,
1340 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1341 		.doit		= tipc_nl_compat_recv,
1342 	},
1343 };
1344 
1345 static struct genl_family tipc_genl_compat_family __ro_after_init = {
1346 	.name		= TIPC_GENL_NAME,
1347 	.version	= TIPC_GENL_VERSION,
1348 	.hdrsize	= TIPC_GENL_HDRLEN,
1349 	.maxattr	= 0,
1350 	.netnsok	= true,
1351 	.module		= THIS_MODULE,
1352 	.small_ops	= tipc_genl_compat_ops,
1353 	.n_small_ops	= ARRAY_SIZE(tipc_genl_compat_ops),
1354 	.resv_start_op	= TIPC_GENL_CMD + 1,
1355 };
1356 
tipc_netlink_compat_start(void)1357 int __init tipc_netlink_compat_start(void)
1358 {
1359 	int res;
1360 
1361 	res = genl_register_family(&tipc_genl_compat_family);
1362 	if (res) {
1363 		pr_err("Failed to register legacy compat interface\n");
1364 		return res;
1365 	}
1366 
1367 	return 0;
1368 }
1369 
tipc_netlink_compat_stop(void)1370 void tipc_netlink_compat_stop(void)
1371 {
1372 	genl_unregister_family(&tipc_genl_compat_family);
1373 }
1374