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