18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * net/tipc/name_table.c: TIPC name table code 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2000-2006, 2014-2018, Ericsson AB 58c2ecf20Sopenharmony_ci * Copyright (c) 2004-2008, 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 <net/sock.h> 388c2ecf20Sopenharmony_ci#include <linux/list_sort.h> 398c2ecf20Sopenharmony_ci#include <linux/rbtree_augmented.h> 408c2ecf20Sopenharmony_ci#include "core.h" 418c2ecf20Sopenharmony_ci#include "netlink.h" 428c2ecf20Sopenharmony_ci#include "name_table.h" 438c2ecf20Sopenharmony_ci#include "name_distr.h" 448c2ecf20Sopenharmony_ci#include "subscr.h" 458c2ecf20Sopenharmony_ci#include "bcast.h" 468c2ecf20Sopenharmony_ci#include "addr.h" 478c2ecf20Sopenharmony_ci#include "node.h" 488c2ecf20Sopenharmony_ci#include "group.h" 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/** 518c2ecf20Sopenharmony_ci * struct service_range - container for all bindings of a service range 528c2ecf20Sopenharmony_ci * @lower: service range lower bound 538c2ecf20Sopenharmony_ci * @upper: service range upper bound 548c2ecf20Sopenharmony_ci * @tree_node: member of service range RB tree 558c2ecf20Sopenharmony_ci * @max: largest 'upper' in this node subtree 568c2ecf20Sopenharmony_ci * @local_publ: list of identical publications made from this node 578c2ecf20Sopenharmony_ci * Used by closest_first lookup and multicast lookup algorithm 588c2ecf20Sopenharmony_ci * @all_publ: all publications identical to this one, whatever node and scope 598c2ecf20Sopenharmony_ci * Used by round-robin lookup algorithm 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_cistruct service_range { 628c2ecf20Sopenharmony_ci u32 lower; 638c2ecf20Sopenharmony_ci u32 upper; 648c2ecf20Sopenharmony_ci struct rb_node tree_node; 658c2ecf20Sopenharmony_ci u32 max; 668c2ecf20Sopenharmony_ci struct list_head local_publ; 678c2ecf20Sopenharmony_ci struct list_head all_publ; 688c2ecf20Sopenharmony_ci}; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/** 718c2ecf20Sopenharmony_ci * struct tipc_service - container for all published instances of a service type 728c2ecf20Sopenharmony_ci * @type: 32 bit 'type' value for service 738c2ecf20Sopenharmony_ci * @publ_cnt: increasing counter for publications in this service 748c2ecf20Sopenharmony_ci * @ranges: rb tree containing all service ranges for this service 758c2ecf20Sopenharmony_ci * @service_list: links to adjacent name ranges in hash chain 768c2ecf20Sopenharmony_ci * @subscriptions: list of subscriptions for this service type 778c2ecf20Sopenharmony_ci * @lock: spinlock controlling access to pertaining service ranges/publications 788c2ecf20Sopenharmony_ci * @rcu: RCU callback head used for deferred freeing 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_cistruct tipc_service { 818c2ecf20Sopenharmony_ci u32 type; 828c2ecf20Sopenharmony_ci u32 publ_cnt; 838c2ecf20Sopenharmony_ci struct rb_root ranges; 848c2ecf20Sopenharmony_ci struct hlist_node service_list; 858c2ecf20Sopenharmony_ci struct list_head subscriptions; 868c2ecf20Sopenharmony_ci spinlock_t lock; /* Covers service range list */ 878c2ecf20Sopenharmony_ci struct rcu_head rcu; 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#define service_range_upper(sr) ((sr)->upper) 918c2ecf20Sopenharmony_ciRB_DECLARE_CALLBACKS_MAX(static, sr_callbacks, 928c2ecf20Sopenharmony_ci struct service_range, tree_node, u32, max, 938c2ecf20Sopenharmony_ci service_range_upper) 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci#define service_range_entry(rbtree_node) \ 968c2ecf20Sopenharmony_ci (container_of(rbtree_node, struct service_range, tree_node)) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#define service_range_overlap(sr, start, end) \ 998c2ecf20Sopenharmony_ci ((sr)->lower <= (end) && (sr)->upper >= (start)) 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/** 1028c2ecf20Sopenharmony_ci * service_range_foreach_match - iterate over tipc service rbtree for each 1038c2ecf20Sopenharmony_ci * range match 1048c2ecf20Sopenharmony_ci * @sr: the service range pointer as a loop cursor 1058c2ecf20Sopenharmony_ci * @sc: the pointer to tipc service which holds the service range rbtree 1068c2ecf20Sopenharmony_ci * @start, end: the range (end >= start) for matching 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci#define service_range_foreach_match(sr, sc, start, end) \ 1098c2ecf20Sopenharmony_ci for (sr = service_range_match_first((sc)->ranges.rb_node, \ 1108c2ecf20Sopenharmony_ci start, \ 1118c2ecf20Sopenharmony_ci end); \ 1128c2ecf20Sopenharmony_ci sr; \ 1138c2ecf20Sopenharmony_ci sr = service_range_match_next(&(sr)->tree_node, \ 1148c2ecf20Sopenharmony_ci start, \ 1158c2ecf20Sopenharmony_ci end)) 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/** 1188c2ecf20Sopenharmony_ci * service_range_match_first - find first service range matching a range 1198c2ecf20Sopenharmony_ci * @n: the root node of service range rbtree for searching 1208c2ecf20Sopenharmony_ci * @start, end: the range (end >= start) for matching 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * Return: the leftmost service range node in the rbtree that overlaps the 1238c2ecf20Sopenharmony_ci * specific range if any. Otherwise, returns NULL. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_cistatic struct service_range *service_range_match_first(struct rb_node *n, 1268c2ecf20Sopenharmony_ci u32 start, u32 end) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct service_range *sr; 1298c2ecf20Sopenharmony_ci struct rb_node *l, *r; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* Non overlaps in tree at all? */ 1328c2ecf20Sopenharmony_ci if (!n || service_range_entry(n)->max < start) 1338c2ecf20Sopenharmony_ci return NULL; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci while (n) { 1368c2ecf20Sopenharmony_ci l = n->rb_left; 1378c2ecf20Sopenharmony_ci if (l && service_range_entry(l)->max >= start) { 1388c2ecf20Sopenharmony_ci /* A leftmost overlap range node must be one in the left 1398c2ecf20Sopenharmony_ci * subtree. If not, it has lower > end, then nodes on 1408c2ecf20Sopenharmony_ci * the right side cannot satisfy the condition either. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci n = l; 1438c2ecf20Sopenharmony_ci continue; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* No one in the left subtree can match, return if this node is 1478c2ecf20Sopenharmony_ci * an overlap i.e. leftmost. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci sr = service_range_entry(n); 1508c2ecf20Sopenharmony_ci if (service_range_overlap(sr, start, end)) 1518c2ecf20Sopenharmony_ci return sr; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* Ok, try to lookup on the right side */ 1548c2ecf20Sopenharmony_ci r = n->rb_right; 1558c2ecf20Sopenharmony_ci if (sr->lower <= end && 1568c2ecf20Sopenharmony_ci r && service_range_entry(r)->max >= start) { 1578c2ecf20Sopenharmony_ci n = r; 1588c2ecf20Sopenharmony_ci continue; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return NULL; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/** 1678c2ecf20Sopenharmony_ci * service_range_match_next - find next service range matching a range 1688c2ecf20Sopenharmony_ci * @n: a node in service range rbtree from which the searching starts 1698c2ecf20Sopenharmony_ci * @start, end: the range (end >= start) for matching 1708c2ecf20Sopenharmony_ci * 1718c2ecf20Sopenharmony_ci * Return: the next service range node to the given node in the rbtree that 1728c2ecf20Sopenharmony_ci * overlaps the specific range if any. Otherwise, returns NULL. 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_cistatic struct service_range *service_range_match_next(struct rb_node *n, 1758c2ecf20Sopenharmony_ci u32 start, u32 end) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct service_range *sr; 1788c2ecf20Sopenharmony_ci struct rb_node *p, *r; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci while (n) { 1818c2ecf20Sopenharmony_ci r = n->rb_right; 1828c2ecf20Sopenharmony_ci if (r && service_range_entry(r)->max >= start) 1838c2ecf20Sopenharmony_ci /* A next overlap range node must be one in the right 1848c2ecf20Sopenharmony_ci * subtree. If not, it has lower > end, then any next 1858c2ecf20Sopenharmony_ci * successor (- an ancestor) of this node cannot 1868c2ecf20Sopenharmony_ci * satisfy the condition either. 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_ci return service_range_match_first(r, start, end); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* No one in the right subtree can match, go up to find an 1918c2ecf20Sopenharmony_ci * ancestor of this node which is parent of a left-hand child. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ci while ((p = rb_parent(n)) && n == p->rb_right) 1948c2ecf20Sopenharmony_ci n = p; 1958c2ecf20Sopenharmony_ci if (!p) 1968c2ecf20Sopenharmony_ci break; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* Return if this ancestor is an overlap */ 1998c2ecf20Sopenharmony_ci sr = service_range_entry(p); 2008c2ecf20Sopenharmony_ci if (service_range_overlap(sr, start, end)) 2018c2ecf20Sopenharmony_ci return sr; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* Ok, try to lookup more from this ancestor */ 2048c2ecf20Sopenharmony_ci if (sr->lower <= end) { 2058c2ecf20Sopenharmony_ci n = p; 2068c2ecf20Sopenharmony_ci continue; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return NULL; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int hash(int x) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci return x & (TIPC_NAMETBL_SIZE - 1); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/** 2208c2ecf20Sopenharmony_ci * tipc_publ_create - create a publication structure 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_cistatic struct publication *tipc_publ_create(u32 type, u32 lower, u32 upper, 2238c2ecf20Sopenharmony_ci u32 scope, u32 node, u32 port, 2248c2ecf20Sopenharmony_ci u32 key) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct publication *publ = kzalloc(sizeof(*publ), GFP_ATOMIC); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (!publ) 2298c2ecf20Sopenharmony_ci return NULL; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci publ->type = type; 2328c2ecf20Sopenharmony_ci publ->lower = lower; 2338c2ecf20Sopenharmony_ci publ->upper = upper; 2348c2ecf20Sopenharmony_ci publ->scope = scope; 2358c2ecf20Sopenharmony_ci publ->node = node; 2368c2ecf20Sopenharmony_ci publ->port = port; 2378c2ecf20Sopenharmony_ci publ->key = key; 2388c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&publ->binding_sock); 2398c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&publ->binding_node); 2408c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&publ->local_publ); 2418c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&publ->all_publ); 2428c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&publ->list); 2438c2ecf20Sopenharmony_ci return publ; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci/** 2478c2ecf20Sopenharmony_ci * tipc_service_create - create a service structure for the specified 'type' 2488c2ecf20Sopenharmony_ci * 2498c2ecf20Sopenharmony_ci * Allocates a single range structure and sets it to all 0's. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_cistatic struct tipc_service *tipc_service_create(u32 type, struct hlist_head *hd) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct tipc_service *service = kzalloc(sizeof(*service), GFP_ATOMIC); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (!service) { 2568c2ecf20Sopenharmony_ci pr_warn("Service creation failed, no memory\n"); 2578c2ecf20Sopenharmony_ci return NULL; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci spin_lock_init(&service->lock); 2618c2ecf20Sopenharmony_ci service->type = type; 2628c2ecf20Sopenharmony_ci service->ranges = RB_ROOT; 2638c2ecf20Sopenharmony_ci INIT_HLIST_NODE(&service->service_list); 2648c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&service->subscriptions); 2658c2ecf20Sopenharmony_ci hlist_add_head_rcu(&service->service_list, hd); 2668c2ecf20Sopenharmony_ci return service; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci/* tipc_service_find_range - find service range matching publication parameters 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_cistatic struct service_range *tipc_service_find_range(struct tipc_service *sc, 2728c2ecf20Sopenharmony_ci u32 lower, u32 upper) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct service_range *sr; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci service_range_foreach_match(sr, sc, lower, upper) { 2778c2ecf20Sopenharmony_ci /* Look for exact match */ 2788c2ecf20Sopenharmony_ci if (sr->lower == lower && sr->upper == upper) 2798c2ecf20Sopenharmony_ci return sr; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return NULL; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic struct service_range *tipc_service_create_range(struct tipc_service *sc, 2868c2ecf20Sopenharmony_ci u32 lower, u32 upper) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct rb_node **n, *parent = NULL; 2898c2ecf20Sopenharmony_ci struct service_range *sr; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci n = &sc->ranges.rb_node; 2928c2ecf20Sopenharmony_ci while (*n) { 2938c2ecf20Sopenharmony_ci parent = *n; 2948c2ecf20Sopenharmony_ci sr = service_range_entry(parent); 2958c2ecf20Sopenharmony_ci if (lower == sr->lower && upper == sr->upper) 2968c2ecf20Sopenharmony_ci return sr; 2978c2ecf20Sopenharmony_ci if (sr->max < upper) 2988c2ecf20Sopenharmony_ci sr->max = upper; 2998c2ecf20Sopenharmony_ci if (lower <= sr->lower) 3008c2ecf20Sopenharmony_ci n = &parent->rb_left; 3018c2ecf20Sopenharmony_ci else 3028c2ecf20Sopenharmony_ci n = &parent->rb_right; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci sr = kzalloc(sizeof(*sr), GFP_ATOMIC); 3058c2ecf20Sopenharmony_ci if (!sr) 3068c2ecf20Sopenharmony_ci return NULL; 3078c2ecf20Sopenharmony_ci sr->lower = lower; 3088c2ecf20Sopenharmony_ci sr->upper = upper; 3098c2ecf20Sopenharmony_ci sr->max = upper; 3108c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sr->local_publ); 3118c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sr->all_publ); 3128c2ecf20Sopenharmony_ci rb_link_node(&sr->tree_node, parent, n); 3138c2ecf20Sopenharmony_ci rb_insert_augmented(&sr->tree_node, &sc->ranges, &sr_callbacks); 3148c2ecf20Sopenharmony_ci return sr; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic struct publication *tipc_service_insert_publ(struct net *net, 3188c2ecf20Sopenharmony_ci struct tipc_service *sc, 3198c2ecf20Sopenharmony_ci u32 type, u32 lower, 3208c2ecf20Sopenharmony_ci u32 upper, u32 scope, 3218c2ecf20Sopenharmony_ci u32 node, u32 port, 3228c2ecf20Sopenharmony_ci u32 key) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct tipc_subscription *sub, *tmp; 3258c2ecf20Sopenharmony_ci struct service_range *sr; 3268c2ecf20Sopenharmony_ci struct publication *p; 3278c2ecf20Sopenharmony_ci bool first = false; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci sr = tipc_service_create_range(sc, lower, upper); 3308c2ecf20Sopenharmony_ci if (!sr) 3318c2ecf20Sopenharmony_ci goto err; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci first = list_empty(&sr->all_publ); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Return if the publication already exists */ 3368c2ecf20Sopenharmony_ci list_for_each_entry(p, &sr->all_publ, all_publ) { 3378c2ecf20Sopenharmony_ci if (p->key == key && (!p->node || p->node == node)) 3388c2ecf20Sopenharmony_ci return NULL; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* Create and insert publication */ 3428c2ecf20Sopenharmony_ci p = tipc_publ_create(type, lower, upper, scope, node, port, key); 3438c2ecf20Sopenharmony_ci if (!p) 3448c2ecf20Sopenharmony_ci goto err; 3458c2ecf20Sopenharmony_ci /* Suppose there shouldn't be a huge gap btw publs i.e. >INT_MAX */ 3468c2ecf20Sopenharmony_ci p->id = sc->publ_cnt++; 3478c2ecf20Sopenharmony_ci if (in_own_node(net, node)) 3488c2ecf20Sopenharmony_ci list_add(&p->local_publ, &sr->local_publ); 3498c2ecf20Sopenharmony_ci list_add(&p->all_publ, &sr->all_publ); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* Any subscriptions waiting for notification? */ 3528c2ecf20Sopenharmony_ci list_for_each_entry_safe(sub, tmp, &sc->subscriptions, service_list) { 3538c2ecf20Sopenharmony_ci tipc_sub_report_overlap(sub, p->lower, p->upper, TIPC_PUBLISHED, 3548c2ecf20Sopenharmony_ci p->port, p->node, p->scope, first); 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci return p; 3578c2ecf20Sopenharmony_cierr: 3588c2ecf20Sopenharmony_ci pr_warn("Failed to bind to %u,%u,%u, no memory\n", type, lower, upper); 3598c2ecf20Sopenharmony_ci return NULL; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci/** 3638c2ecf20Sopenharmony_ci * tipc_service_remove_publ - remove a publication from a service 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_cistatic struct publication *tipc_service_remove_publ(struct service_range *sr, 3668c2ecf20Sopenharmony_ci u32 node, u32 key) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct publication *p; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci list_for_each_entry(p, &sr->all_publ, all_publ) { 3718c2ecf20Sopenharmony_ci if (p->key != key || (node && node != p->node)) 3728c2ecf20Sopenharmony_ci continue; 3738c2ecf20Sopenharmony_ci list_del(&p->all_publ); 3748c2ecf20Sopenharmony_ci list_del(&p->local_publ); 3758c2ecf20Sopenharmony_ci return p; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci return NULL; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci/** 3818c2ecf20Sopenharmony_ci * Code reused: time_after32() for the same purpose 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci#define publication_after(pa, pb) time_after32((pa)->id, (pb)->id) 3848c2ecf20Sopenharmony_cistatic int tipc_publ_sort(void *priv, const struct list_head *a, 3858c2ecf20Sopenharmony_ci const struct list_head *b) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct publication *pa, *pb; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci pa = container_of(a, struct publication, list); 3908c2ecf20Sopenharmony_ci pb = container_of(b, struct publication, list); 3918c2ecf20Sopenharmony_ci return publication_after(pa, pb); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci/** 3958c2ecf20Sopenharmony_ci * tipc_service_subscribe - attach a subscription, and optionally 3968c2ecf20Sopenharmony_ci * issue the prescribed number of events if there is any service 3978c2ecf20Sopenharmony_ci * range overlapping with the requested range 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_cistatic void tipc_service_subscribe(struct tipc_service *service, 4008c2ecf20Sopenharmony_ci struct tipc_subscription *sub) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct tipc_subscr *sb = &sub->evt.s; 4038c2ecf20Sopenharmony_ci struct publication *p, *first, *tmp; 4048c2ecf20Sopenharmony_ci struct list_head publ_list; 4058c2ecf20Sopenharmony_ci struct service_range *sr; 4068c2ecf20Sopenharmony_ci struct tipc_name_seq ns; 4078c2ecf20Sopenharmony_ci u32 filter; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci ns.type = tipc_sub_read(sb, seq.type); 4108c2ecf20Sopenharmony_ci ns.lower = tipc_sub_read(sb, seq.lower); 4118c2ecf20Sopenharmony_ci ns.upper = tipc_sub_read(sb, seq.upper); 4128c2ecf20Sopenharmony_ci filter = tipc_sub_read(sb, filter); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci tipc_sub_get(sub); 4158c2ecf20Sopenharmony_ci list_add(&sub->service_list, &service->subscriptions); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (filter & TIPC_SUB_NO_STATUS) 4188c2ecf20Sopenharmony_ci return; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&publ_list); 4218c2ecf20Sopenharmony_ci service_range_foreach_match(sr, service, ns.lower, ns.upper) { 4228c2ecf20Sopenharmony_ci first = NULL; 4238c2ecf20Sopenharmony_ci list_for_each_entry(p, &sr->all_publ, all_publ) { 4248c2ecf20Sopenharmony_ci if (filter & TIPC_SUB_PORTS) 4258c2ecf20Sopenharmony_ci list_add_tail(&p->list, &publ_list); 4268c2ecf20Sopenharmony_ci else if (!first || publication_after(first, p)) 4278c2ecf20Sopenharmony_ci /* Pick this range's *first* publication */ 4288c2ecf20Sopenharmony_ci first = p; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci if (first) 4318c2ecf20Sopenharmony_ci list_add_tail(&first->list, &publ_list); 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* Sort the publications before reporting */ 4358c2ecf20Sopenharmony_ci list_sort(NULL, &publ_list, tipc_publ_sort); 4368c2ecf20Sopenharmony_ci list_for_each_entry_safe(p, tmp, &publ_list, list) { 4378c2ecf20Sopenharmony_ci tipc_sub_report_overlap(sub, p->lower, p->upper, 4388c2ecf20Sopenharmony_ci TIPC_PUBLISHED, p->port, p->node, 4398c2ecf20Sopenharmony_ci p->scope, true); 4408c2ecf20Sopenharmony_ci list_del_init(&p->list); 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic struct tipc_service *tipc_service_find(struct net *net, u32 type) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci struct name_table *nt = tipc_name_table(net); 4478c2ecf20Sopenharmony_ci struct hlist_head *service_head; 4488c2ecf20Sopenharmony_ci struct tipc_service *service; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci service_head = &nt->services[hash(type)]; 4518c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(service, service_head, service_list) { 4528c2ecf20Sopenharmony_ci if (service->type == type) 4538c2ecf20Sopenharmony_ci return service; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci return NULL; 4568c2ecf20Sopenharmony_ci}; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistruct publication *tipc_nametbl_insert_publ(struct net *net, u32 type, 4598c2ecf20Sopenharmony_ci u32 lower, u32 upper, 4608c2ecf20Sopenharmony_ci u32 scope, u32 node, 4618c2ecf20Sopenharmony_ci u32 port, u32 key) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct name_table *nt = tipc_name_table(net); 4648c2ecf20Sopenharmony_ci struct tipc_service *sc; 4658c2ecf20Sopenharmony_ci struct publication *p; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (scope > TIPC_NODE_SCOPE || lower > upper) { 4688c2ecf20Sopenharmony_ci pr_debug("Failed to bind illegal {%u,%u,%u} with scope %u\n", 4698c2ecf20Sopenharmony_ci type, lower, upper, scope); 4708c2ecf20Sopenharmony_ci return NULL; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci sc = tipc_service_find(net, type); 4738c2ecf20Sopenharmony_ci if (!sc) 4748c2ecf20Sopenharmony_ci sc = tipc_service_create(type, &nt->services[hash(type)]); 4758c2ecf20Sopenharmony_ci if (!sc) 4768c2ecf20Sopenharmony_ci return NULL; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci spin_lock_bh(&sc->lock); 4798c2ecf20Sopenharmony_ci p = tipc_service_insert_publ(net, sc, type, lower, upper, 4808c2ecf20Sopenharmony_ci scope, node, port, key); 4818c2ecf20Sopenharmony_ci spin_unlock_bh(&sc->lock); 4828c2ecf20Sopenharmony_ci return p; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistruct publication *tipc_nametbl_remove_publ(struct net *net, u32 type, 4868c2ecf20Sopenharmony_ci u32 lower, u32 upper, 4878c2ecf20Sopenharmony_ci u32 node, u32 key) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct tipc_service *sc = tipc_service_find(net, type); 4908c2ecf20Sopenharmony_ci struct tipc_subscription *sub, *tmp; 4918c2ecf20Sopenharmony_ci struct service_range *sr = NULL; 4928c2ecf20Sopenharmony_ci struct publication *p = NULL; 4938c2ecf20Sopenharmony_ci bool last; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci if (!sc) 4968c2ecf20Sopenharmony_ci return NULL; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci spin_lock_bh(&sc->lock); 4998c2ecf20Sopenharmony_ci sr = tipc_service_find_range(sc, lower, upper); 5008c2ecf20Sopenharmony_ci if (!sr) 5018c2ecf20Sopenharmony_ci goto exit; 5028c2ecf20Sopenharmony_ci p = tipc_service_remove_publ(sr, node, key); 5038c2ecf20Sopenharmony_ci if (!p) 5048c2ecf20Sopenharmony_ci goto exit; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci /* Notify any waiting subscriptions */ 5078c2ecf20Sopenharmony_ci last = list_empty(&sr->all_publ); 5088c2ecf20Sopenharmony_ci list_for_each_entry_safe(sub, tmp, &sc->subscriptions, service_list) { 5098c2ecf20Sopenharmony_ci tipc_sub_report_overlap(sub, lower, upper, TIPC_WITHDRAWN, 5108c2ecf20Sopenharmony_ci p->port, node, p->scope, last); 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* Remove service range item if this was its last publication */ 5148c2ecf20Sopenharmony_ci if (list_empty(&sr->all_publ)) { 5158c2ecf20Sopenharmony_ci rb_erase_augmented(&sr->tree_node, &sc->ranges, &sr_callbacks); 5168c2ecf20Sopenharmony_ci kfree(sr); 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci /* Delete service item if this no more publications and subscriptions */ 5208c2ecf20Sopenharmony_ci if (RB_EMPTY_ROOT(&sc->ranges) && list_empty(&sc->subscriptions)) { 5218c2ecf20Sopenharmony_ci hlist_del_init_rcu(&sc->service_list); 5228c2ecf20Sopenharmony_ci kfree_rcu(sc, rcu); 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ciexit: 5258c2ecf20Sopenharmony_ci spin_unlock_bh(&sc->lock); 5268c2ecf20Sopenharmony_ci return p; 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci/** 5308c2ecf20Sopenharmony_ci * tipc_nametbl_translate - perform service instance to socket translation 5318c2ecf20Sopenharmony_ci * 5328c2ecf20Sopenharmony_ci * On entry, 'dnode' is the search domain used during translation. 5338c2ecf20Sopenharmony_ci * 5348c2ecf20Sopenharmony_ci * On exit: 5358c2ecf20Sopenharmony_ci * - if translation is deferred to another node, leave 'dnode' unchanged and 5368c2ecf20Sopenharmony_ci * return 0 5378c2ecf20Sopenharmony_ci * - if translation is attempted and succeeds, set 'dnode' to the publishing 5388c2ecf20Sopenharmony_ci * node and return the published (non-zero) port number 5398c2ecf20Sopenharmony_ci * - if translation is attempted and fails, set 'dnode' to 0 and return 0 5408c2ecf20Sopenharmony_ci * 5418c2ecf20Sopenharmony_ci * Note that for legacy users (node configured with Z.C.N address format) the 5428c2ecf20Sopenharmony_ci * 'closest-first' lookup algorithm must be maintained, i.e., if dnode is 0 5438c2ecf20Sopenharmony_ci * we must look in the local binding list first 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_ciu32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance, u32 *dnode) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 5488c2ecf20Sopenharmony_ci bool legacy = tn->legacy_addr_format; 5498c2ecf20Sopenharmony_ci u32 self = tipc_own_addr(net); 5508c2ecf20Sopenharmony_ci struct service_range *sr; 5518c2ecf20Sopenharmony_ci struct tipc_service *sc; 5528c2ecf20Sopenharmony_ci struct list_head *list; 5538c2ecf20Sopenharmony_ci struct publication *p; 5548c2ecf20Sopenharmony_ci u32 port = 0; 5558c2ecf20Sopenharmony_ci u32 node = 0; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (!tipc_in_scope(legacy, *dnode, self)) 5588c2ecf20Sopenharmony_ci return 0; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci rcu_read_lock(); 5618c2ecf20Sopenharmony_ci sc = tipc_service_find(net, type); 5628c2ecf20Sopenharmony_ci if (unlikely(!sc)) 5638c2ecf20Sopenharmony_ci goto exit; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci spin_lock_bh(&sc->lock); 5668c2ecf20Sopenharmony_ci service_range_foreach_match(sr, sc, instance, instance) { 5678c2ecf20Sopenharmony_ci /* Select lookup algo: local, closest-first or round-robin */ 5688c2ecf20Sopenharmony_ci if (*dnode == self) { 5698c2ecf20Sopenharmony_ci list = &sr->local_publ; 5708c2ecf20Sopenharmony_ci if (list_empty(list)) 5718c2ecf20Sopenharmony_ci continue; 5728c2ecf20Sopenharmony_ci p = list_first_entry(list, struct publication, 5738c2ecf20Sopenharmony_ci local_publ); 5748c2ecf20Sopenharmony_ci list_move_tail(&p->local_publ, &sr->local_publ); 5758c2ecf20Sopenharmony_ci } else if (legacy && !*dnode && !list_empty(&sr->local_publ)) { 5768c2ecf20Sopenharmony_ci list = &sr->local_publ; 5778c2ecf20Sopenharmony_ci p = list_first_entry(list, struct publication, 5788c2ecf20Sopenharmony_ci local_publ); 5798c2ecf20Sopenharmony_ci list_move_tail(&p->local_publ, &sr->local_publ); 5808c2ecf20Sopenharmony_ci } else { 5818c2ecf20Sopenharmony_ci list = &sr->all_publ; 5828c2ecf20Sopenharmony_ci p = list_first_entry(list, struct publication, 5838c2ecf20Sopenharmony_ci all_publ); 5848c2ecf20Sopenharmony_ci list_move_tail(&p->all_publ, &sr->all_publ); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci port = p->port; 5878c2ecf20Sopenharmony_ci node = p->node; 5888c2ecf20Sopenharmony_ci /* Todo: as for legacy, pick the first matching range only, a 5898c2ecf20Sopenharmony_ci * "true" round-robin will be performed as needed. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ci break; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci spin_unlock_bh(&sc->lock); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ciexit: 5968c2ecf20Sopenharmony_ci rcu_read_unlock(); 5978c2ecf20Sopenharmony_ci *dnode = node; 5988c2ecf20Sopenharmony_ci return port; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cibool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 scope, 6028c2ecf20Sopenharmony_ci struct list_head *dsts, int *dstcnt, u32 exclude, 6038c2ecf20Sopenharmony_ci bool all) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci u32 self = tipc_own_addr(net); 6068c2ecf20Sopenharmony_ci struct service_range *sr; 6078c2ecf20Sopenharmony_ci struct tipc_service *sc; 6088c2ecf20Sopenharmony_ci struct publication *p; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci *dstcnt = 0; 6118c2ecf20Sopenharmony_ci rcu_read_lock(); 6128c2ecf20Sopenharmony_ci sc = tipc_service_find(net, type); 6138c2ecf20Sopenharmony_ci if (unlikely(!sc)) 6148c2ecf20Sopenharmony_ci goto exit; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci spin_lock_bh(&sc->lock); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci /* Todo: a full search i.e. service_range_foreach_match() instead? */ 6198c2ecf20Sopenharmony_ci sr = service_range_match_first(sc->ranges.rb_node, instance, instance); 6208c2ecf20Sopenharmony_ci if (!sr) 6218c2ecf20Sopenharmony_ci goto no_match; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci list_for_each_entry(p, &sr->all_publ, all_publ) { 6248c2ecf20Sopenharmony_ci if (p->scope != scope) 6258c2ecf20Sopenharmony_ci continue; 6268c2ecf20Sopenharmony_ci if (p->port == exclude && p->node == self) 6278c2ecf20Sopenharmony_ci continue; 6288c2ecf20Sopenharmony_ci tipc_dest_push(dsts, p->node, p->port); 6298c2ecf20Sopenharmony_ci (*dstcnt)++; 6308c2ecf20Sopenharmony_ci if (all) 6318c2ecf20Sopenharmony_ci continue; 6328c2ecf20Sopenharmony_ci list_move_tail(&p->all_publ, &sr->all_publ); 6338c2ecf20Sopenharmony_ci break; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_cino_match: 6368c2ecf20Sopenharmony_ci spin_unlock_bh(&sc->lock); 6378c2ecf20Sopenharmony_ciexit: 6388c2ecf20Sopenharmony_ci rcu_read_unlock(); 6398c2ecf20Sopenharmony_ci return !list_empty(dsts); 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_civoid tipc_nametbl_mc_lookup(struct net *net, u32 type, u32 lower, u32 upper, 6438c2ecf20Sopenharmony_ci u32 scope, bool exact, struct list_head *dports) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci struct service_range *sr; 6468c2ecf20Sopenharmony_ci struct tipc_service *sc; 6478c2ecf20Sopenharmony_ci struct publication *p; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci rcu_read_lock(); 6508c2ecf20Sopenharmony_ci sc = tipc_service_find(net, type); 6518c2ecf20Sopenharmony_ci if (!sc) 6528c2ecf20Sopenharmony_ci goto exit; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci spin_lock_bh(&sc->lock); 6558c2ecf20Sopenharmony_ci service_range_foreach_match(sr, sc, lower, upper) { 6568c2ecf20Sopenharmony_ci list_for_each_entry(p, &sr->local_publ, local_publ) { 6578c2ecf20Sopenharmony_ci if (p->scope == scope || (!exact && p->scope < scope)) 6588c2ecf20Sopenharmony_ci tipc_dest_push(dports, 0, p->port); 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci spin_unlock_bh(&sc->lock); 6628c2ecf20Sopenharmony_ciexit: 6638c2ecf20Sopenharmony_ci rcu_read_unlock(); 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci/* tipc_nametbl_lookup_dst_nodes - find broadcast destination nodes 6678c2ecf20Sopenharmony_ci * - Creates list of nodes that overlap the given multicast address 6688c2ecf20Sopenharmony_ci * - Determines if any node local destinations overlap 6698c2ecf20Sopenharmony_ci */ 6708c2ecf20Sopenharmony_civoid tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower, 6718c2ecf20Sopenharmony_ci u32 upper, struct tipc_nlist *nodes) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci struct service_range *sr; 6748c2ecf20Sopenharmony_ci struct tipc_service *sc; 6758c2ecf20Sopenharmony_ci struct publication *p; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci rcu_read_lock(); 6788c2ecf20Sopenharmony_ci sc = tipc_service_find(net, type); 6798c2ecf20Sopenharmony_ci if (!sc) 6808c2ecf20Sopenharmony_ci goto exit; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci spin_lock_bh(&sc->lock); 6838c2ecf20Sopenharmony_ci service_range_foreach_match(sr, sc, lower, upper) { 6848c2ecf20Sopenharmony_ci list_for_each_entry(p, &sr->all_publ, all_publ) { 6858c2ecf20Sopenharmony_ci tipc_nlist_add(nodes, p->node); 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci spin_unlock_bh(&sc->lock); 6898c2ecf20Sopenharmony_ciexit: 6908c2ecf20Sopenharmony_ci rcu_read_unlock(); 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci/* tipc_nametbl_build_group - build list of communication group members 6948c2ecf20Sopenharmony_ci */ 6958c2ecf20Sopenharmony_civoid tipc_nametbl_build_group(struct net *net, struct tipc_group *grp, 6968c2ecf20Sopenharmony_ci u32 type, u32 scope) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci struct service_range *sr; 6998c2ecf20Sopenharmony_ci struct tipc_service *sc; 7008c2ecf20Sopenharmony_ci struct publication *p; 7018c2ecf20Sopenharmony_ci struct rb_node *n; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci rcu_read_lock(); 7048c2ecf20Sopenharmony_ci sc = tipc_service_find(net, type); 7058c2ecf20Sopenharmony_ci if (!sc) 7068c2ecf20Sopenharmony_ci goto exit; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci spin_lock_bh(&sc->lock); 7098c2ecf20Sopenharmony_ci for (n = rb_first(&sc->ranges); n; n = rb_next(n)) { 7108c2ecf20Sopenharmony_ci sr = container_of(n, struct service_range, tree_node); 7118c2ecf20Sopenharmony_ci list_for_each_entry(p, &sr->all_publ, all_publ) { 7128c2ecf20Sopenharmony_ci if (p->scope != scope) 7138c2ecf20Sopenharmony_ci continue; 7148c2ecf20Sopenharmony_ci tipc_group_add_member(grp, p->node, p->port, p->lower); 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci spin_unlock_bh(&sc->lock); 7188c2ecf20Sopenharmony_ciexit: 7198c2ecf20Sopenharmony_ci rcu_read_unlock(); 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci/* tipc_nametbl_publish - add service binding to name table 7238c2ecf20Sopenharmony_ci */ 7248c2ecf20Sopenharmony_cistruct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower, 7258c2ecf20Sopenharmony_ci u32 upper, u32 scope, u32 port, 7268c2ecf20Sopenharmony_ci u32 key) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci struct name_table *nt = tipc_name_table(net); 7298c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 7308c2ecf20Sopenharmony_ci struct publication *p = NULL; 7318c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 7328c2ecf20Sopenharmony_ci u32 rc_dests; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci spin_lock_bh(&tn->nametbl_lock); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (nt->local_publ_count >= TIPC_MAX_PUBL) { 7378c2ecf20Sopenharmony_ci pr_warn("Bind failed, max limit %u reached\n", TIPC_MAX_PUBL); 7388c2ecf20Sopenharmony_ci goto exit; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci p = tipc_nametbl_insert_publ(net, type, lower, upper, scope, 7428c2ecf20Sopenharmony_ci tipc_own_addr(net), port, key); 7438c2ecf20Sopenharmony_ci if (p) { 7448c2ecf20Sopenharmony_ci nt->local_publ_count++; 7458c2ecf20Sopenharmony_ci skb = tipc_named_publish(net, p); 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci rc_dests = nt->rc_dests; 7488c2ecf20Sopenharmony_ciexit: 7498c2ecf20Sopenharmony_ci spin_unlock_bh(&tn->nametbl_lock); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (skb) 7528c2ecf20Sopenharmony_ci tipc_node_broadcast(net, skb, rc_dests); 7538c2ecf20Sopenharmony_ci return p; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci/** 7588c2ecf20Sopenharmony_ci * tipc_nametbl_withdraw - withdraw a service binding 7598c2ecf20Sopenharmony_ci */ 7608c2ecf20Sopenharmony_ciint tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, 7618c2ecf20Sopenharmony_ci u32 upper, u32 key) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci struct name_table *nt = tipc_name_table(net); 7648c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 7658c2ecf20Sopenharmony_ci u32 self = tipc_own_addr(net); 7668c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 7678c2ecf20Sopenharmony_ci struct publication *p; 7688c2ecf20Sopenharmony_ci u32 rc_dests; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci spin_lock_bh(&tn->nametbl_lock); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci p = tipc_nametbl_remove_publ(net, type, lower, upper, self, key); 7738c2ecf20Sopenharmony_ci if (p) { 7748c2ecf20Sopenharmony_ci nt->local_publ_count--; 7758c2ecf20Sopenharmony_ci skb = tipc_named_withdraw(net, p); 7768c2ecf20Sopenharmony_ci list_del_init(&p->binding_sock); 7778c2ecf20Sopenharmony_ci kfree_rcu(p, rcu); 7788c2ecf20Sopenharmony_ci } else { 7798c2ecf20Sopenharmony_ci pr_err("Failed to remove local publication {%u,%u,%u}/%u\n", 7808c2ecf20Sopenharmony_ci type, lower, upper, key); 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci rc_dests = nt->rc_dests; 7838c2ecf20Sopenharmony_ci spin_unlock_bh(&tn->nametbl_lock); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (skb) { 7868c2ecf20Sopenharmony_ci tipc_node_broadcast(net, skb, rc_dests); 7878c2ecf20Sopenharmony_ci return 1; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci return 0; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci/** 7938c2ecf20Sopenharmony_ci * tipc_nametbl_subscribe - add a subscription object to the name table 7948c2ecf20Sopenharmony_ci */ 7958c2ecf20Sopenharmony_cibool tipc_nametbl_subscribe(struct tipc_subscription *sub) 7968c2ecf20Sopenharmony_ci{ 7978c2ecf20Sopenharmony_ci struct name_table *nt = tipc_name_table(sub->net); 7988c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(sub->net); 7998c2ecf20Sopenharmony_ci struct tipc_subscr *s = &sub->evt.s; 8008c2ecf20Sopenharmony_ci u32 type = tipc_sub_read(s, seq.type); 8018c2ecf20Sopenharmony_ci struct tipc_service *sc; 8028c2ecf20Sopenharmony_ci bool res = true; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci spin_lock_bh(&tn->nametbl_lock); 8058c2ecf20Sopenharmony_ci sc = tipc_service_find(sub->net, type); 8068c2ecf20Sopenharmony_ci if (!sc) 8078c2ecf20Sopenharmony_ci sc = tipc_service_create(type, &nt->services[hash(type)]); 8088c2ecf20Sopenharmony_ci if (sc) { 8098c2ecf20Sopenharmony_ci spin_lock_bh(&sc->lock); 8108c2ecf20Sopenharmony_ci tipc_service_subscribe(sc, sub); 8118c2ecf20Sopenharmony_ci spin_unlock_bh(&sc->lock); 8128c2ecf20Sopenharmony_ci } else { 8138c2ecf20Sopenharmony_ci pr_warn("Failed to subscribe for {%u,%u,%u}\n", type, 8148c2ecf20Sopenharmony_ci tipc_sub_read(s, seq.lower), 8158c2ecf20Sopenharmony_ci tipc_sub_read(s, seq.upper)); 8168c2ecf20Sopenharmony_ci res = false; 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci spin_unlock_bh(&tn->nametbl_lock); 8198c2ecf20Sopenharmony_ci return res; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci/** 8238c2ecf20Sopenharmony_ci * tipc_nametbl_unsubscribe - remove a subscription object from name table 8248c2ecf20Sopenharmony_ci */ 8258c2ecf20Sopenharmony_civoid tipc_nametbl_unsubscribe(struct tipc_subscription *sub) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(sub->net); 8288c2ecf20Sopenharmony_ci struct tipc_subscr *s = &sub->evt.s; 8298c2ecf20Sopenharmony_ci u32 type = tipc_sub_read(s, seq.type); 8308c2ecf20Sopenharmony_ci struct tipc_service *sc; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci spin_lock_bh(&tn->nametbl_lock); 8338c2ecf20Sopenharmony_ci sc = tipc_service_find(sub->net, type); 8348c2ecf20Sopenharmony_ci if (!sc) 8358c2ecf20Sopenharmony_ci goto exit; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci spin_lock_bh(&sc->lock); 8388c2ecf20Sopenharmony_ci list_del_init(&sub->service_list); 8398c2ecf20Sopenharmony_ci tipc_sub_put(sub); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* Delete service item if no more publications and subscriptions */ 8428c2ecf20Sopenharmony_ci if (RB_EMPTY_ROOT(&sc->ranges) && list_empty(&sc->subscriptions)) { 8438c2ecf20Sopenharmony_ci hlist_del_init_rcu(&sc->service_list); 8448c2ecf20Sopenharmony_ci kfree_rcu(sc, rcu); 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci spin_unlock_bh(&sc->lock); 8478c2ecf20Sopenharmony_ciexit: 8488c2ecf20Sopenharmony_ci spin_unlock_bh(&tn->nametbl_lock); 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ciint tipc_nametbl_init(struct net *net) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 8548c2ecf20Sopenharmony_ci struct name_table *nt; 8558c2ecf20Sopenharmony_ci int i; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci nt = kzalloc(sizeof(*nt), GFP_KERNEL); 8588c2ecf20Sopenharmony_ci if (!nt) 8598c2ecf20Sopenharmony_ci return -ENOMEM; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci for (i = 0; i < TIPC_NAMETBL_SIZE; i++) 8628c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&nt->services[i]); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&nt->node_scope); 8658c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&nt->cluster_scope); 8668c2ecf20Sopenharmony_ci rwlock_init(&nt->cluster_scope_lock); 8678c2ecf20Sopenharmony_ci tn->nametbl = nt; 8688c2ecf20Sopenharmony_ci spin_lock_init(&tn->nametbl_lock); 8698c2ecf20Sopenharmony_ci return 0; 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci/** 8738c2ecf20Sopenharmony_ci * tipc_service_delete - purge all publications for a service and delete it 8748c2ecf20Sopenharmony_ci */ 8758c2ecf20Sopenharmony_cistatic void tipc_service_delete(struct net *net, struct tipc_service *sc) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci struct service_range *sr, *tmpr; 8788c2ecf20Sopenharmony_ci struct publication *p, *tmp; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci spin_lock_bh(&sc->lock); 8818c2ecf20Sopenharmony_ci rbtree_postorder_for_each_entry_safe(sr, tmpr, &sc->ranges, tree_node) { 8828c2ecf20Sopenharmony_ci list_for_each_entry_safe(p, tmp, &sr->all_publ, all_publ) { 8838c2ecf20Sopenharmony_ci tipc_service_remove_publ(sr, p->node, p->key); 8848c2ecf20Sopenharmony_ci kfree_rcu(p, rcu); 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci rb_erase_augmented(&sr->tree_node, &sc->ranges, &sr_callbacks); 8878c2ecf20Sopenharmony_ci kfree(sr); 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci hlist_del_init_rcu(&sc->service_list); 8908c2ecf20Sopenharmony_ci spin_unlock_bh(&sc->lock); 8918c2ecf20Sopenharmony_ci kfree_rcu(sc, rcu); 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_civoid tipc_nametbl_stop(struct net *net) 8958c2ecf20Sopenharmony_ci{ 8968c2ecf20Sopenharmony_ci struct name_table *nt = tipc_name_table(net); 8978c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 8988c2ecf20Sopenharmony_ci struct hlist_head *service_head; 8998c2ecf20Sopenharmony_ci struct tipc_service *service; 9008c2ecf20Sopenharmony_ci u32 i; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci /* Verify name table is empty and purge any lingering 9038c2ecf20Sopenharmony_ci * publications, then release the name table 9048c2ecf20Sopenharmony_ci */ 9058c2ecf20Sopenharmony_ci spin_lock_bh(&tn->nametbl_lock); 9068c2ecf20Sopenharmony_ci for (i = 0; i < TIPC_NAMETBL_SIZE; i++) { 9078c2ecf20Sopenharmony_ci if (hlist_empty(&nt->services[i])) 9088c2ecf20Sopenharmony_ci continue; 9098c2ecf20Sopenharmony_ci service_head = &nt->services[i]; 9108c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(service, service_head, service_list) { 9118c2ecf20Sopenharmony_ci tipc_service_delete(net, service); 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci spin_unlock_bh(&tn->nametbl_lock); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci synchronize_net(); 9178c2ecf20Sopenharmony_ci kfree(nt); 9188c2ecf20Sopenharmony_ci} 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_cistatic int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg, 9218c2ecf20Sopenharmony_ci struct tipc_service *service, 9228c2ecf20Sopenharmony_ci struct service_range *sr, 9238c2ecf20Sopenharmony_ci u32 *last_key) 9248c2ecf20Sopenharmony_ci{ 9258c2ecf20Sopenharmony_ci struct publication *p; 9268c2ecf20Sopenharmony_ci struct nlattr *attrs; 9278c2ecf20Sopenharmony_ci struct nlattr *b; 9288c2ecf20Sopenharmony_ci void *hdr; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (*last_key) { 9318c2ecf20Sopenharmony_ci list_for_each_entry(p, &sr->all_publ, all_publ) 9328c2ecf20Sopenharmony_ci if (p->key == *last_key) 9338c2ecf20Sopenharmony_ci break; 9348c2ecf20Sopenharmony_ci if (list_entry_is_head(p, &sr->all_publ, all_publ)) 9358c2ecf20Sopenharmony_ci return -EPIPE; 9368c2ecf20Sopenharmony_ci } else { 9378c2ecf20Sopenharmony_ci p = list_first_entry(&sr->all_publ, 9388c2ecf20Sopenharmony_ci struct publication, 9398c2ecf20Sopenharmony_ci all_publ); 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci list_for_each_entry_from(p, &sr->all_publ, all_publ) { 9438c2ecf20Sopenharmony_ci *last_key = p->key; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, 9468c2ecf20Sopenharmony_ci &tipc_genl_family, NLM_F_MULTI, 9478c2ecf20Sopenharmony_ci TIPC_NL_NAME_TABLE_GET); 9488c2ecf20Sopenharmony_ci if (!hdr) 9498c2ecf20Sopenharmony_ci return -EMSGSIZE; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_NAME_TABLE); 9528c2ecf20Sopenharmony_ci if (!attrs) 9538c2ecf20Sopenharmony_ci goto msg_full; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci b = nla_nest_start_noflag(msg->skb, TIPC_NLA_NAME_TABLE_PUBL); 9568c2ecf20Sopenharmony_ci if (!b) 9578c2ecf20Sopenharmony_ci goto attr_msg_full; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_TYPE, service->type)) 9608c2ecf20Sopenharmony_ci goto publ_msg_full; 9618c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_LOWER, sr->lower)) 9628c2ecf20Sopenharmony_ci goto publ_msg_full; 9638c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_UPPER, sr->upper)) 9648c2ecf20Sopenharmony_ci goto publ_msg_full; 9658c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_SCOPE, p->scope)) 9668c2ecf20Sopenharmony_ci goto publ_msg_full; 9678c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_NODE, p->node)) 9688c2ecf20Sopenharmony_ci goto publ_msg_full; 9698c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_REF, p->port)) 9708c2ecf20Sopenharmony_ci goto publ_msg_full; 9718c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_KEY, p->key)) 9728c2ecf20Sopenharmony_ci goto publ_msg_full; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci nla_nest_end(msg->skb, b); 9758c2ecf20Sopenharmony_ci nla_nest_end(msg->skb, attrs); 9768c2ecf20Sopenharmony_ci genlmsg_end(msg->skb, hdr); 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci *last_key = 0; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci return 0; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_cipubl_msg_full: 9838c2ecf20Sopenharmony_ci nla_nest_cancel(msg->skb, b); 9848c2ecf20Sopenharmony_ciattr_msg_full: 9858c2ecf20Sopenharmony_ci nla_nest_cancel(msg->skb, attrs); 9868c2ecf20Sopenharmony_cimsg_full: 9878c2ecf20Sopenharmony_ci genlmsg_cancel(msg->skb, hdr); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci return -EMSGSIZE; 9908c2ecf20Sopenharmony_ci} 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_cistatic int __tipc_nl_service_range_list(struct tipc_nl_msg *msg, 9938c2ecf20Sopenharmony_ci struct tipc_service *sc, 9948c2ecf20Sopenharmony_ci u32 *last_lower, u32 *last_key) 9958c2ecf20Sopenharmony_ci{ 9968c2ecf20Sopenharmony_ci struct service_range *sr; 9978c2ecf20Sopenharmony_ci struct rb_node *n; 9988c2ecf20Sopenharmony_ci int err; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci for (n = rb_first(&sc->ranges); n; n = rb_next(n)) { 10018c2ecf20Sopenharmony_ci sr = container_of(n, struct service_range, tree_node); 10028c2ecf20Sopenharmony_ci if (sr->lower < *last_lower) 10038c2ecf20Sopenharmony_ci continue; 10048c2ecf20Sopenharmony_ci err = __tipc_nl_add_nametable_publ(msg, sc, sr, last_key); 10058c2ecf20Sopenharmony_ci if (err) { 10068c2ecf20Sopenharmony_ci *last_lower = sr->lower; 10078c2ecf20Sopenharmony_ci return err; 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci *last_lower = 0; 10118c2ecf20Sopenharmony_ci return 0; 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_cistatic int tipc_nl_service_list(struct net *net, struct tipc_nl_msg *msg, 10158c2ecf20Sopenharmony_ci u32 *last_type, u32 *last_lower, u32 *last_key) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 10188c2ecf20Sopenharmony_ci struct tipc_service *service = NULL; 10198c2ecf20Sopenharmony_ci struct hlist_head *head; 10208c2ecf20Sopenharmony_ci int err; 10218c2ecf20Sopenharmony_ci int i; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (*last_type) 10248c2ecf20Sopenharmony_ci i = hash(*last_type); 10258c2ecf20Sopenharmony_ci else 10268c2ecf20Sopenharmony_ci i = 0; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci for (; i < TIPC_NAMETBL_SIZE; i++) { 10298c2ecf20Sopenharmony_ci head = &tn->nametbl->services[i]; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (*last_type || 10328c2ecf20Sopenharmony_ci (!i && *last_key && (*last_lower == *last_key))) { 10338c2ecf20Sopenharmony_ci service = tipc_service_find(net, *last_type); 10348c2ecf20Sopenharmony_ci if (!service) 10358c2ecf20Sopenharmony_ci return -EPIPE; 10368c2ecf20Sopenharmony_ci } else { 10378c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(service, head, service_list) 10388c2ecf20Sopenharmony_ci break; 10398c2ecf20Sopenharmony_ci if (!service) 10408c2ecf20Sopenharmony_ci continue; 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci hlist_for_each_entry_from_rcu(service, service_list) { 10448c2ecf20Sopenharmony_ci spin_lock_bh(&service->lock); 10458c2ecf20Sopenharmony_ci err = __tipc_nl_service_range_list(msg, service, 10468c2ecf20Sopenharmony_ci last_lower, 10478c2ecf20Sopenharmony_ci last_key); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (err) { 10508c2ecf20Sopenharmony_ci *last_type = service->type; 10518c2ecf20Sopenharmony_ci spin_unlock_bh(&service->lock); 10528c2ecf20Sopenharmony_ci return err; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci spin_unlock_bh(&service->lock); 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci *last_type = 0; 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci return 0; 10598c2ecf20Sopenharmony_ci} 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ciint tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb) 10628c2ecf20Sopenharmony_ci{ 10638c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 10648c2ecf20Sopenharmony_ci u32 last_type = cb->args[0]; 10658c2ecf20Sopenharmony_ci u32 last_lower = cb->args[1]; 10668c2ecf20Sopenharmony_ci u32 last_key = cb->args[2]; 10678c2ecf20Sopenharmony_ci int done = cb->args[3]; 10688c2ecf20Sopenharmony_ci struct tipc_nl_msg msg; 10698c2ecf20Sopenharmony_ci int err; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (done) 10728c2ecf20Sopenharmony_ci return 0; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci msg.skb = skb; 10758c2ecf20Sopenharmony_ci msg.portid = NETLINK_CB(cb->skb).portid; 10768c2ecf20Sopenharmony_ci msg.seq = cb->nlh->nlmsg_seq; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci rcu_read_lock(); 10798c2ecf20Sopenharmony_ci err = tipc_nl_service_list(net, &msg, &last_type, 10808c2ecf20Sopenharmony_ci &last_lower, &last_key); 10818c2ecf20Sopenharmony_ci if (!err) { 10828c2ecf20Sopenharmony_ci done = 1; 10838c2ecf20Sopenharmony_ci } else if (err != -EMSGSIZE) { 10848c2ecf20Sopenharmony_ci /* We never set seq or call nl_dump_check_consistent() this 10858c2ecf20Sopenharmony_ci * means that setting prev_seq here will cause the consistence 10868c2ecf20Sopenharmony_ci * check to fail in the netlink callback handler. Resulting in 10878c2ecf20Sopenharmony_ci * the NLMSG_DONE message having the NLM_F_DUMP_INTR flag set if 10888c2ecf20Sopenharmony_ci * we got an error. 10898c2ecf20Sopenharmony_ci */ 10908c2ecf20Sopenharmony_ci cb->prev_seq = 1; 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci rcu_read_unlock(); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci cb->args[0] = last_type; 10958c2ecf20Sopenharmony_ci cb->args[1] = last_lower; 10968c2ecf20Sopenharmony_ci cb->args[2] = last_key; 10978c2ecf20Sopenharmony_ci cb->args[3] = done; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci return skb->len; 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_cistruct tipc_dest *tipc_dest_find(struct list_head *l, u32 node, u32 port) 11038c2ecf20Sopenharmony_ci{ 11048c2ecf20Sopenharmony_ci struct tipc_dest *dst; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci list_for_each_entry(dst, l, list) { 11078c2ecf20Sopenharmony_ci if (dst->node == node && dst->port == port) 11088c2ecf20Sopenharmony_ci return dst; 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci return NULL; 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cibool tipc_dest_push(struct list_head *l, u32 node, u32 port) 11148c2ecf20Sopenharmony_ci{ 11158c2ecf20Sopenharmony_ci struct tipc_dest *dst; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci if (tipc_dest_find(l, node, port)) 11188c2ecf20Sopenharmony_ci return false; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci dst = kmalloc(sizeof(*dst), GFP_ATOMIC); 11218c2ecf20Sopenharmony_ci if (unlikely(!dst)) 11228c2ecf20Sopenharmony_ci return false; 11238c2ecf20Sopenharmony_ci dst->node = node; 11248c2ecf20Sopenharmony_ci dst->port = port; 11258c2ecf20Sopenharmony_ci list_add(&dst->list, l); 11268c2ecf20Sopenharmony_ci return true; 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_cibool tipc_dest_pop(struct list_head *l, u32 *node, u32 *port) 11308c2ecf20Sopenharmony_ci{ 11318c2ecf20Sopenharmony_ci struct tipc_dest *dst; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (list_empty(l)) 11348c2ecf20Sopenharmony_ci return false; 11358c2ecf20Sopenharmony_ci dst = list_first_entry(l, typeof(*dst), list); 11368c2ecf20Sopenharmony_ci if (port) 11378c2ecf20Sopenharmony_ci *port = dst->port; 11388c2ecf20Sopenharmony_ci if (node) 11398c2ecf20Sopenharmony_ci *node = dst->node; 11408c2ecf20Sopenharmony_ci list_del(&dst->list); 11418c2ecf20Sopenharmony_ci kfree(dst); 11428c2ecf20Sopenharmony_ci return true; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cibool tipc_dest_del(struct list_head *l, u32 node, u32 port) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci struct tipc_dest *dst; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci dst = tipc_dest_find(l, node, port); 11508c2ecf20Sopenharmony_ci if (!dst) 11518c2ecf20Sopenharmony_ci return false; 11528c2ecf20Sopenharmony_ci list_del(&dst->list); 11538c2ecf20Sopenharmony_ci kfree(dst); 11548c2ecf20Sopenharmony_ci return true; 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_civoid tipc_dest_list_purge(struct list_head *l) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci struct tipc_dest *dst, *tmp; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci list_for_each_entry_safe(dst, tmp, l, list) { 11628c2ecf20Sopenharmony_ci list_del(&dst->list); 11638c2ecf20Sopenharmony_ci kfree(dst); 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci} 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ciint tipc_dest_list_len(struct list_head *l) 11688c2ecf20Sopenharmony_ci{ 11698c2ecf20Sopenharmony_ci struct tipc_dest *dst; 11708c2ecf20Sopenharmony_ci int i = 0; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci list_for_each_entry(dst, l, list) { 11738c2ecf20Sopenharmony_ci i++; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci return i; 11768c2ecf20Sopenharmony_ci} 1177