18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2014, Ericsson AB 38c2ecf20Sopenharmony_ci * All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 68c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 98c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 108c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 118c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 128c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 138c2ecf20Sopenharmony_ci * 3. Neither the names of the copyright holders nor the names of its 148c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived from 158c2ecf20Sopenharmony_ci * this software without specific prior written permission. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 188c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free 198c2ecf20Sopenharmony_ci * Software Foundation. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 228c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 238c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 248c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 258c2ecf20Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 268c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 278c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 288c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 298c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 308c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 318c2ecf20Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include "core.h" 358c2ecf20Sopenharmony_ci#include "bearer.h" 368c2ecf20Sopenharmony_ci#include "link.h" 378c2ecf20Sopenharmony_ci#include "name_table.h" 388c2ecf20Sopenharmony_ci#include "socket.h" 398c2ecf20Sopenharmony_ci#include "node.h" 408c2ecf20Sopenharmony_ci#include "net.h" 418c2ecf20Sopenharmony_ci#include <net/genetlink.h> 428c2ecf20Sopenharmony_ci#include <linux/tipc_config.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* The legacy API had an artificial message length limit called 458c2ecf20Sopenharmony_ci * ULTRA_STRING_MAX_LEN. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci#define ULTRA_STRING_MAX_LEN 32768 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define TIPC_SKB_MAX TLV_SPACE(ULTRA_STRING_MAX_LEN) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define REPLY_TRUNCATED "<truncated>\n" 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistruct tipc_nl_compat_msg { 548c2ecf20Sopenharmony_ci u16 cmd; 558c2ecf20Sopenharmony_ci int rep_type; 568c2ecf20Sopenharmony_ci int rep_size; 578c2ecf20Sopenharmony_ci int req_type; 588c2ecf20Sopenharmony_ci int req_size; 598c2ecf20Sopenharmony_ci struct net *net; 608c2ecf20Sopenharmony_ci struct sk_buff *rep; 618c2ecf20Sopenharmony_ci struct tlv_desc *req; 628c2ecf20Sopenharmony_ci struct sock *dst_sk; 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistruct tipc_nl_compat_cmd_dump { 668c2ecf20Sopenharmony_ci int (*header)(struct tipc_nl_compat_msg *); 678c2ecf20Sopenharmony_ci int (*dumpit)(struct sk_buff *, struct netlink_callback *); 688c2ecf20Sopenharmony_ci int (*format)(struct tipc_nl_compat_msg *msg, struct nlattr **attrs); 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct tipc_nl_compat_cmd_doit { 728c2ecf20Sopenharmony_ci int (*doit)(struct sk_buff *skb, struct genl_info *info); 738c2ecf20Sopenharmony_ci int (*transcode)(struct tipc_nl_compat_cmd_doit *cmd, 748c2ecf20Sopenharmony_ci struct sk_buff *skb, struct tipc_nl_compat_msg *msg); 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int tipc_skb_tailroom(struct sk_buff *skb) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci int tailroom; 808c2ecf20Sopenharmony_ci int limit; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci tailroom = skb_tailroom(skb); 838c2ecf20Sopenharmony_ci limit = TIPC_SKB_MAX - skb->len; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (tailroom < limit) 868c2ecf20Sopenharmony_ci return tailroom; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return limit; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic inline int TLV_GET_DATA_LEN(struct tlv_desc *tlv) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci return TLV_GET_LEN(tlv) - TLV_SPACE(0); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic int tipc_add_tlv(struct sk_buff *skb, u16 type, void *data, u16 len) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(skb); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (tipc_skb_tailroom(skb) < TLV_SPACE(len)) 1018c2ecf20Sopenharmony_ci return -EMSGSIZE; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci skb_put(skb, TLV_SPACE(len)); 1048c2ecf20Sopenharmony_ci memset(tlv, 0, TLV_SPACE(len)); 1058c2ecf20Sopenharmony_ci tlv->tlv_type = htons(type); 1068c2ecf20Sopenharmony_ci tlv->tlv_len = htons(TLV_LENGTH(len)); 1078c2ecf20Sopenharmony_ci if (len && data) 1088c2ecf20Sopenharmony_ci memcpy(TLV_DATA(tlv), data, len); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci return 0; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic void tipc_tlv_init(struct sk_buff *skb, u16 type) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct tlv_desc *tlv = (struct tlv_desc *)skb->data; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci TLV_SET_LEN(tlv, 0); 1188c2ecf20Sopenharmony_ci TLV_SET_TYPE(tlv, type); 1198c2ecf20Sopenharmony_ci skb_put(skb, sizeof(struct tlv_desc)); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int tipc_tlv_sprintf(struct sk_buff *skb, const char *fmt, ...) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci int n; 1258c2ecf20Sopenharmony_ci u16 len; 1268c2ecf20Sopenharmony_ci u32 rem; 1278c2ecf20Sopenharmony_ci char *buf; 1288c2ecf20Sopenharmony_ci struct tlv_desc *tlv; 1298c2ecf20Sopenharmony_ci va_list args; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci rem = tipc_skb_tailroom(skb); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci tlv = (struct tlv_desc *)skb->data; 1348c2ecf20Sopenharmony_ci len = TLV_GET_LEN(tlv); 1358c2ecf20Sopenharmony_ci buf = TLV_DATA(tlv) + len; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci va_start(args, fmt); 1388c2ecf20Sopenharmony_ci n = vscnprintf(buf, rem, fmt, args); 1398c2ecf20Sopenharmony_ci va_end(args); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci TLV_SET_LEN(tlv, n + len); 1428c2ecf20Sopenharmony_ci skb_put(skb, n); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return n; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic struct sk_buff *tipc_tlv_alloc(int size) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci int hdr_len; 1508c2ecf20Sopenharmony_ci struct sk_buff *buf; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci size = TLV_SPACE(size); 1538c2ecf20Sopenharmony_ci hdr_len = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci buf = alloc_skb(hdr_len + size, GFP_KERNEL); 1568c2ecf20Sopenharmony_ci if (!buf) 1578c2ecf20Sopenharmony_ci return NULL; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci skb_reserve(buf, hdr_len); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return buf; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic struct sk_buff *tipc_get_err_tlv(char *str) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci int str_len = strlen(str) + 1; 1678c2ecf20Sopenharmony_ci struct sk_buff *buf; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci buf = tipc_tlv_alloc(TLV_SPACE(str_len)); 1708c2ecf20Sopenharmony_ci if (buf) 1718c2ecf20Sopenharmony_ci tipc_add_tlv(buf, TIPC_TLV_ERROR_STRING, str, str_len); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return buf; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic inline bool string_is_valid(char *s, int len) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return memchr(s, '\0', len) ? true : false; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd, 1828c2ecf20Sopenharmony_ci struct tipc_nl_compat_msg *msg, 1838c2ecf20Sopenharmony_ci struct sk_buff *arg) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct genl_dumpit_info info; 1868c2ecf20Sopenharmony_ci int len = 0; 1878c2ecf20Sopenharmony_ci int err; 1888c2ecf20Sopenharmony_ci struct sk_buff *buf; 1898c2ecf20Sopenharmony_ci struct nlmsghdr *nlmsg; 1908c2ecf20Sopenharmony_ci struct netlink_callback cb; 1918c2ecf20Sopenharmony_ci struct nlattr **attrbuf; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci memset(&cb, 0, sizeof(cb)); 1948c2ecf20Sopenharmony_ci cb.nlh = (struct nlmsghdr *)arg->data; 1958c2ecf20Sopenharmony_ci cb.skb = arg; 1968c2ecf20Sopenharmony_ci cb.data = &info; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci buf = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1998c2ecf20Sopenharmony_ci if (!buf) 2008c2ecf20Sopenharmony_ci return -ENOMEM; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci buf->sk = msg->dst_sk; 2038c2ecf20Sopenharmony_ci if (__tipc_dump_start(&cb, msg->net)) { 2048c2ecf20Sopenharmony_ci kfree_skb(buf); 2058c2ecf20Sopenharmony_ci return -ENOMEM; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci attrbuf = kcalloc(tipc_genl_family.maxattr + 1, 2098c2ecf20Sopenharmony_ci sizeof(struct nlattr *), GFP_KERNEL); 2108c2ecf20Sopenharmony_ci if (!attrbuf) { 2118c2ecf20Sopenharmony_ci err = -ENOMEM; 2128c2ecf20Sopenharmony_ci goto err_out; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci info.attrs = attrbuf; 2168c2ecf20Sopenharmony_ci err = nlmsg_parse_deprecated(cb.nlh, GENL_HDRLEN, attrbuf, 2178c2ecf20Sopenharmony_ci tipc_genl_family.maxattr, 2188c2ecf20Sopenharmony_ci tipc_genl_family.policy, NULL); 2198c2ecf20Sopenharmony_ci if (err) 2208c2ecf20Sopenharmony_ci goto err_out; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci do { 2238c2ecf20Sopenharmony_ci int rem; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci len = (*cmd->dumpit)(buf, &cb); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci nlmsg_for_each_msg(nlmsg, nlmsg_hdr(buf), len, rem) { 2288c2ecf20Sopenharmony_ci err = nlmsg_parse_deprecated(nlmsg, GENL_HDRLEN, 2298c2ecf20Sopenharmony_ci attrbuf, 2308c2ecf20Sopenharmony_ci tipc_genl_family.maxattr, 2318c2ecf20Sopenharmony_ci tipc_genl_family.policy, 2328c2ecf20Sopenharmony_ci NULL); 2338c2ecf20Sopenharmony_ci if (err) 2348c2ecf20Sopenharmony_ci goto err_out; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci err = (*cmd->format)(msg, attrbuf); 2378c2ecf20Sopenharmony_ci if (err) 2388c2ecf20Sopenharmony_ci goto err_out; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (tipc_skb_tailroom(msg->rep) <= 1) { 2418c2ecf20Sopenharmony_ci err = -EMSGSIZE; 2428c2ecf20Sopenharmony_ci goto err_out; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci skb_reset_tail_pointer(buf); 2478c2ecf20Sopenharmony_ci buf->len = 0; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci } while (len); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci err = 0; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cierr_out: 2548c2ecf20Sopenharmony_ci kfree(attrbuf); 2558c2ecf20Sopenharmony_ci tipc_dump_done(&cb); 2568c2ecf20Sopenharmony_ci kfree_skb(buf); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (err == -EMSGSIZE) { 2598c2ecf20Sopenharmony_ci /* The legacy API only considered messages filling 2608c2ecf20Sopenharmony_ci * "ULTRA_STRING_MAX_LEN" to be truncated. 2618c2ecf20Sopenharmony_ci */ 2628c2ecf20Sopenharmony_ci if ((TIPC_SKB_MAX - msg->rep->len) <= 1) { 2638c2ecf20Sopenharmony_ci char *tail = skb_tail_pointer(msg->rep); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (*tail != '\0') 2668c2ecf20Sopenharmony_ci sprintf(tail - sizeof(REPLY_TRUNCATED) - 1, 2678c2ecf20Sopenharmony_ci REPLY_TRUNCATED); 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return 0; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return err; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd, 2778c2ecf20Sopenharmony_ci struct tipc_nl_compat_msg *msg) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci struct nlmsghdr *nlh; 2808c2ecf20Sopenharmony_ci struct sk_buff *arg; 2818c2ecf20Sopenharmony_ci int err; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (msg->req_type && (!msg->req_size || 2848c2ecf20Sopenharmony_ci !TLV_CHECK_TYPE(msg->req, msg->req_type))) 2858c2ecf20Sopenharmony_ci return -EINVAL; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci msg->rep = tipc_tlv_alloc(msg->rep_size); 2888c2ecf20Sopenharmony_ci if (!msg->rep) 2898c2ecf20Sopenharmony_ci return -ENOMEM; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (msg->rep_type) 2928c2ecf20Sopenharmony_ci tipc_tlv_init(msg->rep, msg->rep_type); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (cmd->header) { 2958c2ecf20Sopenharmony_ci err = (*cmd->header)(msg); 2968c2ecf20Sopenharmony_ci if (err) { 2978c2ecf20Sopenharmony_ci kfree_skb(msg->rep); 2988c2ecf20Sopenharmony_ci msg->rep = NULL; 2998c2ecf20Sopenharmony_ci return err; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci arg = nlmsg_new(0, GFP_KERNEL); 3048c2ecf20Sopenharmony_ci if (!arg) { 3058c2ecf20Sopenharmony_ci kfree_skb(msg->rep); 3068c2ecf20Sopenharmony_ci msg->rep = NULL; 3078c2ecf20Sopenharmony_ci return -ENOMEM; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci nlh = nlmsg_put(arg, 0, 0, tipc_genl_family.id, 0, NLM_F_MULTI); 3118c2ecf20Sopenharmony_ci if (!nlh) { 3128c2ecf20Sopenharmony_ci kfree_skb(arg); 3138c2ecf20Sopenharmony_ci kfree_skb(msg->rep); 3148c2ecf20Sopenharmony_ci msg->rep = NULL; 3158c2ecf20Sopenharmony_ci return -EMSGSIZE; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci nlmsg_end(arg, nlh); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci err = __tipc_nl_compat_dumpit(cmd, msg, arg); 3208c2ecf20Sopenharmony_ci if (err) { 3218c2ecf20Sopenharmony_ci kfree_skb(msg->rep); 3228c2ecf20Sopenharmony_ci msg->rep = NULL; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci kfree_skb(arg); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return err; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd, 3308c2ecf20Sopenharmony_ci struct tipc_nl_compat_msg *msg) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci int err; 3338c2ecf20Sopenharmony_ci struct sk_buff *doit_buf; 3348c2ecf20Sopenharmony_ci struct sk_buff *trans_buf; 3358c2ecf20Sopenharmony_ci struct nlattr **attrbuf; 3368c2ecf20Sopenharmony_ci struct genl_info info; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci trans_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 3398c2ecf20Sopenharmony_ci if (!trans_buf) 3408c2ecf20Sopenharmony_ci return -ENOMEM; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci attrbuf = kmalloc_array(tipc_genl_family.maxattr + 1, 3438c2ecf20Sopenharmony_ci sizeof(struct nlattr *), 3448c2ecf20Sopenharmony_ci GFP_KERNEL); 3458c2ecf20Sopenharmony_ci if (!attrbuf) { 3468c2ecf20Sopenharmony_ci err = -ENOMEM; 3478c2ecf20Sopenharmony_ci goto trans_out; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 3518c2ecf20Sopenharmony_ci if (!doit_buf) { 3528c2ecf20Sopenharmony_ci err = -ENOMEM; 3538c2ecf20Sopenharmony_ci goto attrbuf_out; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(info)); 3578c2ecf20Sopenharmony_ci info.attrs = attrbuf; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci rtnl_lock(); 3608c2ecf20Sopenharmony_ci err = (*cmd->transcode)(cmd, trans_buf, msg); 3618c2ecf20Sopenharmony_ci if (err) 3628c2ecf20Sopenharmony_ci goto doit_out; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci err = nla_parse_deprecated(attrbuf, tipc_genl_family.maxattr, 3658c2ecf20Sopenharmony_ci (const struct nlattr *)trans_buf->data, 3668c2ecf20Sopenharmony_ci trans_buf->len, NULL, NULL); 3678c2ecf20Sopenharmony_ci if (err) 3688c2ecf20Sopenharmony_ci goto doit_out; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci doit_buf->sk = msg->dst_sk; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci err = (*cmd->doit)(doit_buf, &info); 3738c2ecf20Sopenharmony_cidoit_out: 3748c2ecf20Sopenharmony_ci rtnl_unlock(); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci kfree_skb(doit_buf); 3778c2ecf20Sopenharmony_ciattrbuf_out: 3788c2ecf20Sopenharmony_ci kfree(attrbuf); 3798c2ecf20Sopenharmony_citrans_out: 3808c2ecf20Sopenharmony_ci kfree_skb(trans_buf); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci return err; 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic int tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd, 3868c2ecf20Sopenharmony_ci struct tipc_nl_compat_msg *msg) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci int err; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (msg->req_type && (!msg->req_size || 3918c2ecf20Sopenharmony_ci !TLV_CHECK_TYPE(msg->req, msg->req_type))) 3928c2ecf20Sopenharmony_ci return -EINVAL; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci err = __tipc_nl_compat_doit(cmd, msg); 3958c2ecf20Sopenharmony_ci if (err) 3968c2ecf20Sopenharmony_ci return err; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* The legacy API considered an empty message a success message */ 3998c2ecf20Sopenharmony_ci msg->rep = tipc_tlv_alloc(0); 4008c2ecf20Sopenharmony_ci if (!msg->rep) 4018c2ecf20Sopenharmony_ci return -ENOMEM; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return 0; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic int tipc_nl_compat_bearer_dump(struct tipc_nl_compat_msg *msg, 4078c2ecf20Sopenharmony_ci struct nlattr **attrs) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct nlattr *bearer[TIPC_NLA_BEARER_MAX + 1]; 4108c2ecf20Sopenharmony_ci int err; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_BEARER]) 4138c2ecf20Sopenharmony_ci return -EINVAL; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(bearer, TIPC_NLA_BEARER_MAX, 4168c2ecf20Sopenharmony_ci attrs[TIPC_NLA_BEARER], NULL, NULL); 4178c2ecf20Sopenharmony_ci if (err) 4188c2ecf20Sopenharmony_ci return err; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return tipc_add_tlv(msg->rep, TIPC_TLV_BEARER_NAME, 4218c2ecf20Sopenharmony_ci nla_data(bearer[TIPC_NLA_BEARER_NAME]), 4228c2ecf20Sopenharmony_ci nla_len(bearer[TIPC_NLA_BEARER_NAME])); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int tipc_nl_compat_bearer_enable(struct tipc_nl_compat_cmd_doit *cmd, 4268c2ecf20Sopenharmony_ci struct sk_buff *skb, 4278c2ecf20Sopenharmony_ci struct tipc_nl_compat_msg *msg) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci struct nlattr *prop; 4308c2ecf20Sopenharmony_ci struct nlattr *bearer; 4318c2ecf20Sopenharmony_ci struct tipc_bearer_config *b; 4328c2ecf20Sopenharmony_ci int len; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci b = (struct tipc_bearer_config *)TLV_DATA(msg->req); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci bearer = nla_nest_start_noflag(skb, TIPC_NLA_BEARER); 4378c2ecf20Sopenharmony_ci if (!bearer) 4388c2ecf20Sopenharmony_ci return -EMSGSIZE; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci len = TLV_GET_DATA_LEN(msg->req); 4418c2ecf20Sopenharmony_ci len -= offsetof(struct tipc_bearer_config, name); 4428c2ecf20Sopenharmony_ci if (len <= 0) 4438c2ecf20Sopenharmony_ci return -EINVAL; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci len = min_t(int, len, TIPC_MAX_BEARER_NAME); 4468c2ecf20Sopenharmony_ci if (!string_is_valid(b->name, len)) 4478c2ecf20Sopenharmony_ci return -EINVAL; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, b->name)) 4508c2ecf20Sopenharmony_ci return -EMSGSIZE; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TIPC_NLA_BEARER_DOMAIN, ntohl(b->disc_domain))) 4538c2ecf20Sopenharmony_ci return -EMSGSIZE; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (ntohl(b->priority) <= TIPC_MAX_LINK_PRI) { 4568c2ecf20Sopenharmony_ci prop = nla_nest_start_noflag(skb, TIPC_NLA_BEARER_PROP); 4578c2ecf20Sopenharmony_ci if (!prop) 4588c2ecf20Sopenharmony_ci return -EMSGSIZE; 4598c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(b->priority))) 4608c2ecf20Sopenharmony_ci return -EMSGSIZE; 4618c2ecf20Sopenharmony_ci nla_nest_end(skb, prop); 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci nla_nest_end(skb, bearer); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci return 0; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic int tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit *cmd, 4698c2ecf20Sopenharmony_ci struct sk_buff *skb, 4708c2ecf20Sopenharmony_ci struct tipc_nl_compat_msg *msg) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci char *name; 4738c2ecf20Sopenharmony_ci struct nlattr *bearer; 4748c2ecf20Sopenharmony_ci int len; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci name = (char *)TLV_DATA(msg->req); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci bearer = nla_nest_start_noflag(skb, TIPC_NLA_BEARER); 4798c2ecf20Sopenharmony_ci if (!bearer) 4808c2ecf20Sopenharmony_ci return -EMSGSIZE; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci len = TLV_GET_DATA_LEN(msg->req); 4838c2ecf20Sopenharmony_ci if (len <= 0) 4848c2ecf20Sopenharmony_ci return -EINVAL; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci len = min_t(int, len, TIPC_MAX_BEARER_NAME); 4878c2ecf20Sopenharmony_ci if (!string_is_valid(name, len)) 4888c2ecf20Sopenharmony_ci return -EINVAL; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, name)) 4918c2ecf20Sopenharmony_ci return -EMSGSIZE; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci nla_nest_end(skb, bearer); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic inline u32 perc(u32 count, u32 total) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci return (count * 100 + (total / 2)) / total; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic void __fill_bc_link_stat(struct tipc_nl_compat_msg *msg, 5048c2ecf20Sopenharmony_ci struct nlattr *prop[], struct nlattr *stats[]) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " Window:%u packets\n", 5078c2ecf20Sopenharmony_ci nla_get_u32(prop[TIPC_NLA_PROP_WIN])); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 5108c2ecf20Sopenharmony_ci " RX packets:%u fragments:%u/%u bundles:%u/%u\n", 5118c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_INFO]), 5128c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]), 5138c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]), 5148c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]), 5158c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED])); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 5188c2ecf20Sopenharmony_ci " TX packets:%u fragments:%u/%u bundles:%u/%u\n", 5198c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_INFO]), 5208c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]), 5218c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]), 5228c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]), 5238c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED])); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " RX naks:%u defs:%u dups:%u\n", 5268c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]), 5278c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]), 5288c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_DUPLICATES])); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " TX naks:%u acks:%u dups:%u\n", 5318c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]), 5328c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]), 5338c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED])); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 5368c2ecf20Sopenharmony_ci " Congestion link:%u Send queue max:%u avg:%u", 5378c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]), 5388c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]), 5398c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE])); 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg, 5438c2ecf20Sopenharmony_ci struct nlattr **attrs) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci char *name; 5468c2ecf20Sopenharmony_ci struct nlattr *link[TIPC_NLA_LINK_MAX + 1]; 5478c2ecf20Sopenharmony_ci struct nlattr *prop[TIPC_NLA_PROP_MAX + 1]; 5488c2ecf20Sopenharmony_ci struct nlattr *stats[TIPC_NLA_STATS_MAX + 1]; 5498c2ecf20Sopenharmony_ci int err; 5508c2ecf20Sopenharmony_ci int len; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_LINK]) 5538c2ecf20Sopenharmony_ci return -EINVAL; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(link, TIPC_NLA_LINK_MAX, 5568c2ecf20Sopenharmony_ci attrs[TIPC_NLA_LINK], NULL, NULL); 5578c2ecf20Sopenharmony_ci if (err) 5588c2ecf20Sopenharmony_ci return err; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (!link[TIPC_NLA_LINK_PROP]) 5618c2ecf20Sopenharmony_ci return -EINVAL; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(prop, TIPC_NLA_PROP_MAX, 5648c2ecf20Sopenharmony_ci link[TIPC_NLA_LINK_PROP], NULL, 5658c2ecf20Sopenharmony_ci NULL); 5668c2ecf20Sopenharmony_ci if (err) 5678c2ecf20Sopenharmony_ci return err; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (!link[TIPC_NLA_LINK_STATS]) 5708c2ecf20Sopenharmony_ci return -EINVAL; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(stats, TIPC_NLA_STATS_MAX, 5738c2ecf20Sopenharmony_ci link[TIPC_NLA_LINK_STATS], NULL, 5748c2ecf20Sopenharmony_ci NULL); 5758c2ecf20Sopenharmony_ci if (err) 5768c2ecf20Sopenharmony_ci return err; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci name = (char *)TLV_DATA(msg->req); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci len = TLV_GET_DATA_LEN(msg->req); 5818c2ecf20Sopenharmony_ci if (len <= 0) 5828c2ecf20Sopenharmony_ci return -EINVAL; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci len = min_t(int, len, TIPC_MAX_LINK_NAME); 5858c2ecf20Sopenharmony_ci if (!string_is_valid(name, len)) 5868c2ecf20Sopenharmony_ci return -EINVAL; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (strcmp(name, nla_data(link[TIPC_NLA_LINK_NAME])) != 0) 5898c2ecf20Sopenharmony_ci return 0; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "\nLink <%s>\n", 5928c2ecf20Sopenharmony_ci nla_data(link[TIPC_NLA_LINK_NAME])); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (link[TIPC_NLA_LINK_BROADCAST]) { 5958c2ecf20Sopenharmony_ci __fill_bc_link_stat(msg, prop, stats); 5968c2ecf20Sopenharmony_ci return 0; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (link[TIPC_NLA_LINK_ACTIVE]) 6008c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " ACTIVE"); 6018c2ecf20Sopenharmony_ci else if (link[TIPC_NLA_LINK_UP]) 6028c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " STANDBY"); 6038c2ecf20Sopenharmony_ci else 6048c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " DEFUNCT"); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " MTU:%u Priority:%u", 6078c2ecf20Sopenharmony_ci nla_get_u32(link[TIPC_NLA_LINK_MTU]), 6088c2ecf20Sopenharmony_ci nla_get_u32(prop[TIPC_NLA_PROP_PRIO])); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " Tolerance:%u ms Window:%u packets\n", 6118c2ecf20Sopenharmony_ci nla_get_u32(prop[TIPC_NLA_PROP_TOL]), 6128c2ecf20Sopenharmony_ci nla_get_u32(prop[TIPC_NLA_PROP_WIN])); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 6158c2ecf20Sopenharmony_ci " RX packets:%u fragments:%u/%u bundles:%u/%u\n", 6168c2ecf20Sopenharmony_ci nla_get_u32(link[TIPC_NLA_LINK_RX]) - 6178c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_INFO]), 6188c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]), 6198c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]), 6208c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]), 6218c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED])); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 6248c2ecf20Sopenharmony_ci " TX packets:%u fragments:%u/%u bundles:%u/%u\n", 6258c2ecf20Sopenharmony_ci nla_get_u32(link[TIPC_NLA_LINK_TX]) - 6268c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_INFO]), 6278c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]), 6288c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]), 6298c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]), 6308c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED])); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 6338c2ecf20Sopenharmony_ci " TX profile sample:%u packets average:%u octets\n", 6348c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_CNT]), 6358c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_TOT]) / 6368c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 6398c2ecf20Sopenharmony_ci " 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% ", 6408c2ecf20Sopenharmony_ci perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P0]), 6418c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])), 6428c2ecf20Sopenharmony_ci perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P1]), 6438c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])), 6448c2ecf20Sopenharmony_ci perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P2]), 6458c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])), 6468c2ecf20Sopenharmony_ci perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P3]), 6478c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT]))); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "-16384:%u%% -32768:%u%% -66000:%u%%\n", 6508c2ecf20Sopenharmony_ci perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P4]), 6518c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])), 6528c2ecf20Sopenharmony_ci perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P5]), 6538c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])), 6548c2ecf20Sopenharmony_ci perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P6]), 6558c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT]))); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 6588c2ecf20Sopenharmony_ci " RX states:%u probes:%u naks:%u defs:%u dups:%u\n", 6598c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_STATES]), 6608c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_PROBES]), 6618c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]), 6628c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]), 6638c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_DUPLICATES])); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 6668c2ecf20Sopenharmony_ci " TX states:%u probes:%u naks:%u acks:%u dups:%u\n", 6678c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_STATES]), 6688c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_PROBES]), 6698c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]), 6708c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]), 6718c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED])); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 6748c2ecf20Sopenharmony_ci " Congestion link:%u Send queue max:%u avg:%u", 6758c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]), 6768c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]), 6778c2ecf20Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE])); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci return 0; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic int tipc_nl_compat_link_dump(struct tipc_nl_compat_msg *msg, 6838c2ecf20Sopenharmony_ci struct nlattr **attrs) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct nlattr *link[TIPC_NLA_LINK_MAX + 1]; 6868c2ecf20Sopenharmony_ci struct tipc_link_info link_info; 6878c2ecf20Sopenharmony_ci int err; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_LINK]) 6908c2ecf20Sopenharmony_ci return -EINVAL; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(link, TIPC_NLA_LINK_MAX, 6938c2ecf20Sopenharmony_ci attrs[TIPC_NLA_LINK], NULL, NULL); 6948c2ecf20Sopenharmony_ci if (err) 6958c2ecf20Sopenharmony_ci return err; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci link_info.dest = htonl(nla_get_flag(link[TIPC_NLA_LINK_DEST])); 6988c2ecf20Sopenharmony_ci link_info.up = htonl(nla_get_flag(link[TIPC_NLA_LINK_UP])); 6998c2ecf20Sopenharmony_ci nla_strlcpy(link_info.str, link[TIPC_NLA_LINK_NAME], 7008c2ecf20Sopenharmony_ci TIPC_MAX_LINK_NAME); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci return tipc_add_tlv(msg->rep, TIPC_TLV_LINK_INFO, 7038c2ecf20Sopenharmony_ci &link_info, sizeof(link_info)); 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic int __tipc_add_link_prop(struct sk_buff *skb, 7078c2ecf20Sopenharmony_ci struct tipc_nl_compat_msg *msg, 7088c2ecf20Sopenharmony_ci struct tipc_link_config *lc) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci switch (msg->cmd) { 7118c2ecf20Sopenharmony_ci case TIPC_CMD_SET_LINK_PRI: 7128c2ecf20Sopenharmony_ci return nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(lc->value)); 7138c2ecf20Sopenharmony_ci case TIPC_CMD_SET_LINK_TOL: 7148c2ecf20Sopenharmony_ci return nla_put_u32(skb, TIPC_NLA_PROP_TOL, ntohl(lc->value)); 7158c2ecf20Sopenharmony_ci case TIPC_CMD_SET_LINK_WINDOW: 7168c2ecf20Sopenharmony_ci return nla_put_u32(skb, TIPC_NLA_PROP_WIN, ntohl(lc->value)); 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci return -EINVAL; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic int tipc_nl_compat_media_set(struct sk_buff *skb, 7238c2ecf20Sopenharmony_ci struct tipc_nl_compat_msg *msg) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct nlattr *prop; 7268c2ecf20Sopenharmony_ci struct nlattr *media; 7278c2ecf20Sopenharmony_ci struct tipc_link_config *lc; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci lc = (struct tipc_link_config *)TLV_DATA(msg->req); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci media = nla_nest_start_noflag(skb, TIPC_NLA_MEDIA); 7328c2ecf20Sopenharmony_ci if (!media) 7338c2ecf20Sopenharmony_ci return -EMSGSIZE; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (nla_put_string(skb, TIPC_NLA_MEDIA_NAME, lc->name)) 7368c2ecf20Sopenharmony_ci return -EMSGSIZE; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci prop = nla_nest_start_noflag(skb, TIPC_NLA_MEDIA_PROP); 7398c2ecf20Sopenharmony_ci if (!prop) 7408c2ecf20Sopenharmony_ci return -EMSGSIZE; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci __tipc_add_link_prop(skb, msg, lc); 7438c2ecf20Sopenharmony_ci nla_nest_end(skb, prop); 7448c2ecf20Sopenharmony_ci nla_nest_end(skb, media); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return 0; 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic int tipc_nl_compat_bearer_set(struct sk_buff *skb, 7508c2ecf20Sopenharmony_ci struct tipc_nl_compat_msg *msg) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci struct nlattr *prop; 7538c2ecf20Sopenharmony_ci struct nlattr *bearer; 7548c2ecf20Sopenharmony_ci struct tipc_link_config *lc; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci lc = (struct tipc_link_config *)TLV_DATA(msg->req); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci bearer = nla_nest_start_noflag(skb, TIPC_NLA_BEARER); 7598c2ecf20Sopenharmony_ci if (!bearer) 7608c2ecf20Sopenharmony_ci return -EMSGSIZE; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, lc->name)) 7638c2ecf20Sopenharmony_ci return -EMSGSIZE; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci prop = nla_nest_start_noflag(skb, TIPC_NLA_BEARER_PROP); 7668c2ecf20Sopenharmony_ci if (!prop) 7678c2ecf20Sopenharmony_ci return -EMSGSIZE; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci __tipc_add_link_prop(skb, msg, lc); 7708c2ecf20Sopenharmony_ci nla_nest_end(skb, prop); 7718c2ecf20Sopenharmony_ci nla_nest_end(skb, bearer); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci return 0; 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_cistatic int __tipc_nl_compat_link_set(struct sk_buff *skb, 7778c2ecf20Sopenharmony_ci struct tipc_nl_compat_msg *msg) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci struct nlattr *prop; 7808c2ecf20Sopenharmony_ci struct nlattr *link; 7818c2ecf20Sopenharmony_ci struct tipc_link_config *lc; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci lc = (struct tipc_link_config *)TLV_DATA(msg->req); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci link = nla_nest_start_noflag(skb, TIPC_NLA_LINK); 7868c2ecf20Sopenharmony_ci if (!link) 7878c2ecf20Sopenharmony_ci return -EMSGSIZE; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (nla_put_string(skb, TIPC_NLA_LINK_NAME, lc->name)) 7908c2ecf20Sopenharmony_ci return -EMSGSIZE; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci prop = nla_nest_start_noflag(skb, TIPC_NLA_LINK_PROP); 7938c2ecf20Sopenharmony_ci if (!prop) 7948c2ecf20Sopenharmony_ci return -EMSGSIZE; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci __tipc_add_link_prop(skb, msg, lc); 7978c2ecf20Sopenharmony_ci nla_nest_end(skb, prop); 7988c2ecf20Sopenharmony_ci nla_nest_end(skb, link); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci return 0; 8018c2ecf20Sopenharmony_ci} 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd, 8048c2ecf20Sopenharmony_ci struct sk_buff *skb, 8058c2ecf20Sopenharmony_ci struct tipc_nl_compat_msg *msg) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci struct tipc_link_config *lc; 8088c2ecf20Sopenharmony_ci struct tipc_bearer *bearer; 8098c2ecf20Sopenharmony_ci struct tipc_media *media; 8108c2ecf20Sopenharmony_ci int len; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci lc = (struct tipc_link_config *)TLV_DATA(msg->req); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci len = TLV_GET_DATA_LEN(msg->req); 8158c2ecf20Sopenharmony_ci len -= offsetof(struct tipc_link_config, name); 8168c2ecf20Sopenharmony_ci if (len <= 0) 8178c2ecf20Sopenharmony_ci return -EINVAL; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci len = min_t(int, len, TIPC_MAX_LINK_NAME); 8208c2ecf20Sopenharmony_ci if (!string_is_valid(lc->name, len)) 8218c2ecf20Sopenharmony_ci return -EINVAL; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci media = tipc_media_find(lc->name); 8248c2ecf20Sopenharmony_ci if (media) { 8258c2ecf20Sopenharmony_ci cmd->doit = &__tipc_nl_media_set; 8268c2ecf20Sopenharmony_ci return tipc_nl_compat_media_set(skb, msg); 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci bearer = tipc_bearer_find(msg->net, lc->name); 8308c2ecf20Sopenharmony_ci if (bearer) { 8318c2ecf20Sopenharmony_ci cmd->doit = &__tipc_nl_bearer_set; 8328c2ecf20Sopenharmony_ci return tipc_nl_compat_bearer_set(skb, msg); 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci return __tipc_nl_compat_link_set(skb, msg); 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd, 8398c2ecf20Sopenharmony_ci struct sk_buff *skb, 8408c2ecf20Sopenharmony_ci struct tipc_nl_compat_msg *msg) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci char *name; 8438c2ecf20Sopenharmony_ci struct nlattr *link; 8448c2ecf20Sopenharmony_ci int len; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci name = (char *)TLV_DATA(msg->req); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci link = nla_nest_start_noflag(skb, TIPC_NLA_LINK); 8498c2ecf20Sopenharmony_ci if (!link) 8508c2ecf20Sopenharmony_ci return -EMSGSIZE; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci len = TLV_GET_DATA_LEN(msg->req); 8538c2ecf20Sopenharmony_ci if (len <= 0) 8548c2ecf20Sopenharmony_ci return -EINVAL; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci len = min_t(int, len, TIPC_MAX_LINK_NAME); 8578c2ecf20Sopenharmony_ci if (!string_is_valid(name, len)) 8588c2ecf20Sopenharmony_ci return -EINVAL; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (nla_put_string(skb, TIPC_NLA_LINK_NAME, name)) 8618c2ecf20Sopenharmony_ci return -EMSGSIZE; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci nla_nest_end(skb, link); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci return 0; 8668c2ecf20Sopenharmony_ci} 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_cistatic int tipc_nl_compat_name_table_dump_header(struct tipc_nl_compat_msg *msg) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci int i; 8718c2ecf20Sopenharmony_ci u32 depth; 8728c2ecf20Sopenharmony_ci struct tipc_name_table_query *ntq; 8738c2ecf20Sopenharmony_ci static const char * const header[] = { 8748c2ecf20Sopenharmony_ci "Type ", 8758c2ecf20Sopenharmony_ci "Lower Upper ", 8768c2ecf20Sopenharmony_ci "Port Identity ", 8778c2ecf20Sopenharmony_ci "Publication Scope" 8788c2ecf20Sopenharmony_ci }; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req); 8818c2ecf20Sopenharmony_ci if (TLV_GET_DATA_LEN(msg->req) < (int)sizeof(struct tipc_name_table_query)) 8828c2ecf20Sopenharmony_ci return -EINVAL; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci depth = ntohl(ntq->depth); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (depth > 4) 8878c2ecf20Sopenharmony_ci depth = 4; 8888c2ecf20Sopenharmony_ci for (i = 0; i < depth; i++) 8898c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, header[i]); 8908c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "\n"); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci return 0; 8938c2ecf20Sopenharmony_ci} 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_cistatic int tipc_nl_compat_name_table_dump(struct tipc_nl_compat_msg *msg, 8968c2ecf20Sopenharmony_ci struct nlattr **attrs) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci char port_str[27]; 8998c2ecf20Sopenharmony_ci struct tipc_name_table_query *ntq; 9008c2ecf20Sopenharmony_ci struct nlattr *nt[TIPC_NLA_NAME_TABLE_MAX + 1]; 9018c2ecf20Sopenharmony_ci struct nlattr *publ[TIPC_NLA_PUBL_MAX + 1]; 9028c2ecf20Sopenharmony_ci u32 node, depth, type, lowbound, upbound; 9038c2ecf20Sopenharmony_ci static const char * const scope_str[] = {"", " zone", " cluster", 9048c2ecf20Sopenharmony_ci " node"}; 9058c2ecf20Sopenharmony_ci int err; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_NAME_TABLE]) 9088c2ecf20Sopenharmony_ci return -EINVAL; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(nt, TIPC_NLA_NAME_TABLE_MAX, 9118c2ecf20Sopenharmony_ci attrs[TIPC_NLA_NAME_TABLE], NULL, 9128c2ecf20Sopenharmony_ci NULL); 9138c2ecf20Sopenharmony_ci if (err) 9148c2ecf20Sopenharmony_ci return err; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if (!nt[TIPC_NLA_NAME_TABLE_PUBL]) 9178c2ecf20Sopenharmony_ci return -EINVAL; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(publ, TIPC_NLA_PUBL_MAX, 9208c2ecf20Sopenharmony_ci nt[TIPC_NLA_NAME_TABLE_PUBL], NULL, 9218c2ecf20Sopenharmony_ci NULL); 9228c2ecf20Sopenharmony_ci if (err) 9238c2ecf20Sopenharmony_ci return err; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci depth = ntohl(ntq->depth); 9288c2ecf20Sopenharmony_ci type = ntohl(ntq->type); 9298c2ecf20Sopenharmony_ci lowbound = ntohl(ntq->lowbound); 9308c2ecf20Sopenharmony_ci upbound = ntohl(ntq->upbound); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci if (!(depth & TIPC_NTQ_ALLTYPES) && 9338c2ecf20Sopenharmony_ci (type != nla_get_u32(publ[TIPC_NLA_PUBL_TYPE]))) 9348c2ecf20Sopenharmony_ci return 0; 9358c2ecf20Sopenharmony_ci if (lowbound && (lowbound > nla_get_u32(publ[TIPC_NLA_PUBL_UPPER]))) 9368c2ecf20Sopenharmony_ci return 0; 9378c2ecf20Sopenharmony_ci if (upbound && (upbound < nla_get_u32(publ[TIPC_NLA_PUBL_LOWER]))) 9388c2ecf20Sopenharmony_ci return 0; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "%-10u ", 9418c2ecf20Sopenharmony_ci nla_get_u32(publ[TIPC_NLA_PUBL_TYPE])); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci if (depth == 1) 9448c2ecf20Sopenharmony_ci goto out; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "%-10u %-10u ", 9478c2ecf20Sopenharmony_ci nla_get_u32(publ[TIPC_NLA_PUBL_LOWER]), 9488c2ecf20Sopenharmony_ci nla_get_u32(publ[TIPC_NLA_PUBL_UPPER])); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci if (depth == 2) 9518c2ecf20Sopenharmony_ci goto out; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci node = nla_get_u32(publ[TIPC_NLA_PUBL_NODE]); 9548c2ecf20Sopenharmony_ci sprintf(port_str, "<%u.%u.%u:%u>", tipc_zone(node), tipc_cluster(node), 9558c2ecf20Sopenharmony_ci tipc_node(node), nla_get_u32(publ[TIPC_NLA_PUBL_REF])); 9568c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "%-26s ", port_str); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if (depth == 3) 9598c2ecf20Sopenharmony_ci goto out; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "%-10u %s", 9628c2ecf20Sopenharmony_ci nla_get_u32(publ[TIPC_NLA_PUBL_KEY]), 9638c2ecf20Sopenharmony_ci scope_str[nla_get_u32(publ[TIPC_NLA_PUBL_SCOPE])]); 9648c2ecf20Sopenharmony_ciout: 9658c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "\n"); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci return 0; 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_cistatic int __tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg *msg, 9718c2ecf20Sopenharmony_ci struct nlattr **attrs) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci u32 type, lower, upper; 9748c2ecf20Sopenharmony_ci struct nlattr *publ[TIPC_NLA_PUBL_MAX + 1]; 9758c2ecf20Sopenharmony_ci int err; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_PUBL]) 9788c2ecf20Sopenharmony_ci return -EINVAL; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(publ, TIPC_NLA_PUBL_MAX, 9818c2ecf20Sopenharmony_ci attrs[TIPC_NLA_PUBL], NULL, NULL); 9828c2ecf20Sopenharmony_ci if (err) 9838c2ecf20Sopenharmony_ci return err; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci type = nla_get_u32(publ[TIPC_NLA_PUBL_TYPE]); 9868c2ecf20Sopenharmony_ci lower = nla_get_u32(publ[TIPC_NLA_PUBL_LOWER]); 9878c2ecf20Sopenharmony_ci upper = nla_get_u32(publ[TIPC_NLA_PUBL_UPPER]); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (lower == upper) 9908c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " {%u,%u}", type, lower); 9918c2ecf20Sopenharmony_ci else 9928c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " {%u,%u,%u}", type, lower, upper); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci return 0; 9958c2ecf20Sopenharmony_ci} 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_cistatic int tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg *msg, u32 sock) 9988c2ecf20Sopenharmony_ci{ 9998c2ecf20Sopenharmony_ci int err; 10008c2ecf20Sopenharmony_ci void *hdr; 10018c2ecf20Sopenharmony_ci struct nlattr *nest; 10028c2ecf20Sopenharmony_ci struct sk_buff *args; 10038c2ecf20Sopenharmony_ci struct tipc_nl_compat_cmd_dump dump; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci args = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 10068c2ecf20Sopenharmony_ci if (!args) 10078c2ecf20Sopenharmony_ci return -ENOMEM; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci hdr = genlmsg_put(args, 0, 0, &tipc_genl_family, NLM_F_MULTI, 10108c2ecf20Sopenharmony_ci TIPC_NL_PUBL_GET); 10118c2ecf20Sopenharmony_ci if (!hdr) { 10128c2ecf20Sopenharmony_ci kfree_skb(args); 10138c2ecf20Sopenharmony_ci return -EMSGSIZE; 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci nest = nla_nest_start_noflag(args, TIPC_NLA_SOCK); 10178c2ecf20Sopenharmony_ci if (!nest) { 10188c2ecf20Sopenharmony_ci kfree_skb(args); 10198c2ecf20Sopenharmony_ci return -EMSGSIZE; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if (nla_put_u32(args, TIPC_NLA_SOCK_REF, sock)) { 10238c2ecf20Sopenharmony_ci kfree_skb(args); 10248c2ecf20Sopenharmony_ci return -EMSGSIZE; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci nla_nest_end(args, nest); 10288c2ecf20Sopenharmony_ci genlmsg_end(args, hdr); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci dump.dumpit = tipc_nl_publ_dump; 10318c2ecf20Sopenharmony_ci dump.format = __tipc_nl_compat_publ_dump; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci err = __tipc_nl_compat_dumpit(&dump, msg, args); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci kfree_skb(args); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci return err; 10388c2ecf20Sopenharmony_ci} 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic int tipc_nl_compat_sk_dump(struct tipc_nl_compat_msg *msg, 10418c2ecf20Sopenharmony_ci struct nlattr **attrs) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci int err; 10448c2ecf20Sopenharmony_ci u32 sock_ref; 10458c2ecf20Sopenharmony_ci struct nlattr *sock[TIPC_NLA_SOCK_MAX + 1]; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_SOCK]) 10488c2ecf20Sopenharmony_ci return -EINVAL; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(sock, TIPC_NLA_SOCK_MAX, 10518c2ecf20Sopenharmony_ci attrs[TIPC_NLA_SOCK], NULL, NULL); 10528c2ecf20Sopenharmony_ci if (err) 10538c2ecf20Sopenharmony_ci return err; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci sock_ref = nla_get_u32(sock[TIPC_NLA_SOCK_REF]); 10568c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "%u:", sock_ref); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci if (sock[TIPC_NLA_SOCK_CON]) { 10598c2ecf20Sopenharmony_ci u32 node; 10608c2ecf20Sopenharmony_ci struct nlattr *con[TIPC_NLA_CON_MAX + 1]; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(con, TIPC_NLA_CON_MAX, 10638c2ecf20Sopenharmony_ci sock[TIPC_NLA_SOCK_CON], 10648c2ecf20Sopenharmony_ci NULL, NULL); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci if (err) 10678c2ecf20Sopenharmony_ci return err; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci node = nla_get_u32(con[TIPC_NLA_CON_NODE]); 10708c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " connected to <%u.%u.%u:%u>", 10718c2ecf20Sopenharmony_ci tipc_zone(node), 10728c2ecf20Sopenharmony_ci tipc_cluster(node), 10738c2ecf20Sopenharmony_ci tipc_node(node), 10748c2ecf20Sopenharmony_ci nla_get_u32(con[TIPC_NLA_CON_SOCK])); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (con[TIPC_NLA_CON_FLAG]) 10778c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " via {%u,%u}\n", 10788c2ecf20Sopenharmony_ci nla_get_u32(con[TIPC_NLA_CON_TYPE]), 10798c2ecf20Sopenharmony_ci nla_get_u32(con[TIPC_NLA_CON_INST])); 10808c2ecf20Sopenharmony_ci else 10818c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "\n"); 10828c2ecf20Sopenharmony_ci } else if (sock[TIPC_NLA_SOCK_HAS_PUBL]) { 10838c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " bound to"); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci err = tipc_nl_compat_publ_dump(msg, sock_ref); 10868c2ecf20Sopenharmony_ci if (err) 10878c2ecf20Sopenharmony_ci return err; 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "\n"); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci return 0; 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_cistatic int tipc_nl_compat_media_dump(struct tipc_nl_compat_msg *msg, 10958c2ecf20Sopenharmony_ci struct nlattr **attrs) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci struct nlattr *media[TIPC_NLA_MEDIA_MAX + 1]; 10988c2ecf20Sopenharmony_ci int err; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_MEDIA]) 11018c2ecf20Sopenharmony_ci return -EINVAL; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(media, TIPC_NLA_MEDIA_MAX, 11048c2ecf20Sopenharmony_ci attrs[TIPC_NLA_MEDIA], NULL, NULL); 11058c2ecf20Sopenharmony_ci if (err) 11068c2ecf20Sopenharmony_ci return err; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci return tipc_add_tlv(msg->rep, TIPC_TLV_MEDIA_NAME, 11098c2ecf20Sopenharmony_ci nla_data(media[TIPC_NLA_MEDIA_NAME]), 11108c2ecf20Sopenharmony_ci nla_len(media[TIPC_NLA_MEDIA_NAME])); 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cistatic int tipc_nl_compat_node_dump(struct tipc_nl_compat_msg *msg, 11148c2ecf20Sopenharmony_ci struct nlattr **attrs) 11158c2ecf20Sopenharmony_ci{ 11168c2ecf20Sopenharmony_ci struct tipc_node_info node_info; 11178c2ecf20Sopenharmony_ci struct nlattr *node[TIPC_NLA_NODE_MAX + 1]; 11188c2ecf20Sopenharmony_ci int err; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_NODE]) 11218c2ecf20Sopenharmony_ci return -EINVAL; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(node, TIPC_NLA_NODE_MAX, 11248c2ecf20Sopenharmony_ci attrs[TIPC_NLA_NODE], NULL, NULL); 11258c2ecf20Sopenharmony_ci if (err) 11268c2ecf20Sopenharmony_ci return err; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci node_info.addr = htonl(nla_get_u32(node[TIPC_NLA_NODE_ADDR])); 11298c2ecf20Sopenharmony_ci node_info.up = htonl(nla_get_flag(node[TIPC_NLA_NODE_UP])); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci return tipc_add_tlv(msg->rep, TIPC_TLV_NODE_INFO, &node_info, 11328c2ecf20Sopenharmony_ci sizeof(node_info)); 11338c2ecf20Sopenharmony_ci} 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_cistatic int tipc_nl_compat_net_set(struct tipc_nl_compat_cmd_doit *cmd, 11368c2ecf20Sopenharmony_ci struct sk_buff *skb, 11378c2ecf20Sopenharmony_ci struct tipc_nl_compat_msg *msg) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci u32 val; 11408c2ecf20Sopenharmony_ci struct nlattr *net; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci val = ntohl(*(__be32 *)TLV_DATA(msg->req)); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci net = nla_nest_start_noflag(skb, TIPC_NLA_NET); 11458c2ecf20Sopenharmony_ci if (!net) 11468c2ecf20Sopenharmony_ci return -EMSGSIZE; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci if (msg->cmd == TIPC_CMD_SET_NODE_ADDR) { 11498c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TIPC_NLA_NET_ADDR, val)) 11508c2ecf20Sopenharmony_ci return -EMSGSIZE; 11518c2ecf20Sopenharmony_ci } else if (msg->cmd == TIPC_CMD_SET_NETID) { 11528c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TIPC_NLA_NET_ID, val)) 11538c2ecf20Sopenharmony_ci return -EMSGSIZE; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci nla_nest_end(skb, net); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci return 0; 11588c2ecf20Sopenharmony_ci} 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_cistatic int tipc_nl_compat_net_dump(struct tipc_nl_compat_msg *msg, 11618c2ecf20Sopenharmony_ci struct nlattr **attrs) 11628c2ecf20Sopenharmony_ci{ 11638c2ecf20Sopenharmony_ci __be32 id; 11648c2ecf20Sopenharmony_ci struct nlattr *net[TIPC_NLA_NET_MAX + 1]; 11658c2ecf20Sopenharmony_ci int err; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_NET]) 11688c2ecf20Sopenharmony_ci return -EINVAL; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(net, TIPC_NLA_NET_MAX, 11718c2ecf20Sopenharmony_ci attrs[TIPC_NLA_NET], NULL, NULL); 11728c2ecf20Sopenharmony_ci if (err) 11738c2ecf20Sopenharmony_ci return err; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci id = htonl(nla_get_u32(net[TIPC_NLA_NET_ID])); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci return tipc_add_tlv(msg->rep, TIPC_TLV_UNSIGNED, &id, sizeof(id)); 11788c2ecf20Sopenharmony_ci} 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_cistatic int tipc_cmd_show_stats_compat(struct tipc_nl_compat_msg *msg) 11818c2ecf20Sopenharmony_ci{ 11828c2ecf20Sopenharmony_ci msg->rep = tipc_tlv_alloc(ULTRA_STRING_MAX_LEN); 11838c2ecf20Sopenharmony_ci if (!msg->rep) 11848c2ecf20Sopenharmony_ci return -ENOMEM; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci tipc_tlv_init(msg->rep, TIPC_TLV_ULTRA_STRING); 11878c2ecf20Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "TIPC version " TIPC_MOD_VER "\n"); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci return 0; 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci struct tipc_nl_compat_cmd_dump dump; 11958c2ecf20Sopenharmony_ci struct tipc_nl_compat_cmd_doit doit; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci memset(&dump, 0, sizeof(dump)); 11988c2ecf20Sopenharmony_ci memset(&doit, 0, sizeof(doit)); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci switch (msg->cmd) { 12018c2ecf20Sopenharmony_ci case TIPC_CMD_NOOP: 12028c2ecf20Sopenharmony_ci msg->rep = tipc_tlv_alloc(0); 12038c2ecf20Sopenharmony_ci if (!msg->rep) 12048c2ecf20Sopenharmony_ci return -ENOMEM; 12058c2ecf20Sopenharmony_ci return 0; 12068c2ecf20Sopenharmony_ci case TIPC_CMD_GET_BEARER_NAMES: 12078c2ecf20Sopenharmony_ci msg->rep_size = MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME); 12088c2ecf20Sopenharmony_ci dump.dumpit = tipc_nl_bearer_dump; 12098c2ecf20Sopenharmony_ci dump.format = tipc_nl_compat_bearer_dump; 12108c2ecf20Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 12118c2ecf20Sopenharmony_ci case TIPC_CMD_ENABLE_BEARER: 12128c2ecf20Sopenharmony_ci msg->req_type = TIPC_TLV_BEARER_CONFIG; 12138c2ecf20Sopenharmony_ci doit.doit = __tipc_nl_bearer_enable; 12148c2ecf20Sopenharmony_ci doit.transcode = tipc_nl_compat_bearer_enable; 12158c2ecf20Sopenharmony_ci return tipc_nl_compat_doit(&doit, msg); 12168c2ecf20Sopenharmony_ci case TIPC_CMD_DISABLE_BEARER: 12178c2ecf20Sopenharmony_ci msg->req_type = TIPC_TLV_BEARER_NAME; 12188c2ecf20Sopenharmony_ci doit.doit = __tipc_nl_bearer_disable; 12198c2ecf20Sopenharmony_ci doit.transcode = tipc_nl_compat_bearer_disable; 12208c2ecf20Sopenharmony_ci return tipc_nl_compat_doit(&doit, msg); 12218c2ecf20Sopenharmony_ci case TIPC_CMD_SHOW_LINK_STATS: 12228c2ecf20Sopenharmony_ci msg->req_type = TIPC_TLV_LINK_NAME; 12238c2ecf20Sopenharmony_ci msg->rep_size = ULTRA_STRING_MAX_LEN; 12248c2ecf20Sopenharmony_ci msg->rep_type = TIPC_TLV_ULTRA_STRING; 12258c2ecf20Sopenharmony_ci dump.dumpit = tipc_nl_node_dump_link; 12268c2ecf20Sopenharmony_ci dump.format = tipc_nl_compat_link_stat_dump; 12278c2ecf20Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 12288c2ecf20Sopenharmony_ci case TIPC_CMD_GET_LINKS: 12298c2ecf20Sopenharmony_ci msg->req_type = TIPC_TLV_NET_ADDR; 12308c2ecf20Sopenharmony_ci msg->rep_size = ULTRA_STRING_MAX_LEN; 12318c2ecf20Sopenharmony_ci dump.dumpit = tipc_nl_node_dump_link; 12328c2ecf20Sopenharmony_ci dump.format = tipc_nl_compat_link_dump; 12338c2ecf20Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 12348c2ecf20Sopenharmony_ci case TIPC_CMD_SET_LINK_TOL: 12358c2ecf20Sopenharmony_ci case TIPC_CMD_SET_LINK_PRI: 12368c2ecf20Sopenharmony_ci case TIPC_CMD_SET_LINK_WINDOW: 12378c2ecf20Sopenharmony_ci msg->req_type = TIPC_TLV_LINK_CONFIG; 12388c2ecf20Sopenharmony_ci doit.doit = tipc_nl_node_set_link; 12398c2ecf20Sopenharmony_ci doit.transcode = tipc_nl_compat_link_set; 12408c2ecf20Sopenharmony_ci return tipc_nl_compat_doit(&doit, msg); 12418c2ecf20Sopenharmony_ci case TIPC_CMD_RESET_LINK_STATS: 12428c2ecf20Sopenharmony_ci msg->req_type = TIPC_TLV_LINK_NAME; 12438c2ecf20Sopenharmony_ci doit.doit = tipc_nl_node_reset_link_stats; 12448c2ecf20Sopenharmony_ci doit.transcode = tipc_nl_compat_link_reset_stats; 12458c2ecf20Sopenharmony_ci return tipc_nl_compat_doit(&doit, msg); 12468c2ecf20Sopenharmony_ci case TIPC_CMD_SHOW_NAME_TABLE: 12478c2ecf20Sopenharmony_ci msg->req_type = TIPC_TLV_NAME_TBL_QUERY; 12488c2ecf20Sopenharmony_ci msg->rep_size = ULTRA_STRING_MAX_LEN; 12498c2ecf20Sopenharmony_ci msg->rep_type = TIPC_TLV_ULTRA_STRING; 12508c2ecf20Sopenharmony_ci dump.header = tipc_nl_compat_name_table_dump_header; 12518c2ecf20Sopenharmony_ci dump.dumpit = tipc_nl_name_table_dump; 12528c2ecf20Sopenharmony_ci dump.format = tipc_nl_compat_name_table_dump; 12538c2ecf20Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 12548c2ecf20Sopenharmony_ci case TIPC_CMD_SHOW_PORTS: 12558c2ecf20Sopenharmony_ci msg->rep_size = ULTRA_STRING_MAX_LEN; 12568c2ecf20Sopenharmony_ci msg->rep_type = TIPC_TLV_ULTRA_STRING; 12578c2ecf20Sopenharmony_ci dump.dumpit = tipc_nl_sk_dump; 12588c2ecf20Sopenharmony_ci dump.format = tipc_nl_compat_sk_dump; 12598c2ecf20Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 12608c2ecf20Sopenharmony_ci case TIPC_CMD_GET_MEDIA_NAMES: 12618c2ecf20Sopenharmony_ci msg->rep_size = MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME); 12628c2ecf20Sopenharmony_ci dump.dumpit = tipc_nl_media_dump; 12638c2ecf20Sopenharmony_ci dump.format = tipc_nl_compat_media_dump; 12648c2ecf20Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 12658c2ecf20Sopenharmony_ci case TIPC_CMD_GET_NODES: 12668c2ecf20Sopenharmony_ci msg->rep_size = ULTRA_STRING_MAX_LEN; 12678c2ecf20Sopenharmony_ci dump.dumpit = tipc_nl_node_dump; 12688c2ecf20Sopenharmony_ci dump.format = tipc_nl_compat_node_dump; 12698c2ecf20Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 12708c2ecf20Sopenharmony_ci case TIPC_CMD_SET_NODE_ADDR: 12718c2ecf20Sopenharmony_ci msg->req_type = TIPC_TLV_NET_ADDR; 12728c2ecf20Sopenharmony_ci doit.doit = __tipc_nl_net_set; 12738c2ecf20Sopenharmony_ci doit.transcode = tipc_nl_compat_net_set; 12748c2ecf20Sopenharmony_ci return tipc_nl_compat_doit(&doit, msg); 12758c2ecf20Sopenharmony_ci case TIPC_CMD_SET_NETID: 12768c2ecf20Sopenharmony_ci msg->req_type = TIPC_TLV_UNSIGNED; 12778c2ecf20Sopenharmony_ci doit.doit = __tipc_nl_net_set; 12788c2ecf20Sopenharmony_ci doit.transcode = tipc_nl_compat_net_set; 12798c2ecf20Sopenharmony_ci return tipc_nl_compat_doit(&doit, msg); 12808c2ecf20Sopenharmony_ci case TIPC_CMD_GET_NETID: 12818c2ecf20Sopenharmony_ci msg->rep_size = sizeof(u32); 12828c2ecf20Sopenharmony_ci dump.dumpit = tipc_nl_net_dump; 12838c2ecf20Sopenharmony_ci dump.format = tipc_nl_compat_net_dump; 12848c2ecf20Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 12858c2ecf20Sopenharmony_ci case TIPC_CMD_SHOW_STATS: 12868c2ecf20Sopenharmony_ci return tipc_cmd_show_stats_compat(msg); 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12908c2ecf20Sopenharmony_ci} 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_cistatic int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info) 12938c2ecf20Sopenharmony_ci{ 12948c2ecf20Sopenharmony_ci int err; 12958c2ecf20Sopenharmony_ci int len; 12968c2ecf20Sopenharmony_ci struct tipc_nl_compat_msg msg; 12978c2ecf20Sopenharmony_ci struct nlmsghdr *req_nlh; 12988c2ecf20Sopenharmony_ci struct nlmsghdr *rep_nlh; 12998c2ecf20Sopenharmony_ci struct tipc_genlmsghdr *req_userhdr = info->userhdr; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci req_nlh = (struct nlmsghdr *)skb->data; 13048c2ecf20Sopenharmony_ci msg.req = nlmsg_data(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN; 13058c2ecf20Sopenharmony_ci msg.cmd = req_userhdr->cmd; 13068c2ecf20Sopenharmony_ci msg.net = genl_info_net(info); 13078c2ecf20Sopenharmony_ci msg.dst_sk = skb->sk; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if ((msg.cmd & 0xC000) && (!netlink_net_capable(skb, CAP_NET_ADMIN))) { 13108c2ecf20Sopenharmony_ci msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_NET_ADMIN); 13118c2ecf20Sopenharmony_ci err = -EACCES; 13128c2ecf20Sopenharmony_ci goto send; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci msg.req_size = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN); 13168c2ecf20Sopenharmony_ci if (msg.req_size && !TLV_OK(msg.req, msg.req_size)) { 13178c2ecf20Sopenharmony_ci msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED); 13188c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 13198c2ecf20Sopenharmony_ci goto send; 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci err = tipc_nl_compat_handle(&msg); 13238c2ecf20Sopenharmony_ci if ((err == -EOPNOTSUPP) || (err == -EPERM)) 13248c2ecf20Sopenharmony_ci msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED); 13258c2ecf20Sopenharmony_ci else if (err == -EINVAL) 13268c2ecf20Sopenharmony_ci msg.rep = tipc_get_err_tlv(TIPC_CFG_TLV_ERROR); 13278c2ecf20Sopenharmony_cisend: 13288c2ecf20Sopenharmony_ci if (!msg.rep) 13298c2ecf20Sopenharmony_ci return err; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci len = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN); 13328c2ecf20Sopenharmony_ci skb_push(msg.rep, len); 13338c2ecf20Sopenharmony_ci rep_nlh = nlmsg_hdr(msg.rep); 13348c2ecf20Sopenharmony_ci memcpy(rep_nlh, info->nlhdr, len); 13358c2ecf20Sopenharmony_ci rep_nlh->nlmsg_len = msg.rep->len; 13368c2ecf20Sopenharmony_ci genlmsg_unicast(msg.net, msg.rep, NETLINK_CB(skb).portid); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci return err; 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_cistatic const struct genl_small_ops tipc_genl_compat_ops[] = { 13428c2ecf20Sopenharmony_ci { 13438c2ecf20Sopenharmony_ci .cmd = TIPC_GENL_CMD, 13448c2ecf20Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 13458c2ecf20Sopenharmony_ci .doit = tipc_nl_compat_recv, 13468c2ecf20Sopenharmony_ci }, 13478c2ecf20Sopenharmony_ci}; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_cistatic struct genl_family tipc_genl_compat_family __ro_after_init = { 13508c2ecf20Sopenharmony_ci .name = TIPC_GENL_NAME, 13518c2ecf20Sopenharmony_ci .version = TIPC_GENL_VERSION, 13528c2ecf20Sopenharmony_ci .hdrsize = TIPC_GENL_HDRLEN, 13538c2ecf20Sopenharmony_ci .maxattr = 0, 13548c2ecf20Sopenharmony_ci .netnsok = true, 13558c2ecf20Sopenharmony_ci .module = THIS_MODULE, 13568c2ecf20Sopenharmony_ci .small_ops = tipc_genl_compat_ops, 13578c2ecf20Sopenharmony_ci .n_small_ops = ARRAY_SIZE(tipc_genl_compat_ops), 13588c2ecf20Sopenharmony_ci}; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ciint __init tipc_netlink_compat_start(void) 13618c2ecf20Sopenharmony_ci{ 13628c2ecf20Sopenharmony_ci int res; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci res = genl_register_family(&tipc_genl_compat_family); 13658c2ecf20Sopenharmony_ci if (res) { 13668c2ecf20Sopenharmony_ci pr_err("Failed to register legacy compat interface\n"); 13678c2ecf20Sopenharmony_ci return res; 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci return 0; 13718c2ecf20Sopenharmony_ci} 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_civoid tipc_netlink_compat_stop(void) 13748c2ecf20Sopenharmony_ci{ 13758c2ecf20Sopenharmony_ci genl_unregister_family(&tipc_genl_compat_family); 13768c2ecf20Sopenharmony_ci} 1377