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