162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2014, Ericsson AB 362306a36Sopenharmony_ci * All rights reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 662306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 962306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 1062306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 1162306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 1262306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 1362306a36Sopenharmony_ci * 3. Neither the names of the copyright holders nor the names of its 1462306a36Sopenharmony_ci * contributors may be used to endorse or promote products derived from 1562306a36Sopenharmony_ci * this software without specific prior written permission. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 1862306a36Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free 1962306a36Sopenharmony_ci * Software Foundation. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2262306a36Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2362306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2462306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2562306a36Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2662306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2762306a36Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2862306a36Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2962306a36Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3062306a36Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3162306a36Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include "core.h" 3562306a36Sopenharmony_ci#include "bearer.h" 3662306a36Sopenharmony_ci#include "link.h" 3762306a36Sopenharmony_ci#include "name_table.h" 3862306a36Sopenharmony_ci#include "socket.h" 3962306a36Sopenharmony_ci#include "node.h" 4062306a36Sopenharmony_ci#include "net.h" 4162306a36Sopenharmony_ci#include <net/genetlink.h> 4262306a36Sopenharmony_ci#include <linux/string_helpers.h> 4362306a36Sopenharmony_ci#include <linux/tipc_config.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* The legacy API had an artificial message length limit called 4662306a36Sopenharmony_ci * ULTRA_STRING_MAX_LEN. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci#define ULTRA_STRING_MAX_LEN 32768 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define TIPC_SKB_MAX TLV_SPACE(ULTRA_STRING_MAX_LEN) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define REPLY_TRUNCATED "<truncated>\n" 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistruct tipc_nl_compat_msg { 5562306a36Sopenharmony_ci u16 cmd; 5662306a36Sopenharmony_ci int rep_type; 5762306a36Sopenharmony_ci int rep_size; 5862306a36Sopenharmony_ci int req_type; 5962306a36Sopenharmony_ci int req_size; 6062306a36Sopenharmony_ci struct net *net; 6162306a36Sopenharmony_ci struct sk_buff *rep; 6262306a36Sopenharmony_ci struct tlv_desc *req; 6362306a36Sopenharmony_ci struct sock *dst_sk; 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistruct tipc_nl_compat_cmd_dump { 6762306a36Sopenharmony_ci int (*header)(struct tipc_nl_compat_msg *); 6862306a36Sopenharmony_ci int (*dumpit)(struct sk_buff *, struct netlink_callback *); 6962306a36Sopenharmony_ci int (*format)(struct tipc_nl_compat_msg *msg, struct nlattr **attrs); 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistruct tipc_nl_compat_cmd_doit { 7362306a36Sopenharmony_ci int (*doit)(struct sk_buff *skb, struct genl_info *info); 7462306a36Sopenharmony_ci int (*transcode)(struct tipc_nl_compat_cmd_doit *cmd, 7562306a36Sopenharmony_ci struct sk_buff *skb, struct tipc_nl_compat_msg *msg); 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int tipc_skb_tailroom(struct sk_buff *skb) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci int tailroom; 8162306a36Sopenharmony_ci int limit; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci tailroom = skb_tailroom(skb); 8462306a36Sopenharmony_ci limit = TIPC_SKB_MAX - skb->len; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (tailroom < limit) 8762306a36Sopenharmony_ci return tailroom; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci return limit; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic inline int TLV_GET_DATA_LEN(struct tlv_desc *tlv) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci return TLV_GET_LEN(tlv) - TLV_SPACE(0); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int tipc_add_tlv(struct sk_buff *skb, u16 type, void *data, u16 len) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(skb); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (tipc_skb_tailroom(skb) < TLV_SPACE(len)) 10262306a36Sopenharmony_ci return -EMSGSIZE; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci skb_put(skb, TLV_SPACE(len)); 10562306a36Sopenharmony_ci memset(tlv, 0, TLV_SPACE(len)); 10662306a36Sopenharmony_ci tlv->tlv_type = htons(type); 10762306a36Sopenharmony_ci tlv->tlv_len = htons(TLV_LENGTH(len)); 10862306a36Sopenharmony_ci if (len && data) 10962306a36Sopenharmony_ci memcpy(TLV_DATA(tlv), data, len); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic void tipc_tlv_init(struct sk_buff *skb, u16 type) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct tlv_desc *tlv = (struct tlv_desc *)skb->data; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci TLV_SET_LEN(tlv, 0); 11962306a36Sopenharmony_ci TLV_SET_TYPE(tlv, type); 12062306a36Sopenharmony_ci skb_put(skb, sizeof(struct tlv_desc)); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic __printf(2, 3) int tipc_tlv_sprintf(struct sk_buff *skb, 12462306a36Sopenharmony_ci const char *fmt, ...) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci int n; 12762306a36Sopenharmony_ci u16 len; 12862306a36Sopenharmony_ci u32 rem; 12962306a36Sopenharmony_ci char *buf; 13062306a36Sopenharmony_ci struct tlv_desc *tlv; 13162306a36Sopenharmony_ci va_list args; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci rem = tipc_skb_tailroom(skb); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci tlv = (struct tlv_desc *)skb->data; 13662306a36Sopenharmony_ci len = TLV_GET_LEN(tlv); 13762306a36Sopenharmony_ci buf = TLV_DATA(tlv) + len; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci va_start(args, fmt); 14062306a36Sopenharmony_ci n = vscnprintf(buf, rem, fmt, args); 14162306a36Sopenharmony_ci va_end(args); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci TLV_SET_LEN(tlv, n + len); 14462306a36Sopenharmony_ci skb_put(skb, n); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return n; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic struct sk_buff *tipc_tlv_alloc(int size) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci int hdr_len; 15262306a36Sopenharmony_ci struct sk_buff *buf; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci size = TLV_SPACE(size); 15562306a36Sopenharmony_ci hdr_len = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci buf = alloc_skb(hdr_len + size, GFP_KERNEL); 15862306a36Sopenharmony_ci if (!buf) 15962306a36Sopenharmony_ci return NULL; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci skb_reserve(buf, hdr_len); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return buf; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic struct sk_buff *tipc_get_err_tlv(char *str) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci int str_len = strlen(str) + 1; 16962306a36Sopenharmony_ci struct sk_buff *buf; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci buf = tipc_tlv_alloc(TLV_SPACE(str_len)); 17262306a36Sopenharmony_ci if (buf) 17362306a36Sopenharmony_ci tipc_add_tlv(buf, TIPC_TLV_ERROR_STRING, str, str_len); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci return buf; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd, 17962306a36Sopenharmony_ci struct tipc_nl_compat_msg *msg, 18062306a36Sopenharmony_ci struct sk_buff *arg) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct genl_dumpit_info info; 18362306a36Sopenharmony_ci int len = 0; 18462306a36Sopenharmony_ci int err; 18562306a36Sopenharmony_ci struct sk_buff *buf; 18662306a36Sopenharmony_ci struct nlmsghdr *nlmsg; 18762306a36Sopenharmony_ci struct netlink_callback cb; 18862306a36Sopenharmony_ci struct nlattr **attrbuf; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci memset(&cb, 0, sizeof(cb)); 19162306a36Sopenharmony_ci cb.nlh = (struct nlmsghdr *)arg->data; 19262306a36Sopenharmony_ci cb.skb = arg; 19362306a36Sopenharmony_ci cb.data = &info; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci buf = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 19662306a36Sopenharmony_ci if (!buf) 19762306a36Sopenharmony_ci return -ENOMEM; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci buf->sk = msg->dst_sk; 20062306a36Sopenharmony_ci if (__tipc_dump_start(&cb, msg->net)) { 20162306a36Sopenharmony_ci kfree_skb(buf); 20262306a36Sopenharmony_ci return -ENOMEM; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci attrbuf = kcalloc(tipc_genl_family.maxattr + 1, 20662306a36Sopenharmony_ci sizeof(struct nlattr *), GFP_KERNEL); 20762306a36Sopenharmony_ci if (!attrbuf) { 20862306a36Sopenharmony_ci err = -ENOMEM; 20962306a36Sopenharmony_ci goto err_out; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci info.info.attrs = attrbuf; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (nlmsg_len(cb.nlh) > 0) { 21562306a36Sopenharmony_ci err = nlmsg_parse_deprecated(cb.nlh, GENL_HDRLEN, attrbuf, 21662306a36Sopenharmony_ci tipc_genl_family.maxattr, 21762306a36Sopenharmony_ci tipc_genl_family.policy, NULL); 21862306a36Sopenharmony_ci if (err) 21962306a36Sopenharmony_ci goto err_out; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci do { 22262306a36Sopenharmony_ci int rem; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci len = (*cmd->dumpit)(buf, &cb); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci nlmsg_for_each_msg(nlmsg, nlmsg_hdr(buf), len, rem) { 22762306a36Sopenharmony_ci err = nlmsg_parse_deprecated(nlmsg, GENL_HDRLEN, 22862306a36Sopenharmony_ci attrbuf, 22962306a36Sopenharmony_ci tipc_genl_family.maxattr, 23062306a36Sopenharmony_ci tipc_genl_family.policy, 23162306a36Sopenharmony_ci NULL); 23262306a36Sopenharmony_ci if (err) 23362306a36Sopenharmony_ci goto err_out; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci err = (*cmd->format)(msg, attrbuf); 23662306a36Sopenharmony_ci if (err) 23762306a36Sopenharmony_ci goto err_out; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (tipc_skb_tailroom(msg->rep) <= 1) { 24062306a36Sopenharmony_ci err = -EMSGSIZE; 24162306a36Sopenharmony_ci goto err_out; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci skb_reset_tail_pointer(buf); 24662306a36Sopenharmony_ci buf->len = 0; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci } while (len); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci err = 0; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cierr_out: 25362306a36Sopenharmony_ci kfree(attrbuf); 25462306a36Sopenharmony_ci tipc_dump_done(&cb); 25562306a36Sopenharmony_ci kfree_skb(buf); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (err == -EMSGSIZE) { 25862306a36Sopenharmony_ci /* The legacy API only considered messages filling 25962306a36Sopenharmony_ci * "ULTRA_STRING_MAX_LEN" to be truncated. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_ci if ((TIPC_SKB_MAX - msg->rep->len) <= 1) { 26262306a36Sopenharmony_ci char *tail = skb_tail_pointer(msg->rep); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (*tail != '\0') 26562306a36Sopenharmony_ci sprintf(tail - sizeof(REPLY_TRUNCATED) - 1, 26662306a36Sopenharmony_ci REPLY_TRUNCATED); 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return 0; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return err; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd, 27662306a36Sopenharmony_ci struct tipc_nl_compat_msg *msg) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct nlmsghdr *nlh; 27962306a36Sopenharmony_ci struct sk_buff *arg; 28062306a36Sopenharmony_ci int err; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (msg->req_type && (!msg->req_size || 28362306a36Sopenharmony_ci !TLV_CHECK_TYPE(msg->req, msg->req_type))) 28462306a36Sopenharmony_ci return -EINVAL; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci msg->rep = tipc_tlv_alloc(msg->rep_size); 28762306a36Sopenharmony_ci if (!msg->rep) 28862306a36Sopenharmony_ci return -ENOMEM; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (msg->rep_type) 29162306a36Sopenharmony_ci tipc_tlv_init(msg->rep, msg->rep_type); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (cmd->header) { 29462306a36Sopenharmony_ci err = (*cmd->header)(msg); 29562306a36Sopenharmony_ci if (err) { 29662306a36Sopenharmony_ci kfree_skb(msg->rep); 29762306a36Sopenharmony_ci msg->rep = NULL; 29862306a36Sopenharmony_ci return err; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci arg = nlmsg_new(0, GFP_KERNEL); 30362306a36Sopenharmony_ci if (!arg) { 30462306a36Sopenharmony_ci kfree_skb(msg->rep); 30562306a36Sopenharmony_ci msg->rep = NULL; 30662306a36Sopenharmony_ci return -ENOMEM; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci nlh = nlmsg_put(arg, 0, 0, tipc_genl_family.id, 0, NLM_F_MULTI); 31062306a36Sopenharmony_ci if (!nlh) { 31162306a36Sopenharmony_ci kfree_skb(arg); 31262306a36Sopenharmony_ci kfree_skb(msg->rep); 31362306a36Sopenharmony_ci msg->rep = NULL; 31462306a36Sopenharmony_ci return -EMSGSIZE; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci nlmsg_end(arg, nlh); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci err = __tipc_nl_compat_dumpit(cmd, msg, arg); 31962306a36Sopenharmony_ci if (err) { 32062306a36Sopenharmony_ci kfree_skb(msg->rep); 32162306a36Sopenharmony_ci msg->rep = NULL; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci kfree_skb(arg); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return err; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd, 32962306a36Sopenharmony_ci struct tipc_nl_compat_msg *msg) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci int err; 33262306a36Sopenharmony_ci struct sk_buff *doit_buf; 33362306a36Sopenharmony_ci struct sk_buff *trans_buf; 33462306a36Sopenharmony_ci struct nlattr **attrbuf; 33562306a36Sopenharmony_ci struct genl_info info; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci trans_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 33862306a36Sopenharmony_ci if (!trans_buf) 33962306a36Sopenharmony_ci return -ENOMEM; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci attrbuf = kmalloc_array(tipc_genl_family.maxattr + 1, 34262306a36Sopenharmony_ci sizeof(struct nlattr *), 34362306a36Sopenharmony_ci GFP_KERNEL); 34462306a36Sopenharmony_ci if (!attrbuf) { 34562306a36Sopenharmony_ci err = -ENOMEM; 34662306a36Sopenharmony_ci goto trans_out; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 35062306a36Sopenharmony_ci if (!doit_buf) { 35162306a36Sopenharmony_ci err = -ENOMEM; 35262306a36Sopenharmony_ci goto attrbuf_out; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci memset(&info, 0, sizeof(info)); 35662306a36Sopenharmony_ci info.attrs = attrbuf; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci rtnl_lock(); 35962306a36Sopenharmony_ci err = (*cmd->transcode)(cmd, trans_buf, msg); 36062306a36Sopenharmony_ci if (err) 36162306a36Sopenharmony_ci goto doit_out; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci err = nla_parse_deprecated(attrbuf, tipc_genl_family.maxattr, 36462306a36Sopenharmony_ci (const struct nlattr *)trans_buf->data, 36562306a36Sopenharmony_ci trans_buf->len, NULL, NULL); 36662306a36Sopenharmony_ci if (err) 36762306a36Sopenharmony_ci goto doit_out; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci doit_buf->sk = msg->dst_sk; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci err = (*cmd->doit)(doit_buf, &info); 37262306a36Sopenharmony_cidoit_out: 37362306a36Sopenharmony_ci rtnl_unlock(); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci kfree_skb(doit_buf); 37662306a36Sopenharmony_ciattrbuf_out: 37762306a36Sopenharmony_ci kfree(attrbuf); 37862306a36Sopenharmony_citrans_out: 37962306a36Sopenharmony_ci kfree_skb(trans_buf); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return err; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd, 38562306a36Sopenharmony_ci struct tipc_nl_compat_msg *msg) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci int err; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (msg->req_type && (!msg->req_size || 39062306a36Sopenharmony_ci !TLV_CHECK_TYPE(msg->req, msg->req_type))) 39162306a36Sopenharmony_ci return -EINVAL; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci err = __tipc_nl_compat_doit(cmd, msg); 39462306a36Sopenharmony_ci if (err) 39562306a36Sopenharmony_ci return err; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* The legacy API considered an empty message a success message */ 39862306a36Sopenharmony_ci msg->rep = tipc_tlv_alloc(0); 39962306a36Sopenharmony_ci if (!msg->rep) 40062306a36Sopenharmony_ci return -ENOMEM; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic int tipc_nl_compat_bearer_dump(struct tipc_nl_compat_msg *msg, 40662306a36Sopenharmony_ci struct nlattr **attrs) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct nlattr *bearer[TIPC_NLA_BEARER_MAX + 1]; 40962306a36Sopenharmony_ci int err; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (!attrs[TIPC_NLA_BEARER]) 41262306a36Sopenharmony_ci return -EINVAL; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci err = nla_parse_nested_deprecated(bearer, TIPC_NLA_BEARER_MAX, 41562306a36Sopenharmony_ci attrs[TIPC_NLA_BEARER], NULL, NULL); 41662306a36Sopenharmony_ci if (err) 41762306a36Sopenharmony_ci return err; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return tipc_add_tlv(msg->rep, TIPC_TLV_BEARER_NAME, 42062306a36Sopenharmony_ci nla_data(bearer[TIPC_NLA_BEARER_NAME]), 42162306a36Sopenharmony_ci nla_len(bearer[TIPC_NLA_BEARER_NAME])); 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic int tipc_nl_compat_bearer_enable(struct tipc_nl_compat_cmd_doit *cmd, 42562306a36Sopenharmony_ci struct sk_buff *skb, 42662306a36Sopenharmony_ci struct tipc_nl_compat_msg *msg) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct nlattr *prop; 42962306a36Sopenharmony_ci struct nlattr *bearer; 43062306a36Sopenharmony_ci struct tipc_bearer_config *b; 43162306a36Sopenharmony_ci int len; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci b = (struct tipc_bearer_config *)TLV_DATA(msg->req); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci bearer = nla_nest_start_noflag(skb, TIPC_NLA_BEARER); 43662306a36Sopenharmony_ci if (!bearer) 43762306a36Sopenharmony_ci return -EMSGSIZE; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci len = TLV_GET_DATA_LEN(msg->req); 44062306a36Sopenharmony_ci len -= offsetof(struct tipc_bearer_config, name); 44162306a36Sopenharmony_ci if (len <= 0) 44262306a36Sopenharmony_ci return -EINVAL; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci len = min_t(int, len, TIPC_MAX_BEARER_NAME); 44562306a36Sopenharmony_ci if (!string_is_terminated(b->name, len)) 44662306a36Sopenharmony_ci return -EINVAL; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, b->name)) 44962306a36Sopenharmony_ci return -EMSGSIZE; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (nla_put_u32(skb, TIPC_NLA_BEARER_DOMAIN, ntohl(b->disc_domain))) 45262306a36Sopenharmony_ci return -EMSGSIZE; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (ntohl(b->priority) <= TIPC_MAX_LINK_PRI) { 45562306a36Sopenharmony_ci prop = nla_nest_start_noflag(skb, TIPC_NLA_BEARER_PROP); 45662306a36Sopenharmony_ci if (!prop) 45762306a36Sopenharmony_ci return -EMSGSIZE; 45862306a36Sopenharmony_ci if (nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(b->priority))) 45962306a36Sopenharmony_ci return -EMSGSIZE; 46062306a36Sopenharmony_ci nla_nest_end(skb, prop); 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci nla_nest_end(skb, bearer); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci return 0; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic int tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit *cmd, 46862306a36Sopenharmony_ci struct sk_buff *skb, 46962306a36Sopenharmony_ci struct tipc_nl_compat_msg *msg) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci char *name; 47262306a36Sopenharmony_ci struct nlattr *bearer; 47362306a36Sopenharmony_ci int len; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci name = (char *)TLV_DATA(msg->req); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci bearer = nla_nest_start_noflag(skb, TIPC_NLA_BEARER); 47862306a36Sopenharmony_ci if (!bearer) 47962306a36Sopenharmony_ci return -EMSGSIZE; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci len = TLV_GET_DATA_LEN(msg->req); 48262306a36Sopenharmony_ci if (len <= 0) 48362306a36Sopenharmony_ci return -EINVAL; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci len = min_t(int, len, TIPC_MAX_BEARER_NAME); 48662306a36Sopenharmony_ci if (!string_is_terminated(name, len)) 48762306a36Sopenharmony_ci return -EINVAL; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, name)) 49062306a36Sopenharmony_ci return -EMSGSIZE; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci nla_nest_end(skb, bearer); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci return 0; 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic inline u32 perc(u32 count, u32 total) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci return (count * 100 + (total / 2)) / total; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic void __fill_bc_link_stat(struct tipc_nl_compat_msg *msg, 50362306a36Sopenharmony_ci struct nlattr *prop[], struct nlattr *stats[]) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " Window:%u packets\n", 50662306a36Sopenharmony_ci nla_get_u32(prop[TIPC_NLA_PROP_WIN])); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 50962306a36Sopenharmony_ci " RX packets:%u fragments:%u/%u bundles:%u/%u\n", 51062306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_INFO]), 51162306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]), 51262306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]), 51362306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]), 51462306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED])); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 51762306a36Sopenharmony_ci " TX packets:%u fragments:%u/%u bundles:%u/%u\n", 51862306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_INFO]), 51962306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]), 52062306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]), 52162306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]), 52262306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED])); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " RX naks:%u defs:%u dups:%u\n", 52562306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]), 52662306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]), 52762306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_DUPLICATES])); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " TX naks:%u acks:%u dups:%u\n", 53062306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]), 53162306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]), 53262306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED])); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 53562306a36Sopenharmony_ci " Congestion link:%u Send queue max:%u avg:%u", 53662306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]), 53762306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]), 53862306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE])); 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg, 54262306a36Sopenharmony_ci struct nlattr **attrs) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci char *name; 54562306a36Sopenharmony_ci struct nlattr *link[TIPC_NLA_LINK_MAX + 1]; 54662306a36Sopenharmony_ci struct nlattr *prop[TIPC_NLA_PROP_MAX + 1]; 54762306a36Sopenharmony_ci struct nlattr *stats[TIPC_NLA_STATS_MAX + 1]; 54862306a36Sopenharmony_ci int err; 54962306a36Sopenharmony_ci int len; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (!attrs[TIPC_NLA_LINK]) 55262306a36Sopenharmony_ci return -EINVAL; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci err = nla_parse_nested_deprecated(link, TIPC_NLA_LINK_MAX, 55562306a36Sopenharmony_ci attrs[TIPC_NLA_LINK], NULL, NULL); 55662306a36Sopenharmony_ci if (err) 55762306a36Sopenharmony_ci return err; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (!link[TIPC_NLA_LINK_PROP]) 56062306a36Sopenharmony_ci return -EINVAL; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci err = nla_parse_nested_deprecated(prop, TIPC_NLA_PROP_MAX, 56362306a36Sopenharmony_ci link[TIPC_NLA_LINK_PROP], NULL, 56462306a36Sopenharmony_ci NULL); 56562306a36Sopenharmony_ci if (err) 56662306a36Sopenharmony_ci return err; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (!link[TIPC_NLA_LINK_STATS]) 56962306a36Sopenharmony_ci return -EINVAL; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci err = nla_parse_nested_deprecated(stats, TIPC_NLA_STATS_MAX, 57262306a36Sopenharmony_ci link[TIPC_NLA_LINK_STATS], NULL, 57362306a36Sopenharmony_ci NULL); 57462306a36Sopenharmony_ci if (err) 57562306a36Sopenharmony_ci return err; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci name = (char *)TLV_DATA(msg->req); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci len = TLV_GET_DATA_LEN(msg->req); 58062306a36Sopenharmony_ci if (len <= 0) 58162306a36Sopenharmony_ci return -EINVAL; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci len = min_t(int, len, TIPC_MAX_LINK_NAME); 58462306a36Sopenharmony_ci if (!string_is_terminated(name, len)) 58562306a36Sopenharmony_ci return -EINVAL; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (strcmp(name, nla_data(link[TIPC_NLA_LINK_NAME])) != 0) 58862306a36Sopenharmony_ci return 0; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "\nLink <%s>\n", 59162306a36Sopenharmony_ci (char *)nla_data(link[TIPC_NLA_LINK_NAME])); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (link[TIPC_NLA_LINK_BROADCAST]) { 59462306a36Sopenharmony_ci __fill_bc_link_stat(msg, prop, stats); 59562306a36Sopenharmony_ci return 0; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (link[TIPC_NLA_LINK_ACTIVE]) 59962306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " ACTIVE"); 60062306a36Sopenharmony_ci else if (link[TIPC_NLA_LINK_UP]) 60162306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " STANDBY"); 60262306a36Sopenharmony_ci else 60362306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " DEFUNCT"); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " MTU:%u Priority:%u", 60662306a36Sopenharmony_ci nla_get_u32(link[TIPC_NLA_LINK_MTU]), 60762306a36Sopenharmony_ci nla_get_u32(prop[TIPC_NLA_PROP_PRIO])); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " Tolerance:%u ms Window:%u packets\n", 61062306a36Sopenharmony_ci nla_get_u32(prop[TIPC_NLA_PROP_TOL]), 61162306a36Sopenharmony_ci nla_get_u32(prop[TIPC_NLA_PROP_WIN])); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 61462306a36Sopenharmony_ci " RX packets:%u fragments:%u/%u bundles:%u/%u\n", 61562306a36Sopenharmony_ci nla_get_u32(link[TIPC_NLA_LINK_RX]) - 61662306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_INFO]), 61762306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]), 61862306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]), 61962306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]), 62062306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED])); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 62362306a36Sopenharmony_ci " TX packets:%u fragments:%u/%u bundles:%u/%u\n", 62462306a36Sopenharmony_ci nla_get_u32(link[TIPC_NLA_LINK_TX]) - 62562306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_INFO]), 62662306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]), 62762306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]), 62862306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]), 62962306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED])); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 63262306a36Sopenharmony_ci " TX profile sample:%u packets average:%u octets\n", 63362306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_CNT]), 63462306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_TOT]) / 63562306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 63862306a36Sopenharmony_ci " 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% ", 63962306a36Sopenharmony_ci perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P0]), 64062306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])), 64162306a36Sopenharmony_ci perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P1]), 64262306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])), 64362306a36Sopenharmony_ci perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P2]), 64462306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])), 64562306a36Sopenharmony_ci perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P3]), 64662306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT]))); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "-16384:%u%% -32768:%u%% -66000:%u%%\n", 64962306a36Sopenharmony_ci perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P4]), 65062306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])), 65162306a36Sopenharmony_ci perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P5]), 65262306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])), 65362306a36Sopenharmony_ci perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P6]), 65462306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT]))); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 65762306a36Sopenharmony_ci " RX states:%u probes:%u naks:%u defs:%u dups:%u\n", 65862306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_STATES]), 65962306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_PROBES]), 66062306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]), 66162306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]), 66262306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_DUPLICATES])); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 66562306a36Sopenharmony_ci " TX states:%u probes:%u naks:%u acks:%u dups:%u\n", 66662306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_STATES]), 66762306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_PROBES]), 66862306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]), 66962306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]), 67062306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED])); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, 67362306a36Sopenharmony_ci " Congestion link:%u Send queue max:%u avg:%u", 67462306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]), 67562306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]), 67662306a36Sopenharmony_ci nla_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE])); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci return 0; 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic int tipc_nl_compat_link_dump(struct tipc_nl_compat_msg *msg, 68262306a36Sopenharmony_ci struct nlattr **attrs) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci struct nlattr *link[TIPC_NLA_LINK_MAX + 1]; 68562306a36Sopenharmony_ci struct tipc_link_info link_info; 68662306a36Sopenharmony_ci int err; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci if (!attrs[TIPC_NLA_LINK]) 68962306a36Sopenharmony_ci return -EINVAL; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci err = nla_parse_nested_deprecated(link, TIPC_NLA_LINK_MAX, 69262306a36Sopenharmony_ci attrs[TIPC_NLA_LINK], NULL, NULL); 69362306a36Sopenharmony_ci if (err) 69462306a36Sopenharmony_ci return err; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci link_info.dest = htonl(nla_get_flag(link[TIPC_NLA_LINK_DEST])); 69762306a36Sopenharmony_ci link_info.up = htonl(nla_get_flag(link[TIPC_NLA_LINK_UP])); 69862306a36Sopenharmony_ci nla_strscpy(link_info.str, link[TIPC_NLA_LINK_NAME], 69962306a36Sopenharmony_ci TIPC_MAX_LINK_NAME); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci return tipc_add_tlv(msg->rep, TIPC_TLV_LINK_INFO, 70262306a36Sopenharmony_ci &link_info, sizeof(link_info)); 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_cistatic int __tipc_add_link_prop(struct sk_buff *skb, 70662306a36Sopenharmony_ci struct tipc_nl_compat_msg *msg, 70762306a36Sopenharmony_ci struct tipc_link_config *lc) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci switch (msg->cmd) { 71062306a36Sopenharmony_ci case TIPC_CMD_SET_LINK_PRI: 71162306a36Sopenharmony_ci return nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(lc->value)); 71262306a36Sopenharmony_ci case TIPC_CMD_SET_LINK_TOL: 71362306a36Sopenharmony_ci return nla_put_u32(skb, TIPC_NLA_PROP_TOL, ntohl(lc->value)); 71462306a36Sopenharmony_ci case TIPC_CMD_SET_LINK_WINDOW: 71562306a36Sopenharmony_ci return nla_put_u32(skb, TIPC_NLA_PROP_WIN, ntohl(lc->value)); 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci return -EINVAL; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic int tipc_nl_compat_media_set(struct sk_buff *skb, 72262306a36Sopenharmony_ci struct tipc_nl_compat_msg *msg) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci struct nlattr *prop; 72562306a36Sopenharmony_ci struct nlattr *media; 72662306a36Sopenharmony_ci struct tipc_link_config *lc; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci lc = (struct tipc_link_config *)TLV_DATA(msg->req); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci media = nla_nest_start_noflag(skb, TIPC_NLA_MEDIA); 73162306a36Sopenharmony_ci if (!media) 73262306a36Sopenharmony_ci return -EMSGSIZE; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (nla_put_string(skb, TIPC_NLA_MEDIA_NAME, lc->name)) 73562306a36Sopenharmony_ci return -EMSGSIZE; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci prop = nla_nest_start_noflag(skb, TIPC_NLA_MEDIA_PROP); 73862306a36Sopenharmony_ci if (!prop) 73962306a36Sopenharmony_ci return -EMSGSIZE; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci __tipc_add_link_prop(skb, msg, lc); 74262306a36Sopenharmony_ci nla_nest_end(skb, prop); 74362306a36Sopenharmony_ci nla_nest_end(skb, media); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci return 0; 74662306a36Sopenharmony_ci} 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cistatic int tipc_nl_compat_bearer_set(struct sk_buff *skb, 74962306a36Sopenharmony_ci struct tipc_nl_compat_msg *msg) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci struct nlattr *prop; 75262306a36Sopenharmony_ci struct nlattr *bearer; 75362306a36Sopenharmony_ci struct tipc_link_config *lc; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci lc = (struct tipc_link_config *)TLV_DATA(msg->req); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci bearer = nla_nest_start_noflag(skb, TIPC_NLA_BEARER); 75862306a36Sopenharmony_ci if (!bearer) 75962306a36Sopenharmony_ci return -EMSGSIZE; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, lc->name)) 76262306a36Sopenharmony_ci return -EMSGSIZE; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci prop = nla_nest_start_noflag(skb, TIPC_NLA_BEARER_PROP); 76562306a36Sopenharmony_ci if (!prop) 76662306a36Sopenharmony_ci return -EMSGSIZE; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci __tipc_add_link_prop(skb, msg, lc); 76962306a36Sopenharmony_ci nla_nest_end(skb, prop); 77062306a36Sopenharmony_ci nla_nest_end(skb, bearer); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci return 0; 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_cistatic int __tipc_nl_compat_link_set(struct sk_buff *skb, 77662306a36Sopenharmony_ci struct tipc_nl_compat_msg *msg) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci struct nlattr *prop; 77962306a36Sopenharmony_ci struct nlattr *link; 78062306a36Sopenharmony_ci struct tipc_link_config *lc; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci lc = (struct tipc_link_config *)TLV_DATA(msg->req); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci link = nla_nest_start_noflag(skb, TIPC_NLA_LINK); 78562306a36Sopenharmony_ci if (!link) 78662306a36Sopenharmony_ci return -EMSGSIZE; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (nla_put_string(skb, TIPC_NLA_LINK_NAME, lc->name)) 78962306a36Sopenharmony_ci return -EMSGSIZE; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci prop = nla_nest_start_noflag(skb, TIPC_NLA_LINK_PROP); 79262306a36Sopenharmony_ci if (!prop) 79362306a36Sopenharmony_ci return -EMSGSIZE; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci __tipc_add_link_prop(skb, msg, lc); 79662306a36Sopenharmony_ci nla_nest_end(skb, prop); 79762306a36Sopenharmony_ci nla_nest_end(skb, link); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci return 0; 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd, 80362306a36Sopenharmony_ci struct sk_buff *skb, 80462306a36Sopenharmony_ci struct tipc_nl_compat_msg *msg) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci struct tipc_link_config *lc; 80762306a36Sopenharmony_ci struct tipc_bearer *bearer; 80862306a36Sopenharmony_ci struct tipc_media *media; 80962306a36Sopenharmony_ci int len; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci lc = (struct tipc_link_config *)TLV_DATA(msg->req); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci len = TLV_GET_DATA_LEN(msg->req); 81462306a36Sopenharmony_ci len -= offsetof(struct tipc_link_config, name); 81562306a36Sopenharmony_ci if (len <= 0) 81662306a36Sopenharmony_ci return -EINVAL; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci len = min_t(int, len, TIPC_MAX_LINK_NAME); 81962306a36Sopenharmony_ci if (!string_is_terminated(lc->name, len)) 82062306a36Sopenharmony_ci return -EINVAL; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci media = tipc_media_find(lc->name); 82362306a36Sopenharmony_ci if (media) { 82462306a36Sopenharmony_ci cmd->doit = &__tipc_nl_media_set; 82562306a36Sopenharmony_ci return tipc_nl_compat_media_set(skb, msg); 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci bearer = tipc_bearer_find(msg->net, lc->name); 82962306a36Sopenharmony_ci if (bearer) { 83062306a36Sopenharmony_ci cmd->doit = &__tipc_nl_bearer_set; 83162306a36Sopenharmony_ci return tipc_nl_compat_bearer_set(skb, msg); 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci return __tipc_nl_compat_link_set(skb, msg); 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd, 83862306a36Sopenharmony_ci struct sk_buff *skb, 83962306a36Sopenharmony_ci struct tipc_nl_compat_msg *msg) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci char *name; 84262306a36Sopenharmony_ci struct nlattr *link; 84362306a36Sopenharmony_ci int len; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci name = (char *)TLV_DATA(msg->req); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci link = nla_nest_start_noflag(skb, TIPC_NLA_LINK); 84862306a36Sopenharmony_ci if (!link) 84962306a36Sopenharmony_ci return -EMSGSIZE; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci len = TLV_GET_DATA_LEN(msg->req); 85262306a36Sopenharmony_ci if (len <= 0) 85362306a36Sopenharmony_ci return -EINVAL; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci len = min_t(int, len, TIPC_MAX_LINK_NAME); 85662306a36Sopenharmony_ci if (!string_is_terminated(name, len)) 85762306a36Sopenharmony_ci return -EINVAL; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (nla_put_string(skb, TIPC_NLA_LINK_NAME, name)) 86062306a36Sopenharmony_ci return -EMSGSIZE; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci nla_nest_end(skb, link); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci return 0; 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic int tipc_nl_compat_name_table_dump_header(struct tipc_nl_compat_msg *msg) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci int i; 87062306a36Sopenharmony_ci u32 depth; 87162306a36Sopenharmony_ci struct tipc_name_table_query *ntq; 87262306a36Sopenharmony_ci static const char * const header[] = { 87362306a36Sopenharmony_ci "Type ", 87462306a36Sopenharmony_ci "Lower Upper ", 87562306a36Sopenharmony_ci "Port Identity ", 87662306a36Sopenharmony_ci "Publication Scope" 87762306a36Sopenharmony_ci }; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req); 88062306a36Sopenharmony_ci if (TLV_GET_DATA_LEN(msg->req) < (int)sizeof(struct tipc_name_table_query)) 88162306a36Sopenharmony_ci return -EINVAL; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci depth = ntohl(ntq->depth); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci if (depth > 4) 88662306a36Sopenharmony_ci depth = 4; 88762306a36Sopenharmony_ci for (i = 0; i < depth; i++) 88862306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, header[i]); 88962306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "\n"); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci return 0; 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cistatic int tipc_nl_compat_name_table_dump(struct tipc_nl_compat_msg *msg, 89562306a36Sopenharmony_ci struct nlattr **attrs) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci char port_str[27]; 89862306a36Sopenharmony_ci struct tipc_name_table_query *ntq; 89962306a36Sopenharmony_ci struct nlattr *nt[TIPC_NLA_NAME_TABLE_MAX + 1]; 90062306a36Sopenharmony_ci struct nlattr *publ[TIPC_NLA_PUBL_MAX + 1]; 90162306a36Sopenharmony_ci u32 node, depth, type, lowbound, upbound; 90262306a36Sopenharmony_ci static const char * const scope_str[] = {"", " zone", " cluster", 90362306a36Sopenharmony_ci " node"}; 90462306a36Sopenharmony_ci int err; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci if (!attrs[TIPC_NLA_NAME_TABLE]) 90762306a36Sopenharmony_ci return -EINVAL; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci err = nla_parse_nested_deprecated(nt, TIPC_NLA_NAME_TABLE_MAX, 91062306a36Sopenharmony_ci attrs[TIPC_NLA_NAME_TABLE], NULL, 91162306a36Sopenharmony_ci NULL); 91262306a36Sopenharmony_ci if (err) 91362306a36Sopenharmony_ci return err; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (!nt[TIPC_NLA_NAME_TABLE_PUBL]) 91662306a36Sopenharmony_ci return -EINVAL; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci err = nla_parse_nested_deprecated(publ, TIPC_NLA_PUBL_MAX, 91962306a36Sopenharmony_ci nt[TIPC_NLA_NAME_TABLE_PUBL], NULL, 92062306a36Sopenharmony_ci NULL); 92162306a36Sopenharmony_ci if (err) 92262306a36Sopenharmony_ci return err; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci depth = ntohl(ntq->depth); 92762306a36Sopenharmony_ci type = ntohl(ntq->type); 92862306a36Sopenharmony_ci lowbound = ntohl(ntq->lowbound); 92962306a36Sopenharmony_ci upbound = ntohl(ntq->upbound); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (!(depth & TIPC_NTQ_ALLTYPES) && 93262306a36Sopenharmony_ci (type != nla_get_u32(publ[TIPC_NLA_PUBL_TYPE]))) 93362306a36Sopenharmony_ci return 0; 93462306a36Sopenharmony_ci if (lowbound && (lowbound > nla_get_u32(publ[TIPC_NLA_PUBL_UPPER]))) 93562306a36Sopenharmony_ci return 0; 93662306a36Sopenharmony_ci if (upbound && (upbound < nla_get_u32(publ[TIPC_NLA_PUBL_LOWER]))) 93762306a36Sopenharmony_ci return 0; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "%-10u ", 94062306a36Sopenharmony_ci nla_get_u32(publ[TIPC_NLA_PUBL_TYPE])); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci if (depth == 1) 94362306a36Sopenharmony_ci goto out; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "%-10u %-10u ", 94662306a36Sopenharmony_ci nla_get_u32(publ[TIPC_NLA_PUBL_LOWER]), 94762306a36Sopenharmony_ci nla_get_u32(publ[TIPC_NLA_PUBL_UPPER])); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci if (depth == 2) 95062306a36Sopenharmony_ci goto out; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci node = nla_get_u32(publ[TIPC_NLA_PUBL_NODE]); 95362306a36Sopenharmony_ci sprintf(port_str, "<%u.%u.%u:%u>", tipc_zone(node), tipc_cluster(node), 95462306a36Sopenharmony_ci tipc_node(node), nla_get_u32(publ[TIPC_NLA_PUBL_REF])); 95562306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "%-26s ", port_str); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (depth == 3) 95862306a36Sopenharmony_ci goto out; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "%-10u %s", 96162306a36Sopenharmony_ci nla_get_u32(publ[TIPC_NLA_PUBL_KEY]), 96262306a36Sopenharmony_ci scope_str[nla_get_u32(publ[TIPC_NLA_PUBL_SCOPE])]); 96362306a36Sopenharmony_ciout: 96462306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "\n"); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci return 0; 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_cistatic int __tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg *msg, 97062306a36Sopenharmony_ci struct nlattr **attrs) 97162306a36Sopenharmony_ci{ 97262306a36Sopenharmony_ci u32 type, lower, upper; 97362306a36Sopenharmony_ci struct nlattr *publ[TIPC_NLA_PUBL_MAX + 1]; 97462306a36Sopenharmony_ci int err; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci if (!attrs[TIPC_NLA_PUBL]) 97762306a36Sopenharmony_ci return -EINVAL; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci err = nla_parse_nested_deprecated(publ, TIPC_NLA_PUBL_MAX, 98062306a36Sopenharmony_ci attrs[TIPC_NLA_PUBL], NULL, NULL); 98162306a36Sopenharmony_ci if (err) 98262306a36Sopenharmony_ci return err; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci type = nla_get_u32(publ[TIPC_NLA_PUBL_TYPE]); 98562306a36Sopenharmony_ci lower = nla_get_u32(publ[TIPC_NLA_PUBL_LOWER]); 98662306a36Sopenharmony_ci upper = nla_get_u32(publ[TIPC_NLA_PUBL_UPPER]); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci if (lower == upper) 98962306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " {%u,%u}", type, lower); 99062306a36Sopenharmony_ci else 99162306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " {%u,%u,%u}", type, lower, upper); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci return 0; 99462306a36Sopenharmony_ci} 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_cistatic int tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg *msg, u32 sock) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci int err; 99962306a36Sopenharmony_ci void *hdr; 100062306a36Sopenharmony_ci struct nlattr *nest; 100162306a36Sopenharmony_ci struct sk_buff *args; 100262306a36Sopenharmony_ci struct tipc_nl_compat_cmd_dump dump; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci args = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 100562306a36Sopenharmony_ci if (!args) 100662306a36Sopenharmony_ci return -ENOMEM; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci hdr = genlmsg_put(args, 0, 0, &tipc_genl_family, NLM_F_MULTI, 100962306a36Sopenharmony_ci TIPC_NL_PUBL_GET); 101062306a36Sopenharmony_ci if (!hdr) { 101162306a36Sopenharmony_ci kfree_skb(args); 101262306a36Sopenharmony_ci return -EMSGSIZE; 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci nest = nla_nest_start_noflag(args, TIPC_NLA_SOCK); 101662306a36Sopenharmony_ci if (!nest) { 101762306a36Sopenharmony_ci kfree_skb(args); 101862306a36Sopenharmony_ci return -EMSGSIZE; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci if (nla_put_u32(args, TIPC_NLA_SOCK_REF, sock)) { 102262306a36Sopenharmony_ci kfree_skb(args); 102362306a36Sopenharmony_ci return -EMSGSIZE; 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci nla_nest_end(args, nest); 102762306a36Sopenharmony_ci genlmsg_end(args, hdr); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci dump.dumpit = tipc_nl_publ_dump; 103062306a36Sopenharmony_ci dump.format = __tipc_nl_compat_publ_dump; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci err = __tipc_nl_compat_dumpit(&dump, msg, args); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci kfree_skb(args); 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci return err; 103762306a36Sopenharmony_ci} 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_cistatic int tipc_nl_compat_sk_dump(struct tipc_nl_compat_msg *msg, 104062306a36Sopenharmony_ci struct nlattr **attrs) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci int err; 104362306a36Sopenharmony_ci u32 sock_ref; 104462306a36Sopenharmony_ci struct nlattr *sock[TIPC_NLA_SOCK_MAX + 1]; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci if (!attrs[TIPC_NLA_SOCK]) 104762306a36Sopenharmony_ci return -EINVAL; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci err = nla_parse_nested_deprecated(sock, TIPC_NLA_SOCK_MAX, 105062306a36Sopenharmony_ci attrs[TIPC_NLA_SOCK], NULL, NULL); 105162306a36Sopenharmony_ci if (err) 105262306a36Sopenharmony_ci return err; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci sock_ref = nla_get_u32(sock[TIPC_NLA_SOCK_REF]); 105562306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "%u:", sock_ref); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci if (sock[TIPC_NLA_SOCK_CON]) { 105862306a36Sopenharmony_ci u32 node; 105962306a36Sopenharmony_ci struct nlattr *con[TIPC_NLA_CON_MAX + 1]; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci err = nla_parse_nested_deprecated(con, TIPC_NLA_CON_MAX, 106262306a36Sopenharmony_ci sock[TIPC_NLA_SOCK_CON], 106362306a36Sopenharmony_ci NULL, NULL); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci if (err) 106662306a36Sopenharmony_ci return err; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci node = nla_get_u32(con[TIPC_NLA_CON_NODE]); 106962306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " connected to <%u.%u.%u:%u>", 107062306a36Sopenharmony_ci tipc_zone(node), 107162306a36Sopenharmony_ci tipc_cluster(node), 107262306a36Sopenharmony_ci tipc_node(node), 107362306a36Sopenharmony_ci nla_get_u32(con[TIPC_NLA_CON_SOCK])); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci if (con[TIPC_NLA_CON_FLAG]) 107662306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " via {%u,%u}\n", 107762306a36Sopenharmony_ci nla_get_u32(con[TIPC_NLA_CON_TYPE]), 107862306a36Sopenharmony_ci nla_get_u32(con[TIPC_NLA_CON_INST])); 107962306a36Sopenharmony_ci else 108062306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "\n"); 108162306a36Sopenharmony_ci } else if (sock[TIPC_NLA_SOCK_HAS_PUBL]) { 108262306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, " bound to"); 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci err = tipc_nl_compat_publ_dump(msg, sock_ref); 108562306a36Sopenharmony_ci if (err) 108662306a36Sopenharmony_ci return err; 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "\n"); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci return 0; 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_cistatic int tipc_nl_compat_media_dump(struct tipc_nl_compat_msg *msg, 109462306a36Sopenharmony_ci struct nlattr **attrs) 109562306a36Sopenharmony_ci{ 109662306a36Sopenharmony_ci struct nlattr *media[TIPC_NLA_MEDIA_MAX + 1]; 109762306a36Sopenharmony_ci int err; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci if (!attrs[TIPC_NLA_MEDIA]) 110062306a36Sopenharmony_ci return -EINVAL; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci err = nla_parse_nested_deprecated(media, TIPC_NLA_MEDIA_MAX, 110362306a36Sopenharmony_ci attrs[TIPC_NLA_MEDIA], NULL, NULL); 110462306a36Sopenharmony_ci if (err) 110562306a36Sopenharmony_ci return err; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci return tipc_add_tlv(msg->rep, TIPC_TLV_MEDIA_NAME, 110862306a36Sopenharmony_ci nla_data(media[TIPC_NLA_MEDIA_NAME]), 110962306a36Sopenharmony_ci nla_len(media[TIPC_NLA_MEDIA_NAME])); 111062306a36Sopenharmony_ci} 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_cistatic int tipc_nl_compat_node_dump(struct tipc_nl_compat_msg *msg, 111362306a36Sopenharmony_ci struct nlattr **attrs) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci struct tipc_node_info node_info; 111662306a36Sopenharmony_ci struct nlattr *node[TIPC_NLA_NODE_MAX + 1]; 111762306a36Sopenharmony_ci int err; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci if (!attrs[TIPC_NLA_NODE]) 112062306a36Sopenharmony_ci return -EINVAL; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci err = nla_parse_nested_deprecated(node, TIPC_NLA_NODE_MAX, 112362306a36Sopenharmony_ci attrs[TIPC_NLA_NODE], NULL, NULL); 112462306a36Sopenharmony_ci if (err) 112562306a36Sopenharmony_ci return err; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci node_info.addr = htonl(nla_get_u32(node[TIPC_NLA_NODE_ADDR])); 112862306a36Sopenharmony_ci node_info.up = htonl(nla_get_flag(node[TIPC_NLA_NODE_UP])); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci return tipc_add_tlv(msg->rep, TIPC_TLV_NODE_INFO, &node_info, 113162306a36Sopenharmony_ci sizeof(node_info)); 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_cistatic int tipc_nl_compat_net_set(struct tipc_nl_compat_cmd_doit *cmd, 113562306a36Sopenharmony_ci struct sk_buff *skb, 113662306a36Sopenharmony_ci struct tipc_nl_compat_msg *msg) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci u32 val; 113962306a36Sopenharmony_ci struct nlattr *net; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci val = ntohl(*(__be32 *)TLV_DATA(msg->req)); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci net = nla_nest_start_noflag(skb, TIPC_NLA_NET); 114462306a36Sopenharmony_ci if (!net) 114562306a36Sopenharmony_ci return -EMSGSIZE; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (msg->cmd == TIPC_CMD_SET_NODE_ADDR) { 114862306a36Sopenharmony_ci if (nla_put_u32(skb, TIPC_NLA_NET_ADDR, val)) 114962306a36Sopenharmony_ci return -EMSGSIZE; 115062306a36Sopenharmony_ci } else if (msg->cmd == TIPC_CMD_SET_NETID) { 115162306a36Sopenharmony_ci if (nla_put_u32(skb, TIPC_NLA_NET_ID, val)) 115262306a36Sopenharmony_ci return -EMSGSIZE; 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci nla_nest_end(skb, net); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci return 0; 115762306a36Sopenharmony_ci} 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_cistatic int tipc_nl_compat_net_dump(struct tipc_nl_compat_msg *msg, 116062306a36Sopenharmony_ci struct nlattr **attrs) 116162306a36Sopenharmony_ci{ 116262306a36Sopenharmony_ci __be32 id; 116362306a36Sopenharmony_ci struct nlattr *net[TIPC_NLA_NET_MAX + 1]; 116462306a36Sopenharmony_ci int err; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci if (!attrs[TIPC_NLA_NET]) 116762306a36Sopenharmony_ci return -EINVAL; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci err = nla_parse_nested_deprecated(net, TIPC_NLA_NET_MAX, 117062306a36Sopenharmony_ci attrs[TIPC_NLA_NET], NULL, NULL); 117162306a36Sopenharmony_ci if (err) 117262306a36Sopenharmony_ci return err; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci id = htonl(nla_get_u32(net[TIPC_NLA_NET_ID])); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci return tipc_add_tlv(msg->rep, TIPC_TLV_UNSIGNED, &id, sizeof(id)); 117762306a36Sopenharmony_ci} 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_cistatic int tipc_cmd_show_stats_compat(struct tipc_nl_compat_msg *msg) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci msg->rep = tipc_tlv_alloc(ULTRA_STRING_MAX_LEN); 118262306a36Sopenharmony_ci if (!msg->rep) 118362306a36Sopenharmony_ci return -ENOMEM; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci tipc_tlv_init(msg->rep, TIPC_TLV_ULTRA_STRING); 118662306a36Sopenharmony_ci tipc_tlv_sprintf(msg->rep, "TIPC version " TIPC_MOD_VER "\n"); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci return 0; 118962306a36Sopenharmony_ci} 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_cistatic int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg) 119262306a36Sopenharmony_ci{ 119362306a36Sopenharmony_ci struct tipc_nl_compat_cmd_dump dump; 119462306a36Sopenharmony_ci struct tipc_nl_compat_cmd_doit doit; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci memset(&dump, 0, sizeof(dump)); 119762306a36Sopenharmony_ci memset(&doit, 0, sizeof(doit)); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci switch (msg->cmd) { 120062306a36Sopenharmony_ci case TIPC_CMD_NOOP: 120162306a36Sopenharmony_ci msg->rep = tipc_tlv_alloc(0); 120262306a36Sopenharmony_ci if (!msg->rep) 120362306a36Sopenharmony_ci return -ENOMEM; 120462306a36Sopenharmony_ci return 0; 120562306a36Sopenharmony_ci case TIPC_CMD_GET_BEARER_NAMES: 120662306a36Sopenharmony_ci msg->rep_size = MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME); 120762306a36Sopenharmony_ci dump.dumpit = tipc_nl_bearer_dump; 120862306a36Sopenharmony_ci dump.format = tipc_nl_compat_bearer_dump; 120962306a36Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 121062306a36Sopenharmony_ci case TIPC_CMD_ENABLE_BEARER: 121162306a36Sopenharmony_ci msg->req_type = TIPC_TLV_BEARER_CONFIG; 121262306a36Sopenharmony_ci doit.doit = __tipc_nl_bearer_enable; 121362306a36Sopenharmony_ci doit.transcode = tipc_nl_compat_bearer_enable; 121462306a36Sopenharmony_ci return tipc_nl_compat_doit(&doit, msg); 121562306a36Sopenharmony_ci case TIPC_CMD_DISABLE_BEARER: 121662306a36Sopenharmony_ci msg->req_type = TIPC_TLV_BEARER_NAME; 121762306a36Sopenharmony_ci doit.doit = __tipc_nl_bearer_disable; 121862306a36Sopenharmony_ci doit.transcode = tipc_nl_compat_bearer_disable; 121962306a36Sopenharmony_ci return tipc_nl_compat_doit(&doit, msg); 122062306a36Sopenharmony_ci case TIPC_CMD_SHOW_LINK_STATS: 122162306a36Sopenharmony_ci msg->req_type = TIPC_TLV_LINK_NAME; 122262306a36Sopenharmony_ci msg->rep_size = ULTRA_STRING_MAX_LEN; 122362306a36Sopenharmony_ci msg->rep_type = TIPC_TLV_ULTRA_STRING; 122462306a36Sopenharmony_ci dump.dumpit = tipc_nl_node_dump_link; 122562306a36Sopenharmony_ci dump.format = tipc_nl_compat_link_stat_dump; 122662306a36Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 122762306a36Sopenharmony_ci case TIPC_CMD_GET_LINKS: 122862306a36Sopenharmony_ci msg->req_type = TIPC_TLV_NET_ADDR; 122962306a36Sopenharmony_ci msg->rep_size = ULTRA_STRING_MAX_LEN; 123062306a36Sopenharmony_ci dump.dumpit = tipc_nl_node_dump_link; 123162306a36Sopenharmony_ci dump.format = tipc_nl_compat_link_dump; 123262306a36Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 123362306a36Sopenharmony_ci case TIPC_CMD_SET_LINK_TOL: 123462306a36Sopenharmony_ci case TIPC_CMD_SET_LINK_PRI: 123562306a36Sopenharmony_ci case TIPC_CMD_SET_LINK_WINDOW: 123662306a36Sopenharmony_ci msg->req_type = TIPC_TLV_LINK_CONFIG; 123762306a36Sopenharmony_ci doit.doit = tipc_nl_node_set_link; 123862306a36Sopenharmony_ci doit.transcode = tipc_nl_compat_link_set; 123962306a36Sopenharmony_ci return tipc_nl_compat_doit(&doit, msg); 124062306a36Sopenharmony_ci case TIPC_CMD_RESET_LINK_STATS: 124162306a36Sopenharmony_ci msg->req_type = TIPC_TLV_LINK_NAME; 124262306a36Sopenharmony_ci doit.doit = tipc_nl_node_reset_link_stats; 124362306a36Sopenharmony_ci doit.transcode = tipc_nl_compat_link_reset_stats; 124462306a36Sopenharmony_ci return tipc_nl_compat_doit(&doit, msg); 124562306a36Sopenharmony_ci case TIPC_CMD_SHOW_NAME_TABLE: 124662306a36Sopenharmony_ci msg->req_type = TIPC_TLV_NAME_TBL_QUERY; 124762306a36Sopenharmony_ci msg->rep_size = ULTRA_STRING_MAX_LEN; 124862306a36Sopenharmony_ci msg->rep_type = TIPC_TLV_ULTRA_STRING; 124962306a36Sopenharmony_ci dump.header = tipc_nl_compat_name_table_dump_header; 125062306a36Sopenharmony_ci dump.dumpit = tipc_nl_name_table_dump; 125162306a36Sopenharmony_ci dump.format = tipc_nl_compat_name_table_dump; 125262306a36Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 125362306a36Sopenharmony_ci case TIPC_CMD_SHOW_PORTS: 125462306a36Sopenharmony_ci msg->rep_size = ULTRA_STRING_MAX_LEN; 125562306a36Sopenharmony_ci msg->rep_type = TIPC_TLV_ULTRA_STRING; 125662306a36Sopenharmony_ci dump.dumpit = tipc_nl_sk_dump; 125762306a36Sopenharmony_ci dump.format = tipc_nl_compat_sk_dump; 125862306a36Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 125962306a36Sopenharmony_ci case TIPC_CMD_GET_MEDIA_NAMES: 126062306a36Sopenharmony_ci msg->rep_size = MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME); 126162306a36Sopenharmony_ci dump.dumpit = tipc_nl_media_dump; 126262306a36Sopenharmony_ci dump.format = tipc_nl_compat_media_dump; 126362306a36Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 126462306a36Sopenharmony_ci case TIPC_CMD_GET_NODES: 126562306a36Sopenharmony_ci msg->rep_size = ULTRA_STRING_MAX_LEN; 126662306a36Sopenharmony_ci dump.dumpit = tipc_nl_node_dump; 126762306a36Sopenharmony_ci dump.format = tipc_nl_compat_node_dump; 126862306a36Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 126962306a36Sopenharmony_ci case TIPC_CMD_SET_NODE_ADDR: 127062306a36Sopenharmony_ci msg->req_type = TIPC_TLV_NET_ADDR; 127162306a36Sopenharmony_ci doit.doit = __tipc_nl_net_set; 127262306a36Sopenharmony_ci doit.transcode = tipc_nl_compat_net_set; 127362306a36Sopenharmony_ci return tipc_nl_compat_doit(&doit, msg); 127462306a36Sopenharmony_ci case TIPC_CMD_SET_NETID: 127562306a36Sopenharmony_ci msg->req_type = TIPC_TLV_UNSIGNED; 127662306a36Sopenharmony_ci doit.doit = __tipc_nl_net_set; 127762306a36Sopenharmony_ci doit.transcode = tipc_nl_compat_net_set; 127862306a36Sopenharmony_ci return tipc_nl_compat_doit(&doit, msg); 127962306a36Sopenharmony_ci case TIPC_CMD_GET_NETID: 128062306a36Sopenharmony_ci msg->rep_size = sizeof(u32); 128162306a36Sopenharmony_ci dump.dumpit = tipc_nl_net_dump; 128262306a36Sopenharmony_ci dump.format = tipc_nl_compat_net_dump; 128362306a36Sopenharmony_ci return tipc_nl_compat_dumpit(&dump, msg); 128462306a36Sopenharmony_ci case TIPC_CMD_SHOW_STATS: 128562306a36Sopenharmony_ci return tipc_cmd_show_stats_compat(msg); 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci return -EOPNOTSUPP; 128962306a36Sopenharmony_ci} 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_cistatic int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info) 129262306a36Sopenharmony_ci{ 129362306a36Sopenharmony_ci int err; 129462306a36Sopenharmony_ci int len; 129562306a36Sopenharmony_ci struct tipc_nl_compat_msg msg; 129662306a36Sopenharmony_ci struct nlmsghdr *req_nlh; 129762306a36Sopenharmony_ci struct nlmsghdr *rep_nlh; 129862306a36Sopenharmony_ci struct tipc_genlmsghdr *req_userhdr = genl_info_userhdr(info); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci req_nlh = (struct nlmsghdr *)skb->data; 130362306a36Sopenharmony_ci msg.req = nlmsg_data(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN; 130462306a36Sopenharmony_ci msg.cmd = req_userhdr->cmd; 130562306a36Sopenharmony_ci msg.net = genl_info_net(info); 130662306a36Sopenharmony_ci msg.dst_sk = skb->sk; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci if ((msg.cmd & 0xC000) && (!netlink_net_capable(skb, CAP_NET_ADMIN))) { 130962306a36Sopenharmony_ci msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_NET_ADMIN); 131062306a36Sopenharmony_ci err = -EACCES; 131162306a36Sopenharmony_ci goto send; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci msg.req_size = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN); 131562306a36Sopenharmony_ci if (msg.req_size && !TLV_OK(msg.req, msg.req_size)) { 131662306a36Sopenharmony_ci msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED); 131762306a36Sopenharmony_ci err = -EOPNOTSUPP; 131862306a36Sopenharmony_ci goto send; 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci err = tipc_nl_compat_handle(&msg); 132262306a36Sopenharmony_ci if ((err == -EOPNOTSUPP) || (err == -EPERM)) 132362306a36Sopenharmony_ci msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED); 132462306a36Sopenharmony_ci else if (err == -EINVAL) 132562306a36Sopenharmony_ci msg.rep = tipc_get_err_tlv(TIPC_CFG_TLV_ERROR); 132662306a36Sopenharmony_cisend: 132762306a36Sopenharmony_ci if (!msg.rep) 132862306a36Sopenharmony_ci return err; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci len = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN); 133162306a36Sopenharmony_ci skb_push(msg.rep, len); 133262306a36Sopenharmony_ci rep_nlh = nlmsg_hdr(msg.rep); 133362306a36Sopenharmony_ci memcpy(rep_nlh, info->nlhdr, len); 133462306a36Sopenharmony_ci rep_nlh->nlmsg_len = msg.rep->len; 133562306a36Sopenharmony_ci genlmsg_unicast(msg.net, msg.rep, NETLINK_CB(skb).portid); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci return err; 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_cistatic const struct genl_small_ops tipc_genl_compat_ops[] = { 134162306a36Sopenharmony_ci { 134262306a36Sopenharmony_ci .cmd = TIPC_GENL_CMD, 134362306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 134462306a36Sopenharmony_ci .doit = tipc_nl_compat_recv, 134562306a36Sopenharmony_ci }, 134662306a36Sopenharmony_ci}; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_cistatic struct genl_family tipc_genl_compat_family __ro_after_init = { 134962306a36Sopenharmony_ci .name = TIPC_GENL_NAME, 135062306a36Sopenharmony_ci .version = TIPC_GENL_VERSION, 135162306a36Sopenharmony_ci .hdrsize = TIPC_GENL_HDRLEN, 135262306a36Sopenharmony_ci .maxattr = 0, 135362306a36Sopenharmony_ci .netnsok = true, 135462306a36Sopenharmony_ci .module = THIS_MODULE, 135562306a36Sopenharmony_ci .small_ops = tipc_genl_compat_ops, 135662306a36Sopenharmony_ci .n_small_ops = ARRAY_SIZE(tipc_genl_compat_ops), 135762306a36Sopenharmony_ci .resv_start_op = TIPC_GENL_CMD + 1, 135862306a36Sopenharmony_ci}; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ciint __init tipc_netlink_compat_start(void) 136162306a36Sopenharmony_ci{ 136262306a36Sopenharmony_ci int res; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci res = genl_register_family(&tipc_genl_compat_family); 136562306a36Sopenharmony_ci if (res) { 136662306a36Sopenharmony_ci pr_err("Failed to register legacy compat interface\n"); 136762306a36Sopenharmony_ci return res; 136862306a36Sopenharmony_ci } 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci return 0; 137162306a36Sopenharmony_ci} 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_civoid tipc_netlink_compat_stop(void) 137462306a36Sopenharmony_ci{ 137562306a36Sopenharmony_ci genl_unregister_family(&tipc_genl_compat_family); 137662306a36Sopenharmony_ci} 1377