18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * net/tipc/node.c: TIPC node management routines 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2000-2006, 2012-2016, Ericsson AB 58c2ecf20Sopenharmony_ci * Copyright (c) 2005-2006, 2010-2014, 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 "link.h" 398c2ecf20Sopenharmony_ci#include "node.h" 408c2ecf20Sopenharmony_ci#include "name_distr.h" 418c2ecf20Sopenharmony_ci#include "socket.h" 428c2ecf20Sopenharmony_ci#include "bcast.h" 438c2ecf20Sopenharmony_ci#include "monitor.h" 448c2ecf20Sopenharmony_ci#include "discover.h" 458c2ecf20Sopenharmony_ci#include "netlink.h" 468c2ecf20Sopenharmony_ci#include "trace.h" 478c2ecf20Sopenharmony_ci#include "crypto.h" 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define INVALID_NODE_SIG 0x10000 508c2ecf20Sopenharmony_ci#define NODE_CLEANUP_AFTER 300000 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* Flags used to take different actions according to flag type 538c2ecf20Sopenharmony_ci * TIPC_NOTIFY_NODE_DOWN: notify node is down 548c2ecf20Sopenharmony_ci * TIPC_NOTIFY_NODE_UP: notify node is up 558c2ecf20Sopenharmony_ci * TIPC_DISTRIBUTE_NAME: publish or withdraw link state name type 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cienum { 588c2ecf20Sopenharmony_ci TIPC_NOTIFY_NODE_DOWN = (1 << 3), 598c2ecf20Sopenharmony_ci TIPC_NOTIFY_NODE_UP = (1 << 4), 608c2ecf20Sopenharmony_ci TIPC_NOTIFY_LINK_UP = (1 << 6), 618c2ecf20Sopenharmony_ci TIPC_NOTIFY_LINK_DOWN = (1 << 7) 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistruct tipc_link_entry { 658c2ecf20Sopenharmony_ci struct tipc_link *link; 668c2ecf20Sopenharmony_ci spinlock_t lock; /* per link */ 678c2ecf20Sopenharmony_ci u32 mtu; 688c2ecf20Sopenharmony_ci struct sk_buff_head inputq; 698c2ecf20Sopenharmony_ci struct tipc_media_addr maddr; 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct tipc_bclink_entry { 738c2ecf20Sopenharmony_ci struct tipc_link *link; 748c2ecf20Sopenharmony_ci struct sk_buff_head inputq1; 758c2ecf20Sopenharmony_ci struct sk_buff_head arrvq; 768c2ecf20Sopenharmony_ci struct sk_buff_head inputq2; 778c2ecf20Sopenharmony_ci struct sk_buff_head namedq; 788c2ecf20Sopenharmony_ci u16 named_rcv_nxt; 798c2ecf20Sopenharmony_ci bool named_open; 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/** 838c2ecf20Sopenharmony_ci * struct tipc_node - TIPC node structure 848c2ecf20Sopenharmony_ci * @addr: network address of node 858c2ecf20Sopenharmony_ci * @ref: reference counter to node object 868c2ecf20Sopenharmony_ci * @lock: rwlock governing access to structure 878c2ecf20Sopenharmony_ci * @net: the applicable net namespace 888c2ecf20Sopenharmony_ci * @hash: links to adjacent nodes in unsorted hash chain 898c2ecf20Sopenharmony_ci * @inputq: pointer to input queue containing messages for msg event 908c2ecf20Sopenharmony_ci * @namedq: pointer to name table input queue with name table messages 918c2ecf20Sopenharmony_ci * @active_links: bearer ids of active links, used as index into links[] array 928c2ecf20Sopenharmony_ci * @links: array containing references to all links to node 938c2ecf20Sopenharmony_ci * @action_flags: bit mask of different types of node actions 948c2ecf20Sopenharmony_ci * @state: connectivity state vs peer node 958c2ecf20Sopenharmony_ci * @preliminary: a preliminary node or not 968c2ecf20Sopenharmony_ci * @sync_point: sequence number where synch/failover is finished 978c2ecf20Sopenharmony_ci * @list: links to adjacent nodes in sorted list of cluster's nodes 988c2ecf20Sopenharmony_ci * @working_links: number of working links to node (both active and standby) 998c2ecf20Sopenharmony_ci * @link_cnt: number of links to node 1008c2ecf20Sopenharmony_ci * @capabilities: bitmap, indicating peer node's functional capabilities 1018c2ecf20Sopenharmony_ci * @signature: node instance identifier 1028c2ecf20Sopenharmony_ci * @link_id: local and remote bearer ids of changing link, if any 1038c2ecf20Sopenharmony_ci * @publ_list: list of publications 1048c2ecf20Sopenharmony_ci * @rcu: rcu struct for tipc_node 1058c2ecf20Sopenharmony_ci * @delete_at: indicates the time for deleting a down node 1068c2ecf20Sopenharmony_ci * @crypto_rx: RX crypto handler 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_cistruct tipc_node { 1098c2ecf20Sopenharmony_ci u32 addr; 1108c2ecf20Sopenharmony_ci struct kref kref; 1118c2ecf20Sopenharmony_ci rwlock_t lock; 1128c2ecf20Sopenharmony_ci struct net *net; 1138c2ecf20Sopenharmony_ci struct hlist_node hash; 1148c2ecf20Sopenharmony_ci int active_links[2]; 1158c2ecf20Sopenharmony_ci struct tipc_link_entry links[MAX_BEARERS]; 1168c2ecf20Sopenharmony_ci struct tipc_bclink_entry bc_entry; 1178c2ecf20Sopenharmony_ci int action_flags; 1188c2ecf20Sopenharmony_ci struct list_head list; 1198c2ecf20Sopenharmony_ci int state; 1208c2ecf20Sopenharmony_ci bool preliminary; 1218c2ecf20Sopenharmony_ci bool failover_sent; 1228c2ecf20Sopenharmony_ci u16 sync_point; 1238c2ecf20Sopenharmony_ci int link_cnt; 1248c2ecf20Sopenharmony_ci u16 working_links; 1258c2ecf20Sopenharmony_ci u16 capabilities; 1268c2ecf20Sopenharmony_ci u32 signature; 1278c2ecf20Sopenharmony_ci u32 link_id; 1288c2ecf20Sopenharmony_ci u8 peer_id[16]; 1298c2ecf20Sopenharmony_ci char peer_id_string[NODE_ID_STR_LEN]; 1308c2ecf20Sopenharmony_ci struct list_head publ_list; 1318c2ecf20Sopenharmony_ci struct list_head conn_sks; 1328c2ecf20Sopenharmony_ci unsigned long keepalive_intv; 1338c2ecf20Sopenharmony_ci struct timer_list timer; 1348c2ecf20Sopenharmony_ci struct rcu_head rcu; 1358c2ecf20Sopenharmony_ci unsigned long delete_at; 1368c2ecf20Sopenharmony_ci struct net *peer_net; 1378c2ecf20Sopenharmony_ci u32 peer_hash_mix; 1388c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_CRYPTO 1398c2ecf20Sopenharmony_ci struct tipc_crypto *crypto_rx; 1408c2ecf20Sopenharmony_ci#endif 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* Node FSM states and events: 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_cienum { 1468c2ecf20Sopenharmony_ci SELF_DOWN_PEER_DOWN = 0xdd, 1478c2ecf20Sopenharmony_ci SELF_UP_PEER_UP = 0xaa, 1488c2ecf20Sopenharmony_ci SELF_DOWN_PEER_LEAVING = 0xd1, 1498c2ecf20Sopenharmony_ci SELF_UP_PEER_COMING = 0xac, 1508c2ecf20Sopenharmony_ci SELF_COMING_PEER_UP = 0xca, 1518c2ecf20Sopenharmony_ci SELF_LEAVING_PEER_DOWN = 0x1d, 1528c2ecf20Sopenharmony_ci NODE_FAILINGOVER = 0xf0, 1538c2ecf20Sopenharmony_ci NODE_SYNCHING = 0xcc 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cienum { 1578c2ecf20Sopenharmony_ci SELF_ESTABL_CONTACT_EVT = 0xece, 1588c2ecf20Sopenharmony_ci SELF_LOST_CONTACT_EVT = 0x1ce, 1598c2ecf20Sopenharmony_ci PEER_ESTABL_CONTACT_EVT = 0x9ece, 1608c2ecf20Sopenharmony_ci PEER_LOST_CONTACT_EVT = 0x91ce, 1618c2ecf20Sopenharmony_ci NODE_FAILOVER_BEGIN_EVT = 0xfbe, 1628c2ecf20Sopenharmony_ci NODE_FAILOVER_END_EVT = 0xfee, 1638c2ecf20Sopenharmony_ci NODE_SYNCH_BEGIN_EVT = 0xcbe, 1648c2ecf20Sopenharmony_ci NODE_SYNCH_END_EVT = 0xcee 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic void __tipc_node_link_down(struct tipc_node *n, int *bearer_id, 1688c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq, 1698c2ecf20Sopenharmony_ci struct tipc_media_addr **maddr); 1708c2ecf20Sopenharmony_cistatic void tipc_node_link_down(struct tipc_node *n, int bearer_id, 1718c2ecf20Sopenharmony_ci bool delete); 1728c2ecf20Sopenharmony_cistatic void node_lost_contact(struct tipc_node *n, struct sk_buff_head *inputq); 1738c2ecf20Sopenharmony_cistatic void tipc_node_delete(struct tipc_node *node); 1748c2ecf20Sopenharmony_cistatic void tipc_node_timeout(struct timer_list *t); 1758c2ecf20Sopenharmony_cistatic void tipc_node_fsm_evt(struct tipc_node *n, int evt); 1768c2ecf20Sopenharmony_cistatic struct tipc_node *tipc_node_find(struct net *net, u32 addr); 1778c2ecf20Sopenharmony_cistatic struct tipc_node *tipc_node_find_by_id(struct net *net, u8 *id); 1788c2ecf20Sopenharmony_cistatic bool node_is_up(struct tipc_node *n); 1798c2ecf20Sopenharmony_cistatic void tipc_node_delete_from_list(struct tipc_node *node); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistruct tipc_sock_conn { 1828c2ecf20Sopenharmony_ci u32 port; 1838c2ecf20Sopenharmony_ci u32 peer_port; 1848c2ecf20Sopenharmony_ci u32 peer_node; 1858c2ecf20Sopenharmony_ci struct list_head list; 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic struct tipc_link *node_active_link(struct tipc_node *n, int sel) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci int bearer_id = n->active_links[sel & 1]; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (unlikely(bearer_id == INVALID_BEARER_ID)) 1938c2ecf20Sopenharmony_ci return NULL; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return n->links[bearer_id].link; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ciint tipc_node_get_mtu(struct net *net, u32 addr, u32 sel, bool connected) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct tipc_node *n; 2018c2ecf20Sopenharmony_ci int bearer_id; 2028c2ecf20Sopenharmony_ci unsigned int mtu = MAX_MSG_SIZE; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci n = tipc_node_find(net, addr); 2058c2ecf20Sopenharmony_ci if (unlikely(!n)) 2068c2ecf20Sopenharmony_ci return mtu; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* Allow MAX_MSG_SIZE when building connection oriented message 2098c2ecf20Sopenharmony_ci * if they are in the same core network 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci if (n->peer_net && connected) { 2128c2ecf20Sopenharmony_ci tipc_node_put(n); 2138c2ecf20Sopenharmony_ci return mtu; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci bearer_id = n->active_links[sel & 1]; 2178c2ecf20Sopenharmony_ci if (likely(bearer_id != INVALID_BEARER_ID)) 2188c2ecf20Sopenharmony_ci mtu = n->links[bearer_id].mtu; 2198c2ecf20Sopenharmony_ci tipc_node_put(n); 2208c2ecf20Sopenharmony_ci return mtu; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cibool tipc_node_get_id(struct net *net, u32 addr, u8 *id) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci u8 *own_id = tipc_own_id(net); 2268c2ecf20Sopenharmony_ci struct tipc_node *n; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (!own_id) 2298c2ecf20Sopenharmony_ci return true; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (addr == tipc_own_addr(net)) { 2328c2ecf20Sopenharmony_ci memcpy(id, own_id, TIPC_NODEID_LEN); 2338c2ecf20Sopenharmony_ci return true; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci n = tipc_node_find(net, addr); 2368c2ecf20Sopenharmony_ci if (!n) 2378c2ecf20Sopenharmony_ci return false; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci memcpy(id, &n->peer_id, TIPC_NODEID_LEN); 2408c2ecf20Sopenharmony_ci tipc_node_put(n); 2418c2ecf20Sopenharmony_ci return true; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ciu16 tipc_node_get_capabilities(struct net *net, u32 addr) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct tipc_node *n; 2478c2ecf20Sopenharmony_ci u16 caps; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci n = tipc_node_find(net, addr); 2508c2ecf20Sopenharmony_ci if (unlikely(!n)) 2518c2ecf20Sopenharmony_ci return TIPC_NODE_CAPABILITIES; 2528c2ecf20Sopenharmony_ci caps = n->capabilities; 2538c2ecf20Sopenharmony_ci tipc_node_put(n); 2548c2ecf20Sopenharmony_ci return caps; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ciu32 tipc_node_get_addr(struct tipc_node *node) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci return (node) ? node->addr : 0; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cichar *tipc_node_get_id_str(struct tipc_node *node) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci return node->peer_id_string; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_CRYPTO 2688c2ecf20Sopenharmony_ci/** 2698c2ecf20Sopenharmony_ci * tipc_node_crypto_rx - Retrieve crypto RX handle from node 2708c2ecf20Sopenharmony_ci * Note: node ref counter must be held first! 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_cistruct tipc_crypto *tipc_node_crypto_rx(struct tipc_node *__n) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci return (__n) ? __n->crypto_rx : NULL; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistruct tipc_crypto *tipc_node_crypto_rx_by_list(struct list_head *pos) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci return container_of(pos, struct tipc_node, list)->crypto_rx; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistruct tipc_crypto *tipc_node_crypto_rx_by_addr(struct net *net, u32 addr) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct tipc_node *n; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci n = tipc_node_find(net, addr); 2878c2ecf20Sopenharmony_ci return (n) ? n->crypto_rx : NULL; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci#endif 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic void tipc_node_free(struct rcu_head *rp) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct tipc_node *n = container_of(rp, struct tipc_node, rcu); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_CRYPTO 2968c2ecf20Sopenharmony_ci tipc_crypto_stop(&n->crypto_rx); 2978c2ecf20Sopenharmony_ci#endif 2988c2ecf20Sopenharmony_ci kfree(n); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void tipc_node_kref_release(struct kref *kref) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct tipc_node *n = container_of(kref, struct tipc_node, kref); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci kfree(n->bc_entry.link); 3068c2ecf20Sopenharmony_ci call_rcu(&n->rcu, tipc_node_free); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_civoid tipc_node_put(struct tipc_node *node) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci kref_put(&node->kref, tipc_node_kref_release); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_civoid tipc_node_get(struct tipc_node *node) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci kref_get(&node->kref); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci/* 3208c2ecf20Sopenharmony_ci * tipc_node_find - locate specified node object, if it exists 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_cistatic struct tipc_node *tipc_node_find(struct net *net, u32 addr) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 3258c2ecf20Sopenharmony_ci struct tipc_node *node; 3268c2ecf20Sopenharmony_ci unsigned int thash = tipc_hashfn(addr); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci rcu_read_lock(); 3298c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(node, &tn->node_htable[thash], hash) { 3308c2ecf20Sopenharmony_ci if (node->addr != addr || node->preliminary) 3318c2ecf20Sopenharmony_ci continue; 3328c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&node->kref)) 3338c2ecf20Sopenharmony_ci node = NULL; 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci rcu_read_unlock(); 3378c2ecf20Sopenharmony_ci return node; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci/* tipc_node_find_by_id - locate specified node object by its 128-bit id 3418c2ecf20Sopenharmony_ci * Note: this function is called only when a discovery request failed 3428c2ecf20Sopenharmony_ci * to find the node by its 32-bit id, and is not time critical 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_cistatic struct tipc_node *tipc_node_find_by_id(struct net *net, u8 *id) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 3478c2ecf20Sopenharmony_ci struct tipc_node *n; 3488c2ecf20Sopenharmony_ci bool found = false; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci rcu_read_lock(); 3518c2ecf20Sopenharmony_ci list_for_each_entry_rcu(n, &tn->node_list, list) { 3528c2ecf20Sopenharmony_ci read_lock_bh(&n->lock); 3538c2ecf20Sopenharmony_ci if (!memcmp(id, n->peer_id, 16) && 3548c2ecf20Sopenharmony_ci kref_get_unless_zero(&n->kref)) 3558c2ecf20Sopenharmony_ci found = true; 3568c2ecf20Sopenharmony_ci read_unlock_bh(&n->lock); 3578c2ecf20Sopenharmony_ci if (found) 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci rcu_read_unlock(); 3618c2ecf20Sopenharmony_ci return found ? n : NULL; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic void tipc_node_read_lock(struct tipc_node *n) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci read_lock_bh(&n->lock); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic void tipc_node_read_unlock(struct tipc_node *n) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci read_unlock_bh(&n->lock); 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic void tipc_node_write_lock(struct tipc_node *n) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci write_lock_bh(&n->lock); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic void tipc_node_write_unlock_fast(struct tipc_node *n) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci write_unlock_bh(&n->lock); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic void tipc_node_write_unlock(struct tipc_node *n) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct net *net = n->net; 3878c2ecf20Sopenharmony_ci u32 addr = 0; 3888c2ecf20Sopenharmony_ci u32 flags = n->action_flags; 3898c2ecf20Sopenharmony_ci u32 link_id = 0; 3908c2ecf20Sopenharmony_ci u32 bearer_id; 3918c2ecf20Sopenharmony_ci struct list_head *publ_list; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (likely(!flags)) { 3948c2ecf20Sopenharmony_ci write_unlock_bh(&n->lock); 3958c2ecf20Sopenharmony_ci return; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci addr = n->addr; 3998c2ecf20Sopenharmony_ci link_id = n->link_id; 4008c2ecf20Sopenharmony_ci bearer_id = link_id & 0xffff; 4018c2ecf20Sopenharmony_ci publ_list = &n->publ_list; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci n->action_flags &= ~(TIPC_NOTIFY_NODE_DOWN | TIPC_NOTIFY_NODE_UP | 4048c2ecf20Sopenharmony_ci TIPC_NOTIFY_LINK_DOWN | TIPC_NOTIFY_LINK_UP); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci write_unlock_bh(&n->lock); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (flags & TIPC_NOTIFY_NODE_DOWN) 4098c2ecf20Sopenharmony_ci tipc_publ_notify(net, publ_list, addr, n->capabilities); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (flags & TIPC_NOTIFY_NODE_UP) 4128c2ecf20Sopenharmony_ci tipc_named_node_up(net, addr, n->capabilities); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (flags & TIPC_NOTIFY_LINK_UP) { 4158c2ecf20Sopenharmony_ci tipc_mon_peer_up(net, addr, bearer_id); 4168c2ecf20Sopenharmony_ci tipc_nametbl_publish(net, TIPC_LINK_STATE, addr, addr, 4178c2ecf20Sopenharmony_ci TIPC_NODE_SCOPE, link_id, link_id); 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci if (flags & TIPC_NOTIFY_LINK_DOWN) { 4208c2ecf20Sopenharmony_ci tipc_mon_peer_down(net, addr, bearer_id); 4218c2ecf20Sopenharmony_ci tipc_nametbl_withdraw(net, TIPC_LINK_STATE, addr, 4228c2ecf20Sopenharmony_ci addr, link_id); 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic void tipc_node_assign_peer_net(struct tipc_node *n, u32 hash_mixes) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci int net_id = tipc_netid(n->net); 4298c2ecf20Sopenharmony_ci struct tipc_net *tn_peer; 4308c2ecf20Sopenharmony_ci struct net *tmp; 4318c2ecf20Sopenharmony_ci u32 hash_chk; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (n->peer_net) 4348c2ecf20Sopenharmony_ci return; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci for_each_net_rcu(tmp) { 4378c2ecf20Sopenharmony_ci tn_peer = tipc_net(tmp); 4388c2ecf20Sopenharmony_ci if (!tn_peer) 4398c2ecf20Sopenharmony_ci continue; 4408c2ecf20Sopenharmony_ci /* Integrity checking whether node exists in namespace or not */ 4418c2ecf20Sopenharmony_ci if (tn_peer->net_id != net_id) 4428c2ecf20Sopenharmony_ci continue; 4438c2ecf20Sopenharmony_ci if (memcmp(n->peer_id, tn_peer->node_id, NODE_ID_LEN)) 4448c2ecf20Sopenharmony_ci continue; 4458c2ecf20Sopenharmony_ci hash_chk = tipc_net_hash_mixes(tmp, tn_peer->random); 4468c2ecf20Sopenharmony_ci if (hash_mixes ^ hash_chk) 4478c2ecf20Sopenharmony_ci continue; 4488c2ecf20Sopenharmony_ci n->peer_net = tmp; 4498c2ecf20Sopenharmony_ci n->peer_hash_mix = hash_mixes; 4508c2ecf20Sopenharmony_ci break; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistruct tipc_node *tipc_node_create(struct net *net, u32 addr, u8 *peer_id, 4558c2ecf20Sopenharmony_ci u16 capabilities, u32 hash_mixes, 4568c2ecf20Sopenharmony_ci bool preliminary) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct tipc_net *tn = net_generic(net, tipc_net_id); 4598c2ecf20Sopenharmony_ci struct tipc_link *l, *snd_l = tipc_bc_sndlink(net); 4608c2ecf20Sopenharmony_ci struct tipc_node *n, *temp_node; 4618c2ecf20Sopenharmony_ci unsigned long intv; 4628c2ecf20Sopenharmony_ci int bearer_id; 4638c2ecf20Sopenharmony_ci int i; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci spin_lock_bh(&tn->node_list_lock); 4668c2ecf20Sopenharmony_ci n = tipc_node_find(net, addr) ?: 4678c2ecf20Sopenharmony_ci tipc_node_find_by_id(net, peer_id); 4688c2ecf20Sopenharmony_ci if (n) { 4698c2ecf20Sopenharmony_ci if (!n->preliminary) 4708c2ecf20Sopenharmony_ci goto update; 4718c2ecf20Sopenharmony_ci if (preliminary) 4728c2ecf20Sopenharmony_ci goto exit; 4738c2ecf20Sopenharmony_ci /* A preliminary node becomes "real" now, refresh its data */ 4748c2ecf20Sopenharmony_ci tipc_node_write_lock(n); 4758c2ecf20Sopenharmony_ci if (!tipc_link_bc_create(net, tipc_own_addr(net), addr, peer_id, U16_MAX, 4768c2ecf20Sopenharmony_ci tipc_link_min_win(snd_l), tipc_link_max_win(snd_l), 4778c2ecf20Sopenharmony_ci n->capabilities, &n->bc_entry.inputq1, 4788c2ecf20Sopenharmony_ci &n->bc_entry.namedq, snd_l, &n->bc_entry.link)) { 4798c2ecf20Sopenharmony_ci pr_warn("Broadcast rcv link refresh failed, no memory\n"); 4808c2ecf20Sopenharmony_ci tipc_node_write_unlock_fast(n); 4818c2ecf20Sopenharmony_ci tipc_node_put(n); 4828c2ecf20Sopenharmony_ci n = NULL; 4838c2ecf20Sopenharmony_ci goto exit; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci n->preliminary = false; 4868c2ecf20Sopenharmony_ci n->addr = addr; 4878c2ecf20Sopenharmony_ci hlist_del_rcu(&n->hash); 4888c2ecf20Sopenharmony_ci hlist_add_head_rcu(&n->hash, 4898c2ecf20Sopenharmony_ci &tn->node_htable[tipc_hashfn(addr)]); 4908c2ecf20Sopenharmony_ci list_del_rcu(&n->list); 4918c2ecf20Sopenharmony_ci list_for_each_entry_rcu(temp_node, &tn->node_list, list) { 4928c2ecf20Sopenharmony_ci if (n->addr < temp_node->addr) 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci list_add_tail_rcu(&n->list, &temp_node->list); 4968c2ecf20Sopenharmony_ci tipc_node_write_unlock_fast(n); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ciupdate: 4998c2ecf20Sopenharmony_ci if (n->peer_hash_mix ^ hash_mixes) 5008c2ecf20Sopenharmony_ci tipc_node_assign_peer_net(n, hash_mixes); 5018c2ecf20Sopenharmony_ci if (n->capabilities == capabilities) 5028c2ecf20Sopenharmony_ci goto exit; 5038c2ecf20Sopenharmony_ci /* Same node may come back with new capabilities */ 5048c2ecf20Sopenharmony_ci tipc_node_write_lock(n); 5058c2ecf20Sopenharmony_ci n->capabilities = capabilities; 5068c2ecf20Sopenharmony_ci for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) { 5078c2ecf20Sopenharmony_ci l = n->links[bearer_id].link; 5088c2ecf20Sopenharmony_ci if (l) 5098c2ecf20Sopenharmony_ci tipc_link_update_caps(l, capabilities); 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci tipc_node_write_unlock_fast(n); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* Calculate cluster capabilities */ 5148c2ecf20Sopenharmony_ci tn->capabilities = TIPC_NODE_CAPABILITIES; 5158c2ecf20Sopenharmony_ci list_for_each_entry_rcu(temp_node, &tn->node_list, list) { 5168c2ecf20Sopenharmony_ci tn->capabilities &= temp_node->capabilities; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci tipc_bcast_toggle_rcast(net, 5208c2ecf20Sopenharmony_ci (tn->capabilities & TIPC_BCAST_RCAST)); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci goto exit; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci n = kzalloc(sizeof(*n), GFP_ATOMIC); 5258c2ecf20Sopenharmony_ci if (!n) { 5268c2ecf20Sopenharmony_ci pr_warn("Node creation failed, no memory\n"); 5278c2ecf20Sopenharmony_ci goto exit; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci tipc_nodeid2string(n->peer_id_string, peer_id); 5308c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_CRYPTO 5318c2ecf20Sopenharmony_ci if (unlikely(tipc_crypto_start(&n->crypto_rx, net, n))) { 5328c2ecf20Sopenharmony_ci pr_warn("Failed to start crypto RX(%s)!\n", n->peer_id_string); 5338c2ecf20Sopenharmony_ci kfree(n); 5348c2ecf20Sopenharmony_ci n = NULL; 5358c2ecf20Sopenharmony_ci goto exit; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci#endif 5388c2ecf20Sopenharmony_ci n->addr = addr; 5398c2ecf20Sopenharmony_ci n->preliminary = preliminary; 5408c2ecf20Sopenharmony_ci memcpy(&n->peer_id, peer_id, 16); 5418c2ecf20Sopenharmony_ci n->net = net; 5428c2ecf20Sopenharmony_ci n->peer_net = NULL; 5438c2ecf20Sopenharmony_ci n->peer_hash_mix = 0; 5448c2ecf20Sopenharmony_ci /* Assign kernel local namespace if exists */ 5458c2ecf20Sopenharmony_ci tipc_node_assign_peer_net(n, hash_mixes); 5468c2ecf20Sopenharmony_ci n->capabilities = capabilities; 5478c2ecf20Sopenharmony_ci kref_init(&n->kref); 5488c2ecf20Sopenharmony_ci rwlock_init(&n->lock); 5498c2ecf20Sopenharmony_ci INIT_HLIST_NODE(&n->hash); 5508c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&n->list); 5518c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&n->publ_list); 5528c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&n->conn_sks); 5538c2ecf20Sopenharmony_ci skb_queue_head_init(&n->bc_entry.namedq); 5548c2ecf20Sopenharmony_ci skb_queue_head_init(&n->bc_entry.inputq1); 5558c2ecf20Sopenharmony_ci __skb_queue_head_init(&n->bc_entry.arrvq); 5568c2ecf20Sopenharmony_ci skb_queue_head_init(&n->bc_entry.inputq2); 5578c2ecf20Sopenharmony_ci for (i = 0; i < MAX_BEARERS; i++) 5588c2ecf20Sopenharmony_ci spin_lock_init(&n->links[i].lock); 5598c2ecf20Sopenharmony_ci n->state = SELF_DOWN_PEER_LEAVING; 5608c2ecf20Sopenharmony_ci n->delete_at = jiffies + msecs_to_jiffies(NODE_CLEANUP_AFTER); 5618c2ecf20Sopenharmony_ci n->signature = INVALID_NODE_SIG; 5628c2ecf20Sopenharmony_ci n->active_links[0] = INVALID_BEARER_ID; 5638c2ecf20Sopenharmony_ci n->active_links[1] = INVALID_BEARER_ID; 5648c2ecf20Sopenharmony_ci if (!preliminary && 5658c2ecf20Sopenharmony_ci !tipc_link_bc_create(net, tipc_own_addr(net), addr, peer_id, U16_MAX, 5668c2ecf20Sopenharmony_ci tipc_link_min_win(snd_l), tipc_link_max_win(snd_l), 5678c2ecf20Sopenharmony_ci n->capabilities, &n->bc_entry.inputq1, 5688c2ecf20Sopenharmony_ci &n->bc_entry.namedq, snd_l, &n->bc_entry.link)) { 5698c2ecf20Sopenharmony_ci pr_warn("Broadcast rcv link creation failed, no memory\n"); 5708c2ecf20Sopenharmony_ci tipc_node_put(n); 5718c2ecf20Sopenharmony_ci n = NULL; 5728c2ecf20Sopenharmony_ci goto exit; 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci tipc_node_get(n); 5758c2ecf20Sopenharmony_ci timer_setup(&n->timer, tipc_node_timeout, 0); 5768c2ecf20Sopenharmony_ci /* Start a slow timer anyway, crypto needs it */ 5778c2ecf20Sopenharmony_ci n->keepalive_intv = 10000; 5788c2ecf20Sopenharmony_ci intv = jiffies + msecs_to_jiffies(n->keepalive_intv); 5798c2ecf20Sopenharmony_ci if (!mod_timer(&n->timer, intv)) 5808c2ecf20Sopenharmony_ci tipc_node_get(n); 5818c2ecf20Sopenharmony_ci hlist_add_head_rcu(&n->hash, &tn->node_htable[tipc_hashfn(addr)]); 5828c2ecf20Sopenharmony_ci list_for_each_entry_rcu(temp_node, &tn->node_list, list) { 5838c2ecf20Sopenharmony_ci if (n->addr < temp_node->addr) 5848c2ecf20Sopenharmony_ci break; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci list_add_tail_rcu(&n->list, &temp_node->list); 5878c2ecf20Sopenharmony_ci /* Calculate cluster capabilities */ 5888c2ecf20Sopenharmony_ci tn->capabilities = TIPC_NODE_CAPABILITIES; 5898c2ecf20Sopenharmony_ci list_for_each_entry_rcu(temp_node, &tn->node_list, list) { 5908c2ecf20Sopenharmony_ci tn->capabilities &= temp_node->capabilities; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci tipc_bcast_toggle_rcast(net, (tn->capabilities & TIPC_BCAST_RCAST)); 5938c2ecf20Sopenharmony_ci trace_tipc_node_create(n, true, " "); 5948c2ecf20Sopenharmony_ciexit: 5958c2ecf20Sopenharmony_ci spin_unlock_bh(&tn->node_list_lock); 5968c2ecf20Sopenharmony_ci return n; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic void tipc_node_calculate_timer(struct tipc_node *n, struct tipc_link *l) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci unsigned long tol = tipc_link_tolerance(l); 6028c2ecf20Sopenharmony_ci unsigned long intv = ((tol / 4) > 500) ? 500 : tol / 4; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* Link with lowest tolerance determines timer interval */ 6058c2ecf20Sopenharmony_ci if (intv < n->keepalive_intv) 6068c2ecf20Sopenharmony_ci n->keepalive_intv = intv; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci /* Ensure link's abort limit corresponds to current tolerance */ 6098c2ecf20Sopenharmony_ci tipc_link_set_abort_limit(l, tol / n->keepalive_intv); 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic void tipc_node_delete_from_list(struct tipc_node *node) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_CRYPTO 6158c2ecf20Sopenharmony_ci tipc_crypto_key_flush(node->crypto_rx); 6168c2ecf20Sopenharmony_ci#endif 6178c2ecf20Sopenharmony_ci list_del_rcu(&node->list); 6188c2ecf20Sopenharmony_ci hlist_del_rcu(&node->hash); 6198c2ecf20Sopenharmony_ci tipc_node_put(node); 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic void tipc_node_delete(struct tipc_node *node) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci trace_tipc_node_delete(node, true, " "); 6258c2ecf20Sopenharmony_ci tipc_node_delete_from_list(node); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci del_timer_sync(&node->timer); 6288c2ecf20Sopenharmony_ci tipc_node_put(node); 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_civoid tipc_node_stop(struct net *net) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 6348c2ecf20Sopenharmony_ci struct tipc_node *node, *t_node; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci spin_lock_bh(&tn->node_list_lock); 6378c2ecf20Sopenharmony_ci list_for_each_entry_safe(node, t_node, &tn->node_list, list) 6388c2ecf20Sopenharmony_ci tipc_node_delete(node); 6398c2ecf20Sopenharmony_ci spin_unlock_bh(&tn->node_list_lock); 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_civoid tipc_node_subscribe(struct net *net, struct list_head *subscr, u32 addr) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci struct tipc_node *n; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (in_own_node(net, addr)) 6478c2ecf20Sopenharmony_ci return; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci n = tipc_node_find(net, addr); 6508c2ecf20Sopenharmony_ci if (!n) { 6518c2ecf20Sopenharmony_ci pr_warn("Node subscribe rejected, unknown node 0x%x\n", addr); 6528c2ecf20Sopenharmony_ci return; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci tipc_node_write_lock(n); 6558c2ecf20Sopenharmony_ci list_add_tail(subscr, &n->publ_list); 6568c2ecf20Sopenharmony_ci tipc_node_write_unlock_fast(n); 6578c2ecf20Sopenharmony_ci tipc_node_put(n); 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_civoid tipc_node_unsubscribe(struct net *net, struct list_head *subscr, u32 addr) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci struct tipc_node *n; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci if (in_own_node(net, addr)) 6658c2ecf20Sopenharmony_ci return; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci n = tipc_node_find(net, addr); 6688c2ecf20Sopenharmony_ci if (!n) { 6698c2ecf20Sopenharmony_ci pr_warn("Node unsubscribe rejected, unknown node 0x%x\n", addr); 6708c2ecf20Sopenharmony_ci return; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci tipc_node_write_lock(n); 6738c2ecf20Sopenharmony_ci list_del_init(subscr); 6748c2ecf20Sopenharmony_ci tipc_node_write_unlock_fast(n); 6758c2ecf20Sopenharmony_ci tipc_node_put(n); 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ciint tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci struct tipc_node *node; 6818c2ecf20Sopenharmony_ci struct tipc_sock_conn *conn; 6828c2ecf20Sopenharmony_ci int err = 0; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (in_own_node(net, dnode)) 6858c2ecf20Sopenharmony_ci return 0; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci node = tipc_node_find(net, dnode); 6888c2ecf20Sopenharmony_ci if (!node) { 6898c2ecf20Sopenharmony_ci pr_warn("Connecting sock to node 0x%x failed\n", dnode); 6908c2ecf20Sopenharmony_ci return -EHOSTUNREACH; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci conn = kmalloc(sizeof(*conn), GFP_ATOMIC); 6938c2ecf20Sopenharmony_ci if (!conn) { 6948c2ecf20Sopenharmony_ci err = -EHOSTUNREACH; 6958c2ecf20Sopenharmony_ci goto exit; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci conn->peer_node = dnode; 6988c2ecf20Sopenharmony_ci conn->port = port; 6998c2ecf20Sopenharmony_ci conn->peer_port = peer_port; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci tipc_node_write_lock(node); 7028c2ecf20Sopenharmony_ci list_add_tail(&conn->list, &node->conn_sks); 7038c2ecf20Sopenharmony_ci tipc_node_write_unlock(node); 7048c2ecf20Sopenharmony_ciexit: 7058c2ecf20Sopenharmony_ci tipc_node_put(node); 7068c2ecf20Sopenharmony_ci return err; 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_civoid tipc_node_remove_conn(struct net *net, u32 dnode, u32 port) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci struct tipc_node *node; 7128c2ecf20Sopenharmony_ci struct tipc_sock_conn *conn, *safe; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci if (in_own_node(net, dnode)) 7158c2ecf20Sopenharmony_ci return; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci node = tipc_node_find(net, dnode); 7188c2ecf20Sopenharmony_ci if (!node) 7198c2ecf20Sopenharmony_ci return; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci tipc_node_write_lock(node); 7228c2ecf20Sopenharmony_ci list_for_each_entry_safe(conn, safe, &node->conn_sks, list) { 7238c2ecf20Sopenharmony_ci if (port != conn->port) 7248c2ecf20Sopenharmony_ci continue; 7258c2ecf20Sopenharmony_ci list_del(&conn->list); 7268c2ecf20Sopenharmony_ci kfree(conn); 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci tipc_node_write_unlock(node); 7298c2ecf20Sopenharmony_ci tipc_node_put(node); 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic void tipc_node_clear_links(struct tipc_node *node) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci int i; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci for (i = 0; i < MAX_BEARERS; i++) { 7378c2ecf20Sopenharmony_ci struct tipc_link_entry *le = &node->links[i]; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (le->link) { 7408c2ecf20Sopenharmony_ci kfree(le->link); 7418c2ecf20Sopenharmony_ci le->link = NULL; 7428c2ecf20Sopenharmony_ci node->link_cnt--; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci/* tipc_node_cleanup - delete nodes that does not 7488c2ecf20Sopenharmony_ci * have active links for NODE_CLEANUP_AFTER time 7498c2ecf20Sopenharmony_ci */ 7508c2ecf20Sopenharmony_cistatic bool tipc_node_cleanup(struct tipc_node *peer) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci struct tipc_node *temp_node; 7538c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(peer->net); 7548c2ecf20Sopenharmony_ci bool deleted = false; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* If lock held by tipc_node_stop() the node will be deleted anyway */ 7578c2ecf20Sopenharmony_ci if (!spin_trylock_bh(&tn->node_list_lock)) 7588c2ecf20Sopenharmony_ci return false; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci tipc_node_write_lock(peer); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (!node_is_up(peer) && time_after(jiffies, peer->delete_at)) { 7638c2ecf20Sopenharmony_ci tipc_node_clear_links(peer); 7648c2ecf20Sopenharmony_ci tipc_node_delete_from_list(peer); 7658c2ecf20Sopenharmony_ci deleted = true; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci tipc_node_write_unlock(peer); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (!deleted) { 7708c2ecf20Sopenharmony_ci spin_unlock_bh(&tn->node_list_lock); 7718c2ecf20Sopenharmony_ci return deleted; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* Calculate cluster capabilities */ 7758c2ecf20Sopenharmony_ci tn->capabilities = TIPC_NODE_CAPABILITIES; 7768c2ecf20Sopenharmony_ci list_for_each_entry_rcu(temp_node, &tn->node_list, list) { 7778c2ecf20Sopenharmony_ci tn->capabilities &= temp_node->capabilities; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci tipc_bcast_toggle_rcast(peer->net, 7808c2ecf20Sopenharmony_ci (tn->capabilities & TIPC_BCAST_RCAST)); 7818c2ecf20Sopenharmony_ci spin_unlock_bh(&tn->node_list_lock); 7828c2ecf20Sopenharmony_ci return deleted; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci/* tipc_node_timeout - handle expiration of node timer 7868c2ecf20Sopenharmony_ci */ 7878c2ecf20Sopenharmony_cistatic void tipc_node_timeout(struct timer_list *t) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci struct tipc_node *n = from_timer(n, t, timer); 7908c2ecf20Sopenharmony_ci struct tipc_link_entry *le; 7918c2ecf20Sopenharmony_ci struct sk_buff_head xmitq; 7928c2ecf20Sopenharmony_ci int remains = n->link_cnt; 7938c2ecf20Sopenharmony_ci int bearer_id; 7948c2ecf20Sopenharmony_ci int rc = 0; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci trace_tipc_node_timeout(n, false, " "); 7978c2ecf20Sopenharmony_ci if (!node_is_up(n) && tipc_node_cleanup(n)) { 7988c2ecf20Sopenharmony_ci /*Removing the reference of Timer*/ 7998c2ecf20Sopenharmony_ci tipc_node_put(n); 8008c2ecf20Sopenharmony_ci return; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_CRYPTO 8048c2ecf20Sopenharmony_ci /* Take any crypto key related actions first */ 8058c2ecf20Sopenharmony_ci tipc_crypto_timeout(n->crypto_rx); 8068c2ecf20Sopenharmony_ci#endif 8078c2ecf20Sopenharmony_ci __skb_queue_head_init(&xmitq); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* Initial node interval to value larger (10 seconds), then it will be 8108c2ecf20Sopenharmony_ci * recalculated with link lowest tolerance 8118c2ecf20Sopenharmony_ci */ 8128c2ecf20Sopenharmony_ci tipc_node_read_lock(n); 8138c2ecf20Sopenharmony_ci n->keepalive_intv = 10000; 8148c2ecf20Sopenharmony_ci tipc_node_read_unlock(n); 8158c2ecf20Sopenharmony_ci for (bearer_id = 0; remains && (bearer_id < MAX_BEARERS); bearer_id++) { 8168c2ecf20Sopenharmony_ci tipc_node_read_lock(n); 8178c2ecf20Sopenharmony_ci le = &n->links[bearer_id]; 8188c2ecf20Sopenharmony_ci if (le->link) { 8198c2ecf20Sopenharmony_ci spin_lock_bh(&le->lock); 8208c2ecf20Sopenharmony_ci /* Link tolerance may change asynchronously: */ 8218c2ecf20Sopenharmony_ci tipc_node_calculate_timer(n, le->link); 8228c2ecf20Sopenharmony_ci rc = tipc_link_timeout(le->link, &xmitq); 8238c2ecf20Sopenharmony_ci spin_unlock_bh(&le->lock); 8248c2ecf20Sopenharmony_ci remains--; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci tipc_node_read_unlock(n); 8278c2ecf20Sopenharmony_ci tipc_bearer_xmit(n->net, bearer_id, &xmitq, &le->maddr, n); 8288c2ecf20Sopenharmony_ci if (rc & TIPC_LINK_DOWN_EVT) 8298c2ecf20Sopenharmony_ci tipc_node_link_down(n, bearer_id, false); 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci mod_timer(&n->timer, jiffies + msecs_to_jiffies(n->keepalive_intv)); 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci/** 8358c2ecf20Sopenharmony_ci * __tipc_node_link_up - handle addition of link 8368c2ecf20Sopenharmony_ci * Node lock must be held by caller 8378c2ecf20Sopenharmony_ci * Link becomes active (alone or shared) or standby, depending on its priority. 8388c2ecf20Sopenharmony_ci */ 8398c2ecf20Sopenharmony_cistatic void __tipc_node_link_up(struct tipc_node *n, int bearer_id, 8408c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci int *slot0 = &n->active_links[0]; 8438c2ecf20Sopenharmony_ci int *slot1 = &n->active_links[1]; 8448c2ecf20Sopenharmony_ci struct tipc_link *ol = node_active_link(n, 0); 8458c2ecf20Sopenharmony_ci struct tipc_link *nl = n->links[bearer_id].link; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (!nl || tipc_link_is_up(nl)) 8488c2ecf20Sopenharmony_ci return; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci tipc_link_fsm_evt(nl, LINK_ESTABLISH_EVT); 8518c2ecf20Sopenharmony_ci if (!tipc_link_is_up(nl)) 8528c2ecf20Sopenharmony_ci return; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci n->working_links++; 8558c2ecf20Sopenharmony_ci n->action_flags |= TIPC_NOTIFY_LINK_UP; 8568c2ecf20Sopenharmony_ci n->link_id = tipc_link_id(nl); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci /* Leave room for tunnel header when returning 'mtu' to users: */ 8598c2ecf20Sopenharmony_ci n->links[bearer_id].mtu = tipc_link_mss(nl); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci tipc_bearer_add_dest(n->net, bearer_id, n->addr); 8628c2ecf20Sopenharmony_ci tipc_bcast_inc_bearer_dst_cnt(n->net, bearer_id); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci pr_debug("Established link <%s> on network plane %c\n", 8658c2ecf20Sopenharmony_ci tipc_link_name(nl), tipc_link_plane(nl)); 8668c2ecf20Sopenharmony_ci trace_tipc_node_link_up(n, true, " "); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci /* Ensure that a STATE message goes first */ 8698c2ecf20Sopenharmony_ci tipc_link_build_state_msg(nl, xmitq); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /* First link? => give it both slots */ 8728c2ecf20Sopenharmony_ci if (!ol) { 8738c2ecf20Sopenharmony_ci *slot0 = bearer_id; 8748c2ecf20Sopenharmony_ci *slot1 = bearer_id; 8758c2ecf20Sopenharmony_ci tipc_node_fsm_evt(n, SELF_ESTABL_CONTACT_EVT); 8768c2ecf20Sopenharmony_ci n->action_flags |= TIPC_NOTIFY_NODE_UP; 8778c2ecf20Sopenharmony_ci tipc_link_set_active(nl, true); 8788c2ecf20Sopenharmony_ci tipc_bcast_add_peer(n->net, nl, xmitq); 8798c2ecf20Sopenharmony_ci return; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* Second link => redistribute slots */ 8838c2ecf20Sopenharmony_ci if (tipc_link_prio(nl) > tipc_link_prio(ol)) { 8848c2ecf20Sopenharmony_ci pr_debug("Old link <%s> becomes standby\n", tipc_link_name(ol)); 8858c2ecf20Sopenharmony_ci *slot0 = bearer_id; 8868c2ecf20Sopenharmony_ci *slot1 = bearer_id; 8878c2ecf20Sopenharmony_ci tipc_link_set_active(nl, true); 8888c2ecf20Sopenharmony_ci tipc_link_set_active(ol, false); 8898c2ecf20Sopenharmony_ci } else if (tipc_link_prio(nl) == tipc_link_prio(ol)) { 8908c2ecf20Sopenharmony_ci tipc_link_set_active(nl, true); 8918c2ecf20Sopenharmony_ci *slot1 = bearer_id; 8928c2ecf20Sopenharmony_ci } else { 8938c2ecf20Sopenharmony_ci pr_debug("New link <%s> is standby\n", tipc_link_name(nl)); 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci /* Prepare synchronization with first link */ 8978c2ecf20Sopenharmony_ci tipc_link_tnl_prepare(ol, nl, SYNCH_MSG, xmitq); 8988c2ecf20Sopenharmony_ci} 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci/** 9018c2ecf20Sopenharmony_ci * tipc_node_link_up - handle addition of link 9028c2ecf20Sopenharmony_ci * 9038c2ecf20Sopenharmony_ci * Link becomes active (alone or shared) or standby, depending on its priority. 9048c2ecf20Sopenharmony_ci */ 9058c2ecf20Sopenharmony_cistatic void tipc_node_link_up(struct tipc_node *n, int bearer_id, 9068c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci struct tipc_media_addr *maddr; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci tipc_node_write_lock(n); 9118c2ecf20Sopenharmony_ci __tipc_node_link_up(n, bearer_id, xmitq); 9128c2ecf20Sopenharmony_ci maddr = &n->links[bearer_id].maddr; 9138c2ecf20Sopenharmony_ci tipc_bearer_xmit(n->net, bearer_id, xmitq, maddr, n); 9148c2ecf20Sopenharmony_ci tipc_node_write_unlock(n); 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci/** 9188c2ecf20Sopenharmony_ci * tipc_node_link_failover() - start failover in case "half-failover" 9198c2ecf20Sopenharmony_ci * 9208c2ecf20Sopenharmony_ci * This function is only called in a very special situation where link 9218c2ecf20Sopenharmony_ci * failover can be already started on peer node but not on this node. 9228c2ecf20Sopenharmony_ci * This can happen when e.g. 9238c2ecf20Sopenharmony_ci * 1. Both links <1A-2A>, <1B-2B> down 9248c2ecf20Sopenharmony_ci * 2. Link endpoint 2A up, but 1A still down (e.g. due to network 9258c2ecf20Sopenharmony_ci * disturbance, wrong session, etc.) 9268c2ecf20Sopenharmony_ci * 3. Link <1B-2B> up 9278c2ecf20Sopenharmony_ci * 4. Link endpoint 2A down (e.g. due to link tolerance timeout) 9288c2ecf20Sopenharmony_ci * 5. Node 2 starts failover onto link <1B-2B> 9298c2ecf20Sopenharmony_ci * 9308c2ecf20Sopenharmony_ci * ==> Node 1 does never start link/node failover! 9318c2ecf20Sopenharmony_ci * 9328c2ecf20Sopenharmony_ci * @n: tipc node structure 9338c2ecf20Sopenharmony_ci * @l: link peer endpoint failingover (- can be NULL) 9348c2ecf20Sopenharmony_ci * @tnl: tunnel link 9358c2ecf20Sopenharmony_ci * @xmitq: queue for messages to be xmited on tnl link later 9368c2ecf20Sopenharmony_ci */ 9378c2ecf20Sopenharmony_cistatic void tipc_node_link_failover(struct tipc_node *n, struct tipc_link *l, 9388c2ecf20Sopenharmony_ci struct tipc_link *tnl, 9398c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci /* Avoid to be "self-failover" that can never end */ 9428c2ecf20Sopenharmony_ci if (!tipc_link_is_up(tnl)) 9438c2ecf20Sopenharmony_ci return; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci /* Don't rush, failure link may be in the process of resetting */ 9468c2ecf20Sopenharmony_ci if (l && !tipc_link_is_reset(l)) 9478c2ecf20Sopenharmony_ci return; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci tipc_link_fsm_evt(tnl, LINK_SYNCH_END_EVT); 9508c2ecf20Sopenharmony_ci tipc_node_fsm_evt(n, NODE_SYNCH_END_EVT); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci n->sync_point = tipc_link_rcv_nxt(tnl) + (U16_MAX / 2 - 1); 9538c2ecf20Sopenharmony_ci tipc_link_failover_prepare(l, tnl, xmitq); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci if (l) 9568c2ecf20Sopenharmony_ci tipc_link_fsm_evt(l, LINK_FAILOVER_BEGIN_EVT); 9578c2ecf20Sopenharmony_ci tipc_node_fsm_evt(n, NODE_FAILOVER_BEGIN_EVT); 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci/** 9618c2ecf20Sopenharmony_ci * __tipc_node_link_down - handle loss of link 9628c2ecf20Sopenharmony_ci */ 9638c2ecf20Sopenharmony_cistatic void __tipc_node_link_down(struct tipc_node *n, int *bearer_id, 9648c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq, 9658c2ecf20Sopenharmony_ci struct tipc_media_addr **maddr) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci struct tipc_link_entry *le = &n->links[*bearer_id]; 9688c2ecf20Sopenharmony_ci int *slot0 = &n->active_links[0]; 9698c2ecf20Sopenharmony_ci int *slot1 = &n->active_links[1]; 9708c2ecf20Sopenharmony_ci int i, highest = 0, prio; 9718c2ecf20Sopenharmony_ci struct tipc_link *l, *_l, *tnl; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci l = n->links[*bearer_id].link; 9748c2ecf20Sopenharmony_ci if (!l || tipc_link_is_reset(l)) 9758c2ecf20Sopenharmony_ci return; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci n->working_links--; 9788c2ecf20Sopenharmony_ci n->action_flags |= TIPC_NOTIFY_LINK_DOWN; 9798c2ecf20Sopenharmony_ci n->link_id = tipc_link_id(l); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci tipc_bearer_remove_dest(n->net, *bearer_id, n->addr); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci pr_debug("Lost link <%s> on network plane %c\n", 9848c2ecf20Sopenharmony_ci tipc_link_name(l), tipc_link_plane(l)); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* Select new active link if any available */ 9878c2ecf20Sopenharmony_ci *slot0 = INVALID_BEARER_ID; 9888c2ecf20Sopenharmony_ci *slot1 = INVALID_BEARER_ID; 9898c2ecf20Sopenharmony_ci for (i = 0; i < MAX_BEARERS; i++) { 9908c2ecf20Sopenharmony_ci _l = n->links[i].link; 9918c2ecf20Sopenharmony_ci if (!_l || !tipc_link_is_up(_l)) 9928c2ecf20Sopenharmony_ci continue; 9938c2ecf20Sopenharmony_ci if (_l == l) 9948c2ecf20Sopenharmony_ci continue; 9958c2ecf20Sopenharmony_ci prio = tipc_link_prio(_l); 9968c2ecf20Sopenharmony_ci if (prio < highest) 9978c2ecf20Sopenharmony_ci continue; 9988c2ecf20Sopenharmony_ci if (prio > highest) { 9998c2ecf20Sopenharmony_ci highest = prio; 10008c2ecf20Sopenharmony_ci *slot0 = i; 10018c2ecf20Sopenharmony_ci *slot1 = i; 10028c2ecf20Sopenharmony_ci continue; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci *slot1 = i; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (!node_is_up(n)) { 10088c2ecf20Sopenharmony_ci if (tipc_link_peer_is_down(l)) 10098c2ecf20Sopenharmony_ci tipc_node_fsm_evt(n, PEER_LOST_CONTACT_EVT); 10108c2ecf20Sopenharmony_ci tipc_node_fsm_evt(n, SELF_LOST_CONTACT_EVT); 10118c2ecf20Sopenharmony_ci trace_tipc_link_reset(l, TIPC_DUMP_ALL, "link down!"); 10128c2ecf20Sopenharmony_ci tipc_link_fsm_evt(l, LINK_RESET_EVT); 10138c2ecf20Sopenharmony_ci tipc_link_reset(l); 10148c2ecf20Sopenharmony_ci tipc_link_build_reset_msg(l, xmitq); 10158c2ecf20Sopenharmony_ci *maddr = &n->links[*bearer_id].maddr; 10168c2ecf20Sopenharmony_ci node_lost_contact(n, &le->inputq); 10178c2ecf20Sopenharmony_ci tipc_bcast_dec_bearer_dst_cnt(n->net, *bearer_id); 10188c2ecf20Sopenharmony_ci return; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci tipc_bcast_dec_bearer_dst_cnt(n->net, *bearer_id); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci /* There is still a working link => initiate failover */ 10238c2ecf20Sopenharmony_ci *bearer_id = n->active_links[0]; 10248c2ecf20Sopenharmony_ci tnl = n->links[*bearer_id].link; 10258c2ecf20Sopenharmony_ci tipc_link_fsm_evt(tnl, LINK_SYNCH_END_EVT); 10268c2ecf20Sopenharmony_ci tipc_node_fsm_evt(n, NODE_SYNCH_END_EVT); 10278c2ecf20Sopenharmony_ci n->sync_point = tipc_link_rcv_nxt(tnl) + (U16_MAX / 2 - 1); 10288c2ecf20Sopenharmony_ci tipc_link_tnl_prepare(l, tnl, FAILOVER_MSG, xmitq); 10298c2ecf20Sopenharmony_ci trace_tipc_link_reset(l, TIPC_DUMP_ALL, "link down -> failover!"); 10308c2ecf20Sopenharmony_ci tipc_link_reset(l); 10318c2ecf20Sopenharmony_ci tipc_link_fsm_evt(l, LINK_RESET_EVT); 10328c2ecf20Sopenharmony_ci tipc_link_fsm_evt(l, LINK_FAILOVER_BEGIN_EVT); 10338c2ecf20Sopenharmony_ci tipc_node_fsm_evt(n, NODE_FAILOVER_BEGIN_EVT); 10348c2ecf20Sopenharmony_ci *maddr = &n->links[*bearer_id].maddr; 10358c2ecf20Sopenharmony_ci} 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_cistatic void tipc_node_link_down(struct tipc_node *n, int bearer_id, bool delete) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci struct tipc_link_entry *le = &n->links[bearer_id]; 10408c2ecf20Sopenharmony_ci struct tipc_media_addr *maddr = NULL; 10418c2ecf20Sopenharmony_ci struct tipc_link *l = le->link; 10428c2ecf20Sopenharmony_ci int old_bearer_id = bearer_id; 10438c2ecf20Sopenharmony_ci struct sk_buff_head xmitq; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (!l) 10468c2ecf20Sopenharmony_ci return; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci __skb_queue_head_init(&xmitq); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci tipc_node_write_lock(n); 10518c2ecf20Sopenharmony_ci if (!tipc_link_is_establishing(l)) { 10528c2ecf20Sopenharmony_ci __tipc_node_link_down(n, &bearer_id, &xmitq, &maddr); 10538c2ecf20Sopenharmony_ci } else { 10548c2ecf20Sopenharmony_ci /* Defuse pending tipc_node_link_up() */ 10558c2ecf20Sopenharmony_ci tipc_link_reset(l); 10568c2ecf20Sopenharmony_ci tipc_link_fsm_evt(l, LINK_RESET_EVT); 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci if (delete) { 10598c2ecf20Sopenharmony_ci kfree(l); 10608c2ecf20Sopenharmony_ci le->link = NULL; 10618c2ecf20Sopenharmony_ci n->link_cnt--; 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci trace_tipc_node_link_down(n, true, "node link down or deleted!"); 10648c2ecf20Sopenharmony_ci tipc_node_write_unlock(n); 10658c2ecf20Sopenharmony_ci if (delete) 10668c2ecf20Sopenharmony_ci tipc_mon_remove_peer(n->net, n->addr, old_bearer_id); 10678c2ecf20Sopenharmony_ci if (!skb_queue_empty(&xmitq)) 10688c2ecf20Sopenharmony_ci tipc_bearer_xmit(n->net, bearer_id, &xmitq, maddr, n); 10698c2ecf20Sopenharmony_ci tipc_sk_rcv(n->net, &le->inputq); 10708c2ecf20Sopenharmony_ci} 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cistatic bool node_is_up(struct tipc_node *n) 10738c2ecf20Sopenharmony_ci{ 10748c2ecf20Sopenharmony_ci return n->active_links[0] != INVALID_BEARER_ID; 10758c2ecf20Sopenharmony_ci} 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_cibool tipc_node_is_up(struct net *net, u32 addr) 10788c2ecf20Sopenharmony_ci{ 10798c2ecf20Sopenharmony_ci struct tipc_node *n; 10808c2ecf20Sopenharmony_ci bool retval = false; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci if (in_own_node(net, addr)) 10838c2ecf20Sopenharmony_ci return true; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci n = tipc_node_find(net, addr); 10868c2ecf20Sopenharmony_ci if (!n) 10878c2ecf20Sopenharmony_ci return false; 10888c2ecf20Sopenharmony_ci retval = node_is_up(n); 10898c2ecf20Sopenharmony_ci tipc_node_put(n); 10908c2ecf20Sopenharmony_ci return retval; 10918c2ecf20Sopenharmony_ci} 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_cistatic u32 tipc_node_suggest_addr(struct net *net, u32 addr) 10948c2ecf20Sopenharmony_ci{ 10958c2ecf20Sopenharmony_ci struct tipc_node *n; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci addr ^= tipc_net(net)->random; 10988c2ecf20Sopenharmony_ci while ((n = tipc_node_find(net, addr))) { 10998c2ecf20Sopenharmony_ci tipc_node_put(n); 11008c2ecf20Sopenharmony_ci addr++; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci return addr; 11038c2ecf20Sopenharmony_ci} 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci/* tipc_node_try_addr(): Check if addr can be used by peer, suggest other if not 11068c2ecf20Sopenharmony_ci * Returns suggested address if any, otherwise 0 11078c2ecf20Sopenharmony_ci */ 11088c2ecf20Sopenharmony_ciu32 tipc_node_try_addr(struct net *net, u8 *id, u32 addr) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 11118c2ecf20Sopenharmony_ci struct tipc_node *n; 11128c2ecf20Sopenharmony_ci bool preliminary; 11138c2ecf20Sopenharmony_ci u32 sugg_addr; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci /* Suggest new address if some other peer is using this one */ 11168c2ecf20Sopenharmony_ci n = tipc_node_find(net, addr); 11178c2ecf20Sopenharmony_ci if (n) { 11188c2ecf20Sopenharmony_ci if (!memcmp(n->peer_id, id, NODE_ID_LEN)) 11198c2ecf20Sopenharmony_ci addr = 0; 11208c2ecf20Sopenharmony_ci tipc_node_put(n); 11218c2ecf20Sopenharmony_ci if (!addr) 11228c2ecf20Sopenharmony_ci return 0; 11238c2ecf20Sopenharmony_ci return tipc_node_suggest_addr(net, addr); 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci /* Suggest previously used address if peer is known */ 11278c2ecf20Sopenharmony_ci n = tipc_node_find_by_id(net, id); 11288c2ecf20Sopenharmony_ci if (n) { 11298c2ecf20Sopenharmony_ci sugg_addr = n->addr; 11308c2ecf20Sopenharmony_ci preliminary = n->preliminary; 11318c2ecf20Sopenharmony_ci tipc_node_put(n); 11328c2ecf20Sopenharmony_ci if (!preliminary) 11338c2ecf20Sopenharmony_ci return sugg_addr; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci /* Even this node may be in conflict */ 11378c2ecf20Sopenharmony_ci if (tn->trial_addr == addr) 11388c2ecf20Sopenharmony_ci return tipc_node_suggest_addr(net, addr); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci return 0; 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_civoid tipc_node_check_dest(struct net *net, u32 addr, 11448c2ecf20Sopenharmony_ci u8 *peer_id, struct tipc_bearer *b, 11458c2ecf20Sopenharmony_ci u16 capabilities, u32 signature, u32 hash_mixes, 11468c2ecf20Sopenharmony_ci struct tipc_media_addr *maddr, 11478c2ecf20Sopenharmony_ci bool *respond, bool *dupl_addr) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci struct tipc_node *n; 11508c2ecf20Sopenharmony_ci struct tipc_link *l; 11518c2ecf20Sopenharmony_ci struct tipc_link_entry *le; 11528c2ecf20Sopenharmony_ci bool addr_match = false; 11538c2ecf20Sopenharmony_ci bool sign_match = false; 11548c2ecf20Sopenharmony_ci bool link_up = false; 11558c2ecf20Sopenharmony_ci bool link_is_reset = false; 11568c2ecf20Sopenharmony_ci bool accept_addr = false; 11578c2ecf20Sopenharmony_ci bool reset = false; 11588c2ecf20Sopenharmony_ci char *if_name; 11598c2ecf20Sopenharmony_ci unsigned long intv; 11608c2ecf20Sopenharmony_ci u16 session; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci *dupl_addr = false; 11638c2ecf20Sopenharmony_ci *respond = false; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci n = tipc_node_create(net, addr, peer_id, capabilities, hash_mixes, 11668c2ecf20Sopenharmony_ci false); 11678c2ecf20Sopenharmony_ci if (!n) 11688c2ecf20Sopenharmony_ci return; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci tipc_node_write_lock(n); 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci le = &n->links[b->identity]; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci /* Prepare to validate requesting node's signature and media address */ 11758c2ecf20Sopenharmony_ci l = le->link; 11768c2ecf20Sopenharmony_ci link_up = l && tipc_link_is_up(l); 11778c2ecf20Sopenharmony_ci link_is_reset = l && tipc_link_is_reset(l); 11788c2ecf20Sopenharmony_ci addr_match = l && !memcmp(&le->maddr, maddr, sizeof(*maddr)); 11798c2ecf20Sopenharmony_ci sign_match = (signature == n->signature); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci /* These three flags give us eight permutations: */ 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci if (sign_match && addr_match && link_up) { 11848c2ecf20Sopenharmony_ci /* All is fine. Ignore requests. */ 11858c2ecf20Sopenharmony_ci /* Peer node is not a container/local namespace */ 11868c2ecf20Sopenharmony_ci if (!n->peer_hash_mix) 11878c2ecf20Sopenharmony_ci n->peer_hash_mix = hash_mixes; 11888c2ecf20Sopenharmony_ci } else if (sign_match && addr_match && !link_up) { 11898c2ecf20Sopenharmony_ci /* Respond. The link will come up in due time */ 11908c2ecf20Sopenharmony_ci *respond = true; 11918c2ecf20Sopenharmony_ci } else if (sign_match && !addr_match && link_up) { 11928c2ecf20Sopenharmony_ci /* Peer has changed i/f address without rebooting. 11938c2ecf20Sopenharmony_ci * If so, the link will reset soon, and the next 11948c2ecf20Sopenharmony_ci * discovery will be accepted. So we can ignore it. 11958c2ecf20Sopenharmony_ci * It may also be an cloned or malicious peer having 11968c2ecf20Sopenharmony_ci * chosen the same node address and signature as an 11978c2ecf20Sopenharmony_ci * existing one. 11988c2ecf20Sopenharmony_ci * Ignore requests until the link goes down, if ever. 11998c2ecf20Sopenharmony_ci */ 12008c2ecf20Sopenharmony_ci *dupl_addr = true; 12018c2ecf20Sopenharmony_ci } else if (sign_match && !addr_match && !link_up) { 12028c2ecf20Sopenharmony_ci /* Peer link has changed i/f address without rebooting. 12038c2ecf20Sopenharmony_ci * It may also be a cloned or malicious peer; we can't 12048c2ecf20Sopenharmony_ci * distinguish between the two. 12058c2ecf20Sopenharmony_ci * The signature is correct, so we must accept. 12068c2ecf20Sopenharmony_ci */ 12078c2ecf20Sopenharmony_ci accept_addr = true; 12088c2ecf20Sopenharmony_ci *respond = true; 12098c2ecf20Sopenharmony_ci reset = true; 12108c2ecf20Sopenharmony_ci } else if (!sign_match && addr_match && link_up) { 12118c2ecf20Sopenharmony_ci /* Peer node rebooted. Two possibilities: 12128c2ecf20Sopenharmony_ci * - Delayed re-discovery; this link endpoint has already 12138c2ecf20Sopenharmony_ci * reset and re-established contact with the peer, before 12148c2ecf20Sopenharmony_ci * receiving a discovery message from that node. 12158c2ecf20Sopenharmony_ci * (The peer happened to receive one from this node first). 12168c2ecf20Sopenharmony_ci * - The peer came back so fast that our side has not 12178c2ecf20Sopenharmony_ci * discovered it yet. Probing from this side will soon 12188c2ecf20Sopenharmony_ci * reset the link, since there can be no working link 12198c2ecf20Sopenharmony_ci * endpoint at the peer end, and the link will re-establish. 12208c2ecf20Sopenharmony_ci * Accept the signature, since it comes from a known peer. 12218c2ecf20Sopenharmony_ci */ 12228c2ecf20Sopenharmony_ci n->signature = signature; 12238c2ecf20Sopenharmony_ci } else if (!sign_match && addr_match && !link_up) { 12248c2ecf20Sopenharmony_ci /* The peer node has rebooted. 12258c2ecf20Sopenharmony_ci * Accept signature, since it is a known peer. 12268c2ecf20Sopenharmony_ci */ 12278c2ecf20Sopenharmony_ci n->signature = signature; 12288c2ecf20Sopenharmony_ci *respond = true; 12298c2ecf20Sopenharmony_ci } else if (!sign_match && !addr_match && link_up) { 12308c2ecf20Sopenharmony_ci /* Peer rebooted with new address, or a new/duplicate peer. 12318c2ecf20Sopenharmony_ci * Ignore until the link goes down, if ever. 12328c2ecf20Sopenharmony_ci */ 12338c2ecf20Sopenharmony_ci *dupl_addr = true; 12348c2ecf20Sopenharmony_ci } else if (!sign_match && !addr_match && !link_up) { 12358c2ecf20Sopenharmony_ci /* Peer rebooted with new address, or it is a new peer. 12368c2ecf20Sopenharmony_ci * Accept signature and address. 12378c2ecf20Sopenharmony_ci */ 12388c2ecf20Sopenharmony_ci n->signature = signature; 12398c2ecf20Sopenharmony_ci accept_addr = true; 12408c2ecf20Sopenharmony_ci *respond = true; 12418c2ecf20Sopenharmony_ci reset = true; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci if (!accept_addr) 12458c2ecf20Sopenharmony_ci goto exit; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci /* Now create new link if not already existing */ 12488c2ecf20Sopenharmony_ci if (!l) { 12498c2ecf20Sopenharmony_ci if (n->link_cnt == 2) 12508c2ecf20Sopenharmony_ci goto exit; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci if_name = strchr(b->name, ':') + 1; 12538c2ecf20Sopenharmony_ci get_random_bytes(&session, sizeof(u16)); 12548c2ecf20Sopenharmony_ci if (!tipc_link_create(net, if_name, b->identity, b->tolerance, 12558c2ecf20Sopenharmony_ci b->net_plane, b->mtu, b->priority, 12568c2ecf20Sopenharmony_ci b->min_win, b->max_win, session, 12578c2ecf20Sopenharmony_ci tipc_own_addr(net), addr, peer_id, 12588c2ecf20Sopenharmony_ci n->capabilities, 12598c2ecf20Sopenharmony_ci tipc_bc_sndlink(n->net), n->bc_entry.link, 12608c2ecf20Sopenharmony_ci &le->inputq, 12618c2ecf20Sopenharmony_ci &n->bc_entry.namedq, &l)) { 12628c2ecf20Sopenharmony_ci *respond = false; 12638c2ecf20Sopenharmony_ci goto exit; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci trace_tipc_link_reset(l, TIPC_DUMP_ALL, "link created!"); 12668c2ecf20Sopenharmony_ci tipc_link_reset(l); 12678c2ecf20Sopenharmony_ci tipc_link_fsm_evt(l, LINK_RESET_EVT); 12688c2ecf20Sopenharmony_ci if (n->state == NODE_FAILINGOVER) 12698c2ecf20Sopenharmony_ci tipc_link_fsm_evt(l, LINK_FAILOVER_BEGIN_EVT); 12708c2ecf20Sopenharmony_ci link_is_reset = tipc_link_is_reset(l); 12718c2ecf20Sopenharmony_ci le->link = l; 12728c2ecf20Sopenharmony_ci n->link_cnt++; 12738c2ecf20Sopenharmony_ci tipc_node_calculate_timer(n, l); 12748c2ecf20Sopenharmony_ci if (n->link_cnt == 1) { 12758c2ecf20Sopenharmony_ci intv = jiffies + msecs_to_jiffies(n->keepalive_intv); 12768c2ecf20Sopenharmony_ci if (!mod_timer(&n->timer, intv)) 12778c2ecf20Sopenharmony_ci tipc_node_get(n); 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci memcpy(&le->maddr, maddr, sizeof(*maddr)); 12818c2ecf20Sopenharmony_ciexit: 12828c2ecf20Sopenharmony_ci tipc_node_write_unlock(n); 12838c2ecf20Sopenharmony_ci if (reset && !link_is_reset) 12848c2ecf20Sopenharmony_ci tipc_node_link_down(n, b->identity, false); 12858c2ecf20Sopenharmony_ci tipc_node_put(n); 12868c2ecf20Sopenharmony_ci} 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_civoid tipc_node_delete_links(struct net *net, int bearer_id) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci struct tipc_net *tn = net_generic(net, tipc_net_id); 12918c2ecf20Sopenharmony_ci struct tipc_node *n; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci rcu_read_lock(); 12948c2ecf20Sopenharmony_ci list_for_each_entry_rcu(n, &tn->node_list, list) { 12958c2ecf20Sopenharmony_ci tipc_node_link_down(n, bearer_id, true); 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci rcu_read_unlock(); 12988c2ecf20Sopenharmony_ci} 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_cistatic void tipc_node_reset_links(struct tipc_node *n) 13018c2ecf20Sopenharmony_ci{ 13028c2ecf20Sopenharmony_ci int i; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci pr_warn("Resetting all links to %x\n", n->addr); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci trace_tipc_node_reset_links(n, true, " "); 13078c2ecf20Sopenharmony_ci for (i = 0; i < MAX_BEARERS; i++) { 13088c2ecf20Sopenharmony_ci tipc_node_link_down(n, i, false); 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci/* tipc_node_fsm_evt - node finite state machine 13138c2ecf20Sopenharmony_ci * Determines when contact is allowed with peer node 13148c2ecf20Sopenharmony_ci */ 13158c2ecf20Sopenharmony_cistatic void tipc_node_fsm_evt(struct tipc_node *n, int evt) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci int state = n->state; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci switch (state) { 13208c2ecf20Sopenharmony_ci case SELF_DOWN_PEER_DOWN: 13218c2ecf20Sopenharmony_ci switch (evt) { 13228c2ecf20Sopenharmony_ci case SELF_ESTABL_CONTACT_EVT: 13238c2ecf20Sopenharmony_ci state = SELF_UP_PEER_COMING; 13248c2ecf20Sopenharmony_ci break; 13258c2ecf20Sopenharmony_ci case PEER_ESTABL_CONTACT_EVT: 13268c2ecf20Sopenharmony_ci state = SELF_COMING_PEER_UP; 13278c2ecf20Sopenharmony_ci break; 13288c2ecf20Sopenharmony_ci case SELF_LOST_CONTACT_EVT: 13298c2ecf20Sopenharmony_ci case PEER_LOST_CONTACT_EVT: 13308c2ecf20Sopenharmony_ci break; 13318c2ecf20Sopenharmony_ci case NODE_SYNCH_END_EVT: 13328c2ecf20Sopenharmony_ci case NODE_SYNCH_BEGIN_EVT: 13338c2ecf20Sopenharmony_ci case NODE_FAILOVER_BEGIN_EVT: 13348c2ecf20Sopenharmony_ci case NODE_FAILOVER_END_EVT: 13358c2ecf20Sopenharmony_ci default: 13368c2ecf20Sopenharmony_ci goto illegal_evt; 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci break; 13398c2ecf20Sopenharmony_ci case SELF_UP_PEER_UP: 13408c2ecf20Sopenharmony_ci switch (evt) { 13418c2ecf20Sopenharmony_ci case SELF_LOST_CONTACT_EVT: 13428c2ecf20Sopenharmony_ci state = SELF_DOWN_PEER_LEAVING; 13438c2ecf20Sopenharmony_ci break; 13448c2ecf20Sopenharmony_ci case PEER_LOST_CONTACT_EVT: 13458c2ecf20Sopenharmony_ci state = SELF_LEAVING_PEER_DOWN; 13468c2ecf20Sopenharmony_ci break; 13478c2ecf20Sopenharmony_ci case NODE_SYNCH_BEGIN_EVT: 13488c2ecf20Sopenharmony_ci state = NODE_SYNCHING; 13498c2ecf20Sopenharmony_ci break; 13508c2ecf20Sopenharmony_ci case NODE_FAILOVER_BEGIN_EVT: 13518c2ecf20Sopenharmony_ci state = NODE_FAILINGOVER; 13528c2ecf20Sopenharmony_ci break; 13538c2ecf20Sopenharmony_ci case SELF_ESTABL_CONTACT_EVT: 13548c2ecf20Sopenharmony_ci case PEER_ESTABL_CONTACT_EVT: 13558c2ecf20Sopenharmony_ci case NODE_SYNCH_END_EVT: 13568c2ecf20Sopenharmony_ci case NODE_FAILOVER_END_EVT: 13578c2ecf20Sopenharmony_ci break; 13588c2ecf20Sopenharmony_ci default: 13598c2ecf20Sopenharmony_ci goto illegal_evt; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci break; 13628c2ecf20Sopenharmony_ci case SELF_DOWN_PEER_LEAVING: 13638c2ecf20Sopenharmony_ci switch (evt) { 13648c2ecf20Sopenharmony_ci case PEER_LOST_CONTACT_EVT: 13658c2ecf20Sopenharmony_ci state = SELF_DOWN_PEER_DOWN; 13668c2ecf20Sopenharmony_ci break; 13678c2ecf20Sopenharmony_ci case SELF_ESTABL_CONTACT_EVT: 13688c2ecf20Sopenharmony_ci case PEER_ESTABL_CONTACT_EVT: 13698c2ecf20Sopenharmony_ci case SELF_LOST_CONTACT_EVT: 13708c2ecf20Sopenharmony_ci break; 13718c2ecf20Sopenharmony_ci case NODE_SYNCH_END_EVT: 13728c2ecf20Sopenharmony_ci case NODE_SYNCH_BEGIN_EVT: 13738c2ecf20Sopenharmony_ci case NODE_FAILOVER_BEGIN_EVT: 13748c2ecf20Sopenharmony_ci case NODE_FAILOVER_END_EVT: 13758c2ecf20Sopenharmony_ci default: 13768c2ecf20Sopenharmony_ci goto illegal_evt; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci break; 13798c2ecf20Sopenharmony_ci case SELF_UP_PEER_COMING: 13808c2ecf20Sopenharmony_ci switch (evt) { 13818c2ecf20Sopenharmony_ci case PEER_ESTABL_CONTACT_EVT: 13828c2ecf20Sopenharmony_ci state = SELF_UP_PEER_UP; 13838c2ecf20Sopenharmony_ci break; 13848c2ecf20Sopenharmony_ci case SELF_LOST_CONTACT_EVT: 13858c2ecf20Sopenharmony_ci state = SELF_DOWN_PEER_DOWN; 13868c2ecf20Sopenharmony_ci break; 13878c2ecf20Sopenharmony_ci case SELF_ESTABL_CONTACT_EVT: 13888c2ecf20Sopenharmony_ci case PEER_LOST_CONTACT_EVT: 13898c2ecf20Sopenharmony_ci case NODE_SYNCH_END_EVT: 13908c2ecf20Sopenharmony_ci case NODE_FAILOVER_BEGIN_EVT: 13918c2ecf20Sopenharmony_ci break; 13928c2ecf20Sopenharmony_ci case NODE_SYNCH_BEGIN_EVT: 13938c2ecf20Sopenharmony_ci case NODE_FAILOVER_END_EVT: 13948c2ecf20Sopenharmony_ci default: 13958c2ecf20Sopenharmony_ci goto illegal_evt; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci break; 13988c2ecf20Sopenharmony_ci case SELF_COMING_PEER_UP: 13998c2ecf20Sopenharmony_ci switch (evt) { 14008c2ecf20Sopenharmony_ci case SELF_ESTABL_CONTACT_EVT: 14018c2ecf20Sopenharmony_ci state = SELF_UP_PEER_UP; 14028c2ecf20Sopenharmony_ci break; 14038c2ecf20Sopenharmony_ci case PEER_LOST_CONTACT_EVT: 14048c2ecf20Sopenharmony_ci state = SELF_DOWN_PEER_DOWN; 14058c2ecf20Sopenharmony_ci break; 14068c2ecf20Sopenharmony_ci case SELF_LOST_CONTACT_EVT: 14078c2ecf20Sopenharmony_ci case PEER_ESTABL_CONTACT_EVT: 14088c2ecf20Sopenharmony_ci break; 14098c2ecf20Sopenharmony_ci case NODE_SYNCH_END_EVT: 14108c2ecf20Sopenharmony_ci case NODE_SYNCH_BEGIN_EVT: 14118c2ecf20Sopenharmony_ci case NODE_FAILOVER_BEGIN_EVT: 14128c2ecf20Sopenharmony_ci case NODE_FAILOVER_END_EVT: 14138c2ecf20Sopenharmony_ci default: 14148c2ecf20Sopenharmony_ci goto illegal_evt; 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci break; 14178c2ecf20Sopenharmony_ci case SELF_LEAVING_PEER_DOWN: 14188c2ecf20Sopenharmony_ci switch (evt) { 14198c2ecf20Sopenharmony_ci case SELF_LOST_CONTACT_EVT: 14208c2ecf20Sopenharmony_ci state = SELF_DOWN_PEER_DOWN; 14218c2ecf20Sopenharmony_ci break; 14228c2ecf20Sopenharmony_ci case SELF_ESTABL_CONTACT_EVT: 14238c2ecf20Sopenharmony_ci case PEER_ESTABL_CONTACT_EVT: 14248c2ecf20Sopenharmony_ci case PEER_LOST_CONTACT_EVT: 14258c2ecf20Sopenharmony_ci break; 14268c2ecf20Sopenharmony_ci case NODE_SYNCH_END_EVT: 14278c2ecf20Sopenharmony_ci case NODE_SYNCH_BEGIN_EVT: 14288c2ecf20Sopenharmony_ci case NODE_FAILOVER_BEGIN_EVT: 14298c2ecf20Sopenharmony_ci case NODE_FAILOVER_END_EVT: 14308c2ecf20Sopenharmony_ci default: 14318c2ecf20Sopenharmony_ci goto illegal_evt; 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci break; 14348c2ecf20Sopenharmony_ci case NODE_FAILINGOVER: 14358c2ecf20Sopenharmony_ci switch (evt) { 14368c2ecf20Sopenharmony_ci case SELF_LOST_CONTACT_EVT: 14378c2ecf20Sopenharmony_ci state = SELF_DOWN_PEER_LEAVING; 14388c2ecf20Sopenharmony_ci break; 14398c2ecf20Sopenharmony_ci case PEER_LOST_CONTACT_EVT: 14408c2ecf20Sopenharmony_ci state = SELF_LEAVING_PEER_DOWN; 14418c2ecf20Sopenharmony_ci break; 14428c2ecf20Sopenharmony_ci case NODE_FAILOVER_END_EVT: 14438c2ecf20Sopenharmony_ci state = SELF_UP_PEER_UP; 14448c2ecf20Sopenharmony_ci break; 14458c2ecf20Sopenharmony_ci case NODE_FAILOVER_BEGIN_EVT: 14468c2ecf20Sopenharmony_ci case SELF_ESTABL_CONTACT_EVT: 14478c2ecf20Sopenharmony_ci case PEER_ESTABL_CONTACT_EVT: 14488c2ecf20Sopenharmony_ci break; 14498c2ecf20Sopenharmony_ci case NODE_SYNCH_BEGIN_EVT: 14508c2ecf20Sopenharmony_ci case NODE_SYNCH_END_EVT: 14518c2ecf20Sopenharmony_ci default: 14528c2ecf20Sopenharmony_ci goto illegal_evt; 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci break; 14558c2ecf20Sopenharmony_ci case NODE_SYNCHING: 14568c2ecf20Sopenharmony_ci switch (evt) { 14578c2ecf20Sopenharmony_ci case SELF_LOST_CONTACT_EVT: 14588c2ecf20Sopenharmony_ci state = SELF_DOWN_PEER_LEAVING; 14598c2ecf20Sopenharmony_ci break; 14608c2ecf20Sopenharmony_ci case PEER_LOST_CONTACT_EVT: 14618c2ecf20Sopenharmony_ci state = SELF_LEAVING_PEER_DOWN; 14628c2ecf20Sopenharmony_ci break; 14638c2ecf20Sopenharmony_ci case NODE_SYNCH_END_EVT: 14648c2ecf20Sopenharmony_ci state = SELF_UP_PEER_UP; 14658c2ecf20Sopenharmony_ci break; 14668c2ecf20Sopenharmony_ci case NODE_FAILOVER_BEGIN_EVT: 14678c2ecf20Sopenharmony_ci state = NODE_FAILINGOVER; 14688c2ecf20Sopenharmony_ci break; 14698c2ecf20Sopenharmony_ci case NODE_SYNCH_BEGIN_EVT: 14708c2ecf20Sopenharmony_ci case SELF_ESTABL_CONTACT_EVT: 14718c2ecf20Sopenharmony_ci case PEER_ESTABL_CONTACT_EVT: 14728c2ecf20Sopenharmony_ci break; 14738c2ecf20Sopenharmony_ci case NODE_FAILOVER_END_EVT: 14748c2ecf20Sopenharmony_ci default: 14758c2ecf20Sopenharmony_ci goto illegal_evt; 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci break; 14788c2ecf20Sopenharmony_ci default: 14798c2ecf20Sopenharmony_ci pr_err("Unknown node fsm state %x\n", state); 14808c2ecf20Sopenharmony_ci break; 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci trace_tipc_node_fsm(n->peer_id, n->state, state, evt); 14838c2ecf20Sopenharmony_ci n->state = state; 14848c2ecf20Sopenharmony_ci return; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ciillegal_evt: 14878c2ecf20Sopenharmony_ci pr_err("Illegal node fsm evt %x in state %x\n", evt, state); 14888c2ecf20Sopenharmony_ci trace_tipc_node_fsm(n->peer_id, n->state, state, evt); 14898c2ecf20Sopenharmony_ci} 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_cistatic void node_lost_contact(struct tipc_node *n, 14928c2ecf20Sopenharmony_ci struct sk_buff_head *inputq) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci struct tipc_sock_conn *conn, *safe; 14958c2ecf20Sopenharmony_ci struct tipc_link *l; 14968c2ecf20Sopenharmony_ci struct list_head *conns = &n->conn_sks; 14978c2ecf20Sopenharmony_ci struct sk_buff *skb; 14988c2ecf20Sopenharmony_ci uint i; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci pr_debug("Lost contact with %x\n", n->addr); 15018c2ecf20Sopenharmony_ci n->delete_at = jiffies + msecs_to_jiffies(NODE_CLEANUP_AFTER); 15028c2ecf20Sopenharmony_ci trace_tipc_node_lost_contact(n, true, " "); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci /* Clean up broadcast state */ 15058c2ecf20Sopenharmony_ci tipc_bcast_remove_peer(n->net, n->bc_entry.link); 15068c2ecf20Sopenharmony_ci skb_queue_purge(&n->bc_entry.namedq); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci /* Abort any ongoing link failover */ 15098c2ecf20Sopenharmony_ci for (i = 0; i < MAX_BEARERS; i++) { 15108c2ecf20Sopenharmony_ci l = n->links[i].link; 15118c2ecf20Sopenharmony_ci if (l) 15128c2ecf20Sopenharmony_ci tipc_link_fsm_evt(l, LINK_FAILOVER_END_EVT); 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci /* Notify publications from this node */ 15168c2ecf20Sopenharmony_ci n->action_flags |= TIPC_NOTIFY_NODE_DOWN; 15178c2ecf20Sopenharmony_ci n->peer_net = NULL; 15188c2ecf20Sopenharmony_ci n->peer_hash_mix = 0; 15198c2ecf20Sopenharmony_ci /* Notify sockets connected to node */ 15208c2ecf20Sopenharmony_ci list_for_each_entry_safe(conn, safe, conns, list) { 15218c2ecf20Sopenharmony_ci skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG, 15228c2ecf20Sopenharmony_ci SHORT_H_SIZE, 0, tipc_own_addr(n->net), 15238c2ecf20Sopenharmony_ci conn->peer_node, conn->port, 15248c2ecf20Sopenharmony_ci conn->peer_port, TIPC_ERR_NO_NODE); 15258c2ecf20Sopenharmony_ci if (likely(skb)) 15268c2ecf20Sopenharmony_ci skb_queue_tail(inputq, skb); 15278c2ecf20Sopenharmony_ci list_del(&conn->list); 15288c2ecf20Sopenharmony_ci kfree(conn); 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci} 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci/** 15338c2ecf20Sopenharmony_ci * tipc_node_get_linkname - get the name of a link 15348c2ecf20Sopenharmony_ci * 15358c2ecf20Sopenharmony_ci * @bearer_id: id of the bearer 15368c2ecf20Sopenharmony_ci * @addr: peer node address 15378c2ecf20Sopenharmony_ci * @linkname: link name output buffer 15388c2ecf20Sopenharmony_ci * 15398c2ecf20Sopenharmony_ci * Returns 0 on success 15408c2ecf20Sopenharmony_ci */ 15418c2ecf20Sopenharmony_ciint tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 addr, 15428c2ecf20Sopenharmony_ci char *linkname, size_t len) 15438c2ecf20Sopenharmony_ci{ 15448c2ecf20Sopenharmony_ci struct tipc_link *link; 15458c2ecf20Sopenharmony_ci int err = -EINVAL; 15468c2ecf20Sopenharmony_ci struct tipc_node *node = tipc_node_find(net, addr); 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci if (!node) 15498c2ecf20Sopenharmony_ci return err; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci if (bearer_id >= MAX_BEARERS) 15528c2ecf20Sopenharmony_ci goto exit; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci tipc_node_read_lock(node); 15558c2ecf20Sopenharmony_ci link = node->links[bearer_id].link; 15568c2ecf20Sopenharmony_ci if (link) { 15578c2ecf20Sopenharmony_ci strncpy(linkname, tipc_link_name(link), len); 15588c2ecf20Sopenharmony_ci err = 0; 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci tipc_node_read_unlock(node); 15618c2ecf20Sopenharmony_ciexit: 15628c2ecf20Sopenharmony_ci tipc_node_put(node); 15638c2ecf20Sopenharmony_ci return err; 15648c2ecf20Sopenharmony_ci} 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci/* Caller should hold node lock for the passed node */ 15678c2ecf20Sopenharmony_cistatic int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node) 15688c2ecf20Sopenharmony_ci{ 15698c2ecf20Sopenharmony_ci void *hdr; 15708c2ecf20Sopenharmony_ci struct nlattr *attrs; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family, 15738c2ecf20Sopenharmony_ci NLM_F_MULTI, TIPC_NL_NODE_GET); 15748c2ecf20Sopenharmony_ci if (!hdr) 15758c2ecf20Sopenharmony_ci return -EMSGSIZE; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_NODE); 15788c2ecf20Sopenharmony_ci if (!attrs) 15798c2ecf20Sopenharmony_ci goto msg_full; 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_NODE_ADDR, node->addr)) 15828c2ecf20Sopenharmony_ci goto attr_msg_full; 15838c2ecf20Sopenharmony_ci if (node_is_up(node)) 15848c2ecf20Sopenharmony_ci if (nla_put_flag(msg->skb, TIPC_NLA_NODE_UP)) 15858c2ecf20Sopenharmony_ci goto attr_msg_full; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci nla_nest_end(msg->skb, attrs); 15888c2ecf20Sopenharmony_ci genlmsg_end(msg->skb, hdr); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci return 0; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ciattr_msg_full: 15938c2ecf20Sopenharmony_ci nla_nest_cancel(msg->skb, attrs); 15948c2ecf20Sopenharmony_cimsg_full: 15958c2ecf20Sopenharmony_ci genlmsg_cancel(msg->skb, hdr); 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci return -EMSGSIZE; 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_cistatic void tipc_lxc_xmit(struct net *peer_net, struct sk_buff_head *list) 16018c2ecf20Sopenharmony_ci{ 16028c2ecf20Sopenharmony_ci struct tipc_msg *hdr = buf_msg(skb_peek(list)); 16038c2ecf20Sopenharmony_ci struct sk_buff_head inputq; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci switch (msg_user(hdr)) { 16068c2ecf20Sopenharmony_ci case TIPC_LOW_IMPORTANCE: 16078c2ecf20Sopenharmony_ci case TIPC_MEDIUM_IMPORTANCE: 16088c2ecf20Sopenharmony_ci case TIPC_HIGH_IMPORTANCE: 16098c2ecf20Sopenharmony_ci case TIPC_CRITICAL_IMPORTANCE: 16108c2ecf20Sopenharmony_ci if (msg_connected(hdr) || msg_named(hdr) || 16118c2ecf20Sopenharmony_ci msg_direct(hdr)) { 16128c2ecf20Sopenharmony_ci tipc_loopback_trace(peer_net, list); 16138c2ecf20Sopenharmony_ci spin_lock_init(&list->lock); 16148c2ecf20Sopenharmony_ci tipc_sk_rcv(peer_net, list); 16158c2ecf20Sopenharmony_ci return; 16168c2ecf20Sopenharmony_ci } 16178c2ecf20Sopenharmony_ci if (msg_mcast(hdr)) { 16188c2ecf20Sopenharmony_ci tipc_loopback_trace(peer_net, list); 16198c2ecf20Sopenharmony_ci skb_queue_head_init(&inputq); 16208c2ecf20Sopenharmony_ci tipc_sk_mcast_rcv(peer_net, list, &inputq); 16218c2ecf20Sopenharmony_ci __skb_queue_purge(list); 16228c2ecf20Sopenharmony_ci skb_queue_purge(&inputq); 16238c2ecf20Sopenharmony_ci return; 16248c2ecf20Sopenharmony_ci } 16258c2ecf20Sopenharmony_ci return; 16268c2ecf20Sopenharmony_ci case MSG_FRAGMENTER: 16278c2ecf20Sopenharmony_ci if (tipc_msg_assemble(list)) { 16288c2ecf20Sopenharmony_ci tipc_loopback_trace(peer_net, list); 16298c2ecf20Sopenharmony_ci skb_queue_head_init(&inputq); 16308c2ecf20Sopenharmony_ci tipc_sk_mcast_rcv(peer_net, list, &inputq); 16318c2ecf20Sopenharmony_ci __skb_queue_purge(list); 16328c2ecf20Sopenharmony_ci skb_queue_purge(&inputq); 16338c2ecf20Sopenharmony_ci } 16348c2ecf20Sopenharmony_ci return; 16358c2ecf20Sopenharmony_ci case GROUP_PROTOCOL: 16368c2ecf20Sopenharmony_ci case CONN_MANAGER: 16378c2ecf20Sopenharmony_ci tipc_loopback_trace(peer_net, list); 16388c2ecf20Sopenharmony_ci spin_lock_init(&list->lock); 16398c2ecf20Sopenharmony_ci tipc_sk_rcv(peer_net, list); 16408c2ecf20Sopenharmony_ci return; 16418c2ecf20Sopenharmony_ci case LINK_PROTOCOL: 16428c2ecf20Sopenharmony_ci case NAME_DISTRIBUTOR: 16438c2ecf20Sopenharmony_ci case TUNNEL_PROTOCOL: 16448c2ecf20Sopenharmony_ci case BCAST_PROTOCOL: 16458c2ecf20Sopenharmony_ci return; 16468c2ecf20Sopenharmony_ci default: 16478c2ecf20Sopenharmony_ci return; 16488c2ecf20Sopenharmony_ci }; 16498c2ecf20Sopenharmony_ci} 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci/** 16528c2ecf20Sopenharmony_ci * tipc_node_xmit() is the general link level function for message sending 16538c2ecf20Sopenharmony_ci * @net: the applicable net namespace 16548c2ecf20Sopenharmony_ci * @list: chain of buffers containing message 16558c2ecf20Sopenharmony_ci * @dnode: address of destination node 16568c2ecf20Sopenharmony_ci * @selector: a number used for deterministic link selection 16578c2ecf20Sopenharmony_ci * Consumes the buffer chain. 16588c2ecf20Sopenharmony_ci * Returns 0 if success, otherwise: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE,-ENOBUF 16598c2ecf20Sopenharmony_ci */ 16608c2ecf20Sopenharmony_ciint tipc_node_xmit(struct net *net, struct sk_buff_head *list, 16618c2ecf20Sopenharmony_ci u32 dnode, int selector) 16628c2ecf20Sopenharmony_ci{ 16638c2ecf20Sopenharmony_ci struct tipc_link_entry *le = NULL; 16648c2ecf20Sopenharmony_ci struct tipc_node *n; 16658c2ecf20Sopenharmony_ci struct sk_buff_head xmitq; 16668c2ecf20Sopenharmony_ci bool node_up = false; 16678c2ecf20Sopenharmony_ci struct net *peer_net; 16688c2ecf20Sopenharmony_ci int bearer_id; 16698c2ecf20Sopenharmony_ci int rc; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci if (in_own_node(net, dnode)) { 16728c2ecf20Sopenharmony_ci tipc_loopback_trace(net, list); 16738c2ecf20Sopenharmony_ci spin_lock_init(&list->lock); 16748c2ecf20Sopenharmony_ci tipc_sk_rcv(net, list); 16758c2ecf20Sopenharmony_ci return 0; 16768c2ecf20Sopenharmony_ci } 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci n = tipc_node_find(net, dnode); 16798c2ecf20Sopenharmony_ci if (unlikely(!n)) { 16808c2ecf20Sopenharmony_ci __skb_queue_purge(list); 16818c2ecf20Sopenharmony_ci return -EHOSTUNREACH; 16828c2ecf20Sopenharmony_ci } 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci rcu_read_lock(); 16858c2ecf20Sopenharmony_ci tipc_node_read_lock(n); 16868c2ecf20Sopenharmony_ci node_up = node_is_up(n); 16878c2ecf20Sopenharmony_ci peer_net = n->peer_net; 16888c2ecf20Sopenharmony_ci tipc_node_read_unlock(n); 16898c2ecf20Sopenharmony_ci if (node_up && peer_net && check_net(peer_net)) { 16908c2ecf20Sopenharmony_ci /* xmit inner linux container */ 16918c2ecf20Sopenharmony_ci tipc_lxc_xmit(peer_net, list); 16928c2ecf20Sopenharmony_ci if (likely(skb_queue_empty(list))) { 16938c2ecf20Sopenharmony_ci rcu_read_unlock(); 16948c2ecf20Sopenharmony_ci tipc_node_put(n); 16958c2ecf20Sopenharmony_ci return 0; 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci rcu_read_unlock(); 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci tipc_node_read_lock(n); 17018c2ecf20Sopenharmony_ci bearer_id = n->active_links[selector & 1]; 17028c2ecf20Sopenharmony_ci if (unlikely(bearer_id == INVALID_BEARER_ID)) { 17038c2ecf20Sopenharmony_ci tipc_node_read_unlock(n); 17048c2ecf20Sopenharmony_ci tipc_node_put(n); 17058c2ecf20Sopenharmony_ci __skb_queue_purge(list); 17068c2ecf20Sopenharmony_ci return -EHOSTUNREACH; 17078c2ecf20Sopenharmony_ci } 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci __skb_queue_head_init(&xmitq); 17108c2ecf20Sopenharmony_ci le = &n->links[bearer_id]; 17118c2ecf20Sopenharmony_ci spin_lock_bh(&le->lock); 17128c2ecf20Sopenharmony_ci rc = tipc_link_xmit(le->link, list, &xmitq); 17138c2ecf20Sopenharmony_ci spin_unlock_bh(&le->lock); 17148c2ecf20Sopenharmony_ci tipc_node_read_unlock(n); 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci if (unlikely(rc == -ENOBUFS)) 17178c2ecf20Sopenharmony_ci tipc_node_link_down(n, bearer_id, false); 17188c2ecf20Sopenharmony_ci else 17198c2ecf20Sopenharmony_ci tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr, n); 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci tipc_node_put(n); 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci return rc; 17248c2ecf20Sopenharmony_ci} 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci/* tipc_node_xmit_skb(): send single buffer to destination 17278c2ecf20Sopenharmony_ci * Buffers sent via this functon are generally TIPC_SYSTEM_IMPORTANCE 17288c2ecf20Sopenharmony_ci * messages, which will not be rejected 17298c2ecf20Sopenharmony_ci * The only exception is datagram messages rerouted after secondary 17308c2ecf20Sopenharmony_ci * lookup, which are rare and safe to dispose of anyway. 17318c2ecf20Sopenharmony_ci */ 17328c2ecf20Sopenharmony_ciint tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode, 17338c2ecf20Sopenharmony_ci u32 selector) 17348c2ecf20Sopenharmony_ci{ 17358c2ecf20Sopenharmony_ci struct sk_buff_head head; 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci __skb_queue_head_init(&head); 17388c2ecf20Sopenharmony_ci __skb_queue_tail(&head, skb); 17398c2ecf20Sopenharmony_ci tipc_node_xmit(net, &head, dnode, selector); 17408c2ecf20Sopenharmony_ci return 0; 17418c2ecf20Sopenharmony_ci} 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci/* tipc_node_distr_xmit(): send single buffer msgs to individual destinations 17448c2ecf20Sopenharmony_ci * Note: this is only for SYSTEM_IMPORTANCE messages, which cannot be rejected 17458c2ecf20Sopenharmony_ci */ 17468c2ecf20Sopenharmony_ciint tipc_node_distr_xmit(struct net *net, struct sk_buff_head *xmitq) 17478c2ecf20Sopenharmony_ci{ 17488c2ecf20Sopenharmony_ci struct sk_buff *skb; 17498c2ecf20Sopenharmony_ci u32 selector, dnode; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(xmitq))) { 17528c2ecf20Sopenharmony_ci selector = msg_origport(buf_msg(skb)); 17538c2ecf20Sopenharmony_ci dnode = msg_destnode(buf_msg(skb)); 17548c2ecf20Sopenharmony_ci tipc_node_xmit_skb(net, skb, dnode, selector); 17558c2ecf20Sopenharmony_ci } 17568c2ecf20Sopenharmony_ci return 0; 17578c2ecf20Sopenharmony_ci} 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_civoid tipc_node_broadcast(struct net *net, struct sk_buff *skb, int rc_dests) 17608c2ecf20Sopenharmony_ci{ 17618c2ecf20Sopenharmony_ci struct sk_buff_head xmitq; 17628c2ecf20Sopenharmony_ci struct sk_buff *txskb; 17638c2ecf20Sopenharmony_ci struct tipc_node *n; 17648c2ecf20Sopenharmony_ci u16 dummy; 17658c2ecf20Sopenharmony_ci u32 dst; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci /* Use broadcast if all nodes support it */ 17688c2ecf20Sopenharmony_ci if (!rc_dests && tipc_bcast_get_mode(net) != BCLINK_MODE_RCAST) { 17698c2ecf20Sopenharmony_ci __skb_queue_head_init(&xmitq); 17708c2ecf20Sopenharmony_ci __skb_queue_tail(&xmitq, skb); 17718c2ecf20Sopenharmony_ci tipc_bcast_xmit(net, &xmitq, &dummy); 17728c2ecf20Sopenharmony_ci return; 17738c2ecf20Sopenharmony_ci } 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci /* Otherwise use legacy replicast method */ 17768c2ecf20Sopenharmony_ci rcu_read_lock(); 17778c2ecf20Sopenharmony_ci list_for_each_entry_rcu(n, tipc_nodes(net), list) { 17788c2ecf20Sopenharmony_ci dst = n->addr; 17798c2ecf20Sopenharmony_ci if (in_own_node(net, dst)) 17808c2ecf20Sopenharmony_ci continue; 17818c2ecf20Sopenharmony_ci if (!node_is_up(n)) 17828c2ecf20Sopenharmony_ci continue; 17838c2ecf20Sopenharmony_ci txskb = pskb_copy(skb, GFP_ATOMIC); 17848c2ecf20Sopenharmony_ci if (!txskb) 17858c2ecf20Sopenharmony_ci break; 17868c2ecf20Sopenharmony_ci msg_set_destnode(buf_msg(txskb), dst); 17878c2ecf20Sopenharmony_ci tipc_node_xmit_skb(net, txskb, dst, 0); 17888c2ecf20Sopenharmony_ci } 17898c2ecf20Sopenharmony_ci rcu_read_unlock(); 17908c2ecf20Sopenharmony_ci kfree_skb(skb); 17918c2ecf20Sopenharmony_ci} 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_cistatic void tipc_node_mcast_rcv(struct tipc_node *n) 17948c2ecf20Sopenharmony_ci{ 17958c2ecf20Sopenharmony_ci struct tipc_bclink_entry *be = &n->bc_entry; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci /* 'arrvq' is under inputq2's lock protection */ 17988c2ecf20Sopenharmony_ci spin_lock_bh(&be->inputq2.lock); 17998c2ecf20Sopenharmony_ci spin_lock_bh(&be->inputq1.lock); 18008c2ecf20Sopenharmony_ci skb_queue_splice_tail_init(&be->inputq1, &be->arrvq); 18018c2ecf20Sopenharmony_ci spin_unlock_bh(&be->inputq1.lock); 18028c2ecf20Sopenharmony_ci spin_unlock_bh(&be->inputq2.lock); 18038c2ecf20Sopenharmony_ci tipc_sk_mcast_rcv(n->net, &be->arrvq, &be->inputq2); 18048c2ecf20Sopenharmony_ci} 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_cistatic void tipc_node_bc_sync_rcv(struct tipc_node *n, struct tipc_msg *hdr, 18078c2ecf20Sopenharmony_ci int bearer_id, struct sk_buff_head *xmitq) 18088c2ecf20Sopenharmony_ci{ 18098c2ecf20Sopenharmony_ci struct tipc_link *ucl; 18108c2ecf20Sopenharmony_ci int rc; 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci rc = tipc_bcast_sync_rcv(n->net, n->bc_entry.link, hdr, xmitq); 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci if (rc & TIPC_LINK_DOWN_EVT) { 18158c2ecf20Sopenharmony_ci tipc_node_reset_links(n); 18168c2ecf20Sopenharmony_ci return; 18178c2ecf20Sopenharmony_ci } 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci if (!(rc & TIPC_LINK_SND_STATE)) 18208c2ecf20Sopenharmony_ci return; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci /* If probe message, a STATE response will be sent anyway */ 18238c2ecf20Sopenharmony_ci if (msg_probe(hdr)) 18248c2ecf20Sopenharmony_ci return; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci /* Produce a STATE message carrying broadcast NACK */ 18278c2ecf20Sopenharmony_ci tipc_node_read_lock(n); 18288c2ecf20Sopenharmony_ci ucl = n->links[bearer_id].link; 18298c2ecf20Sopenharmony_ci if (ucl) 18308c2ecf20Sopenharmony_ci tipc_link_build_state_msg(ucl, xmitq); 18318c2ecf20Sopenharmony_ci tipc_node_read_unlock(n); 18328c2ecf20Sopenharmony_ci} 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci/** 18358c2ecf20Sopenharmony_ci * tipc_node_bc_rcv - process TIPC broadcast packet arriving from off-node 18368c2ecf20Sopenharmony_ci * @net: the applicable net namespace 18378c2ecf20Sopenharmony_ci * @skb: TIPC packet 18388c2ecf20Sopenharmony_ci * @bearer_id: id of bearer message arrived on 18398c2ecf20Sopenharmony_ci * 18408c2ecf20Sopenharmony_ci * Invoked with no locks held. 18418c2ecf20Sopenharmony_ci */ 18428c2ecf20Sopenharmony_cistatic void tipc_node_bc_rcv(struct net *net, struct sk_buff *skb, int bearer_id) 18438c2ecf20Sopenharmony_ci{ 18448c2ecf20Sopenharmony_ci int rc; 18458c2ecf20Sopenharmony_ci struct sk_buff_head xmitq; 18468c2ecf20Sopenharmony_ci struct tipc_bclink_entry *be; 18478c2ecf20Sopenharmony_ci struct tipc_link_entry *le; 18488c2ecf20Sopenharmony_ci struct tipc_msg *hdr = buf_msg(skb); 18498c2ecf20Sopenharmony_ci int usr = msg_user(hdr); 18508c2ecf20Sopenharmony_ci u32 dnode = msg_destnode(hdr); 18518c2ecf20Sopenharmony_ci struct tipc_node *n; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci __skb_queue_head_init(&xmitq); 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci /* If NACK for other node, let rcv link for that node peek into it */ 18568c2ecf20Sopenharmony_ci if ((usr == BCAST_PROTOCOL) && (dnode != tipc_own_addr(net))) 18578c2ecf20Sopenharmony_ci n = tipc_node_find(net, dnode); 18588c2ecf20Sopenharmony_ci else 18598c2ecf20Sopenharmony_ci n = tipc_node_find(net, msg_prevnode(hdr)); 18608c2ecf20Sopenharmony_ci if (!n) { 18618c2ecf20Sopenharmony_ci kfree_skb(skb); 18628c2ecf20Sopenharmony_ci return; 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci be = &n->bc_entry; 18658c2ecf20Sopenharmony_ci le = &n->links[bearer_id]; 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci rc = tipc_bcast_rcv(net, be->link, skb); 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci /* Broadcast ACKs are sent on a unicast link */ 18708c2ecf20Sopenharmony_ci if (rc & TIPC_LINK_SND_STATE) { 18718c2ecf20Sopenharmony_ci tipc_node_read_lock(n); 18728c2ecf20Sopenharmony_ci tipc_link_build_state_msg(le->link, &xmitq); 18738c2ecf20Sopenharmony_ci tipc_node_read_unlock(n); 18748c2ecf20Sopenharmony_ci } 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci if (!skb_queue_empty(&xmitq)) 18778c2ecf20Sopenharmony_ci tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr, n); 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci if (!skb_queue_empty(&be->inputq1)) 18808c2ecf20Sopenharmony_ci tipc_node_mcast_rcv(n); 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci /* Handle NAME_DISTRIBUTOR messages sent from 1.7 nodes */ 18838c2ecf20Sopenharmony_ci if (!skb_queue_empty(&n->bc_entry.namedq)) 18848c2ecf20Sopenharmony_ci tipc_named_rcv(net, &n->bc_entry.namedq, 18858c2ecf20Sopenharmony_ci &n->bc_entry.named_rcv_nxt, 18868c2ecf20Sopenharmony_ci &n->bc_entry.named_open); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci /* If reassembly or retransmission failure => reset all links to peer */ 18898c2ecf20Sopenharmony_ci if (rc & TIPC_LINK_DOWN_EVT) 18908c2ecf20Sopenharmony_ci tipc_node_reset_links(n); 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci tipc_node_put(n); 18938c2ecf20Sopenharmony_ci} 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci/** 18968c2ecf20Sopenharmony_ci * tipc_node_check_state - check and if necessary update node state 18978c2ecf20Sopenharmony_ci * @skb: TIPC packet 18988c2ecf20Sopenharmony_ci * @bearer_id: identity of bearer delivering the packet 18998c2ecf20Sopenharmony_ci * Returns true if state and msg are ok, otherwise false 19008c2ecf20Sopenharmony_ci */ 19018c2ecf20Sopenharmony_cistatic bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb, 19028c2ecf20Sopenharmony_ci int bearer_id, struct sk_buff_head *xmitq) 19038c2ecf20Sopenharmony_ci{ 19048c2ecf20Sopenharmony_ci struct tipc_msg *hdr = buf_msg(skb); 19058c2ecf20Sopenharmony_ci int usr = msg_user(hdr); 19068c2ecf20Sopenharmony_ci int mtyp = msg_type(hdr); 19078c2ecf20Sopenharmony_ci u16 oseqno = msg_seqno(hdr); 19088c2ecf20Sopenharmony_ci u16 exp_pkts = msg_msgcnt(hdr); 19098c2ecf20Sopenharmony_ci u16 rcv_nxt, syncpt, dlv_nxt, inputq_len; 19108c2ecf20Sopenharmony_ci int state = n->state; 19118c2ecf20Sopenharmony_ci struct tipc_link *l, *tnl, *pl = NULL; 19128c2ecf20Sopenharmony_ci struct tipc_media_addr *maddr; 19138c2ecf20Sopenharmony_ci int pb_id; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci if (trace_tipc_node_check_state_enabled()) { 19168c2ecf20Sopenharmony_ci trace_tipc_skb_dump(skb, false, "skb for node state check"); 19178c2ecf20Sopenharmony_ci trace_tipc_node_check_state(n, true, " "); 19188c2ecf20Sopenharmony_ci } 19198c2ecf20Sopenharmony_ci l = n->links[bearer_id].link; 19208c2ecf20Sopenharmony_ci if (!l) 19218c2ecf20Sopenharmony_ci return false; 19228c2ecf20Sopenharmony_ci rcv_nxt = tipc_link_rcv_nxt(l); 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci if (likely((state == SELF_UP_PEER_UP) && (usr != TUNNEL_PROTOCOL))) 19268c2ecf20Sopenharmony_ci return true; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci /* Find parallel link, if any */ 19298c2ecf20Sopenharmony_ci for (pb_id = 0; pb_id < MAX_BEARERS; pb_id++) { 19308c2ecf20Sopenharmony_ci if ((pb_id != bearer_id) && n->links[pb_id].link) { 19318c2ecf20Sopenharmony_ci pl = n->links[pb_id].link; 19328c2ecf20Sopenharmony_ci break; 19338c2ecf20Sopenharmony_ci } 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci if (!tipc_link_validate_msg(l, hdr)) { 19378c2ecf20Sopenharmony_ci trace_tipc_skb_dump(skb, false, "PROTO invalid (2)!"); 19388c2ecf20Sopenharmony_ci trace_tipc_link_dump(l, TIPC_DUMP_NONE, "PROTO invalid (2)!"); 19398c2ecf20Sopenharmony_ci return false; 19408c2ecf20Sopenharmony_ci } 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci /* Check and update node accesibility if applicable */ 19438c2ecf20Sopenharmony_ci if (state == SELF_UP_PEER_COMING) { 19448c2ecf20Sopenharmony_ci if (!tipc_link_is_up(l)) 19458c2ecf20Sopenharmony_ci return true; 19468c2ecf20Sopenharmony_ci if (!msg_peer_link_is_up(hdr)) 19478c2ecf20Sopenharmony_ci return true; 19488c2ecf20Sopenharmony_ci tipc_node_fsm_evt(n, PEER_ESTABL_CONTACT_EVT); 19498c2ecf20Sopenharmony_ci } 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci if (state == SELF_DOWN_PEER_LEAVING) { 19528c2ecf20Sopenharmony_ci if (msg_peer_node_is_up(hdr)) 19538c2ecf20Sopenharmony_ci return false; 19548c2ecf20Sopenharmony_ci tipc_node_fsm_evt(n, PEER_LOST_CONTACT_EVT); 19558c2ecf20Sopenharmony_ci return true; 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci if (state == SELF_LEAVING_PEER_DOWN) 19598c2ecf20Sopenharmony_ci return false; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci /* Ignore duplicate packets */ 19628c2ecf20Sopenharmony_ci if ((usr != LINK_PROTOCOL) && less(oseqno, rcv_nxt)) 19638c2ecf20Sopenharmony_ci return true; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci /* Initiate or update failover mode if applicable */ 19668c2ecf20Sopenharmony_ci if ((usr == TUNNEL_PROTOCOL) && (mtyp == FAILOVER_MSG)) { 19678c2ecf20Sopenharmony_ci syncpt = oseqno + exp_pkts - 1; 19688c2ecf20Sopenharmony_ci if (pl && !tipc_link_is_reset(pl)) { 19698c2ecf20Sopenharmony_ci __tipc_node_link_down(n, &pb_id, xmitq, &maddr); 19708c2ecf20Sopenharmony_ci trace_tipc_node_link_down(n, true, 19718c2ecf20Sopenharmony_ci "node link down <- failover!"); 19728c2ecf20Sopenharmony_ci tipc_skb_queue_splice_tail_init(tipc_link_inputq(pl), 19738c2ecf20Sopenharmony_ci tipc_link_inputq(l)); 19748c2ecf20Sopenharmony_ci } 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci /* If parallel link was already down, and this happened before 19778c2ecf20Sopenharmony_ci * the tunnel link came up, node failover was never started. 19788c2ecf20Sopenharmony_ci * Ensure that a FAILOVER_MSG is sent to get peer out of 19798c2ecf20Sopenharmony_ci * NODE_FAILINGOVER state, also this node must accept 19808c2ecf20Sopenharmony_ci * TUNNEL_MSGs from peer. 19818c2ecf20Sopenharmony_ci */ 19828c2ecf20Sopenharmony_ci if (n->state != NODE_FAILINGOVER) 19838c2ecf20Sopenharmony_ci tipc_node_link_failover(n, pl, l, xmitq); 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci /* If pkts arrive out of order, use lowest calculated syncpt */ 19868c2ecf20Sopenharmony_ci if (less(syncpt, n->sync_point)) 19878c2ecf20Sopenharmony_ci n->sync_point = syncpt; 19888c2ecf20Sopenharmony_ci } 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci /* Open parallel link when tunnel link reaches synch point */ 19918c2ecf20Sopenharmony_ci if ((n->state == NODE_FAILINGOVER) && tipc_link_is_up(l)) { 19928c2ecf20Sopenharmony_ci if (!more(rcv_nxt, n->sync_point)) 19938c2ecf20Sopenharmony_ci return true; 19948c2ecf20Sopenharmony_ci tipc_node_fsm_evt(n, NODE_FAILOVER_END_EVT); 19958c2ecf20Sopenharmony_ci if (pl) 19968c2ecf20Sopenharmony_ci tipc_link_fsm_evt(pl, LINK_FAILOVER_END_EVT); 19978c2ecf20Sopenharmony_ci return true; 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci /* No synching needed if only one link */ 20018c2ecf20Sopenharmony_ci if (!pl || !tipc_link_is_up(pl)) 20028c2ecf20Sopenharmony_ci return true; 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci /* Initiate synch mode if applicable */ 20058c2ecf20Sopenharmony_ci if ((usr == TUNNEL_PROTOCOL) && (mtyp == SYNCH_MSG) && (oseqno == 1)) { 20068c2ecf20Sopenharmony_ci if (n->capabilities & TIPC_TUNNEL_ENHANCED) 20078c2ecf20Sopenharmony_ci syncpt = msg_syncpt(hdr); 20088c2ecf20Sopenharmony_ci else 20098c2ecf20Sopenharmony_ci syncpt = msg_seqno(msg_inner_hdr(hdr)) + exp_pkts - 1; 20108c2ecf20Sopenharmony_ci if (!tipc_link_is_up(l)) 20118c2ecf20Sopenharmony_ci __tipc_node_link_up(n, bearer_id, xmitq); 20128c2ecf20Sopenharmony_ci if (n->state == SELF_UP_PEER_UP) { 20138c2ecf20Sopenharmony_ci n->sync_point = syncpt; 20148c2ecf20Sopenharmony_ci tipc_link_fsm_evt(l, LINK_SYNCH_BEGIN_EVT); 20158c2ecf20Sopenharmony_ci tipc_node_fsm_evt(n, NODE_SYNCH_BEGIN_EVT); 20168c2ecf20Sopenharmony_ci } 20178c2ecf20Sopenharmony_ci } 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci /* Open tunnel link when parallel link reaches synch point */ 20208c2ecf20Sopenharmony_ci if (n->state == NODE_SYNCHING) { 20218c2ecf20Sopenharmony_ci if (tipc_link_is_synching(l)) { 20228c2ecf20Sopenharmony_ci tnl = l; 20238c2ecf20Sopenharmony_ci } else { 20248c2ecf20Sopenharmony_ci tnl = pl; 20258c2ecf20Sopenharmony_ci pl = l; 20268c2ecf20Sopenharmony_ci } 20278c2ecf20Sopenharmony_ci inputq_len = skb_queue_len(tipc_link_inputq(pl)); 20288c2ecf20Sopenharmony_ci dlv_nxt = tipc_link_rcv_nxt(pl) - inputq_len; 20298c2ecf20Sopenharmony_ci if (more(dlv_nxt, n->sync_point)) { 20308c2ecf20Sopenharmony_ci tipc_link_fsm_evt(tnl, LINK_SYNCH_END_EVT); 20318c2ecf20Sopenharmony_ci tipc_node_fsm_evt(n, NODE_SYNCH_END_EVT); 20328c2ecf20Sopenharmony_ci return true; 20338c2ecf20Sopenharmony_ci } 20348c2ecf20Sopenharmony_ci if (l == pl) 20358c2ecf20Sopenharmony_ci return true; 20368c2ecf20Sopenharmony_ci if ((usr == TUNNEL_PROTOCOL) && (mtyp == SYNCH_MSG)) 20378c2ecf20Sopenharmony_ci return true; 20388c2ecf20Sopenharmony_ci if (usr == LINK_PROTOCOL) 20398c2ecf20Sopenharmony_ci return true; 20408c2ecf20Sopenharmony_ci return false; 20418c2ecf20Sopenharmony_ci } 20428c2ecf20Sopenharmony_ci return true; 20438c2ecf20Sopenharmony_ci} 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci/** 20468c2ecf20Sopenharmony_ci * tipc_rcv - process TIPC packets/messages arriving from off-node 20478c2ecf20Sopenharmony_ci * @net: the applicable net namespace 20488c2ecf20Sopenharmony_ci * @skb: TIPC packet 20498c2ecf20Sopenharmony_ci * @b: pointer to bearer message arrived on 20508c2ecf20Sopenharmony_ci * 20518c2ecf20Sopenharmony_ci * Invoked with no locks held. Bearer pointer must point to a valid bearer 20528c2ecf20Sopenharmony_ci * structure (i.e. cannot be NULL), but bearer can be inactive. 20538c2ecf20Sopenharmony_ci */ 20548c2ecf20Sopenharmony_civoid tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b) 20558c2ecf20Sopenharmony_ci{ 20568c2ecf20Sopenharmony_ci struct sk_buff_head xmitq; 20578c2ecf20Sopenharmony_ci struct tipc_link_entry *le; 20588c2ecf20Sopenharmony_ci struct tipc_msg *hdr; 20598c2ecf20Sopenharmony_ci struct tipc_node *n; 20608c2ecf20Sopenharmony_ci int bearer_id = b->identity; 20618c2ecf20Sopenharmony_ci u32 self = tipc_own_addr(net); 20628c2ecf20Sopenharmony_ci int usr, rc = 0; 20638c2ecf20Sopenharmony_ci u16 bc_ack; 20648c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_CRYPTO 20658c2ecf20Sopenharmony_ci struct tipc_ehdr *ehdr; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci /* Check if message must be decrypted first */ 20688c2ecf20Sopenharmony_ci if (TIPC_SKB_CB(skb)->decrypted || !tipc_ehdr_validate(skb)) 20698c2ecf20Sopenharmony_ci goto rcv; 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci ehdr = (struct tipc_ehdr *)skb->data; 20728c2ecf20Sopenharmony_ci if (likely(ehdr->user != LINK_CONFIG)) { 20738c2ecf20Sopenharmony_ci n = tipc_node_find(net, ntohl(ehdr->addr)); 20748c2ecf20Sopenharmony_ci if (unlikely(!n)) 20758c2ecf20Sopenharmony_ci goto discard; 20768c2ecf20Sopenharmony_ci } else { 20778c2ecf20Sopenharmony_ci n = tipc_node_find_by_id(net, ehdr->id); 20788c2ecf20Sopenharmony_ci } 20798c2ecf20Sopenharmony_ci tipc_crypto_rcv(net, (n) ? n->crypto_rx : NULL, &skb, b); 20808c2ecf20Sopenharmony_ci if (!skb) 20818c2ecf20Sopenharmony_ci return; 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_circv: 20848c2ecf20Sopenharmony_ci#endif 20858c2ecf20Sopenharmony_ci /* Ensure message is well-formed before touching the header */ 20868c2ecf20Sopenharmony_ci if (unlikely(!tipc_msg_validate(&skb))) 20878c2ecf20Sopenharmony_ci goto discard; 20888c2ecf20Sopenharmony_ci __skb_queue_head_init(&xmitq); 20898c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 20908c2ecf20Sopenharmony_ci usr = msg_user(hdr); 20918c2ecf20Sopenharmony_ci bc_ack = msg_bcast_ack(hdr); 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci /* Handle arrival of discovery or broadcast packet */ 20948c2ecf20Sopenharmony_ci if (unlikely(msg_non_seq(hdr))) { 20958c2ecf20Sopenharmony_ci if (unlikely(usr == LINK_CONFIG)) 20968c2ecf20Sopenharmony_ci return tipc_disc_rcv(net, skb, b); 20978c2ecf20Sopenharmony_ci else 20988c2ecf20Sopenharmony_ci return tipc_node_bc_rcv(net, skb, bearer_id); 20998c2ecf20Sopenharmony_ci } 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci /* Discard unicast link messages destined for another node */ 21028c2ecf20Sopenharmony_ci if (unlikely(!msg_short(hdr) && (msg_destnode(hdr) != self))) 21038c2ecf20Sopenharmony_ci goto discard; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci /* Locate neighboring node that sent packet */ 21068c2ecf20Sopenharmony_ci n = tipc_node_find(net, msg_prevnode(hdr)); 21078c2ecf20Sopenharmony_ci if (unlikely(!n)) 21088c2ecf20Sopenharmony_ci goto discard; 21098c2ecf20Sopenharmony_ci le = &n->links[bearer_id]; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci /* Ensure broadcast reception is in synch with peer's send state */ 21128c2ecf20Sopenharmony_ci if (unlikely(usr == LINK_PROTOCOL)) { 21138c2ecf20Sopenharmony_ci if (unlikely(skb_linearize(skb))) { 21148c2ecf20Sopenharmony_ci tipc_node_put(n); 21158c2ecf20Sopenharmony_ci goto discard; 21168c2ecf20Sopenharmony_ci } 21178c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 21188c2ecf20Sopenharmony_ci tipc_node_bc_sync_rcv(n, hdr, bearer_id, &xmitq); 21198c2ecf20Sopenharmony_ci } else if (unlikely(tipc_link_acked(n->bc_entry.link) != bc_ack)) { 21208c2ecf20Sopenharmony_ci tipc_bcast_ack_rcv(net, n->bc_entry.link, hdr); 21218c2ecf20Sopenharmony_ci } 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci /* Receive packet directly if conditions permit */ 21248c2ecf20Sopenharmony_ci tipc_node_read_lock(n); 21258c2ecf20Sopenharmony_ci if (likely((n->state == SELF_UP_PEER_UP) && (usr != TUNNEL_PROTOCOL))) { 21268c2ecf20Sopenharmony_ci spin_lock_bh(&le->lock); 21278c2ecf20Sopenharmony_ci if (le->link) { 21288c2ecf20Sopenharmony_ci rc = tipc_link_rcv(le->link, skb, &xmitq); 21298c2ecf20Sopenharmony_ci skb = NULL; 21308c2ecf20Sopenharmony_ci } 21318c2ecf20Sopenharmony_ci spin_unlock_bh(&le->lock); 21328c2ecf20Sopenharmony_ci } 21338c2ecf20Sopenharmony_ci tipc_node_read_unlock(n); 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci /* Check/update node state before receiving */ 21368c2ecf20Sopenharmony_ci if (unlikely(skb)) { 21378c2ecf20Sopenharmony_ci if (unlikely(skb_linearize(skb))) 21388c2ecf20Sopenharmony_ci goto out_node_put; 21398c2ecf20Sopenharmony_ci tipc_node_write_lock(n); 21408c2ecf20Sopenharmony_ci if (tipc_node_check_state(n, skb, bearer_id, &xmitq)) { 21418c2ecf20Sopenharmony_ci if (le->link) { 21428c2ecf20Sopenharmony_ci rc = tipc_link_rcv(le->link, skb, &xmitq); 21438c2ecf20Sopenharmony_ci skb = NULL; 21448c2ecf20Sopenharmony_ci } 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci tipc_node_write_unlock(n); 21478c2ecf20Sopenharmony_ci } 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci if (unlikely(rc & TIPC_LINK_UP_EVT)) 21508c2ecf20Sopenharmony_ci tipc_node_link_up(n, bearer_id, &xmitq); 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci if (unlikely(rc & TIPC_LINK_DOWN_EVT)) 21538c2ecf20Sopenharmony_ci tipc_node_link_down(n, bearer_id, false); 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci if (unlikely(!skb_queue_empty(&n->bc_entry.namedq))) 21568c2ecf20Sopenharmony_ci tipc_named_rcv(net, &n->bc_entry.namedq, 21578c2ecf20Sopenharmony_ci &n->bc_entry.named_rcv_nxt, 21588c2ecf20Sopenharmony_ci &n->bc_entry.named_open); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci if (unlikely(!skb_queue_empty(&n->bc_entry.inputq1))) 21618c2ecf20Sopenharmony_ci tipc_node_mcast_rcv(n); 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci if (!skb_queue_empty(&le->inputq)) 21648c2ecf20Sopenharmony_ci tipc_sk_rcv(net, &le->inputq); 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci if (!skb_queue_empty(&xmitq)) 21678c2ecf20Sopenharmony_ci tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr, n); 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ciout_node_put: 21708c2ecf20Sopenharmony_ci tipc_node_put(n); 21718c2ecf20Sopenharmony_cidiscard: 21728c2ecf20Sopenharmony_ci kfree_skb(skb); 21738c2ecf20Sopenharmony_ci} 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_civoid tipc_node_apply_property(struct net *net, struct tipc_bearer *b, 21768c2ecf20Sopenharmony_ci int prop) 21778c2ecf20Sopenharmony_ci{ 21788c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 21798c2ecf20Sopenharmony_ci int bearer_id = b->identity; 21808c2ecf20Sopenharmony_ci struct sk_buff_head xmitq; 21818c2ecf20Sopenharmony_ci struct tipc_link_entry *e; 21828c2ecf20Sopenharmony_ci struct tipc_node *n; 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci __skb_queue_head_init(&xmitq); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci rcu_read_lock(); 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci list_for_each_entry_rcu(n, &tn->node_list, list) { 21898c2ecf20Sopenharmony_ci tipc_node_write_lock(n); 21908c2ecf20Sopenharmony_ci e = &n->links[bearer_id]; 21918c2ecf20Sopenharmony_ci if (e->link) { 21928c2ecf20Sopenharmony_ci if (prop == TIPC_NLA_PROP_TOL) 21938c2ecf20Sopenharmony_ci tipc_link_set_tolerance(e->link, b->tolerance, 21948c2ecf20Sopenharmony_ci &xmitq); 21958c2ecf20Sopenharmony_ci else if (prop == TIPC_NLA_PROP_MTU) 21968c2ecf20Sopenharmony_ci tipc_link_set_mtu(e->link, b->mtu); 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci /* Update MTU for node link entry */ 21998c2ecf20Sopenharmony_ci e->mtu = tipc_link_mss(e->link); 22008c2ecf20Sopenharmony_ci } 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci tipc_node_write_unlock(n); 22038c2ecf20Sopenharmony_ci tipc_bearer_xmit(net, bearer_id, &xmitq, &e->maddr, NULL); 22048c2ecf20Sopenharmony_ci } 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci rcu_read_unlock(); 22078c2ecf20Sopenharmony_ci} 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ciint tipc_nl_peer_rm(struct sk_buff *skb, struct genl_info *info) 22108c2ecf20Sopenharmony_ci{ 22118c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 22128c2ecf20Sopenharmony_ci struct tipc_net *tn = net_generic(net, tipc_net_id); 22138c2ecf20Sopenharmony_ci struct nlattr *attrs[TIPC_NLA_NET_MAX + 1]; 22148c2ecf20Sopenharmony_ci struct tipc_node *peer, *temp_node; 22158c2ecf20Sopenharmony_ci u32 addr; 22168c2ecf20Sopenharmony_ci int err; 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci /* We identify the peer by its net */ 22198c2ecf20Sopenharmony_ci if (!info->attrs[TIPC_NLA_NET]) 22208c2ecf20Sopenharmony_ci return -EINVAL; 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(attrs, TIPC_NLA_NET_MAX, 22238c2ecf20Sopenharmony_ci info->attrs[TIPC_NLA_NET], 22248c2ecf20Sopenharmony_ci tipc_nl_net_policy, info->extack); 22258c2ecf20Sopenharmony_ci if (err) 22268c2ecf20Sopenharmony_ci return err; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_NET_ADDR]) 22298c2ecf20Sopenharmony_ci return -EINVAL; 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci addr = nla_get_u32(attrs[TIPC_NLA_NET_ADDR]); 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci if (in_own_node(net, addr)) 22348c2ecf20Sopenharmony_ci return -ENOTSUPP; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci spin_lock_bh(&tn->node_list_lock); 22378c2ecf20Sopenharmony_ci peer = tipc_node_find(net, addr); 22388c2ecf20Sopenharmony_ci if (!peer) { 22398c2ecf20Sopenharmony_ci spin_unlock_bh(&tn->node_list_lock); 22408c2ecf20Sopenharmony_ci return -ENXIO; 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci tipc_node_write_lock(peer); 22448c2ecf20Sopenharmony_ci if (peer->state != SELF_DOWN_PEER_DOWN && 22458c2ecf20Sopenharmony_ci peer->state != SELF_DOWN_PEER_LEAVING) { 22468c2ecf20Sopenharmony_ci tipc_node_write_unlock(peer); 22478c2ecf20Sopenharmony_ci err = -EBUSY; 22488c2ecf20Sopenharmony_ci goto err_out; 22498c2ecf20Sopenharmony_ci } 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci tipc_node_clear_links(peer); 22528c2ecf20Sopenharmony_ci tipc_node_write_unlock(peer); 22538c2ecf20Sopenharmony_ci tipc_node_delete(peer); 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci /* Calculate cluster capabilities */ 22568c2ecf20Sopenharmony_ci tn->capabilities = TIPC_NODE_CAPABILITIES; 22578c2ecf20Sopenharmony_ci list_for_each_entry_rcu(temp_node, &tn->node_list, list) { 22588c2ecf20Sopenharmony_ci tn->capabilities &= temp_node->capabilities; 22598c2ecf20Sopenharmony_ci } 22608c2ecf20Sopenharmony_ci tipc_bcast_toggle_rcast(net, (tn->capabilities & TIPC_BCAST_RCAST)); 22618c2ecf20Sopenharmony_ci err = 0; 22628c2ecf20Sopenharmony_cierr_out: 22638c2ecf20Sopenharmony_ci tipc_node_put(peer); 22648c2ecf20Sopenharmony_ci spin_unlock_bh(&tn->node_list_lock); 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci return err; 22678c2ecf20Sopenharmony_ci} 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ciint tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb) 22708c2ecf20Sopenharmony_ci{ 22718c2ecf20Sopenharmony_ci int err; 22728c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 22738c2ecf20Sopenharmony_ci struct tipc_net *tn = net_generic(net, tipc_net_id); 22748c2ecf20Sopenharmony_ci int done = cb->args[0]; 22758c2ecf20Sopenharmony_ci int last_addr = cb->args[1]; 22768c2ecf20Sopenharmony_ci struct tipc_node *node; 22778c2ecf20Sopenharmony_ci struct tipc_nl_msg msg; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci if (done) 22808c2ecf20Sopenharmony_ci return 0; 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci msg.skb = skb; 22838c2ecf20Sopenharmony_ci msg.portid = NETLINK_CB(cb->skb).portid; 22848c2ecf20Sopenharmony_ci msg.seq = cb->nlh->nlmsg_seq; 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci rcu_read_lock(); 22878c2ecf20Sopenharmony_ci if (last_addr) { 22888c2ecf20Sopenharmony_ci node = tipc_node_find(net, last_addr); 22898c2ecf20Sopenharmony_ci if (!node) { 22908c2ecf20Sopenharmony_ci rcu_read_unlock(); 22918c2ecf20Sopenharmony_ci /* We never set seq or call nl_dump_check_consistent() 22928c2ecf20Sopenharmony_ci * this means that setting prev_seq here will cause the 22938c2ecf20Sopenharmony_ci * consistence check to fail in the netlink callback 22948c2ecf20Sopenharmony_ci * handler. Resulting in the NLMSG_DONE message having 22958c2ecf20Sopenharmony_ci * the NLM_F_DUMP_INTR flag set if the node state 22968c2ecf20Sopenharmony_ci * changed while we released the lock. 22978c2ecf20Sopenharmony_ci */ 22988c2ecf20Sopenharmony_ci cb->prev_seq = 1; 22998c2ecf20Sopenharmony_ci return -EPIPE; 23008c2ecf20Sopenharmony_ci } 23018c2ecf20Sopenharmony_ci tipc_node_put(node); 23028c2ecf20Sopenharmony_ci } 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci list_for_each_entry_rcu(node, &tn->node_list, list) { 23058c2ecf20Sopenharmony_ci if (node->preliminary) 23068c2ecf20Sopenharmony_ci continue; 23078c2ecf20Sopenharmony_ci if (last_addr) { 23088c2ecf20Sopenharmony_ci if (node->addr == last_addr) 23098c2ecf20Sopenharmony_ci last_addr = 0; 23108c2ecf20Sopenharmony_ci else 23118c2ecf20Sopenharmony_ci continue; 23128c2ecf20Sopenharmony_ci } 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci tipc_node_read_lock(node); 23158c2ecf20Sopenharmony_ci err = __tipc_nl_add_node(&msg, node); 23168c2ecf20Sopenharmony_ci if (err) { 23178c2ecf20Sopenharmony_ci last_addr = node->addr; 23188c2ecf20Sopenharmony_ci tipc_node_read_unlock(node); 23198c2ecf20Sopenharmony_ci goto out; 23208c2ecf20Sopenharmony_ci } 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci tipc_node_read_unlock(node); 23238c2ecf20Sopenharmony_ci } 23248c2ecf20Sopenharmony_ci done = 1; 23258c2ecf20Sopenharmony_ciout: 23268c2ecf20Sopenharmony_ci cb->args[0] = done; 23278c2ecf20Sopenharmony_ci cb->args[1] = last_addr; 23288c2ecf20Sopenharmony_ci rcu_read_unlock(); 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci return skb->len; 23318c2ecf20Sopenharmony_ci} 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci/* tipc_node_find_by_name - locate owner node of link by link's name 23348c2ecf20Sopenharmony_ci * @net: the applicable net namespace 23358c2ecf20Sopenharmony_ci * @name: pointer to link name string 23368c2ecf20Sopenharmony_ci * @bearer_id: pointer to index in 'node->links' array where the link was found. 23378c2ecf20Sopenharmony_ci * 23388c2ecf20Sopenharmony_ci * Returns pointer to node owning the link, or 0 if no matching link is found. 23398c2ecf20Sopenharmony_ci */ 23408c2ecf20Sopenharmony_cistatic struct tipc_node *tipc_node_find_by_name(struct net *net, 23418c2ecf20Sopenharmony_ci const char *link_name, 23428c2ecf20Sopenharmony_ci unsigned int *bearer_id) 23438c2ecf20Sopenharmony_ci{ 23448c2ecf20Sopenharmony_ci struct tipc_net *tn = net_generic(net, tipc_net_id); 23458c2ecf20Sopenharmony_ci struct tipc_link *l; 23468c2ecf20Sopenharmony_ci struct tipc_node *n; 23478c2ecf20Sopenharmony_ci struct tipc_node *found_node = NULL; 23488c2ecf20Sopenharmony_ci int i; 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci *bearer_id = 0; 23518c2ecf20Sopenharmony_ci rcu_read_lock(); 23528c2ecf20Sopenharmony_ci list_for_each_entry_rcu(n, &tn->node_list, list) { 23538c2ecf20Sopenharmony_ci tipc_node_read_lock(n); 23548c2ecf20Sopenharmony_ci for (i = 0; i < MAX_BEARERS; i++) { 23558c2ecf20Sopenharmony_ci l = n->links[i].link; 23568c2ecf20Sopenharmony_ci if (l && !strcmp(tipc_link_name(l), link_name)) { 23578c2ecf20Sopenharmony_ci *bearer_id = i; 23588c2ecf20Sopenharmony_ci found_node = n; 23598c2ecf20Sopenharmony_ci break; 23608c2ecf20Sopenharmony_ci } 23618c2ecf20Sopenharmony_ci } 23628c2ecf20Sopenharmony_ci tipc_node_read_unlock(n); 23638c2ecf20Sopenharmony_ci if (found_node) 23648c2ecf20Sopenharmony_ci break; 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci rcu_read_unlock(); 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci return found_node; 23698c2ecf20Sopenharmony_ci} 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ciint tipc_nl_node_set_link(struct sk_buff *skb, struct genl_info *info) 23728c2ecf20Sopenharmony_ci{ 23738c2ecf20Sopenharmony_ci int err; 23748c2ecf20Sopenharmony_ci int res = 0; 23758c2ecf20Sopenharmony_ci int bearer_id; 23768c2ecf20Sopenharmony_ci char *name; 23778c2ecf20Sopenharmony_ci struct tipc_link *link; 23788c2ecf20Sopenharmony_ci struct tipc_node *node; 23798c2ecf20Sopenharmony_ci struct sk_buff_head xmitq; 23808c2ecf20Sopenharmony_ci struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; 23818c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci __skb_queue_head_init(&xmitq); 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci if (!info->attrs[TIPC_NLA_LINK]) 23868c2ecf20Sopenharmony_ci return -EINVAL; 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(attrs, TIPC_NLA_LINK_MAX, 23898c2ecf20Sopenharmony_ci info->attrs[TIPC_NLA_LINK], 23908c2ecf20Sopenharmony_ci tipc_nl_link_policy, info->extack); 23918c2ecf20Sopenharmony_ci if (err) 23928c2ecf20Sopenharmony_ci return err; 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_LINK_NAME]) 23958c2ecf20Sopenharmony_ci return -EINVAL; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci name = nla_data(attrs[TIPC_NLA_LINK_NAME]); 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci if (strcmp(name, tipc_bclink_name) == 0) 24008c2ecf20Sopenharmony_ci return tipc_nl_bc_link_set(net, attrs); 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci node = tipc_node_find_by_name(net, name, &bearer_id); 24038c2ecf20Sopenharmony_ci if (!node) 24048c2ecf20Sopenharmony_ci return -EINVAL; 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci tipc_node_read_lock(node); 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci link = node->links[bearer_id].link; 24098c2ecf20Sopenharmony_ci if (!link) { 24108c2ecf20Sopenharmony_ci res = -EINVAL; 24118c2ecf20Sopenharmony_ci goto out; 24128c2ecf20Sopenharmony_ci } 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci if (attrs[TIPC_NLA_LINK_PROP]) { 24158c2ecf20Sopenharmony_ci struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_LINK_PROP], props); 24188c2ecf20Sopenharmony_ci if (err) { 24198c2ecf20Sopenharmony_ci res = err; 24208c2ecf20Sopenharmony_ci goto out; 24218c2ecf20Sopenharmony_ci } 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_TOL]) { 24248c2ecf20Sopenharmony_ci u32 tol; 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci tol = nla_get_u32(props[TIPC_NLA_PROP_TOL]); 24278c2ecf20Sopenharmony_ci tipc_link_set_tolerance(link, tol, &xmitq); 24288c2ecf20Sopenharmony_ci } 24298c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_PRIO]) { 24308c2ecf20Sopenharmony_ci u32 prio; 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); 24338c2ecf20Sopenharmony_ci tipc_link_set_prio(link, prio, &xmitq); 24348c2ecf20Sopenharmony_ci } 24358c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_WIN]) { 24368c2ecf20Sopenharmony_ci u32 max_win; 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci max_win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 24398c2ecf20Sopenharmony_ci tipc_link_set_queue_limits(link, 24408c2ecf20Sopenharmony_ci tipc_link_min_win(link), 24418c2ecf20Sopenharmony_ci max_win); 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci } 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ciout: 24468c2ecf20Sopenharmony_ci tipc_node_read_unlock(node); 24478c2ecf20Sopenharmony_ci tipc_bearer_xmit(net, bearer_id, &xmitq, &node->links[bearer_id].maddr, 24488c2ecf20Sopenharmony_ci NULL); 24498c2ecf20Sopenharmony_ci return res; 24508c2ecf20Sopenharmony_ci} 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ciint tipc_nl_node_get_link(struct sk_buff *skb, struct genl_info *info) 24538c2ecf20Sopenharmony_ci{ 24548c2ecf20Sopenharmony_ci struct net *net = genl_info_net(info); 24558c2ecf20Sopenharmony_ci struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; 24568c2ecf20Sopenharmony_ci struct tipc_nl_msg msg; 24578c2ecf20Sopenharmony_ci char *name; 24588c2ecf20Sopenharmony_ci int err; 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci msg.portid = info->snd_portid; 24618c2ecf20Sopenharmony_ci msg.seq = info->snd_seq; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci if (!info->attrs[TIPC_NLA_LINK]) 24648c2ecf20Sopenharmony_ci return -EINVAL; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(attrs, TIPC_NLA_LINK_MAX, 24678c2ecf20Sopenharmony_ci info->attrs[TIPC_NLA_LINK], 24688c2ecf20Sopenharmony_ci tipc_nl_link_policy, info->extack); 24698c2ecf20Sopenharmony_ci if (err) 24708c2ecf20Sopenharmony_ci return err; 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_LINK_NAME]) 24738c2ecf20Sopenharmony_ci return -EINVAL; 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci name = nla_data(attrs[TIPC_NLA_LINK_NAME]); 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci msg.skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 24788c2ecf20Sopenharmony_ci if (!msg.skb) 24798c2ecf20Sopenharmony_ci return -ENOMEM; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci if (strcmp(name, tipc_bclink_name) == 0) { 24828c2ecf20Sopenharmony_ci err = tipc_nl_add_bc_link(net, &msg, tipc_net(net)->bcl); 24838c2ecf20Sopenharmony_ci if (err) 24848c2ecf20Sopenharmony_ci goto err_free; 24858c2ecf20Sopenharmony_ci } else { 24868c2ecf20Sopenharmony_ci int bearer_id; 24878c2ecf20Sopenharmony_ci struct tipc_node *node; 24888c2ecf20Sopenharmony_ci struct tipc_link *link; 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci node = tipc_node_find_by_name(net, name, &bearer_id); 24918c2ecf20Sopenharmony_ci if (!node) { 24928c2ecf20Sopenharmony_ci err = -EINVAL; 24938c2ecf20Sopenharmony_ci goto err_free; 24948c2ecf20Sopenharmony_ci } 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci tipc_node_read_lock(node); 24978c2ecf20Sopenharmony_ci link = node->links[bearer_id].link; 24988c2ecf20Sopenharmony_ci if (!link) { 24998c2ecf20Sopenharmony_ci tipc_node_read_unlock(node); 25008c2ecf20Sopenharmony_ci err = -EINVAL; 25018c2ecf20Sopenharmony_ci goto err_free; 25028c2ecf20Sopenharmony_ci } 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci err = __tipc_nl_add_link(net, &msg, link, 0); 25058c2ecf20Sopenharmony_ci tipc_node_read_unlock(node); 25068c2ecf20Sopenharmony_ci if (err) 25078c2ecf20Sopenharmony_ci goto err_free; 25088c2ecf20Sopenharmony_ci } 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci return genlmsg_reply(msg.skb, info); 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_cierr_free: 25138c2ecf20Sopenharmony_ci nlmsg_free(msg.skb); 25148c2ecf20Sopenharmony_ci return err; 25158c2ecf20Sopenharmony_ci} 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ciint tipc_nl_node_reset_link_stats(struct sk_buff *skb, struct genl_info *info) 25188c2ecf20Sopenharmony_ci{ 25198c2ecf20Sopenharmony_ci int err; 25208c2ecf20Sopenharmony_ci char *link_name; 25218c2ecf20Sopenharmony_ci unsigned int bearer_id; 25228c2ecf20Sopenharmony_ci struct tipc_link *link; 25238c2ecf20Sopenharmony_ci struct tipc_node *node; 25248c2ecf20Sopenharmony_ci struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; 25258c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 25268c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 25278c2ecf20Sopenharmony_ci struct tipc_link_entry *le; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci if (!info->attrs[TIPC_NLA_LINK]) 25308c2ecf20Sopenharmony_ci return -EINVAL; 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(attrs, TIPC_NLA_LINK_MAX, 25338c2ecf20Sopenharmony_ci info->attrs[TIPC_NLA_LINK], 25348c2ecf20Sopenharmony_ci tipc_nl_link_policy, info->extack); 25358c2ecf20Sopenharmony_ci if (err) 25368c2ecf20Sopenharmony_ci return err; 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_LINK_NAME]) 25398c2ecf20Sopenharmony_ci return -EINVAL; 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci link_name = nla_data(attrs[TIPC_NLA_LINK_NAME]); 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci err = -EINVAL; 25448c2ecf20Sopenharmony_ci if (!strcmp(link_name, tipc_bclink_name)) { 25458c2ecf20Sopenharmony_ci err = tipc_bclink_reset_stats(net, tipc_bc_sndlink(net)); 25468c2ecf20Sopenharmony_ci if (err) 25478c2ecf20Sopenharmony_ci return err; 25488c2ecf20Sopenharmony_ci return 0; 25498c2ecf20Sopenharmony_ci } else if (strstr(link_name, tipc_bclink_name)) { 25508c2ecf20Sopenharmony_ci rcu_read_lock(); 25518c2ecf20Sopenharmony_ci list_for_each_entry_rcu(node, &tn->node_list, list) { 25528c2ecf20Sopenharmony_ci tipc_node_read_lock(node); 25538c2ecf20Sopenharmony_ci link = node->bc_entry.link; 25548c2ecf20Sopenharmony_ci if (link && !strcmp(link_name, tipc_link_name(link))) { 25558c2ecf20Sopenharmony_ci err = tipc_bclink_reset_stats(net, link); 25568c2ecf20Sopenharmony_ci tipc_node_read_unlock(node); 25578c2ecf20Sopenharmony_ci break; 25588c2ecf20Sopenharmony_ci } 25598c2ecf20Sopenharmony_ci tipc_node_read_unlock(node); 25608c2ecf20Sopenharmony_ci } 25618c2ecf20Sopenharmony_ci rcu_read_unlock(); 25628c2ecf20Sopenharmony_ci return err; 25638c2ecf20Sopenharmony_ci } 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci node = tipc_node_find_by_name(net, link_name, &bearer_id); 25668c2ecf20Sopenharmony_ci if (!node) 25678c2ecf20Sopenharmony_ci return -EINVAL; 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci le = &node->links[bearer_id]; 25708c2ecf20Sopenharmony_ci tipc_node_read_lock(node); 25718c2ecf20Sopenharmony_ci spin_lock_bh(&le->lock); 25728c2ecf20Sopenharmony_ci link = node->links[bearer_id].link; 25738c2ecf20Sopenharmony_ci if (!link) { 25748c2ecf20Sopenharmony_ci spin_unlock_bh(&le->lock); 25758c2ecf20Sopenharmony_ci tipc_node_read_unlock(node); 25768c2ecf20Sopenharmony_ci return -EINVAL; 25778c2ecf20Sopenharmony_ci } 25788c2ecf20Sopenharmony_ci tipc_link_reset_stats(link); 25798c2ecf20Sopenharmony_ci spin_unlock_bh(&le->lock); 25808c2ecf20Sopenharmony_ci tipc_node_read_unlock(node); 25818c2ecf20Sopenharmony_ci return 0; 25828c2ecf20Sopenharmony_ci} 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci/* Caller should hold node lock */ 25858c2ecf20Sopenharmony_cistatic int __tipc_nl_add_node_links(struct net *net, struct tipc_nl_msg *msg, 25868c2ecf20Sopenharmony_ci struct tipc_node *node, u32 *prev_link, 25878c2ecf20Sopenharmony_ci bool bc_link) 25888c2ecf20Sopenharmony_ci{ 25898c2ecf20Sopenharmony_ci u32 i; 25908c2ecf20Sopenharmony_ci int err; 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci for (i = *prev_link; i < MAX_BEARERS; i++) { 25938c2ecf20Sopenharmony_ci *prev_link = i; 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci if (!node->links[i].link) 25968c2ecf20Sopenharmony_ci continue; 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci err = __tipc_nl_add_link(net, msg, 25998c2ecf20Sopenharmony_ci node->links[i].link, NLM_F_MULTI); 26008c2ecf20Sopenharmony_ci if (err) 26018c2ecf20Sopenharmony_ci return err; 26028c2ecf20Sopenharmony_ci } 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci if (bc_link) { 26058c2ecf20Sopenharmony_ci *prev_link = i; 26068c2ecf20Sopenharmony_ci err = tipc_nl_add_bc_link(net, msg, node->bc_entry.link); 26078c2ecf20Sopenharmony_ci if (err) 26088c2ecf20Sopenharmony_ci return err; 26098c2ecf20Sopenharmony_ci } 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci *prev_link = 0; 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci return 0; 26148c2ecf20Sopenharmony_ci} 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ciint tipc_nl_node_dump_link(struct sk_buff *skb, struct netlink_callback *cb) 26178c2ecf20Sopenharmony_ci{ 26188c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 26198c2ecf20Sopenharmony_ci struct nlattr **attrs = genl_dumpit_info(cb)->attrs; 26208c2ecf20Sopenharmony_ci struct nlattr *link[TIPC_NLA_LINK_MAX + 1]; 26218c2ecf20Sopenharmony_ci struct tipc_net *tn = net_generic(net, tipc_net_id); 26228c2ecf20Sopenharmony_ci struct tipc_node *node; 26238c2ecf20Sopenharmony_ci struct tipc_nl_msg msg; 26248c2ecf20Sopenharmony_ci u32 prev_node = cb->args[0]; 26258c2ecf20Sopenharmony_ci u32 prev_link = cb->args[1]; 26268c2ecf20Sopenharmony_ci int done = cb->args[2]; 26278c2ecf20Sopenharmony_ci bool bc_link = cb->args[3]; 26288c2ecf20Sopenharmony_ci int err; 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci if (done) 26318c2ecf20Sopenharmony_ci return 0; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci if (!prev_node) { 26348c2ecf20Sopenharmony_ci /* Check if broadcast-receiver links dumping is needed */ 26358c2ecf20Sopenharmony_ci if (attrs && attrs[TIPC_NLA_LINK]) { 26368c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(link, 26378c2ecf20Sopenharmony_ci TIPC_NLA_LINK_MAX, 26388c2ecf20Sopenharmony_ci attrs[TIPC_NLA_LINK], 26398c2ecf20Sopenharmony_ci tipc_nl_link_policy, 26408c2ecf20Sopenharmony_ci NULL); 26418c2ecf20Sopenharmony_ci if (unlikely(err)) 26428c2ecf20Sopenharmony_ci return err; 26438c2ecf20Sopenharmony_ci if (unlikely(!link[TIPC_NLA_LINK_BROADCAST])) 26448c2ecf20Sopenharmony_ci return -EINVAL; 26458c2ecf20Sopenharmony_ci bc_link = true; 26468c2ecf20Sopenharmony_ci } 26478c2ecf20Sopenharmony_ci } 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci msg.skb = skb; 26508c2ecf20Sopenharmony_ci msg.portid = NETLINK_CB(cb->skb).portid; 26518c2ecf20Sopenharmony_ci msg.seq = cb->nlh->nlmsg_seq; 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci rcu_read_lock(); 26548c2ecf20Sopenharmony_ci if (prev_node) { 26558c2ecf20Sopenharmony_ci node = tipc_node_find(net, prev_node); 26568c2ecf20Sopenharmony_ci if (!node) { 26578c2ecf20Sopenharmony_ci /* We never set seq or call nl_dump_check_consistent() 26588c2ecf20Sopenharmony_ci * this means that setting prev_seq here will cause the 26598c2ecf20Sopenharmony_ci * consistence check to fail in the netlink callback 26608c2ecf20Sopenharmony_ci * handler. Resulting in the last NLMSG_DONE message 26618c2ecf20Sopenharmony_ci * having the NLM_F_DUMP_INTR flag set. 26628c2ecf20Sopenharmony_ci */ 26638c2ecf20Sopenharmony_ci cb->prev_seq = 1; 26648c2ecf20Sopenharmony_ci goto out; 26658c2ecf20Sopenharmony_ci } 26668c2ecf20Sopenharmony_ci tipc_node_put(node); 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci list_for_each_entry_continue_rcu(node, &tn->node_list, 26698c2ecf20Sopenharmony_ci list) { 26708c2ecf20Sopenharmony_ci tipc_node_read_lock(node); 26718c2ecf20Sopenharmony_ci err = __tipc_nl_add_node_links(net, &msg, node, 26728c2ecf20Sopenharmony_ci &prev_link, bc_link); 26738c2ecf20Sopenharmony_ci tipc_node_read_unlock(node); 26748c2ecf20Sopenharmony_ci if (err) 26758c2ecf20Sopenharmony_ci goto out; 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci prev_node = node->addr; 26788c2ecf20Sopenharmony_ci } 26798c2ecf20Sopenharmony_ci } else { 26808c2ecf20Sopenharmony_ci err = tipc_nl_add_bc_link(net, &msg, tn->bcl); 26818c2ecf20Sopenharmony_ci if (err) 26828c2ecf20Sopenharmony_ci goto out; 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci list_for_each_entry_rcu(node, &tn->node_list, list) { 26858c2ecf20Sopenharmony_ci tipc_node_read_lock(node); 26868c2ecf20Sopenharmony_ci err = __tipc_nl_add_node_links(net, &msg, node, 26878c2ecf20Sopenharmony_ci &prev_link, bc_link); 26888c2ecf20Sopenharmony_ci tipc_node_read_unlock(node); 26898c2ecf20Sopenharmony_ci if (err) 26908c2ecf20Sopenharmony_ci goto out; 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci prev_node = node->addr; 26938c2ecf20Sopenharmony_ci } 26948c2ecf20Sopenharmony_ci } 26958c2ecf20Sopenharmony_ci done = 1; 26968c2ecf20Sopenharmony_ciout: 26978c2ecf20Sopenharmony_ci rcu_read_unlock(); 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci cb->args[0] = prev_node; 27008c2ecf20Sopenharmony_ci cb->args[1] = prev_link; 27018c2ecf20Sopenharmony_ci cb->args[2] = done; 27028c2ecf20Sopenharmony_ci cb->args[3] = bc_link; 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci return skb->len; 27058c2ecf20Sopenharmony_ci} 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ciint tipc_nl_node_set_monitor(struct sk_buff *skb, struct genl_info *info) 27088c2ecf20Sopenharmony_ci{ 27098c2ecf20Sopenharmony_ci struct nlattr *attrs[TIPC_NLA_MON_MAX + 1]; 27108c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 27118c2ecf20Sopenharmony_ci int err; 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci if (!info->attrs[TIPC_NLA_MON]) 27148c2ecf20Sopenharmony_ci return -EINVAL; 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(attrs, TIPC_NLA_MON_MAX, 27178c2ecf20Sopenharmony_ci info->attrs[TIPC_NLA_MON], 27188c2ecf20Sopenharmony_ci tipc_nl_monitor_policy, 27198c2ecf20Sopenharmony_ci info->extack); 27208c2ecf20Sopenharmony_ci if (err) 27218c2ecf20Sopenharmony_ci return err; 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_ci if (attrs[TIPC_NLA_MON_ACTIVATION_THRESHOLD]) { 27248c2ecf20Sopenharmony_ci u32 val; 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci val = nla_get_u32(attrs[TIPC_NLA_MON_ACTIVATION_THRESHOLD]); 27278c2ecf20Sopenharmony_ci err = tipc_nl_monitor_set_threshold(net, val); 27288c2ecf20Sopenharmony_ci if (err) 27298c2ecf20Sopenharmony_ci return err; 27308c2ecf20Sopenharmony_ci } 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci return 0; 27338c2ecf20Sopenharmony_ci} 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_cistatic int __tipc_nl_add_monitor_prop(struct net *net, struct tipc_nl_msg *msg) 27368c2ecf20Sopenharmony_ci{ 27378c2ecf20Sopenharmony_ci struct nlattr *attrs; 27388c2ecf20Sopenharmony_ci void *hdr; 27398c2ecf20Sopenharmony_ci u32 val; 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family, 27428c2ecf20Sopenharmony_ci 0, TIPC_NL_MON_GET); 27438c2ecf20Sopenharmony_ci if (!hdr) 27448c2ecf20Sopenharmony_ci return -EMSGSIZE; 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_MON); 27478c2ecf20Sopenharmony_ci if (!attrs) 27488c2ecf20Sopenharmony_ci goto msg_full; 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci val = tipc_nl_monitor_get_threshold(net); 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_MON_ACTIVATION_THRESHOLD, val)) 27538c2ecf20Sopenharmony_ci goto attr_msg_full; 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci nla_nest_end(msg->skb, attrs); 27568c2ecf20Sopenharmony_ci genlmsg_end(msg->skb, hdr); 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_ci return 0; 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ciattr_msg_full: 27618c2ecf20Sopenharmony_ci nla_nest_cancel(msg->skb, attrs); 27628c2ecf20Sopenharmony_cimsg_full: 27638c2ecf20Sopenharmony_ci genlmsg_cancel(msg->skb, hdr); 27648c2ecf20Sopenharmony_ci 27658c2ecf20Sopenharmony_ci return -EMSGSIZE; 27668c2ecf20Sopenharmony_ci} 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ciint tipc_nl_node_get_monitor(struct sk_buff *skb, struct genl_info *info) 27698c2ecf20Sopenharmony_ci{ 27708c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 27718c2ecf20Sopenharmony_ci struct tipc_nl_msg msg; 27728c2ecf20Sopenharmony_ci int err; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci msg.skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 27758c2ecf20Sopenharmony_ci if (!msg.skb) 27768c2ecf20Sopenharmony_ci return -ENOMEM; 27778c2ecf20Sopenharmony_ci msg.portid = info->snd_portid; 27788c2ecf20Sopenharmony_ci msg.seq = info->snd_seq; 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci err = __tipc_nl_add_monitor_prop(net, &msg); 27818c2ecf20Sopenharmony_ci if (err) { 27828c2ecf20Sopenharmony_ci nlmsg_free(msg.skb); 27838c2ecf20Sopenharmony_ci return err; 27848c2ecf20Sopenharmony_ci } 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci return genlmsg_reply(msg.skb, info); 27878c2ecf20Sopenharmony_ci} 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ciint tipc_nl_node_dump_monitor(struct sk_buff *skb, struct netlink_callback *cb) 27908c2ecf20Sopenharmony_ci{ 27918c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 27928c2ecf20Sopenharmony_ci u32 prev_bearer = cb->args[0]; 27938c2ecf20Sopenharmony_ci struct tipc_nl_msg msg; 27948c2ecf20Sopenharmony_ci int bearer_id; 27958c2ecf20Sopenharmony_ci int err; 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci if (prev_bearer == MAX_BEARERS) 27988c2ecf20Sopenharmony_ci return 0; 27998c2ecf20Sopenharmony_ci 28008c2ecf20Sopenharmony_ci msg.skb = skb; 28018c2ecf20Sopenharmony_ci msg.portid = NETLINK_CB(cb->skb).portid; 28028c2ecf20Sopenharmony_ci msg.seq = cb->nlh->nlmsg_seq; 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci rtnl_lock(); 28058c2ecf20Sopenharmony_ci for (bearer_id = prev_bearer; bearer_id < MAX_BEARERS; bearer_id++) { 28068c2ecf20Sopenharmony_ci err = __tipc_nl_add_monitor(net, &msg, bearer_id); 28078c2ecf20Sopenharmony_ci if (err) 28088c2ecf20Sopenharmony_ci break; 28098c2ecf20Sopenharmony_ci } 28108c2ecf20Sopenharmony_ci rtnl_unlock(); 28118c2ecf20Sopenharmony_ci cb->args[0] = bearer_id; 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci return skb->len; 28148c2ecf20Sopenharmony_ci} 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ciint tipc_nl_node_dump_monitor_peer(struct sk_buff *skb, 28178c2ecf20Sopenharmony_ci struct netlink_callback *cb) 28188c2ecf20Sopenharmony_ci{ 28198c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 28208c2ecf20Sopenharmony_ci u32 prev_node = cb->args[1]; 28218c2ecf20Sopenharmony_ci u32 bearer_id = cb->args[2]; 28228c2ecf20Sopenharmony_ci int done = cb->args[0]; 28238c2ecf20Sopenharmony_ci struct tipc_nl_msg msg; 28248c2ecf20Sopenharmony_ci int err; 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci if (!prev_node) { 28278c2ecf20Sopenharmony_ci struct nlattr **attrs = genl_dumpit_info(cb)->attrs; 28288c2ecf20Sopenharmony_ci struct nlattr *mon[TIPC_NLA_MON_MAX + 1]; 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_MON]) 28318c2ecf20Sopenharmony_ci return -EINVAL; 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(mon, TIPC_NLA_MON_MAX, 28348c2ecf20Sopenharmony_ci attrs[TIPC_NLA_MON], 28358c2ecf20Sopenharmony_ci tipc_nl_monitor_policy, 28368c2ecf20Sopenharmony_ci NULL); 28378c2ecf20Sopenharmony_ci if (err) 28388c2ecf20Sopenharmony_ci return err; 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_ci if (!mon[TIPC_NLA_MON_REF]) 28418c2ecf20Sopenharmony_ci return -EINVAL; 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_ci bearer_id = nla_get_u32(mon[TIPC_NLA_MON_REF]); 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_ci if (bearer_id >= MAX_BEARERS) 28468c2ecf20Sopenharmony_ci return -EINVAL; 28478c2ecf20Sopenharmony_ci } 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci if (done) 28508c2ecf20Sopenharmony_ci return 0; 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci msg.skb = skb; 28538c2ecf20Sopenharmony_ci msg.portid = NETLINK_CB(cb->skb).portid; 28548c2ecf20Sopenharmony_ci msg.seq = cb->nlh->nlmsg_seq; 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci rtnl_lock(); 28578c2ecf20Sopenharmony_ci err = tipc_nl_add_monitor_peer(net, &msg, bearer_id, &prev_node); 28588c2ecf20Sopenharmony_ci if (!err) 28598c2ecf20Sopenharmony_ci done = 1; 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci rtnl_unlock(); 28628c2ecf20Sopenharmony_ci cb->args[0] = done; 28638c2ecf20Sopenharmony_ci cb->args[1] = prev_node; 28648c2ecf20Sopenharmony_ci cb->args[2] = bearer_id; 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci return skb->len; 28678c2ecf20Sopenharmony_ci} 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_CRYPTO 28708c2ecf20Sopenharmony_cistatic int tipc_nl_retrieve_key(struct nlattr **attrs, 28718c2ecf20Sopenharmony_ci struct tipc_aead_key **pkey) 28728c2ecf20Sopenharmony_ci{ 28738c2ecf20Sopenharmony_ci struct nlattr *attr = attrs[TIPC_NLA_NODE_KEY]; 28748c2ecf20Sopenharmony_ci struct tipc_aead_key *key; 28758c2ecf20Sopenharmony_ci 28768c2ecf20Sopenharmony_ci if (!attr) 28778c2ecf20Sopenharmony_ci return -ENODATA; 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci if (nla_len(attr) < sizeof(*key)) 28808c2ecf20Sopenharmony_ci return -EINVAL; 28818c2ecf20Sopenharmony_ci key = (struct tipc_aead_key *)nla_data(attr); 28828c2ecf20Sopenharmony_ci if (key->keylen > TIPC_AEAD_KEYLEN_MAX || 28838c2ecf20Sopenharmony_ci nla_len(attr) < tipc_aead_key_size(key)) 28848c2ecf20Sopenharmony_ci return -EINVAL; 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci *pkey = key; 28878c2ecf20Sopenharmony_ci return 0; 28888c2ecf20Sopenharmony_ci} 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_cistatic int tipc_nl_retrieve_nodeid(struct nlattr **attrs, u8 **node_id) 28918c2ecf20Sopenharmony_ci{ 28928c2ecf20Sopenharmony_ci struct nlattr *attr = attrs[TIPC_NLA_NODE_ID]; 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci if (!attr) 28958c2ecf20Sopenharmony_ci return -ENODATA; 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci if (nla_len(attr) < TIPC_NODEID_LEN) 28988c2ecf20Sopenharmony_ci return -EINVAL; 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_ci *node_id = (u8 *)nla_data(attr); 29018c2ecf20Sopenharmony_ci return 0; 29028c2ecf20Sopenharmony_ci} 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_cistatic int tipc_nl_retrieve_rekeying(struct nlattr **attrs, u32 *intv) 29058c2ecf20Sopenharmony_ci{ 29068c2ecf20Sopenharmony_ci struct nlattr *attr = attrs[TIPC_NLA_NODE_REKEYING]; 29078c2ecf20Sopenharmony_ci 29088c2ecf20Sopenharmony_ci if (!attr) 29098c2ecf20Sopenharmony_ci return -ENODATA; 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci *intv = nla_get_u32(attr); 29128c2ecf20Sopenharmony_ci return 0; 29138c2ecf20Sopenharmony_ci} 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_cistatic int __tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info) 29168c2ecf20Sopenharmony_ci{ 29178c2ecf20Sopenharmony_ci struct nlattr *attrs[TIPC_NLA_NODE_MAX + 1]; 29188c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 29198c2ecf20Sopenharmony_ci struct tipc_crypto *tx = tipc_net(net)->crypto_tx, *c = tx; 29208c2ecf20Sopenharmony_ci struct tipc_node *n = NULL; 29218c2ecf20Sopenharmony_ci struct tipc_aead_key *ukey; 29228c2ecf20Sopenharmony_ci bool rekeying = true, master_key = false; 29238c2ecf20Sopenharmony_ci u8 *id, *own_id, mode; 29248c2ecf20Sopenharmony_ci u32 intv = 0; 29258c2ecf20Sopenharmony_ci int rc = 0; 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci if (!info->attrs[TIPC_NLA_NODE]) 29288c2ecf20Sopenharmony_ci return -EINVAL; 29298c2ecf20Sopenharmony_ci 29308c2ecf20Sopenharmony_ci rc = nla_parse_nested(attrs, TIPC_NLA_NODE_MAX, 29318c2ecf20Sopenharmony_ci info->attrs[TIPC_NLA_NODE], 29328c2ecf20Sopenharmony_ci tipc_nl_node_policy, info->extack); 29338c2ecf20Sopenharmony_ci if (rc) 29348c2ecf20Sopenharmony_ci return rc; 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci own_id = tipc_own_id(net); 29378c2ecf20Sopenharmony_ci if (!own_id) { 29388c2ecf20Sopenharmony_ci GENL_SET_ERR_MSG(info, "not found own node identity (set id?)"); 29398c2ecf20Sopenharmony_ci return -EPERM; 29408c2ecf20Sopenharmony_ci } 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ci rc = tipc_nl_retrieve_rekeying(attrs, &intv); 29438c2ecf20Sopenharmony_ci if (rc == -ENODATA) 29448c2ecf20Sopenharmony_ci rekeying = false; 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci rc = tipc_nl_retrieve_key(attrs, &ukey); 29478c2ecf20Sopenharmony_ci if (rc == -ENODATA && rekeying) 29488c2ecf20Sopenharmony_ci goto rekeying; 29498c2ecf20Sopenharmony_ci else if (rc) 29508c2ecf20Sopenharmony_ci return rc; 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci rc = tipc_aead_key_validate(ukey, info); 29538c2ecf20Sopenharmony_ci if (rc) 29548c2ecf20Sopenharmony_ci return rc; 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci rc = tipc_nl_retrieve_nodeid(attrs, &id); 29578c2ecf20Sopenharmony_ci switch (rc) { 29588c2ecf20Sopenharmony_ci case -ENODATA: 29598c2ecf20Sopenharmony_ci mode = CLUSTER_KEY; 29608c2ecf20Sopenharmony_ci master_key = !!(attrs[TIPC_NLA_NODE_KEY_MASTER]); 29618c2ecf20Sopenharmony_ci break; 29628c2ecf20Sopenharmony_ci case 0: 29638c2ecf20Sopenharmony_ci mode = PER_NODE_KEY; 29648c2ecf20Sopenharmony_ci if (memcmp(id, own_id, NODE_ID_LEN)) { 29658c2ecf20Sopenharmony_ci n = tipc_node_find_by_id(net, id) ?: 29668c2ecf20Sopenharmony_ci tipc_node_create(net, 0, id, 0xffffu, 0, true); 29678c2ecf20Sopenharmony_ci if (unlikely(!n)) 29688c2ecf20Sopenharmony_ci return -ENOMEM; 29698c2ecf20Sopenharmony_ci c = n->crypto_rx; 29708c2ecf20Sopenharmony_ci } 29718c2ecf20Sopenharmony_ci break; 29728c2ecf20Sopenharmony_ci default: 29738c2ecf20Sopenharmony_ci return rc; 29748c2ecf20Sopenharmony_ci } 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_ci /* Initiate the TX/RX key */ 29778c2ecf20Sopenharmony_ci rc = tipc_crypto_key_init(c, ukey, mode, master_key); 29788c2ecf20Sopenharmony_ci if (n) 29798c2ecf20Sopenharmony_ci tipc_node_put(n); 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci if (unlikely(rc < 0)) { 29828c2ecf20Sopenharmony_ci GENL_SET_ERR_MSG(info, "unable to initiate or attach new key"); 29838c2ecf20Sopenharmony_ci return rc; 29848c2ecf20Sopenharmony_ci } else if (c == tx) { 29858c2ecf20Sopenharmony_ci /* Distribute TX key but not master one */ 29868c2ecf20Sopenharmony_ci if (!master_key && tipc_crypto_key_distr(tx, rc, NULL)) 29878c2ecf20Sopenharmony_ci GENL_SET_ERR_MSG(info, "failed to replicate new key"); 29888c2ecf20Sopenharmony_cirekeying: 29898c2ecf20Sopenharmony_ci /* Schedule TX rekeying if needed */ 29908c2ecf20Sopenharmony_ci tipc_crypto_rekeying_sched(tx, rekeying, intv); 29918c2ecf20Sopenharmony_ci } 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci return 0; 29948c2ecf20Sopenharmony_ci} 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ciint tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info) 29978c2ecf20Sopenharmony_ci{ 29988c2ecf20Sopenharmony_ci int err; 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci rtnl_lock(); 30018c2ecf20Sopenharmony_ci err = __tipc_nl_node_set_key(skb, info); 30028c2ecf20Sopenharmony_ci rtnl_unlock(); 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci return err; 30058c2ecf20Sopenharmony_ci} 30068c2ecf20Sopenharmony_ci 30078c2ecf20Sopenharmony_cistatic int __tipc_nl_node_flush_key(struct sk_buff *skb, 30088c2ecf20Sopenharmony_ci struct genl_info *info) 30098c2ecf20Sopenharmony_ci{ 30108c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 30118c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 30128c2ecf20Sopenharmony_ci struct tipc_node *n; 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci tipc_crypto_key_flush(tn->crypto_tx); 30158c2ecf20Sopenharmony_ci rcu_read_lock(); 30168c2ecf20Sopenharmony_ci list_for_each_entry_rcu(n, &tn->node_list, list) 30178c2ecf20Sopenharmony_ci tipc_crypto_key_flush(n->crypto_rx); 30188c2ecf20Sopenharmony_ci rcu_read_unlock(); 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci return 0; 30218c2ecf20Sopenharmony_ci} 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ciint tipc_nl_node_flush_key(struct sk_buff *skb, struct genl_info *info) 30248c2ecf20Sopenharmony_ci{ 30258c2ecf20Sopenharmony_ci int err; 30268c2ecf20Sopenharmony_ci 30278c2ecf20Sopenharmony_ci rtnl_lock(); 30288c2ecf20Sopenharmony_ci err = __tipc_nl_node_flush_key(skb, info); 30298c2ecf20Sopenharmony_ci rtnl_unlock(); 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci return err; 30328c2ecf20Sopenharmony_ci} 30338c2ecf20Sopenharmony_ci#endif 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_ci/** 30368c2ecf20Sopenharmony_ci * tipc_node_dump - dump TIPC node data 30378c2ecf20Sopenharmony_ci * @n: tipc node to be dumped 30388c2ecf20Sopenharmony_ci * @more: dump more? 30398c2ecf20Sopenharmony_ci * - false: dump only tipc node data 30408c2ecf20Sopenharmony_ci * - true: dump node link data as well 30418c2ecf20Sopenharmony_ci * @buf: returned buffer of dump data in format 30428c2ecf20Sopenharmony_ci */ 30438c2ecf20Sopenharmony_ciint tipc_node_dump(struct tipc_node *n, bool more, char *buf) 30448c2ecf20Sopenharmony_ci{ 30458c2ecf20Sopenharmony_ci int i = 0; 30468c2ecf20Sopenharmony_ci size_t sz = (more) ? NODE_LMAX : NODE_LMIN; 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci if (!n) { 30498c2ecf20Sopenharmony_ci i += scnprintf(buf, sz, "node data: (null)\n"); 30508c2ecf20Sopenharmony_ci return i; 30518c2ecf20Sopenharmony_ci } 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_ci i += scnprintf(buf, sz, "node data: %x", n->addr); 30548c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %x", n->state); 30558c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %d", n->active_links[0]); 30568c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %d", n->active_links[1]); 30578c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %x", n->action_flags); 30588c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", n->failover_sent); 30598c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", n->sync_point); 30608c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %d", n->link_cnt); 30618c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", n->working_links); 30628c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %x", n->capabilities); 30638c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %lu\n", n->keepalive_intv); 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci if (!more) 30668c2ecf20Sopenharmony_ci return i; 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, "link_entry[0]:\n"); 30698c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " mtu: %u\n", n->links[0].mtu); 30708c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " media: "); 30718c2ecf20Sopenharmony_ci i += tipc_media_addr_printf(buf + i, sz - i, &n->links[0].maddr); 30728c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, "\n"); 30738c2ecf20Sopenharmony_ci i += tipc_link_dump(n->links[0].link, TIPC_DUMP_NONE, buf + i); 30748c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " inputq: "); 30758c2ecf20Sopenharmony_ci i += tipc_list_dump(&n->links[0].inputq, false, buf + i); 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, "link_entry[1]:\n"); 30788c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " mtu: %u\n", n->links[1].mtu); 30798c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " media: "); 30808c2ecf20Sopenharmony_ci i += tipc_media_addr_printf(buf + i, sz - i, &n->links[1].maddr); 30818c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, "\n"); 30828c2ecf20Sopenharmony_ci i += tipc_link_dump(n->links[1].link, TIPC_DUMP_NONE, buf + i); 30838c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " inputq: "); 30848c2ecf20Sopenharmony_ci i += tipc_list_dump(&n->links[1].inputq, false, buf + i); 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, "bclink:\n "); 30878c2ecf20Sopenharmony_ci i += tipc_link_dump(n->bc_entry.link, TIPC_DUMP_NONE, buf + i); 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci return i; 30908c2ecf20Sopenharmony_ci} 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_civoid tipc_node_pre_cleanup_net(struct net *exit_net) 30938c2ecf20Sopenharmony_ci{ 30948c2ecf20Sopenharmony_ci struct tipc_node *n; 30958c2ecf20Sopenharmony_ci struct tipc_net *tn; 30968c2ecf20Sopenharmony_ci struct net *tmp; 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ci rcu_read_lock(); 30998c2ecf20Sopenharmony_ci for_each_net_rcu(tmp) { 31008c2ecf20Sopenharmony_ci if (tmp == exit_net) 31018c2ecf20Sopenharmony_ci continue; 31028c2ecf20Sopenharmony_ci tn = tipc_net(tmp); 31038c2ecf20Sopenharmony_ci if (!tn) 31048c2ecf20Sopenharmony_ci continue; 31058c2ecf20Sopenharmony_ci spin_lock_bh(&tn->node_list_lock); 31068c2ecf20Sopenharmony_ci list_for_each_entry_rcu(n, &tn->node_list, list) { 31078c2ecf20Sopenharmony_ci if (!n->peer_net) 31088c2ecf20Sopenharmony_ci continue; 31098c2ecf20Sopenharmony_ci if (n->peer_net != exit_net) 31108c2ecf20Sopenharmony_ci continue; 31118c2ecf20Sopenharmony_ci tipc_node_write_lock(n); 31128c2ecf20Sopenharmony_ci n->peer_net = NULL; 31138c2ecf20Sopenharmony_ci n->peer_hash_mix = 0; 31148c2ecf20Sopenharmony_ci tipc_node_write_unlock_fast(n); 31158c2ecf20Sopenharmony_ci break; 31168c2ecf20Sopenharmony_ci } 31178c2ecf20Sopenharmony_ci spin_unlock_bh(&tn->node_list_lock); 31188c2ecf20Sopenharmony_ci } 31198c2ecf20Sopenharmony_ci rcu_read_unlock(); 31208c2ecf20Sopenharmony_ci} 3121