xref: /kernel/linux/linux-5.10/net/tipc/net.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * net/tipc/net.c: TIPC network routing code
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (c) 1995-2006, 2014, Ericsson AB
58c2ecf20Sopenharmony_ci * Copyright (c) 2005, 2010-2011, Wind River Systems
68c2ecf20Sopenharmony_ci * All rights reserved.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
98c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
128c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
148c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
158c2ecf20Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
168c2ecf20Sopenharmony_ci * 3. Neither the names of the copyright holders nor the names of its
178c2ecf20Sopenharmony_ci *    contributors may be used to endorse or promote products derived from
188c2ecf20Sopenharmony_ci *    this software without specific prior written permission.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the
218c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free
228c2ecf20Sopenharmony_ci * Software Foundation.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
258c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
268c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
278c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
288c2ecf20Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
298c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
308c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
318c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
328c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
338c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
348c2ecf20Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include "core.h"
388c2ecf20Sopenharmony_ci#include "net.h"
398c2ecf20Sopenharmony_ci#include "name_distr.h"
408c2ecf20Sopenharmony_ci#include "subscr.h"
418c2ecf20Sopenharmony_ci#include "socket.h"
428c2ecf20Sopenharmony_ci#include "node.h"
438c2ecf20Sopenharmony_ci#include "bcast.h"
448c2ecf20Sopenharmony_ci#include "link.h"
458c2ecf20Sopenharmony_ci#include "netlink.h"
468c2ecf20Sopenharmony_ci#include "monitor.h"
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/*
498c2ecf20Sopenharmony_ci * The TIPC locking policy is designed to ensure a very fine locking
508c2ecf20Sopenharmony_ci * granularity, permitting complete parallel access to individual
518c2ecf20Sopenharmony_ci * port and node/link instances. The code consists of four major
528c2ecf20Sopenharmony_ci * locking domains, each protected with their own disjunct set of locks.
538c2ecf20Sopenharmony_ci *
548c2ecf20Sopenharmony_ci * 1: The bearer level.
558c2ecf20Sopenharmony_ci *    RTNL lock is used to serialize the process of configuring bearer
568c2ecf20Sopenharmony_ci *    on update side, and RCU lock is applied on read side to make
578c2ecf20Sopenharmony_ci *    bearer instance valid on both paths of message transmission and
588c2ecf20Sopenharmony_ci *    reception.
598c2ecf20Sopenharmony_ci *
608c2ecf20Sopenharmony_ci * 2: The node and link level.
618c2ecf20Sopenharmony_ci *    All node instances are saved into two tipc_node_list and node_htable
628c2ecf20Sopenharmony_ci *    lists. The two lists are protected by node_list_lock on write side,
638c2ecf20Sopenharmony_ci *    and they are guarded with RCU lock on read side. Especially node
648c2ecf20Sopenharmony_ci *    instance is destroyed only when TIPC module is removed, and we can
658c2ecf20Sopenharmony_ci *    confirm that there has no any user who is accessing the node at the
668c2ecf20Sopenharmony_ci *    moment. Therefore, Except for iterating the two lists within RCU
678c2ecf20Sopenharmony_ci *    protection, it's no needed to hold RCU that we access node instance
688c2ecf20Sopenharmony_ci *    in other places.
698c2ecf20Sopenharmony_ci *
708c2ecf20Sopenharmony_ci *    In addition, all members in node structure including link instances
718c2ecf20Sopenharmony_ci *    are protected by node spin lock.
728c2ecf20Sopenharmony_ci *
738c2ecf20Sopenharmony_ci * 3: The transport level of the protocol.
748c2ecf20Sopenharmony_ci *    This consists of the structures port, (and its user level
758c2ecf20Sopenharmony_ci *    representations, such as user_port and tipc_sock), reference and
768c2ecf20Sopenharmony_ci *    tipc_user (port.c, reg.c, socket.c).
778c2ecf20Sopenharmony_ci *
788c2ecf20Sopenharmony_ci *    This layer has four different locks:
798c2ecf20Sopenharmony_ci *     - The tipc_port spin_lock. This is protecting each port instance
808c2ecf20Sopenharmony_ci *       from parallel data access and removal. Since we can not place
818c2ecf20Sopenharmony_ci *       this lock in the port itself, it has been placed in the
828c2ecf20Sopenharmony_ci *       corresponding reference table entry, which has the same life
838c2ecf20Sopenharmony_ci *       cycle as the module. This entry is difficult to access from
848c2ecf20Sopenharmony_ci *       outside the TIPC core, however, so a pointer to the lock has
858c2ecf20Sopenharmony_ci *       been added in the port instance, -to be used for unlocking
868c2ecf20Sopenharmony_ci *       only.
878c2ecf20Sopenharmony_ci *     - A read/write lock to protect the reference table itself (teg.c).
888c2ecf20Sopenharmony_ci *       (Nobody is using read-only access to this, so it can just as
898c2ecf20Sopenharmony_ci *       well be changed to a spin_lock)
908c2ecf20Sopenharmony_ci *     - A spin lock to protect the registry of kernel/driver users (reg.c)
918c2ecf20Sopenharmony_ci *     - A global spin_lock (tipc_port_lock), which only task is to ensure
928c2ecf20Sopenharmony_ci *       consistency where more than one port is involved in an operation,
938c2ecf20Sopenharmony_ci *       i.e., whe a port is part of a linked list of ports.
948c2ecf20Sopenharmony_ci *       There are two such lists; 'port_list', which is used for management,
958c2ecf20Sopenharmony_ci *       and 'wait_list', which is used to queue ports during congestion.
968c2ecf20Sopenharmony_ci *
978c2ecf20Sopenharmony_ci *  4: The name table (name_table.c, name_distr.c, subscription.c)
988c2ecf20Sopenharmony_ci *     - There is one big read/write-lock (tipc_nametbl_lock) protecting the
998c2ecf20Sopenharmony_ci *       overall name table structure. Nothing must be added/removed to
1008c2ecf20Sopenharmony_ci *       this structure without holding write access to it.
1018c2ecf20Sopenharmony_ci *     - There is one local spin_lock per sub_sequence, which can be seen
1028c2ecf20Sopenharmony_ci *       as a sub-domain to the tipc_nametbl_lock domain. It is used only
1038c2ecf20Sopenharmony_ci *       for translation operations, and is needed because a translation
1048c2ecf20Sopenharmony_ci *       steps the root of the 'publication' linked list between each lookup.
1058c2ecf20Sopenharmony_ci *       This is always used within the scope of a tipc_nametbl_lock(read).
1068c2ecf20Sopenharmony_ci *     - A local spin_lock protecting the queue of subscriber events.
1078c2ecf20Sopenharmony_ci*/
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic void tipc_net_finalize(struct net *net, u32 addr);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ciint tipc_net_init(struct net *net, u8 *node_id, u32 addr)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	if (tipc_own_id(net)) {
1148c2ecf20Sopenharmony_ci		pr_info("Cannot configure node identity twice\n");
1158c2ecf20Sopenharmony_ci		return -1;
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci	pr_info("Started in network mode\n");
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (node_id)
1208c2ecf20Sopenharmony_ci		tipc_set_node_id(net, node_id);
1218c2ecf20Sopenharmony_ci	if (addr)
1228c2ecf20Sopenharmony_ci		tipc_net_finalize(net, addr);
1238c2ecf20Sopenharmony_ci	return 0;
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic void tipc_net_finalize(struct net *net, u32 addr)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	struct tipc_net *tn = tipc_net(net);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (cmpxchg(&tn->node_addr, 0, addr))
1318c2ecf20Sopenharmony_ci		return;
1328c2ecf20Sopenharmony_ci	tipc_set_node_addr(net, addr);
1338c2ecf20Sopenharmony_ci	tipc_named_reinit(net);
1348c2ecf20Sopenharmony_ci	tipc_sk_reinit(net);
1358c2ecf20Sopenharmony_ci	tipc_mon_reinit_self(net);
1368c2ecf20Sopenharmony_ci	tipc_nametbl_publish(net, TIPC_CFG_SRV, addr, addr,
1378c2ecf20Sopenharmony_ci			     TIPC_CLUSTER_SCOPE, 0, addr);
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_civoid tipc_net_finalize_work(struct work_struct *work)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	struct tipc_net *tn = container_of(work, struct tipc_net, work);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	tipc_net_finalize(tipc_link_net(tn->bcl), tn->trial_addr);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_civoid tipc_net_stop(struct net *net)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	if (!tipc_own_id(net))
1508c2ecf20Sopenharmony_ci		return;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	rtnl_lock();
1538c2ecf20Sopenharmony_ci	tipc_bearer_stop(net);
1548c2ecf20Sopenharmony_ci	tipc_node_stop(net);
1558c2ecf20Sopenharmony_ci	rtnl_unlock();
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	pr_info("Left network mode\n");
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic int __tipc_nl_add_net(struct net *net, struct tipc_nl_msg *msg)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct tipc_net *tn = net_generic(net, tipc_net_id);
1638c2ecf20Sopenharmony_ci	u64 *w0 = (u64 *)&tn->node_id[0];
1648c2ecf20Sopenharmony_ci	u64 *w1 = (u64 *)&tn->node_id[8];
1658c2ecf20Sopenharmony_ci	struct nlattr *attrs;
1668c2ecf20Sopenharmony_ci	void *hdr;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
1698c2ecf20Sopenharmony_ci			  NLM_F_MULTI, TIPC_NL_NET_GET);
1708c2ecf20Sopenharmony_ci	if (!hdr)
1718c2ecf20Sopenharmony_ci		return -EMSGSIZE;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_NET);
1748c2ecf20Sopenharmony_ci	if (!attrs)
1758c2ecf20Sopenharmony_ci		goto msg_full;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	if (nla_put_u32(msg->skb, TIPC_NLA_NET_ID, tn->net_id))
1788c2ecf20Sopenharmony_ci		goto attr_msg_full;
1798c2ecf20Sopenharmony_ci	if (nla_put_u64_64bit(msg->skb, TIPC_NLA_NET_NODEID, *w0, 0))
1808c2ecf20Sopenharmony_ci		goto attr_msg_full;
1818c2ecf20Sopenharmony_ci	if (nla_put_u64_64bit(msg->skb, TIPC_NLA_NET_NODEID_W1, *w1, 0))
1828c2ecf20Sopenharmony_ci		goto attr_msg_full;
1838c2ecf20Sopenharmony_ci	nla_nest_end(msg->skb, attrs);
1848c2ecf20Sopenharmony_ci	genlmsg_end(msg->skb, hdr);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	return 0;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ciattr_msg_full:
1898c2ecf20Sopenharmony_ci	nla_nest_cancel(msg->skb, attrs);
1908c2ecf20Sopenharmony_cimsg_full:
1918c2ecf20Sopenharmony_ci	genlmsg_cancel(msg->skb, hdr);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	return -EMSGSIZE;
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ciint tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	struct net *net = sock_net(skb->sk);
1998c2ecf20Sopenharmony_ci	int err;
2008c2ecf20Sopenharmony_ci	int done = cb->args[0];
2018c2ecf20Sopenharmony_ci	struct tipc_nl_msg msg;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (done)
2048c2ecf20Sopenharmony_ci		return 0;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	msg.skb = skb;
2078c2ecf20Sopenharmony_ci	msg.portid = NETLINK_CB(cb->skb).portid;
2088c2ecf20Sopenharmony_ci	msg.seq = cb->nlh->nlmsg_seq;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	err = __tipc_nl_add_net(net, &msg);
2118c2ecf20Sopenharmony_ci	if (err)
2128c2ecf20Sopenharmony_ci		goto out;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	done = 1;
2158c2ecf20Sopenharmony_ciout:
2168c2ecf20Sopenharmony_ci	cb->args[0] = done;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return skb->len;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ciint __tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	struct nlattr *attrs[TIPC_NLA_NET_MAX + 1];
2248c2ecf20Sopenharmony_ci	struct net *net = sock_net(skb->sk);
2258c2ecf20Sopenharmony_ci	struct tipc_net *tn = tipc_net(net);
2268c2ecf20Sopenharmony_ci	int err;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if (!info->attrs[TIPC_NLA_NET])
2298c2ecf20Sopenharmony_ci		return -EINVAL;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	err = nla_parse_nested_deprecated(attrs, TIPC_NLA_NET_MAX,
2328c2ecf20Sopenharmony_ci					  info->attrs[TIPC_NLA_NET],
2338c2ecf20Sopenharmony_ci					  tipc_nl_net_policy, info->extack);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (err)
2368c2ecf20Sopenharmony_ci		return err;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/* Can't change net id once TIPC has joined a network */
2398c2ecf20Sopenharmony_ci	if (tipc_own_addr(net))
2408c2ecf20Sopenharmony_ci		return -EPERM;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	if (attrs[TIPC_NLA_NET_ID]) {
2438c2ecf20Sopenharmony_ci		u32 val;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci		val = nla_get_u32(attrs[TIPC_NLA_NET_ID]);
2468c2ecf20Sopenharmony_ci		if (val < 1 || val > 9999)
2478c2ecf20Sopenharmony_ci			return -EINVAL;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci		tn->net_id = val;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	if (attrs[TIPC_NLA_NET_ADDR]) {
2538c2ecf20Sopenharmony_ci		u32 addr;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci		addr = nla_get_u32(attrs[TIPC_NLA_NET_ADDR]);
2568c2ecf20Sopenharmony_ci		if (!addr)
2578c2ecf20Sopenharmony_ci			return -EINVAL;
2588c2ecf20Sopenharmony_ci		tn->legacy_addr_format = true;
2598c2ecf20Sopenharmony_ci		tipc_net_init(net, NULL, addr);
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	if (attrs[TIPC_NLA_NET_NODEID]) {
2638c2ecf20Sopenharmony_ci		u8 node_id[NODE_ID_LEN];
2648c2ecf20Sopenharmony_ci		u64 *w0 = (u64 *)&node_id[0];
2658c2ecf20Sopenharmony_ci		u64 *w1 = (u64 *)&node_id[8];
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci		if (!attrs[TIPC_NLA_NET_NODEID_W1])
2688c2ecf20Sopenharmony_ci			return -EINVAL;
2698c2ecf20Sopenharmony_ci		*w0 = nla_get_u64(attrs[TIPC_NLA_NET_NODEID]);
2708c2ecf20Sopenharmony_ci		*w1 = nla_get_u64(attrs[TIPC_NLA_NET_NODEID_W1]);
2718c2ecf20Sopenharmony_ci		tipc_net_init(net, node_id, 0);
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci	return 0;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ciint tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	int err;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	rtnl_lock();
2818c2ecf20Sopenharmony_ci	err = __tipc_nl_net_set(skb, info);
2828c2ecf20Sopenharmony_ci	rtnl_unlock();
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	return err;
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic int __tipc_nl_addr_legacy_get(struct net *net, struct tipc_nl_msg *msg)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	struct tipc_net *tn = tipc_net(net);
2908c2ecf20Sopenharmony_ci	struct nlattr *attrs;
2918c2ecf20Sopenharmony_ci	void *hdr;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
2948c2ecf20Sopenharmony_ci			  0, TIPC_NL_ADDR_LEGACY_GET);
2958c2ecf20Sopenharmony_ci	if (!hdr)
2968c2ecf20Sopenharmony_ci		return -EMSGSIZE;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	attrs = nla_nest_start(msg->skb, TIPC_NLA_NET);
2998c2ecf20Sopenharmony_ci	if (!attrs)
3008c2ecf20Sopenharmony_ci		goto msg_full;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (tn->legacy_addr_format)
3038c2ecf20Sopenharmony_ci		if (nla_put_flag(msg->skb, TIPC_NLA_NET_ADDR_LEGACY))
3048c2ecf20Sopenharmony_ci			goto attr_msg_full;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	nla_nest_end(msg->skb, attrs);
3078c2ecf20Sopenharmony_ci	genlmsg_end(msg->skb, hdr);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	return 0;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ciattr_msg_full:
3128c2ecf20Sopenharmony_ci	nla_nest_cancel(msg->skb, attrs);
3138c2ecf20Sopenharmony_cimsg_full:
3148c2ecf20Sopenharmony_ci	genlmsg_cancel(msg->skb, hdr);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	return -EMSGSIZE;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ciint tipc_nl_net_addr_legacy_get(struct sk_buff *skb, struct genl_info *info)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	struct net *net = sock_net(skb->sk);
3228c2ecf20Sopenharmony_ci	struct tipc_nl_msg msg;
3238c2ecf20Sopenharmony_ci	struct sk_buff *rep;
3248c2ecf20Sopenharmony_ci	int err;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	rep = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
3278c2ecf20Sopenharmony_ci	if (!rep)
3288c2ecf20Sopenharmony_ci		return -ENOMEM;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	msg.skb = rep;
3318c2ecf20Sopenharmony_ci	msg.portid = info->snd_portid;
3328c2ecf20Sopenharmony_ci	msg.seq = info->snd_seq;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	err = __tipc_nl_addr_legacy_get(net, &msg);
3358c2ecf20Sopenharmony_ci	if (err) {
3368c2ecf20Sopenharmony_ci		nlmsg_free(msg.skb);
3378c2ecf20Sopenharmony_ci		return err;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	return genlmsg_reply(msg.skb, info);
3418c2ecf20Sopenharmony_ci}
342