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