Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2014, Ericsson AB
0003  * All rights reserved.
0004  *
0005  * Redistribution and use in source and binary forms, with or without
0006  * modification, are permitted provided that the following conditions are met:
0007  *
0008  * 1. Redistributions of source code must retain the above copyright
0009  *    notice, this list of conditions and the following disclaimer.
0010  * 2. Redistributions in binary form must reproduce the above copyright
0011  *    notice, this list of conditions and the following disclaimer in the
0012  *    documentation and/or other materials provided with the distribution.
0013  * 3. Neither the names of the copyright holders nor the names of its
0014  *    contributors may be used to endorse or promote products derived from
0015  *    this software without specific prior written permission.
0016  *
0017  * Alternatively, this software may be distributed under the terms of the
0018  * GNU General Public License ("GPL") version 2 as published by the Free
0019  * Software Foundation.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0031  * POSSIBILITY OF SUCH DAMAGE.
0032  */
0033 
0034 #include "core.h"
0035 #include "bearer.h"
0036 #include "link.h"
0037 #include "name_table.h"
0038 #include "socket.h"
0039 #include "node.h"
0040 #include "net.h"
0041 #include <net/genetlink.h>
0042 #include <linux/tipc_config.h>
0043 
0044 /* The legacy API had an artificial message length limit called
0045  * ULTRA_STRING_MAX_LEN.
0046  */
0047 #define ULTRA_STRING_MAX_LEN 32768
0048 
0049 #define TIPC_SKB_MAX TLV_SPACE(ULTRA_STRING_MAX_LEN)
0050 
0051 #define REPLY_TRUNCATED "<truncated>\n"
0052 
0053 struct tipc_nl_compat_msg {
0054     u16 cmd;
0055     int rep_type;
0056     int rep_size;
0057     int req_type;
0058     int req_size;
0059     struct net *net;
0060     struct sk_buff *rep;
0061     struct tlv_desc *req;
0062     struct sock *dst_sk;
0063 };
0064 
0065 struct tipc_nl_compat_cmd_dump {
0066     int (*header)(struct tipc_nl_compat_msg *);
0067     int (*dumpit)(struct sk_buff *, struct netlink_callback *);
0068     int (*format)(struct tipc_nl_compat_msg *msg, struct nlattr **attrs);
0069 };
0070 
0071 struct tipc_nl_compat_cmd_doit {
0072     int (*doit)(struct sk_buff *skb, struct genl_info *info);
0073     int (*transcode)(struct tipc_nl_compat_cmd_doit *cmd,
0074              struct sk_buff *skb, struct tipc_nl_compat_msg *msg);
0075 };
0076 
0077 static int tipc_skb_tailroom(struct sk_buff *skb)
0078 {
0079     int tailroom;
0080     int limit;
0081 
0082     tailroom = skb_tailroom(skb);
0083     limit = TIPC_SKB_MAX - skb->len;
0084 
0085     if (tailroom < limit)
0086         return tailroom;
0087 
0088     return limit;
0089 }
0090 
0091 static inline int TLV_GET_DATA_LEN(struct tlv_desc *tlv)
0092 {
0093     return TLV_GET_LEN(tlv) - TLV_SPACE(0);
0094 }
0095 
0096 static int tipc_add_tlv(struct sk_buff *skb, u16 type, void *data, u16 len)
0097 {
0098     struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(skb);
0099 
0100     if (tipc_skb_tailroom(skb) < TLV_SPACE(len))
0101         return -EMSGSIZE;
0102 
0103     skb_put(skb, TLV_SPACE(len));
0104     tlv->tlv_type = htons(type);
0105     tlv->tlv_len = htons(TLV_LENGTH(len));
0106     if (len && data)
0107         memcpy(TLV_DATA(tlv), data, len);
0108 
0109     return 0;
0110 }
0111 
0112 static void tipc_tlv_init(struct sk_buff *skb, u16 type)
0113 {
0114     struct tlv_desc *tlv = (struct tlv_desc *)skb->data;
0115 
0116     TLV_SET_LEN(tlv, 0);
0117     TLV_SET_TYPE(tlv, type);
0118     skb_put(skb, sizeof(struct tlv_desc));
0119 }
0120 
0121 static __printf(2, 3) int tipc_tlv_sprintf(struct sk_buff *skb,
0122                        const char *fmt, ...)
0123 {
0124     int n;
0125     u16 len;
0126     u32 rem;
0127     char *buf;
0128     struct tlv_desc *tlv;
0129     va_list args;
0130 
0131     rem = tipc_skb_tailroom(skb);
0132 
0133     tlv = (struct tlv_desc *)skb->data;
0134     len = TLV_GET_LEN(tlv);
0135     buf = TLV_DATA(tlv) + len;
0136 
0137     va_start(args, fmt);
0138     n = vscnprintf(buf, rem, fmt, args);
0139     va_end(args);
0140 
0141     TLV_SET_LEN(tlv, n + len);
0142     skb_put(skb, n);
0143 
0144     return n;
0145 }
0146 
0147 static struct sk_buff *tipc_tlv_alloc(int size)
0148 {
0149     int hdr_len;
0150     struct sk_buff *buf;
0151 
0152     size = TLV_SPACE(size);
0153     hdr_len = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
0154 
0155     buf = alloc_skb(hdr_len + size, GFP_KERNEL);
0156     if (!buf)
0157         return NULL;
0158 
0159     skb_reserve(buf, hdr_len);
0160 
0161     return buf;
0162 }
0163 
0164 static struct sk_buff *tipc_get_err_tlv(char *str)
0165 {
0166     int str_len = strlen(str) + 1;
0167     struct sk_buff *buf;
0168 
0169     buf = tipc_tlv_alloc(TLV_SPACE(str_len));
0170     if (buf)
0171         tipc_add_tlv(buf, TIPC_TLV_ERROR_STRING, str, str_len);
0172 
0173     return buf;
0174 }
0175 
0176 static inline bool string_is_valid(char *s, int len)
0177 {
0178     return memchr(s, '\0', len) ? true : false;
0179 }
0180 
0181 static int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
0182                    struct tipc_nl_compat_msg *msg,
0183                    struct sk_buff *arg)
0184 {
0185     struct genl_dumpit_info info;
0186     int len = 0;
0187     int err;
0188     struct sk_buff *buf;
0189     struct nlmsghdr *nlmsg;
0190     struct netlink_callback cb;
0191     struct nlattr **attrbuf;
0192 
0193     memset(&cb, 0, sizeof(cb));
0194     cb.nlh = (struct nlmsghdr *)arg->data;
0195     cb.skb = arg;
0196     cb.data = &info;
0197 
0198     buf = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
0199     if (!buf)
0200         return -ENOMEM;
0201 
0202     buf->sk = msg->dst_sk;
0203     if (__tipc_dump_start(&cb, msg->net)) {
0204         kfree_skb(buf);
0205         return -ENOMEM;
0206     }
0207 
0208     attrbuf = kcalloc(tipc_genl_family.maxattr + 1,
0209               sizeof(struct nlattr *), GFP_KERNEL);
0210     if (!attrbuf) {
0211         err = -ENOMEM;
0212         goto err_out;
0213     }
0214 
0215     info.attrs = attrbuf;
0216 
0217     if (nlmsg_len(cb.nlh) > 0) {
0218         err = nlmsg_parse_deprecated(cb.nlh, GENL_HDRLEN, attrbuf,
0219                          tipc_genl_family.maxattr,
0220                          tipc_genl_family.policy, NULL);
0221         if (err)
0222             goto err_out;
0223     }
0224     do {
0225         int rem;
0226 
0227         len = (*cmd->dumpit)(buf, &cb);
0228 
0229         nlmsg_for_each_msg(nlmsg, nlmsg_hdr(buf), len, rem) {
0230             err = nlmsg_parse_deprecated(nlmsg, GENL_HDRLEN,
0231                              attrbuf,
0232                              tipc_genl_family.maxattr,
0233                              tipc_genl_family.policy,
0234                              NULL);
0235             if (err)
0236                 goto err_out;
0237 
0238             err = (*cmd->format)(msg, attrbuf);
0239             if (err)
0240                 goto err_out;
0241 
0242             if (tipc_skb_tailroom(msg->rep) <= 1) {
0243                 err = -EMSGSIZE;
0244                 goto err_out;
0245             }
0246         }
0247 
0248         skb_reset_tail_pointer(buf);
0249         buf->len = 0;
0250 
0251     } while (len);
0252 
0253     err = 0;
0254 
0255 err_out:
0256     kfree(attrbuf);
0257     tipc_dump_done(&cb);
0258     kfree_skb(buf);
0259 
0260     if (err == -EMSGSIZE) {
0261         /* The legacy API only considered messages filling
0262          * "ULTRA_STRING_MAX_LEN" to be truncated.
0263          */
0264         if ((TIPC_SKB_MAX - msg->rep->len) <= 1) {
0265             char *tail = skb_tail_pointer(msg->rep);
0266 
0267             if (*tail != '\0')
0268                 sprintf(tail - sizeof(REPLY_TRUNCATED) - 1,
0269                     REPLY_TRUNCATED);
0270         }
0271 
0272         return 0;
0273     }
0274 
0275     return err;
0276 }
0277 
0278 static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
0279                  struct tipc_nl_compat_msg *msg)
0280 {
0281     struct nlmsghdr *nlh;
0282     struct sk_buff *arg;
0283     int err;
0284 
0285     if (msg->req_type && (!msg->req_size ||
0286                   !TLV_CHECK_TYPE(msg->req, msg->req_type)))
0287         return -EINVAL;
0288 
0289     msg->rep = tipc_tlv_alloc(msg->rep_size);
0290     if (!msg->rep)
0291         return -ENOMEM;
0292 
0293     if (msg->rep_type)
0294         tipc_tlv_init(msg->rep, msg->rep_type);
0295 
0296     if (cmd->header) {
0297         err = (*cmd->header)(msg);
0298         if (err) {
0299             kfree_skb(msg->rep);
0300             msg->rep = NULL;
0301             return err;
0302         }
0303     }
0304 
0305     arg = nlmsg_new(0, GFP_KERNEL);
0306     if (!arg) {
0307         kfree_skb(msg->rep);
0308         msg->rep = NULL;
0309         return -ENOMEM;
0310     }
0311 
0312     nlh = nlmsg_put(arg, 0, 0, tipc_genl_family.id, 0, NLM_F_MULTI);
0313     if (!nlh) {
0314         kfree_skb(arg);
0315         kfree_skb(msg->rep);
0316         msg->rep = NULL;
0317         return -EMSGSIZE;
0318     }
0319     nlmsg_end(arg, nlh);
0320 
0321     err = __tipc_nl_compat_dumpit(cmd, msg, arg);
0322     if (err) {
0323         kfree_skb(msg->rep);
0324         msg->rep = NULL;
0325     }
0326     kfree_skb(arg);
0327 
0328     return err;
0329 }
0330 
0331 static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
0332                  struct tipc_nl_compat_msg *msg)
0333 {
0334     int err;
0335     struct sk_buff *doit_buf;
0336     struct sk_buff *trans_buf;
0337     struct nlattr **attrbuf;
0338     struct genl_info info;
0339 
0340     trans_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
0341     if (!trans_buf)
0342         return -ENOMEM;
0343 
0344     attrbuf = kmalloc_array(tipc_genl_family.maxattr + 1,
0345                 sizeof(struct nlattr *),
0346                 GFP_KERNEL);
0347     if (!attrbuf) {
0348         err = -ENOMEM;
0349         goto trans_out;
0350     }
0351 
0352     doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
0353     if (!doit_buf) {
0354         err = -ENOMEM;
0355         goto attrbuf_out;
0356     }
0357 
0358     memset(&info, 0, sizeof(info));
0359     info.attrs = attrbuf;
0360 
0361     rtnl_lock();
0362     err = (*cmd->transcode)(cmd, trans_buf, msg);
0363     if (err)
0364         goto doit_out;
0365 
0366     err = nla_parse_deprecated(attrbuf, tipc_genl_family.maxattr,
0367                    (const struct nlattr *)trans_buf->data,
0368                    trans_buf->len, NULL, NULL);
0369     if (err)
0370         goto doit_out;
0371 
0372     doit_buf->sk = msg->dst_sk;
0373 
0374     err = (*cmd->doit)(doit_buf, &info);
0375 doit_out:
0376     rtnl_unlock();
0377 
0378     kfree_skb(doit_buf);
0379 attrbuf_out:
0380     kfree(attrbuf);
0381 trans_out:
0382     kfree_skb(trans_buf);
0383 
0384     return err;
0385 }
0386 
0387 static int tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
0388                    struct tipc_nl_compat_msg *msg)
0389 {
0390     int err;
0391 
0392     if (msg->req_type && (!msg->req_size ||
0393                   !TLV_CHECK_TYPE(msg->req, msg->req_type)))
0394         return -EINVAL;
0395 
0396     err = __tipc_nl_compat_doit(cmd, msg);
0397     if (err)
0398         return err;
0399 
0400     /* The legacy API considered an empty message a success message */
0401     msg->rep = tipc_tlv_alloc(0);
0402     if (!msg->rep)
0403         return -ENOMEM;
0404 
0405     return 0;
0406 }
0407 
0408 static int tipc_nl_compat_bearer_dump(struct tipc_nl_compat_msg *msg,
0409                       struct nlattr **attrs)
0410 {
0411     struct nlattr *bearer[TIPC_NLA_BEARER_MAX + 1];
0412     int err;
0413 
0414     if (!attrs[TIPC_NLA_BEARER])
0415         return -EINVAL;
0416 
0417     err = nla_parse_nested_deprecated(bearer, TIPC_NLA_BEARER_MAX,
0418                       attrs[TIPC_NLA_BEARER], NULL, NULL);
0419     if (err)
0420         return err;
0421 
0422     return tipc_add_tlv(msg->rep, TIPC_TLV_BEARER_NAME,
0423                 nla_data(bearer[TIPC_NLA_BEARER_NAME]),
0424                 nla_len(bearer[TIPC_NLA_BEARER_NAME]));
0425 }
0426 
0427 static int tipc_nl_compat_bearer_enable(struct tipc_nl_compat_cmd_doit *cmd,
0428                     struct sk_buff *skb,
0429                     struct tipc_nl_compat_msg *msg)
0430 {
0431     struct nlattr *prop;
0432     struct nlattr *bearer;
0433     struct tipc_bearer_config *b;
0434     int len;
0435 
0436     b = (struct tipc_bearer_config *)TLV_DATA(msg->req);
0437 
0438     bearer = nla_nest_start_noflag(skb, TIPC_NLA_BEARER);
0439     if (!bearer)
0440         return -EMSGSIZE;
0441 
0442     len = TLV_GET_DATA_LEN(msg->req);
0443     len -= offsetof(struct tipc_bearer_config, name);
0444     if (len <= 0)
0445         return -EINVAL;
0446 
0447     len = min_t(int, len, TIPC_MAX_BEARER_NAME);
0448     if (!string_is_valid(b->name, len))
0449         return -EINVAL;
0450 
0451     if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, b->name))
0452         return -EMSGSIZE;
0453 
0454     if (nla_put_u32(skb, TIPC_NLA_BEARER_DOMAIN, ntohl(b->disc_domain)))
0455         return -EMSGSIZE;
0456 
0457     if (ntohl(b->priority) <= TIPC_MAX_LINK_PRI) {
0458         prop = nla_nest_start_noflag(skb, TIPC_NLA_BEARER_PROP);
0459         if (!prop)
0460             return -EMSGSIZE;
0461         if (nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(b->priority)))
0462             return -EMSGSIZE;
0463         nla_nest_end(skb, prop);
0464     }
0465     nla_nest_end(skb, bearer);
0466 
0467     return 0;
0468 }
0469 
0470 static int tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit *cmd,
0471                      struct sk_buff *skb,
0472                      struct tipc_nl_compat_msg *msg)
0473 {
0474     char *name;
0475     struct nlattr *bearer;
0476     int len;
0477 
0478     name = (char *)TLV_DATA(msg->req);
0479 
0480     bearer = nla_nest_start_noflag(skb, TIPC_NLA_BEARER);
0481     if (!bearer)
0482         return -EMSGSIZE;
0483 
0484     len = TLV_GET_DATA_LEN(msg->req);
0485     if (len <= 0)
0486         return -EINVAL;
0487 
0488     len = min_t(int, len, TIPC_MAX_BEARER_NAME);
0489     if (!string_is_valid(name, len))
0490         return -EINVAL;
0491 
0492     if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, name))
0493         return -EMSGSIZE;
0494 
0495     nla_nest_end(skb, bearer);
0496 
0497     return 0;
0498 }
0499 
0500 static inline u32 perc(u32 count, u32 total)
0501 {
0502     return (count * 100 + (total / 2)) / total;
0503 }
0504 
0505 static void __fill_bc_link_stat(struct tipc_nl_compat_msg *msg,
0506                 struct nlattr *prop[], struct nlattr *stats[])
0507 {
0508     tipc_tlv_sprintf(msg->rep, "  Window:%u packets\n",
0509              nla_get_u32(prop[TIPC_NLA_PROP_WIN]));
0510 
0511     tipc_tlv_sprintf(msg->rep,
0512              "  RX packets:%u fragments:%u/%u bundles:%u/%u\n",
0513              nla_get_u32(stats[TIPC_NLA_STATS_RX_INFO]),
0514              nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]),
0515              nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]),
0516              nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]),
0517              nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED]));
0518 
0519     tipc_tlv_sprintf(msg->rep,
0520              "  TX packets:%u fragments:%u/%u bundles:%u/%u\n",
0521              nla_get_u32(stats[TIPC_NLA_STATS_TX_INFO]),
0522              nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]),
0523              nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]),
0524              nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]),
0525              nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED]));
0526 
0527     tipc_tlv_sprintf(msg->rep, "  RX naks:%u defs:%u dups:%u\n",
0528              nla_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]),
0529              nla_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]),
0530              nla_get_u32(stats[TIPC_NLA_STATS_DUPLICATES]));
0531 
0532     tipc_tlv_sprintf(msg->rep, "  TX naks:%u acks:%u dups:%u\n",
0533              nla_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]),
0534              nla_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]),
0535              nla_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED]));
0536 
0537     tipc_tlv_sprintf(msg->rep,
0538              "  Congestion link:%u  Send queue max:%u avg:%u",
0539              nla_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]),
0540              nla_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]),
0541              nla_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE]));
0542 }
0543 
0544 static int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg,
0545                      struct nlattr **attrs)
0546 {
0547     char *name;
0548     struct nlattr *link[TIPC_NLA_LINK_MAX + 1];
0549     struct nlattr *prop[TIPC_NLA_PROP_MAX + 1];
0550     struct nlattr *stats[TIPC_NLA_STATS_MAX + 1];
0551     int err;
0552     int len;
0553 
0554     if (!attrs[TIPC_NLA_LINK])
0555         return -EINVAL;
0556 
0557     err = nla_parse_nested_deprecated(link, TIPC_NLA_LINK_MAX,
0558                       attrs[TIPC_NLA_LINK], NULL, NULL);
0559     if (err)
0560         return err;
0561 
0562     if (!link[TIPC_NLA_LINK_PROP])
0563         return -EINVAL;
0564 
0565     err = nla_parse_nested_deprecated(prop, TIPC_NLA_PROP_MAX,
0566                       link[TIPC_NLA_LINK_PROP], NULL,
0567                       NULL);
0568     if (err)
0569         return err;
0570 
0571     if (!link[TIPC_NLA_LINK_STATS])
0572         return -EINVAL;
0573 
0574     err = nla_parse_nested_deprecated(stats, TIPC_NLA_STATS_MAX,
0575                       link[TIPC_NLA_LINK_STATS], NULL,
0576                       NULL);
0577     if (err)
0578         return err;
0579 
0580     name = (char *)TLV_DATA(msg->req);
0581 
0582     len = TLV_GET_DATA_LEN(msg->req);
0583     if (len <= 0)
0584         return -EINVAL;
0585 
0586     len = min_t(int, len, TIPC_MAX_LINK_NAME);
0587     if (!string_is_valid(name, len))
0588         return -EINVAL;
0589 
0590     if (strcmp(name, nla_data(link[TIPC_NLA_LINK_NAME])) != 0)
0591         return 0;
0592 
0593     tipc_tlv_sprintf(msg->rep, "\nLink <%s>\n",
0594              (char *)nla_data(link[TIPC_NLA_LINK_NAME]));
0595 
0596     if (link[TIPC_NLA_LINK_BROADCAST]) {
0597         __fill_bc_link_stat(msg, prop, stats);
0598         return 0;
0599     }
0600 
0601     if (link[TIPC_NLA_LINK_ACTIVE])
0602         tipc_tlv_sprintf(msg->rep, "  ACTIVE");
0603     else if (link[TIPC_NLA_LINK_UP])
0604         tipc_tlv_sprintf(msg->rep, "  STANDBY");
0605     else
0606         tipc_tlv_sprintf(msg->rep, "  DEFUNCT");
0607 
0608     tipc_tlv_sprintf(msg->rep, "  MTU:%u  Priority:%u",
0609              nla_get_u32(link[TIPC_NLA_LINK_MTU]),
0610              nla_get_u32(prop[TIPC_NLA_PROP_PRIO]));
0611 
0612     tipc_tlv_sprintf(msg->rep, "  Tolerance:%u ms  Window:%u packets\n",
0613              nla_get_u32(prop[TIPC_NLA_PROP_TOL]),
0614              nla_get_u32(prop[TIPC_NLA_PROP_WIN]));
0615 
0616     tipc_tlv_sprintf(msg->rep,
0617              "  RX packets:%u fragments:%u/%u bundles:%u/%u\n",
0618              nla_get_u32(link[TIPC_NLA_LINK_RX]) -
0619              nla_get_u32(stats[TIPC_NLA_STATS_RX_INFO]),
0620              nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]),
0621              nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]),
0622              nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]),
0623              nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED]));
0624 
0625     tipc_tlv_sprintf(msg->rep,
0626              "  TX packets:%u fragments:%u/%u bundles:%u/%u\n",
0627              nla_get_u32(link[TIPC_NLA_LINK_TX]) -
0628              nla_get_u32(stats[TIPC_NLA_STATS_TX_INFO]),
0629              nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]),
0630              nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]),
0631              nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]),
0632              nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED]));
0633 
0634     tipc_tlv_sprintf(msg->rep,
0635              "  TX profile sample:%u packets  average:%u octets\n",
0636              nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_CNT]),
0637              nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_TOT]) /
0638              nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT]));
0639 
0640     tipc_tlv_sprintf(msg->rep,
0641              "  0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% ",
0642              perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P0]),
0643                   nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
0644              perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P1]),
0645                   nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
0646              perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P2]),
0647                   nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
0648              perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P3]),
0649                   nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])));
0650 
0651     tipc_tlv_sprintf(msg->rep, "-16384:%u%% -32768:%u%% -66000:%u%%\n",
0652              perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P4]),
0653                   nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
0654              perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P5]),
0655                   nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
0656              perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P6]),
0657                   nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])));
0658 
0659     tipc_tlv_sprintf(msg->rep,
0660              "  RX states:%u probes:%u naks:%u defs:%u dups:%u\n",
0661              nla_get_u32(stats[TIPC_NLA_STATS_RX_STATES]),
0662              nla_get_u32(stats[TIPC_NLA_STATS_RX_PROBES]),
0663              nla_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]),
0664              nla_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]),
0665              nla_get_u32(stats[TIPC_NLA_STATS_DUPLICATES]));
0666 
0667     tipc_tlv_sprintf(msg->rep,
0668              "  TX states:%u probes:%u naks:%u acks:%u dups:%u\n",
0669              nla_get_u32(stats[TIPC_NLA_STATS_TX_STATES]),
0670              nla_get_u32(stats[TIPC_NLA_STATS_TX_PROBES]),
0671              nla_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]),
0672              nla_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]),
0673              nla_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED]));
0674 
0675     tipc_tlv_sprintf(msg->rep,
0676              "  Congestion link:%u  Send queue max:%u avg:%u",
0677              nla_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]),
0678              nla_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]),
0679              nla_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE]));
0680 
0681     return 0;
0682 }
0683 
0684 static int tipc_nl_compat_link_dump(struct tipc_nl_compat_msg *msg,
0685                     struct nlattr **attrs)
0686 {
0687     struct nlattr *link[TIPC_NLA_LINK_MAX + 1];
0688     struct tipc_link_info link_info;
0689     int err;
0690 
0691     if (!attrs[TIPC_NLA_LINK])
0692         return -EINVAL;
0693 
0694     err = nla_parse_nested_deprecated(link, TIPC_NLA_LINK_MAX,
0695                       attrs[TIPC_NLA_LINK], NULL, NULL);
0696     if (err)
0697         return err;
0698 
0699     link_info.dest = htonl(nla_get_flag(link[TIPC_NLA_LINK_DEST]));
0700     link_info.up = htonl(nla_get_flag(link[TIPC_NLA_LINK_UP]));
0701     nla_strscpy(link_info.str, link[TIPC_NLA_LINK_NAME],
0702             TIPC_MAX_LINK_NAME);
0703 
0704     return tipc_add_tlv(msg->rep, TIPC_TLV_LINK_INFO,
0705                 &link_info, sizeof(link_info));
0706 }
0707 
0708 static int __tipc_add_link_prop(struct sk_buff *skb,
0709                 struct tipc_nl_compat_msg *msg,
0710                 struct tipc_link_config *lc)
0711 {
0712     switch (msg->cmd) {
0713     case TIPC_CMD_SET_LINK_PRI:
0714         return nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(lc->value));
0715     case TIPC_CMD_SET_LINK_TOL:
0716         return nla_put_u32(skb, TIPC_NLA_PROP_TOL, ntohl(lc->value));
0717     case TIPC_CMD_SET_LINK_WINDOW:
0718         return nla_put_u32(skb, TIPC_NLA_PROP_WIN, ntohl(lc->value));
0719     }
0720 
0721     return -EINVAL;
0722 }
0723 
0724 static int tipc_nl_compat_media_set(struct sk_buff *skb,
0725                     struct tipc_nl_compat_msg *msg)
0726 {
0727     struct nlattr *prop;
0728     struct nlattr *media;
0729     struct tipc_link_config *lc;
0730 
0731     lc = (struct tipc_link_config *)TLV_DATA(msg->req);
0732 
0733     media = nla_nest_start_noflag(skb, TIPC_NLA_MEDIA);
0734     if (!media)
0735         return -EMSGSIZE;
0736 
0737     if (nla_put_string(skb, TIPC_NLA_MEDIA_NAME, lc->name))
0738         return -EMSGSIZE;
0739 
0740     prop = nla_nest_start_noflag(skb, TIPC_NLA_MEDIA_PROP);
0741     if (!prop)
0742         return -EMSGSIZE;
0743 
0744     __tipc_add_link_prop(skb, msg, lc);
0745     nla_nest_end(skb, prop);
0746     nla_nest_end(skb, media);
0747 
0748     return 0;
0749 }
0750 
0751 static int tipc_nl_compat_bearer_set(struct sk_buff *skb,
0752                      struct tipc_nl_compat_msg *msg)
0753 {
0754     struct nlattr *prop;
0755     struct nlattr *bearer;
0756     struct tipc_link_config *lc;
0757 
0758     lc = (struct tipc_link_config *)TLV_DATA(msg->req);
0759 
0760     bearer = nla_nest_start_noflag(skb, TIPC_NLA_BEARER);
0761     if (!bearer)
0762         return -EMSGSIZE;
0763 
0764     if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, lc->name))
0765         return -EMSGSIZE;
0766 
0767     prop = nla_nest_start_noflag(skb, TIPC_NLA_BEARER_PROP);
0768     if (!prop)
0769         return -EMSGSIZE;
0770 
0771     __tipc_add_link_prop(skb, msg, lc);
0772     nla_nest_end(skb, prop);
0773     nla_nest_end(skb, bearer);
0774 
0775     return 0;
0776 }
0777 
0778 static int __tipc_nl_compat_link_set(struct sk_buff *skb,
0779                      struct tipc_nl_compat_msg *msg)
0780 {
0781     struct nlattr *prop;
0782     struct nlattr *link;
0783     struct tipc_link_config *lc;
0784 
0785     lc = (struct tipc_link_config *)TLV_DATA(msg->req);
0786 
0787     link = nla_nest_start_noflag(skb, TIPC_NLA_LINK);
0788     if (!link)
0789         return -EMSGSIZE;
0790 
0791     if (nla_put_string(skb, TIPC_NLA_LINK_NAME, lc->name))
0792         return -EMSGSIZE;
0793 
0794     prop = nla_nest_start_noflag(skb, TIPC_NLA_LINK_PROP);
0795     if (!prop)
0796         return -EMSGSIZE;
0797 
0798     __tipc_add_link_prop(skb, msg, lc);
0799     nla_nest_end(skb, prop);
0800     nla_nest_end(skb, link);
0801 
0802     return 0;
0803 }
0804 
0805 static int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd,
0806                    struct sk_buff *skb,
0807                    struct tipc_nl_compat_msg *msg)
0808 {
0809     struct tipc_link_config *lc;
0810     struct tipc_bearer *bearer;
0811     struct tipc_media *media;
0812     int len;
0813 
0814     lc = (struct tipc_link_config *)TLV_DATA(msg->req);
0815 
0816     len = TLV_GET_DATA_LEN(msg->req);
0817     len -= offsetof(struct tipc_link_config, name);
0818     if (len <= 0)
0819         return -EINVAL;
0820 
0821     len = min_t(int, len, TIPC_MAX_LINK_NAME);
0822     if (!string_is_valid(lc->name, len))
0823         return -EINVAL;
0824 
0825     media = tipc_media_find(lc->name);
0826     if (media) {
0827         cmd->doit = &__tipc_nl_media_set;
0828         return tipc_nl_compat_media_set(skb, msg);
0829     }
0830 
0831     bearer = tipc_bearer_find(msg->net, lc->name);
0832     if (bearer) {
0833         cmd->doit = &__tipc_nl_bearer_set;
0834         return tipc_nl_compat_bearer_set(skb, msg);
0835     }
0836 
0837     return __tipc_nl_compat_link_set(skb, msg);
0838 }
0839 
0840 static int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd,
0841                        struct sk_buff *skb,
0842                        struct tipc_nl_compat_msg *msg)
0843 {
0844     char *name;
0845     struct nlattr *link;
0846     int len;
0847 
0848     name = (char *)TLV_DATA(msg->req);
0849 
0850     link = nla_nest_start_noflag(skb, TIPC_NLA_LINK);
0851     if (!link)
0852         return -EMSGSIZE;
0853 
0854     len = TLV_GET_DATA_LEN(msg->req);
0855     if (len <= 0)
0856         return -EINVAL;
0857 
0858     len = min_t(int, len, TIPC_MAX_LINK_NAME);
0859     if (!string_is_valid(name, len))
0860         return -EINVAL;
0861 
0862     if (nla_put_string(skb, TIPC_NLA_LINK_NAME, name))
0863         return -EMSGSIZE;
0864 
0865     nla_nest_end(skb, link);
0866 
0867     return 0;
0868 }
0869 
0870 static int tipc_nl_compat_name_table_dump_header(struct tipc_nl_compat_msg *msg)
0871 {
0872     int i;
0873     u32 depth;
0874     struct tipc_name_table_query *ntq;
0875     static const char * const header[] = {
0876         "Type       ",
0877         "Lower      Upper      ",
0878         "Port Identity              ",
0879         "Publication Scope"
0880     };
0881 
0882     ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req);
0883     if (TLV_GET_DATA_LEN(msg->req) < sizeof(struct tipc_name_table_query))
0884         return -EINVAL;
0885 
0886     depth = ntohl(ntq->depth);
0887 
0888     if (depth > 4)
0889         depth = 4;
0890     for (i = 0; i < depth; i++)
0891         tipc_tlv_sprintf(msg->rep, header[i]);
0892     tipc_tlv_sprintf(msg->rep, "\n");
0893 
0894     return 0;
0895 }
0896 
0897 static int tipc_nl_compat_name_table_dump(struct tipc_nl_compat_msg *msg,
0898                       struct nlattr **attrs)
0899 {
0900     char port_str[27];
0901     struct tipc_name_table_query *ntq;
0902     struct nlattr *nt[TIPC_NLA_NAME_TABLE_MAX + 1];
0903     struct nlattr *publ[TIPC_NLA_PUBL_MAX + 1];
0904     u32 node, depth, type, lowbound, upbound;
0905     static const char * const scope_str[] = {"", " zone", " cluster",
0906                          " node"};
0907     int err;
0908 
0909     if (!attrs[TIPC_NLA_NAME_TABLE])
0910         return -EINVAL;
0911 
0912     err = nla_parse_nested_deprecated(nt, TIPC_NLA_NAME_TABLE_MAX,
0913                       attrs[TIPC_NLA_NAME_TABLE], NULL,
0914                       NULL);
0915     if (err)
0916         return err;
0917 
0918     if (!nt[TIPC_NLA_NAME_TABLE_PUBL])
0919         return -EINVAL;
0920 
0921     err = nla_parse_nested_deprecated(publ, TIPC_NLA_PUBL_MAX,
0922                       nt[TIPC_NLA_NAME_TABLE_PUBL], NULL,
0923                       NULL);
0924     if (err)
0925         return err;
0926 
0927     ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req);
0928 
0929     depth = ntohl(ntq->depth);
0930     type = ntohl(ntq->type);
0931     lowbound = ntohl(ntq->lowbound);
0932     upbound = ntohl(ntq->upbound);
0933 
0934     if (!(depth & TIPC_NTQ_ALLTYPES) &&
0935         (type != nla_get_u32(publ[TIPC_NLA_PUBL_TYPE])))
0936         return 0;
0937     if (lowbound && (lowbound > nla_get_u32(publ[TIPC_NLA_PUBL_UPPER])))
0938         return 0;
0939     if (upbound && (upbound < nla_get_u32(publ[TIPC_NLA_PUBL_LOWER])))
0940         return 0;
0941 
0942     tipc_tlv_sprintf(msg->rep, "%-10u ",
0943              nla_get_u32(publ[TIPC_NLA_PUBL_TYPE]));
0944 
0945     if (depth == 1)
0946         goto out;
0947 
0948     tipc_tlv_sprintf(msg->rep, "%-10u %-10u ",
0949              nla_get_u32(publ[TIPC_NLA_PUBL_LOWER]),
0950              nla_get_u32(publ[TIPC_NLA_PUBL_UPPER]));
0951 
0952     if (depth == 2)
0953         goto out;
0954 
0955     node = nla_get_u32(publ[TIPC_NLA_PUBL_NODE]);
0956     sprintf(port_str, "<%u.%u.%u:%u>", tipc_zone(node), tipc_cluster(node),
0957         tipc_node(node), nla_get_u32(publ[TIPC_NLA_PUBL_REF]));
0958     tipc_tlv_sprintf(msg->rep, "%-26s ", port_str);
0959 
0960     if (depth == 3)
0961         goto out;
0962 
0963     tipc_tlv_sprintf(msg->rep, "%-10u %s",
0964              nla_get_u32(publ[TIPC_NLA_PUBL_KEY]),
0965              scope_str[nla_get_u32(publ[TIPC_NLA_PUBL_SCOPE])]);
0966 out:
0967     tipc_tlv_sprintf(msg->rep, "\n");
0968 
0969     return 0;
0970 }
0971 
0972 static int __tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg *msg,
0973                       struct nlattr **attrs)
0974 {
0975     u32 type, lower, upper;
0976     struct nlattr *publ[TIPC_NLA_PUBL_MAX + 1];
0977     int err;
0978 
0979     if (!attrs[TIPC_NLA_PUBL])
0980         return -EINVAL;
0981 
0982     err = nla_parse_nested_deprecated(publ, TIPC_NLA_PUBL_MAX,
0983                       attrs[TIPC_NLA_PUBL], NULL, NULL);
0984     if (err)
0985         return err;
0986 
0987     type = nla_get_u32(publ[TIPC_NLA_PUBL_TYPE]);
0988     lower = nla_get_u32(publ[TIPC_NLA_PUBL_LOWER]);
0989     upper = nla_get_u32(publ[TIPC_NLA_PUBL_UPPER]);
0990 
0991     if (lower == upper)
0992         tipc_tlv_sprintf(msg->rep, " {%u,%u}", type, lower);
0993     else
0994         tipc_tlv_sprintf(msg->rep, " {%u,%u,%u}", type, lower, upper);
0995 
0996     return 0;
0997 }
0998 
0999 static int tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg *msg, u32 sock)
1000 {
1001     int err;
1002     void *hdr;
1003     struct nlattr *nest;
1004     struct sk_buff *args;
1005     struct tipc_nl_compat_cmd_dump dump;
1006 
1007     args = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1008     if (!args)
1009         return -ENOMEM;
1010 
1011     hdr = genlmsg_put(args, 0, 0, &tipc_genl_family, NLM_F_MULTI,
1012               TIPC_NL_PUBL_GET);
1013     if (!hdr) {
1014         kfree_skb(args);
1015         return -EMSGSIZE;
1016     }
1017 
1018     nest = nla_nest_start_noflag(args, TIPC_NLA_SOCK);
1019     if (!nest) {
1020         kfree_skb(args);
1021         return -EMSGSIZE;
1022     }
1023 
1024     if (nla_put_u32(args, TIPC_NLA_SOCK_REF, sock)) {
1025         kfree_skb(args);
1026         return -EMSGSIZE;
1027     }
1028 
1029     nla_nest_end(args, nest);
1030     genlmsg_end(args, hdr);
1031 
1032     dump.dumpit = tipc_nl_publ_dump;
1033     dump.format = __tipc_nl_compat_publ_dump;
1034 
1035     err = __tipc_nl_compat_dumpit(&dump, msg, args);
1036 
1037     kfree_skb(args);
1038 
1039     return err;
1040 }
1041 
1042 static int tipc_nl_compat_sk_dump(struct tipc_nl_compat_msg *msg,
1043                   struct nlattr **attrs)
1044 {
1045     int err;
1046     u32 sock_ref;
1047     struct nlattr *sock[TIPC_NLA_SOCK_MAX + 1];
1048 
1049     if (!attrs[TIPC_NLA_SOCK])
1050         return -EINVAL;
1051 
1052     err = nla_parse_nested_deprecated(sock, TIPC_NLA_SOCK_MAX,
1053                       attrs[TIPC_NLA_SOCK], NULL, NULL);
1054     if (err)
1055         return err;
1056 
1057     sock_ref = nla_get_u32(sock[TIPC_NLA_SOCK_REF]);
1058     tipc_tlv_sprintf(msg->rep, "%u:", sock_ref);
1059 
1060     if (sock[TIPC_NLA_SOCK_CON]) {
1061         u32 node;
1062         struct nlattr *con[TIPC_NLA_CON_MAX + 1];
1063 
1064         err = nla_parse_nested_deprecated(con, TIPC_NLA_CON_MAX,
1065                           sock[TIPC_NLA_SOCK_CON],
1066                           NULL, NULL);
1067 
1068         if (err)
1069             return err;
1070 
1071         node = nla_get_u32(con[TIPC_NLA_CON_NODE]);
1072         tipc_tlv_sprintf(msg->rep, "  connected to <%u.%u.%u:%u>",
1073                  tipc_zone(node),
1074                  tipc_cluster(node),
1075                  tipc_node(node),
1076                  nla_get_u32(con[TIPC_NLA_CON_SOCK]));
1077 
1078         if (con[TIPC_NLA_CON_FLAG])
1079             tipc_tlv_sprintf(msg->rep, " via {%u,%u}\n",
1080                      nla_get_u32(con[TIPC_NLA_CON_TYPE]),
1081                      nla_get_u32(con[TIPC_NLA_CON_INST]));
1082         else
1083             tipc_tlv_sprintf(msg->rep, "\n");
1084     } else if (sock[TIPC_NLA_SOCK_HAS_PUBL]) {
1085         tipc_tlv_sprintf(msg->rep, " bound to");
1086 
1087         err = tipc_nl_compat_publ_dump(msg, sock_ref);
1088         if (err)
1089             return err;
1090     }
1091     tipc_tlv_sprintf(msg->rep, "\n");
1092 
1093     return 0;
1094 }
1095 
1096 static int tipc_nl_compat_media_dump(struct tipc_nl_compat_msg *msg,
1097                      struct nlattr **attrs)
1098 {
1099     struct nlattr *media[TIPC_NLA_MEDIA_MAX + 1];
1100     int err;
1101 
1102     if (!attrs[TIPC_NLA_MEDIA])
1103         return -EINVAL;
1104 
1105     err = nla_parse_nested_deprecated(media, TIPC_NLA_MEDIA_MAX,
1106                       attrs[TIPC_NLA_MEDIA], NULL, NULL);
1107     if (err)
1108         return err;
1109 
1110     return tipc_add_tlv(msg->rep, TIPC_TLV_MEDIA_NAME,
1111                 nla_data(media[TIPC_NLA_MEDIA_NAME]),
1112                 nla_len(media[TIPC_NLA_MEDIA_NAME]));
1113 }
1114 
1115 static int tipc_nl_compat_node_dump(struct tipc_nl_compat_msg *msg,
1116                     struct nlattr **attrs)
1117 {
1118     struct tipc_node_info node_info;
1119     struct nlattr *node[TIPC_NLA_NODE_MAX + 1];
1120     int err;
1121 
1122     if (!attrs[TIPC_NLA_NODE])
1123         return -EINVAL;
1124 
1125     err = nla_parse_nested_deprecated(node, TIPC_NLA_NODE_MAX,
1126                       attrs[TIPC_NLA_NODE], NULL, NULL);
1127     if (err)
1128         return err;
1129 
1130     node_info.addr = htonl(nla_get_u32(node[TIPC_NLA_NODE_ADDR]));
1131     node_info.up = htonl(nla_get_flag(node[TIPC_NLA_NODE_UP]));
1132 
1133     return tipc_add_tlv(msg->rep, TIPC_TLV_NODE_INFO, &node_info,
1134                 sizeof(node_info));
1135 }
1136 
1137 static int tipc_nl_compat_net_set(struct tipc_nl_compat_cmd_doit *cmd,
1138                   struct sk_buff *skb,
1139                   struct tipc_nl_compat_msg *msg)
1140 {
1141     u32 val;
1142     struct nlattr *net;
1143 
1144     val = ntohl(*(__be32 *)TLV_DATA(msg->req));
1145 
1146     net = nla_nest_start_noflag(skb, TIPC_NLA_NET);
1147     if (!net)
1148         return -EMSGSIZE;
1149 
1150     if (msg->cmd == TIPC_CMD_SET_NODE_ADDR) {
1151         if (nla_put_u32(skb, TIPC_NLA_NET_ADDR, val))
1152             return -EMSGSIZE;
1153     } else if (msg->cmd == TIPC_CMD_SET_NETID) {
1154         if (nla_put_u32(skb, TIPC_NLA_NET_ID, val))
1155             return -EMSGSIZE;
1156     }
1157     nla_nest_end(skb, net);
1158 
1159     return 0;
1160 }
1161 
1162 static int tipc_nl_compat_net_dump(struct tipc_nl_compat_msg *msg,
1163                    struct nlattr **attrs)
1164 {
1165     __be32 id;
1166     struct nlattr *net[TIPC_NLA_NET_MAX + 1];
1167     int err;
1168 
1169     if (!attrs[TIPC_NLA_NET])
1170         return -EINVAL;
1171 
1172     err = nla_parse_nested_deprecated(net, TIPC_NLA_NET_MAX,
1173                       attrs[TIPC_NLA_NET], NULL, NULL);
1174     if (err)
1175         return err;
1176 
1177     id = htonl(nla_get_u32(net[TIPC_NLA_NET_ID]));
1178 
1179     return tipc_add_tlv(msg->rep, TIPC_TLV_UNSIGNED, &id, sizeof(id));
1180 }
1181 
1182 static int tipc_cmd_show_stats_compat(struct tipc_nl_compat_msg *msg)
1183 {
1184     msg->rep = tipc_tlv_alloc(ULTRA_STRING_MAX_LEN);
1185     if (!msg->rep)
1186         return -ENOMEM;
1187 
1188     tipc_tlv_init(msg->rep, TIPC_TLV_ULTRA_STRING);
1189     tipc_tlv_sprintf(msg->rep, "TIPC version " TIPC_MOD_VER "\n");
1190 
1191     return 0;
1192 }
1193 
1194 static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
1195 {
1196     struct tipc_nl_compat_cmd_dump dump;
1197     struct tipc_nl_compat_cmd_doit doit;
1198 
1199     memset(&dump, 0, sizeof(dump));
1200     memset(&doit, 0, sizeof(doit));
1201 
1202     switch (msg->cmd) {
1203     case TIPC_CMD_NOOP:
1204         msg->rep = tipc_tlv_alloc(0);
1205         if (!msg->rep)
1206             return -ENOMEM;
1207         return 0;
1208     case TIPC_CMD_GET_BEARER_NAMES:
1209         msg->rep_size = MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME);
1210         dump.dumpit = tipc_nl_bearer_dump;
1211         dump.format = tipc_nl_compat_bearer_dump;
1212         return tipc_nl_compat_dumpit(&dump, msg);
1213     case TIPC_CMD_ENABLE_BEARER:
1214         msg->req_type = TIPC_TLV_BEARER_CONFIG;
1215         doit.doit = __tipc_nl_bearer_enable;
1216         doit.transcode = tipc_nl_compat_bearer_enable;
1217         return tipc_nl_compat_doit(&doit, msg);
1218     case TIPC_CMD_DISABLE_BEARER:
1219         msg->req_type = TIPC_TLV_BEARER_NAME;
1220         doit.doit = __tipc_nl_bearer_disable;
1221         doit.transcode = tipc_nl_compat_bearer_disable;
1222         return tipc_nl_compat_doit(&doit, msg);
1223     case TIPC_CMD_SHOW_LINK_STATS:
1224         msg->req_type = TIPC_TLV_LINK_NAME;
1225         msg->rep_size = ULTRA_STRING_MAX_LEN;
1226         msg->rep_type = TIPC_TLV_ULTRA_STRING;
1227         dump.dumpit = tipc_nl_node_dump_link;
1228         dump.format = tipc_nl_compat_link_stat_dump;
1229         return tipc_nl_compat_dumpit(&dump, msg);
1230     case TIPC_CMD_GET_LINKS:
1231         msg->req_type = TIPC_TLV_NET_ADDR;
1232         msg->rep_size = ULTRA_STRING_MAX_LEN;
1233         dump.dumpit = tipc_nl_node_dump_link;
1234         dump.format = tipc_nl_compat_link_dump;
1235         return tipc_nl_compat_dumpit(&dump, msg);
1236     case TIPC_CMD_SET_LINK_TOL:
1237     case TIPC_CMD_SET_LINK_PRI:
1238     case TIPC_CMD_SET_LINK_WINDOW:
1239         msg->req_type =  TIPC_TLV_LINK_CONFIG;
1240         doit.doit = tipc_nl_node_set_link;
1241         doit.transcode = tipc_nl_compat_link_set;
1242         return tipc_nl_compat_doit(&doit, msg);
1243     case TIPC_CMD_RESET_LINK_STATS:
1244         msg->req_type = TIPC_TLV_LINK_NAME;
1245         doit.doit = tipc_nl_node_reset_link_stats;
1246         doit.transcode = tipc_nl_compat_link_reset_stats;
1247         return tipc_nl_compat_doit(&doit, msg);
1248     case TIPC_CMD_SHOW_NAME_TABLE:
1249         msg->req_type = TIPC_TLV_NAME_TBL_QUERY;
1250         msg->rep_size = ULTRA_STRING_MAX_LEN;
1251         msg->rep_type = TIPC_TLV_ULTRA_STRING;
1252         dump.header = tipc_nl_compat_name_table_dump_header;
1253         dump.dumpit = tipc_nl_name_table_dump;
1254         dump.format = tipc_nl_compat_name_table_dump;
1255         return tipc_nl_compat_dumpit(&dump, msg);
1256     case TIPC_CMD_SHOW_PORTS:
1257         msg->rep_size = ULTRA_STRING_MAX_LEN;
1258         msg->rep_type = TIPC_TLV_ULTRA_STRING;
1259         dump.dumpit = tipc_nl_sk_dump;
1260         dump.format = tipc_nl_compat_sk_dump;
1261         return tipc_nl_compat_dumpit(&dump, msg);
1262     case TIPC_CMD_GET_MEDIA_NAMES:
1263         msg->rep_size = MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME);
1264         dump.dumpit = tipc_nl_media_dump;
1265         dump.format = tipc_nl_compat_media_dump;
1266         return tipc_nl_compat_dumpit(&dump, msg);
1267     case TIPC_CMD_GET_NODES:
1268         msg->rep_size = ULTRA_STRING_MAX_LEN;
1269         dump.dumpit = tipc_nl_node_dump;
1270         dump.format = tipc_nl_compat_node_dump;
1271         return tipc_nl_compat_dumpit(&dump, msg);
1272     case TIPC_CMD_SET_NODE_ADDR:
1273         msg->req_type = TIPC_TLV_NET_ADDR;
1274         doit.doit = __tipc_nl_net_set;
1275         doit.transcode = tipc_nl_compat_net_set;
1276         return tipc_nl_compat_doit(&doit, msg);
1277     case TIPC_CMD_SET_NETID:
1278         msg->req_type = TIPC_TLV_UNSIGNED;
1279         doit.doit = __tipc_nl_net_set;
1280         doit.transcode = tipc_nl_compat_net_set;
1281         return tipc_nl_compat_doit(&doit, msg);
1282     case TIPC_CMD_GET_NETID:
1283         msg->rep_size = sizeof(u32);
1284         dump.dumpit = tipc_nl_net_dump;
1285         dump.format = tipc_nl_compat_net_dump;
1286         return tipc_nl_compat_dumpit(&dump, msg);
1287     case TIPC_CMD_SHOW_STATS:
1288         return tipc_cmd_show_stats_compat(msg);
1289     }
1290 
1291     return -EOPNOTSUPP;
1292 }
1293 
1294 static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info)
1295 {
1296     int err;
1297     int len;
1298     struct tipc_nl_compat_msg msg;
1299     struct nlmsghdr *req_nlh;
1300     struct nlmsghdr *rep_nlh;
1301     struct tipc_genlmsghdr *req_userhdr = info->userhdr;
1302 
1303     memset(&msg, 0, sizeof(msg));
1304 
1305     req_nlh = (struct nlmsghdr *)skb->data;
1306     msg.req = nlmsg_data(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN;
1307     msg.cmd = req_userhdr->cmd;
1308     msg.net = genl_info_net(info);
1309     msg.dst_sk = skb->sk;
1310 
1311     if ((msg.cmd & 0xC000) && (!netlink_net_capable(skb, CAP_NET_ADMIN))) {
1312         msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_NET_ADMIN);
1313         err = -EACCES;
1314         goto send;
1315     }
1316 
1317     msg.req_size = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN);
1318     if (msg.req_size && !TLV_OK(msg.req, msg.req_size)) {
1319         msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED);
1320         err = -EOPNOTSUPP;
1321         goto send;
1322     }
1323 
1324     err = tipc_nl_compat_handle(&msg);
1325     if ((err == -EOPNOTSUPP) || (err == -EPERM))
1326         msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED);
1327     else if (err == -EINVAL)
1328         msg.rep = tipc_get_err_tlv(TIPC_CFG_TLV_ERROR);
1329 send:
1330     if (!msg.rep)
1331         return err;
1332 
1333     len = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
1334     skb_push(msg.rep, len);
1335     rep_nlh = nlmsg_hdr(msg.rep);
1336     memcpy(rep_nlh, info->nlhdr, len);
1337     rep_nlh->nlmsg_len = msg.rep->len;
1338     genlmsg_unicast(msg.net, msg.rep, NETLINK_CB(skb).portid);
1339 
1340     return err;
1341 }
1342 
1343 static const struct genl_small_ops tipc_genl_compat_ops[] = {
1344     {
1345         .cmd        = TIPC_GENL_CMD,
1346         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1347         .doit       = tipc_nl_compat_recv,
1348     },
1349 };
1350 
1351 static struct genl_family tipc_genl_compat_family __ro_after_init = {
1352     .name       = TIPC_GENL_NAME,
1353     .version    = TIPC_GENL_VERSION,
1354     .hdrsize    = TIPC_GENL_HDRLEN,
1355     .maxattr    = 0,
1356     .netnsok    = true,
1357     .module     = THIS_MODULE,
1358     .small_ops  = tipc_genl_compat_ops,
1359     .n_small_ops    = ARRAY_SIZE(tipc_genl_compat_ops),
1360 };
1361 
1362 int __init tipc_netlink_compat_start(void)
1363 {
1364     int res;
1365 
1366     res = genl_register_family(&tipc_genl_compat_family);
1367     if (res) {
1368         pr_err("Failed to register legacy compat interface\n");
1369         return res;
1370     }
1371 
1372     return 0;
1373 }
1374 
1375 void tipc_netlink_compat_stop(void)
1376 {
1377     genl_unregister_family(&tipc_genl_compat_family);
1378 }