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