xref: /openbmc/linux/net/tipc/name_table.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1b97bf3fdSPer Liden /*
2b97bf3fdSPer Liden  * net/tipc/name_table.c: TIPC name table code
3b97bf3fdSPer Liden  *
4e50e73e1SJon Maloy  * Copyright (c) 2000-2006, 2014-2018, Ericsson AB
5993bfe5dSYing Xue  * Copyright (c) 2004-2008, 2010-2014, Wind River Systems
6998d3907SJon Maloy  * Copyright (c) 2020-2021, Red Hat Inc
7b97bf3fdSPer Liden  * All rights reserved.
8b97bf3fdSPer Liden  *
9b97bf3fdSPer Liden  * Redistribution and use in source and binary forms, with or without
10b97bf3fdSPer Liden  * modification, are permitted provided that the following conditions are met:
11b97bf3fdSPer Liden  *
129ea1fd3cSPer Liden  * 1. Redistributions of source code must retain the above copyright
139ea1fd3cSPer Liden  *    notice, this list of conditions and the following disclaimer.
149ea1fd3cSPer Liden  * 2. Redistributions in binary form must reproduce the above copyright
159ea1fd3cSPer Liden  *    notice, this list of conditions and the following disclaimer in the
169ea1fd3cSPer Liden  *    documentation and/or other materials provided with the distribution.
179ea1fd3cSPer Liden  * 3. Neither the names of the copyright holders nor the names of its
189ea1fd3cSPer Liden  *    contributors may be used to endorse or promote products derived from
199ea1fd3cSPer Liden  *    this software without specific prior written permission.
209ea1fd3cSPer Liden  *
219ea1fd3cSPer Liden  * Alternatively, this software may be distributed under the terms of the
229ea1fd3cSPer Liden  * GNU General Public License ("GPL") version 2 as published by the Free
239ea1fd3cSPer Liden  * Software Foundation.
24b97bf3fdSPer Liden  *
25b97bf3fdSPer Liden  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26b97bf3fdSPer Liden  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27b97bf3fdSPer Liden  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28b97bf3fdSPer Liden  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29b97bf3fdSPer Liden  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30b97bf3fdSPer Liden  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31b97bf3fdSPer Liden  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32b97bf3fdSPer Liden  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33b97bf3fdSPer Liden  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34b97bf3fdSPer Liden  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35b97bf3fdSPer Liden  * POSSIBILITY OF SUCH DAMAGE.
36b97bf3fdSPer Liden  */
37b97bf3fdSPer Liden 
384ac1c8d0SYing Xue #include <net/sock.h>
3941b416f1STuong Lien #include <linux/list_sort.h>
40d5162f34STuong Lien #include <linux/rbtree_augmented.h>
41b97bf3fdSPer Liden #include "core.h"
4222ae7cffSRichard Alpe #include "netlink.h"
43b97bf3fdSPer Liden #include "name_table.h"
44b97bf3fdSPer Liden #include "name_distr.h"
45b97bf3fdSPer Liden #include "subscr.h"
461da46568SYing Xue #include "bcast.h"
4722ae7cffSRichard Alpe #include "addr.h"
481d7e1c25SJon Paul Maloy #include "node.h"
4975da2163SJon Maloy #include "group.h"
50b97bf3fdSPer Liden 
51b97bf3fdSPer Liden /**
52218527feSJon Maloy  * struct service_range - container for all bindings of a service range
53218527feSJon Maloy  * @lower: service range lower bound
54218527feSJon Maloy  * @upper: service range upper bound
55218527feSJon Maloy  * @tree_node: member of service range RB tree
56d5162f34STuong Lien  * @max: largest 'upper' in this node subtree
57218527feSJon Maloy  * @local_publ: list of identical publications made from this node
58218527feSJon Maloy  *   Used by closest_first lookup and multicast lookup algorithm
59218527feSJon Maloy  * @all_publ: all publications identical to this one, whatever node and scope
60218527feSJon Maloy  *   Used by round-robin lookup algorithm
61b97bf3fdSPer Liden  */
62218527feSJon Maloy struct service_range {
63218527feSJon Maloy 	u32 lower;
64218527feSJon Maloy 	u32 upper;
65218527feSJon Maloy 	struct rb_node tree_node;
66d5162f34STuong Lien 	u32 max;
67e50e73e1SJon Maloy 	struct list_head local_publ;
68e50e73e1SJon Maloy 	struct list_head all_publ;
69b97bf3fdSPer Liden };
70b97bf3fdSPer Liden 
71b97bf3fdSPer Liden /**
72218527feSJon Maloy  * struct tipc_service - container for all published instances of a service type
73218527feSJon Maloy  * @type: 32 bit 'type' value for service
7441b416f1STuong Lien  * @publ_cnt: increasing counter for publications in this service
75218527feSJon Maloy  * @ranges: rb tree containing all service ranges for this service
76218527feSJon Maloy  * @service_list: links to adjacent name ranges in hash chain
77218527feSJon Maloy  * @subscriptions: list of subscriptions for this service type
78218527feSJon Maloy  * @lock: spinlock controlling access to pertaining service ranges/publications
7997ede29eSYing Xue  * @rcu: RCU callback head used for deferred freeing
80b97bf3fdSPer Liden  */
81218527feSJon Maloy struct tipc_service {
82b97bf3fdSPer Liden 	u32 type;
8341b416f1STuong Lien 	u32 publ_cnt;
84218527feSJon Maloy 	struct rb_root ranges;
85218527feSJon Maloy 	struct hlist_node service_list;
86b97bf3fdSPer Liden 	struct list_head subscriptions;
87218527feSJon Maloy 	spinlock_t lock; /* Covers service range list */
8897ede29eSYing Xue 	struct rcu_head rcu;
89b97bf3fdSPer Liden };
90b97bf3fdSPer Liden 
91d5162f34STuong Lien #define service_range_upper(sr) ((sr)->upper)
RB_DECLARE_CALLBACKS_MAX(static,sr_callbacks,struct service_range,tree_node,u32,max,service_range_upper)92d5162f34STuong Lien RB_DECLARE_CALLBACKS_MAX(static, sr_callbacks,
93d5162f34STuong Lien 			 struct service_range, tree_node, u32, max,
94d5162f34STuong Lien 			 service_range_upper)
95d5162f34STuong Lien 
96d5162f34STuong Lien #define service_range_entry(rbtree_node)				\
97d5162f34STuong Lien 	(container_of(rbtree_node, struct service_range, tree_node))
98d5162f34STuong Lien 
99d5162f34STuong Lien #define service_range_overlap(sr, start, end)				\
100d5162f34STuong Lien 	((sr)->lower <= (end) && (sr)->upper >= (start))
101d5162f34STuong Lien 
102d5162f34STuong Lien /**
103d5162f34STuong Lien  * service_range_foreach_match - iterate over tipc service rbtree for each
104d5162f34STuong Lien  *                               range match
105d5162f34STuong Lien  * @sr: the service range pointer as a loop cursor
106d5162f34STuong Lien  * @sc: the pointer to tipc service which holds the service range rbtree
1075c5d6796SRandy Dunlap  * @start: beginning of the search range (end >= start) for matching
1085c5d6796SRandy Dunlap  * @end: end of the search range (end >= start) for matching
109d5162f34STuong Lien  */
110d5162f34STuong Lien #define service_range_foreach_match(sr, sc, start, end)			\
111d5162f34STuong Lien 	for (sr = service_range_match_first((sc)->ranges.rb_node,	\
112d5162f34STuong Lien 					    start,			\
113d5162f34STuong Lien 					    end);			\
114d5162f34STuong Lien 	     sr;							\
115d5162f34STuong Lien 	     sr = service_range_match_next(&(sr)->tree_node,		\
116d5162f34STuong Lien 					   start,			\
117d5162f34STuong Lien 					   end))
118d5162f34STuong Lien 
119d5162f34STuong Lien /**
120d5162f34STuong Lien  * service_range_match_first - find first service range matching a range
121d5162f34STuong Lien  * @n: the root node of service range rbtree for searching
1225c5d6796SRandy Dunlap  * @start: beginning of the search range (end >= start) for matching
1235c5d6796SRandy Dunlap  * @end: end of the search range (end >= start) for matching
124d5162f34STuong Lien  *
125d5162f34STuong Lien  * Return: the leftmost service range node in the rbtree that overlaps the
126d5162f34STuong Lien  * specific range if any. Otherwise, returns NULL.
127d5162f34STuong Lien  */
128d5162f34STuong Lien static struct service_range *service_range_match_first(struct rb_node *n,
129d5162f34STuong Lien 						       u32 start, u32 end)
130d5162f34STuong Lien {
131d5162f34STuong Lien 	struct service_range *sr;
132d5162f34STuong Lien 	struct rb_node *l, *r;
133d5162f34STuong Lien 
134d5162f34STuong Lien 	/* Non overlaps in tree at all? */
135d5162f34STuong Lien 	if (!n || service_range_entry(n)->max < start)
136d5162f34STuong Lien 		return NULL;
137d5162f34STuong Lien 
138d5162f34STuong Lien 	while (n) {
139d5162f34STuong Lien 		l = n->rb_left;
140d5162f34STuong Lien 		if (l && service_range_entry(l)->max >= start) {
141d5162f34STuong Lien 			/* A leftmost overlap range node must be one in the left
142d5162f34STuong Lien 			 * subtree. If not, it has lower > end, then nodes on
143d5162f34STuong Lien 			 * the right side cannot satisfy the condition either.
144d5162f34STuong Lien 			 */
145d5162f34STuong Lien 			n = l;
146d5162f34STuong Lien 			continue;
147d5162f34STuong Lien 		}
148d5162f34STuong Lien 
149d5162f34STuong Lien 		/* No one in the left subtree can match, return if this node is
150d5162f34STuong Lien 		 * an overlap i.e. leftmost.
151d5162f34STuong Lien 		 */
152d5162f34STuong Lien 		sr = service_range_entry(n);
153d5162f34STuong Lien 		if (service_range_overlap(sr, start, end))
154d5162f34STuong Lien 			return sr;
155d5162f34STuong Lien 
156d5162f34STuong Lien 		/* Ok, try to lookup on the right side */
157d5162f34STuong Lien 		r = n->rb_right;
158d5162f34STuong Lien 		if (sr->lower <= end &&
159d5162f34STuong Lien 		    r && service_range_entry(r)->max >= start) {
160d5162f34STuong Lien 			n = r;
161d5162f34STuong Lien 			continue;
162d5162f34STuong Lien 		}
163d5162f34STuong Lien 		break;
164d5162f34STuong Lien 	}
165d5162f34STuong Lien 
166d5162f34STuong Lien 	return NULL;
167d5162f34STuong Lien }
168d5162f34STuong Lien 
169d5162f34STuong Lien /**
170d5162f34STuong Lien  * service_range_match_next - find next service range matching a range
171d5162f34STuong Lien  * @n: a node in service range rbtree from which the searching starts
1725c5d6796SRandy Dunlap  * @start: beginning of the search range (end >= start) for matching
1735c5d6796SRandy Dunlap  * @end: end of the search range (end >= start) for matching
174d5162f34STuong Lien  *
175d5162f34STuong Lien  * Return: the next service range node to the given node in the rbtree that
176d5162f34STuong Lien  * overlaps the specific range if any. Otherwise, returns NULL.
177d5162f34STuong Lien  */
service_range_match_next(struct rb_node * n,u32 start,u32 end)178d5162f34STuong Lien static struct service_range *service_range_match_next(struct rb_node *n,
179d5162f34STuong Lien 						      u32 start, u32 end)
180d5162f34STuong Lien {
181d5162f34STuong Lien 	struct service_range *sr;
182d5162f34STuong Lien 	struct rb_node *p, *r;
183d5162f34STuong Lien 
184d5162f34STuong Lien 	while (n) {
185d5162f34STuong Lien 		r = n->rb_right;
186d5162f34STuong Lien 		if (r && service_range_entry(r)->max >= start)
187d5162f34STuong Lien 			/* A next overlap range node must be one in the right
188d5162f34STuong Lien 			 * subtree. If not, it has lower > end, then any next
189d5162f34STuong Lien 			 * successor (- an ancestor) of this node cannot
190d5162f34STuong Lien 			 * satisfy the condition either.
191d5162f34STuong Lien 			 */
192d5162f34STuong Lien 			return service_range_match_first(r, start, end);
193d5162f34STuong Lien 
194d5162f34STuong Lien 		/* No one in the right subtree can match, go up to find an
195d5162f34STuong Lien 		 * ancestor of this node which is parent of a left-hand child.
196d5162f34STuong Lien 		 */
197d5162f34STuong Lien 		while ((p = rb_parent(n)) && n == p->rb_right)
198d5162f34STuong Lien 			n = p;
199d5162f34STuong Lien 		if (!p)
200d5162f34STuong Lien 			break;
201d5162f34STuong Lien 
202d5162f34STuong Lien 		/* Return if this ancestor is an overlap */
203d5162f34STuong Lien 		sr = service_range_entry(p);
204d5162f34STuong Lien 		if (service_range_overlap(sr, start, end))
205d5162f34STuong Lien 			return sr;
206d5162f34STuong Lien 
207d5162f34STuong Lien 		/* Ok, try to lookup more from this ancestor */
208d5162f34STuong Lien 		if (sr->lower <= end) {
209d5162f34STuong Lien 			n = p;
210d5162f34STuong Lien 			continue;
211d5162f34STuong Lien 		}
212d5162f34STuong Lien 		break;
213d5162f34STuong Lien 	}
214d5162f34STuong Lien 
215d5162f34STuong Lien 	return NULL;
216d5162f34STuong Lien }
217d5162f34STuong Lien 
hash(int x)21805790c64SSam Ravnborg static int hash(int x)
219b97bf3fdSPer Liden {
220f046e7d9SYing Xue 	return x & (TIPC_NAMETBL_SIZE - 1);
221b97bf3fdSPer Liden }
222b97bf3fdSPer Liden 
223b97bf3fdSPer Liden /**
224218527feSJon Maloy  * tipc_publ_create - create a publication structure
225a45ffa68SJon Maloy  * @ua: the service range the user is binding to
226a45ffa68SJon Maloy  * @sk: the address of the socket that is bound
2275c5d6796SRandy Dunlap  * @key: publication key
228b97bf3fdSPer Liden  */
tipc_publ_create(struct tipc_uaddr * ua,struct tipc_socket_addr * sk,u32 key)229a45ffa68SJon Maloy static struct publication *tipc_publ_create(struct tipc_uaddr *ua,
230a45ffa68SJon Maloy 					    struct tipc_socket_addr *sk,
231b97bf3fdSPer Liden 					    u32 key)
232b97bf3fdSPer Liden {
233998d3907SJon Maloy 	struct publication *p = kzalloc(sizeof(*p), GFP_ATOMIC);
234218527feSJon Maloy 
235998d3907SJon Maloy 	if (!p)
2361fc54d8fSSam Ravnborg 		return NULL;
237b97bf3fdSPer Liden 
238a45ffa68SJon Maloy 	p->sr = ua->sr;
239a45ffa68SJon Maloy 	p->sk = *sk;
240a45ffa68SJon Maloy 	p->scope = ua->scope;
241998d3907SJon Maloy 	p->key = key;
242998d3907SJon Maloy 	INIT_LIST_HEAD(&p->binding_sock);
243998d3907SJon Maloy 	INIT_LIST_HEAD(&p->binding_node);
244998d3907SJon Maloy 	INIT_LIST_HEAD(&p->local_publ);
245998d3907SJon Maloy 	INIT_LIST_HEAD(&p->all_publ);
246998d3907SJon Maloy 	INIT_LIST_HEAD(&p->list);
247998d3907SJon Maloy 	return p;
248b97bf3fdSPer Liden }
249b97bf3fdSPer Liden 
250b97bf3fdSPer Liden /**
251218527feSJon Maloy  * tipc_service_create - create a service structure for the specified 'type'
2526e44867bSJon Maloy  * @net: network namespace
2536e44867bSJon Maloy  * @ua: address representing the service to be bound
254b97bf3fdSPer Liden  *
255218527feSJon Maloy  * Allocates a single range structure and sets it to all 0's.
256b97bf3fdSPer Liden  */
tipc_service_create(struct net * net,struct tipc_uaddr * ua)2576e44867bSJon Maloy static struct tipc_service *tipc_service_create(struct net *net,
2586e44867bSJon Maloy 						struct tipc_uaddr *ua)
259b97bf3fdSPer Liden {
2606e44867bSJon Maloy 	struct name_table *nt = tipc_name_table(net);
2616e44867bSJon Maloy 	struct tipc_service *service;
2626e44867bSJon Maloy 	struct hlist_head *hd;
263b97bf3fdSPer Liden 
2646e44867bSJon Maloy 	service = kzalloc(sizeof(*service), GFP_ATOMIC);
265218527feSJon Maloy 	if (!service) {
266218527feSJon Maloy 		pr_warn("Service creation failed, no memory\n");
2671fc54d8fSSam Ravnborg 		return NULL;
268b97bf3fdSPer Liden 	}
269b97bf3fdSPer Liden 
270218527feSJon Maloy 	spin_lock_init(&service->lock);
2716e44867bSJon Maloy 	service->type = ua->sr.type;
272218527feSJon Maloy 	service->ranges = RB_ROOT;
273218527feSJon Maloy 	INIT_HLIST_NODE(&service->service_list);
274218527feSJon Maloy 	INIT_LIST_HEAD(&service->subscriptions);
2756e44867bSJon Maloy 	hd = &nt->services[hash(ua->sr.type)];
276218527feSJon Maloy 	hlist_add_head_rcu(&service->service_list, hd);
277218527feSJon Maloy 	return service;
278b97bf3fdSPer Liden }
279b97bf3fdSPer Liden 
2805f30721cSJon Maloy /*  tipc_service_find_range - find service range matching publication parameters
2815f30721cSJon Maloy  */
tipc_service_find_range(struct tipc_service * sc,struct tipc_uaddr * ua)2825f30721cSJon Maloy static struct service_range *tipc_service_find_range(struct tipc_service *sc,
28313c9d23fSJon Maloy 						     struct tipc_uaddr *ua)
2845f30721cSJon Maloy {
2855f30721cSJon Maloy 	struct service_range *sr;
2865f30721cSJon Maloy 
28713c9d23fSJon Maloy 	service_range_foreach_match(sr, sc, ua->sr.lower, ua->sr.upper) {
2885f30721cSJon Maloy 		/* Look for exact match */
28913c9d23fSJon Maloy 		if (sr->lower == ua->sr.lower && sr->upper == ua->sr.upper)
2905f30721cSJon Maloy 			return sr;
2915f30721cSJon Maloy 	}
2925f30721cSJon Maloy 
293d5162f34STuong Lien 	return NULL;
294d5162f34STuong Lien }
295d5162f34STuong Lien 
tipc_service_create_range(struct tipc_service * sc,struct publication * p)296218527feSJon Maloy static struct service_range *tipc_service_create_range(struct tipc_service *sc,
29713c9d23fSJon Maloy 						       struct publication *p)
298b97bf3fdSPer Liden {
299218527feSJon Maloy 	struct rb_node **n, *parent = NULL;
300d5162f34STuong Lien 	struct service_range *sr;
30113c9d23fSJon Maloy 	u32 lower = p->sr.lower;
30213c9d23fSJon Maloy 	u32 upper = p->sr.upper;
303b97bf3fdSPer Liden 
304218527feSJon Maloy 	n = &sc->ranges.rb_node;
305218527feSJon Maloy 	while (*n) {
306218527feSJon Maloy 		parent = *n;
307d5162f34STuong Lien 		sr = service_range_entry(parent);
308d5162f34STuong Lien 		if (lower == sr->lower && upper == sr->upper)
309d5162f34STuong Lien 			return sr;
310d5162f34STuong Lien 		if (sr->max < upper)
311d5162f34STuong Lien 			sr->max = upper;
312d5162f34STuong Lien 		if (lower <= sr->lower)
313d5162f34STuong Lien 			n = &parent->rb_left;
314b97bf3fdSPer Liden 		else
315d5162f34STuong Lien 			n = &parent->rb_right;
316b97bf3fdSPer Liden 	}
317218527feSJon Maloy 	sr = kzalloc(sizeof(*sr), GFP_ATOMIC);
318218527feSJon Maloy 	if (!sr)
319218527feSJon Maloy 		return NULL;
320218527feSJon Maloy 	sr->lower = lower;
321218527feSJon Maloy 	sr->upper = upper;
322d5162f34STuong Lien 	sr->max = upper;
323218527feSJon Maloy 	INIT_LIST_HEAD(&sr->local_publ);
324218527feSJon Maloy 	INIT_LIST_HEAD(&sr->all_publ);
325218527feSJon Maloy 	rb_link_node(&sr->tree_node, parent, n);
326d5162f34STuong Lien 	rb_insert_augmented(&sr->tree_node, &sc->ranges, &sr_callbacks);
327218527feSJon Maloy 	return sr;
328b97bf3fdSPer Liden }
329b97bf3fdSPer Liden 
tipc_service_insert_publ(struct net * net,struct tipc_service * sc,struct publication * p)330b26b5aa9SJon Maloy static bool tipc_service_insert_publ(struct net *net,
331218527feSJon Maloy 				     struct tipc_service *sc,
332b26b5aa9SJon Maloy 				     struct publication *p)
333b97bf3fdSPer Liden {
334218527feSJon Maloy 	struct tipc_subscription *sub, *tmp;
335218527feSJon Maloy 	struct service_range *sr;
336b26b5aa9SJon Maloy 	struct publication *_p;
337b26b5aa9SJon Maloy 	u32 node = p->sk.node;
338218527feSJon Maloy 	bool first = false;
339b26b5aa9SJon Maloy 	bool res = false;
3405c834950SJon Maloy 	u32 key = p->key;
341b97bf3fdSPer Liden 
342b26b5aa9SJon Maloy 	spin_lock_bh(&sc->lock);
34313c9d23fSJon Maloy 	sr = tipc_service_create_range(sc, p);
344218527feSJon Maloy 	if (!sr)
345b26b5aa9SJon Maloy 		goto  exit;
346b97bf3fdSPer Liden 
34737922ea4SJon Maloy 	first = list_empty(&sr->all_publ);
348218527feSJon Maloy 
349218527feSJon Maloy 	/* Return if the publication already exists */
350b26b5aa9SJon Maloy 	list_for_each_entry(_p, &sr->all_publ, all_publ) {
3515c834950SJon Maloy 		if (_p->key == key && (!_p->sk.node || _p->sk.node == node)) {
3525c834950SJon Maloy 			pr_debug("Failed to bind duplicate %u,%u,%u/%u:%u/%u\n",
3535c834950SJon Maloy 				 p->sr.type, p->sr.lower, p->sr.upper,
3545c834950SJon Maloy 				 node, p->sk.ref, key);
355b26b5aa9SJon Maloy 			goto exit;
356b97bf3fdSPer Liden 		}
357b97bf3fdSPer Liden 	}
358b52124a5SAllan Stephens 
359b26b5aa9SJon Maloy 	if (in_own_node(net, p->sk.node))
360218527feSJon Maloy 		list_add(&p->local_publ, &sr->local_publ);
361218527feSJon Maloy 	list_add(&p->all_publ, &sr->all_publ);
362b26b5aa9SJon Maloy 	p->id = sc->publ_cnt++;
363b97bf3fdSPer Liden 
364617d3c7aSPaul Gortmaker 	/* Any subscriptions waiting for notification?  */
365218527feSJon Maloy 	list_for_each_entry_safe(sub, tmp, &sc->subscriptions, service_list) {
36609f78b85SJon Maloy 		tipc_sub_report_overlap(sub, p, TIPC_PUBLISHED, first);
367b97bf3fdSPer Liden 	}
368b26b5aa9SJon Maloy 	res = true;
369b26b5aa9SJon Maloy exit:
370b26b5aa9SJon Maloy 	if (!res)
371b26b5aa9SJon Maloy 		pr_warn("Failed to bind to %u,%u,%u\n",
372b26b5aa9SJon Maloy 			p->sr.type, p->sr.lower, p->sr.upper);
373b26b5aa9SJon Maloy 	spin_unlock_bh(&sc->lock);
374b26b5aa9SJon Maloy 	return res;
375b97bf3fdSPer Liden }
376b97bf3fdSPer Liden 
377b97bf3fdSPer Liden /**
378218527feSJon Maloy  * tipc_service_remove_publ - remove a publication from a service
3792c98da07SJon Maloy  * @r: service_range to remove publication from
3802c98da07SJon Maloy  * @sk: address publishing socket
3815c5d6796SRandy Dunlap  * @key: target publication key
382b97bf3fdSPer Liden  */
tipc_service_remove_publ(struct service_range * r,struct tipc_socket_addr * sk,u32 key)3832c98da07SJon Maloy static struct publication *tipc_service_remove_publ(struct service_range *r,
3842c98da07SJon Maloy 						    struct tipc_socket_addr *sk,
3852c98da07SJon Maloy 						    u32 key)
386b97bf3fdSPer Liden {
387218527feSJon Maloy 	struct publication *p;
3882c98da07SJon Maloy 	u32 node = sk->node;
389b97bf3fdSPer Liden 
3902c98da07SJon Maloy 	list_for_each_entry(p, &r->all_publ, all_publ) {
391998d3907SJon Maloy 		if (p->key != key || (node && node != p->sk.node))
392218527feSJon Maloy 			continue;
393218527feSJon Maloy 		list_del(&p->all_publ);
394218527feSJon Maloy 		list_del(&p->local_publ);
395218527feSJon Maloy 		return p;
396b97bf3fdSPer Liden 	}
3975f30721cSJon Maloy 	return NULL;
3985f30721cSJon Maloy }
399b97bf3fdSPer Liden 
4005c5d6796SRandy Dunlap /*
40141b416f1STuong Lien  * Code reused: time_after32() for the same purpose
40241b416f1STuong Lien  */
40341b416f1STuong Lien #define publication_after(pa, pb) time_after32((pa)->id, (pb)->id)
tipc_publ_sort(void * priv,const struct list_head * a,const struct list_head * b)4044f0f586bSSami Tolvanen static int tipc_publ_sort(void *priv, const struct list_head *a,
4054f0f586bSSami Tolvanen 			  const struct list_head *b)
40641b416f1STuong Lien {
40741b416f1STuong Lien 	struct publication *pa, *pb;
40841b416f1STuong Lien 
40941b416f1STuong Lien 	pa = container_of(a, struct publication, list);
41041b416f1STuong Lien 	pb = container_of(b, struct publication, list);
41141b416f1STuong Lien 	return publication_after(pa, pb);
41241b416f1STuong Lien }
41341b416f1STuong Lien 
41441b416f1STuong Lien /**
415218527feSJon Maloy  * tipc_service_subscribe - attach a subscription, and optionally
416218527feSJon Maloy  * issue the prescribed number of events if there is any service
417218527feSJon Maloy  * range overlapping with the requested range
4185c5d6796SRandy Dunlap  * @service: the tipc_service to attach the @sub to
4195c5d6796SRandy Dunlap  * @sub: the subscription to attach
420b97bf3fdSPer Liden  */
tipc_service_subscribe(struct tipc_service * service,struct tipc_subscription * sub)421218527feSJon Maloy static void tipc_service_subscribe(struct tipc_service *service,
4228985ecc7SJon Maloy 				   struct tipc_subscription *sub)
423b97bf3fdSPer Liden {
42441b416f1STuong Lien 	struct publication *p, *first, *tmp;
42541b416f1STuong Lien 	struct list_head publ_list;
426218527feSJon Maloy 	struct service_range *sr;
427429189acSJon Maloy 	u32 filter, lower, upper;
428a4273c73SParthasarathy Bhuvaragan 
429429189acSJon Maloy 	filter = sub->s.filter;
430429189acSJon Maloy 	lower = sub->s.seq.lower;
431429189acSJon Maloy 	upper = sub->s.seq.upper;
432b97bf3fdSPer Liden 
433da0a75e8SJon Maloy 	tipc_sub_get(sub);
434218527feSJon Maloy 	list_add(&sub->service_list, &service->subscriptions);
435b97bf3fdSPer Liden 
43641b416f1STuong Lien 	if (filter & TIPC_SUB_NO_STATUS)
437b97bf3fdSPer Liden 		return;
438b97bf3fdSPer Liden 
43941b416f1STuong Lien 	INIT_LIST_HEAD(&publ_list);
440429189acSJon Maloy 	service_range_foreach_match(sr, service, lower, upper) {
44141b416f1STuong Lien 		first = NULL;
442218527feSJon Maloy 		list_for_each_entry(p, &sr->all_publ, all_publ) {
44341b416f1STuong Lien 			if (filter & TIPC_SUB_PORTS)
44441b416f1STuong Lien 				list_add_tail(&p->list, &publ_list);
44541b416f1STuong Lien 			else if (!first || publication_after(first, p))
44641b416f1STuong Lien 				/* Pick this range's *first* publication */
44741b416f1STuong Lien 				first = p;
448f6f0a4d2SAllan Stephens 		}
44941b416f1STuong Lien 		if (first)
45041b416f1STuong Lien 			list_add_tail(&first->list, &publ_list);
45141b416f1STuong Lien 	}
45241b416f1STuong Lien 
45341b416f1STuong Lien 	/* Sort the publications before reporting */
45441b416f1STuong Lien 	list_sort(NULL, &publ_list, tipc_publ_sort);
45541b416f1STuong Lien 	list_for_each_entry_safe(p, tmp, &publ_list, list) {
45609f78b85SJon Maloy 		tipc_sub_report_overlap(sub, p, TIPC_PUBLISHED, true);
45741b416f1STuong Lien 		list_del_init(&p->list);
458b97bf3fdSPer Liden 	}
459b97bf3fdSPer Liden }
460b97bf3fdSPer Liden 
tipc_service_find(struct net * net,struct tipc_uaddr * ua)4616e44867bSJon Maloy static struct tipc_service *tipc_service_find(struct net *net,
4626e44867bSJon Maloy 					      struct tipc_uaddr *ua)
463b97bf3fdSPer Liden {
464218527feSJon Maloy 	struct name_table *nt = tipc_name_table(net);
465218527feSJon Maloy 	struct hlist_head *service_head;
466218527feSJon Maloy 	struct tipc_service *service;
467b97bf3fdSPer Liden 
4686e44867bSJon Maloy 	service_head = &nt->services[hash(ua->sr.type)];
469218527feSJon Maloy 	hlist_for_each_entry_rcu(service, service_head, service_list) {
4706e44867bSJon Maloy 		if (service->type == ua->sr.type)
471218527feSJon Maloy 			return service;
472b97bf3fdSPer Liden 	}
4731fc54d8fSSam Ravnborg 	return NULL;
474b97bf3fdSPer Liden };
475b97bf3fdSPer Liden 
tipc_nametbl_insert_publ(struct net * net,struct tipc_uaddr * ua,struct tipc_socket_addr * sk,u32 key)476a45ffa68SJon Maloy struct publication *tipc_nametbl_insert_publ(struct net *net,
477a45ffa68SJon Maloy 					     struct tipc_uaddr *ua,
478a45ffa68SJon Maloy 					     struct tipc_socket_addr *sk,
479a45ffa68SJon Maloy 					     u32 key)
480b97bf3fdSPer Liden {
481218527feSJon Maloy 	struct tipc_service *sc;
482218527feSJon Maloy 	struct publication *p;
483b97bf3fdSPer Liden 
484a45ffa68SJon Maloy 	p = tipc_publ_create(ua, sk, key);
485b26b5aa9SJon Maloy 	if (!p)
4861fc54d8fSSam Ravnborg 		return NULL;
487b97bf3fdSPer Liden 
4886e44867bSJon Maloy 	sc = tipc_service_find(net, ua);
489b97bf3fdSPer Liden 	if (!sc)
4906e44867bSJon Maloy 		sc = tipc_service_create(net, ua);
491b26b5aa9SJon Maloy 	if (sc && tipc_service_insert_publ(net, sc, p))
492218527feSJon Maloy 		return p;
493b26b5aa9SJon Maloy 	kfree(p);
494b26b5aa9SJon Maloy 	return NULL;
495b97bf3fdSPer Liden }
496b97bf3fdSPer Liden 
tipc_nametbl_remove_publ(struct net * net,struct tipc_uaddr * ua,struct tipc_socket_addr * sk,u32 key)4972c98da07SJon Maloy struct publication *tipc_nametbl_remove_publ(struct net *net,
4982c98da07SJon Maloy 					     struct tipc_uaddr *ua,
4992c98da07SJon Maloy 					     struct tipc_socket_addr *sk,
5002c98da07SJon Maloy 					     u32 key)
501b97bf3fdSPer Liden {
5025f30721cSJon Maloy 	struct tipc_subscription *sub, *tmp;
503218527feSJon Maloy 	struct publication *p = NULL;
5042c98da07SJon Maloy 	struct service_range *sr;
5052c98da07SJon Maloy 	struct tipc_service *sc;
5065f30721cSJon Maloy 	bool last;
507b97bf3fdSPer Liden 
5086e44867bSJon Maloy 	sc = tipc_service_find(net, ua);
509218527feSJon Maloy 	if (!sc)
5105c834950SJon Maloy 		goto exit;
511b97bf3fdSPer Liden 
512218527feSJon Maloy 	spin_lock_bh(&sc->lock);
51313c9d23fSJon Maloy 	sr = tipc_service_find_range(sc, ua);
5145f30721cSJon Maloy 	if (!sr)
5155c834950SJon Maloy 		goto unlock;
5162c98da07SJon Maloy 	p = tipc_service_remove_publ(sr, sk, key);
5175f30721cSJon Maloy 	if (!p)
5185c834950SJon Maloy 		goto unlock;
5195f30721cSJon Maloy 
5205f30721cSJon Maloy 	/* Notify any waiting subscriptions */
5215f30721cSJon Maloy 	last = list_empty(&sr->all_publ);
5225f30721cSJon Maloy 	list_for_each_entry_safe(sub, tmp, &sc->subscriptions, service_list) {
52309f78b85SJon Maloy 		tipc_sub_report_overlap(sub, p, TIPC_WITHDRAWN, last);
5245f30721cSJon Maloy 	}
525be47e41dSJon Maloy 
526be47e41dSJon Maloy 	/* Remove service range item if this was its last publication */
5275f30721cSJon Maloy 	if (list_empty(&sr->all_publ)) {
528d5162f34STuong Lien 		rb_erase_augmented(&sr->tree_node, &sc->ranges, &sr_callbacks);
529be47e41dSJon Maloy 		kfree(sr);
530be47e41dSJon Maloy 	}
531218527feSJon Maloy 
53209f78b85SJon Maloy 	/* Delete service item if no more publications and subscriptions */
533218527feSJon Maloy 	if (RB_EMPTY_ROOT(&sc->ranges) && list_empty(&sc->subscriptions)) {
534218527feSJon Maloy 		hlist_del_init_rcu(&sc->service_list);
535218527feSJon Maloy 		kfree_rcu(sc, rcu);
536fb9962f3SYing Xue 	}
5375c834950SJon Maloy unlock:
538218527feSJon Maloy 	spin_unlock_bh(&sc->lock);
5395c834950SJon Maloy exit:
5405c834950SJon Maloy 	if (!p) {
5415c834950SJon Maloy 		pr_err("Failed to remove unknown binding: %u,%u,%u/%u:%u/%u\n",
5425c834950SJon Maloy 		       ua->sr.type, ua->sr.lower, ua->sr.upper,
5435c834950SJon Maloy 		       sk->node, sk->ref, key);
5445c834950SJon Maloy 	}
545218527feSJon Maloy 	return p;
546b97bf3fdSPer Liden }
547b97bf3fdSPer Liden 
5482c53040fSBen Hutchings /**
54966db239cSJon Maloy  * tipc_nametbl_lookup_anycast - perform service instance to socket translation
5505c5d6796SRandy Dunlap  * @net: network namespace
551908148bcSJon Maloy  * @ua: service address to look up
552908148bcSJon Maloy  * @sk: address to socket we want to find
553bc9f8143SAllan Stephens  *
554908148bcSJon Maloy  * On entry, a non-zero 'sk->node' indicates the node where we want lookup to be
555908148bcSJon Maloy  * performed, which may not be this one.
556bc9f8143SAllan Stephens  *
557bc9f8143SAllan Stephens  * On exit:
55885d091a7SWu XiangCheng  *
559908148bcSJon Maloy  * - If lookup is deferred to another node, leave 'sk->node' unchanged and
560908148bcSJon Maloy  *   return 'true'.
561908148bcSJon Maloy  * - If lookup is successful, set the 'sk->node' and 'sk->ref' (== portid) which
562908148bcSJon Maloy  *   represent the bound socket and return 'true'.
563908148bcSJon Maloy  * - If lookup fails, return 'false'
564f20889f7SJon Maloy  *
565f20889f7SJon Maloy  * Note that for legacy users (node configured with Z.C.N address format) the
566908148bcSJon Maloy  * 'closest-first' lookup algorithm must be maintained, i.e., if sk.node is 0
567f20889f7SJon Maloy  * we must look in the local binding list first
568b97bf3fdSPer Liden  */
tipc_nametbl_lookup_anycast(struct net * net,struct tipc_uaddr * ua,struct tipc_socket_addr * sk)569908148bcSJon Maloy bool tipc_nametbl_lookup_anycast(struct net *net,
570908148bcSJon Maloy 				 struct tipc_uaddr *ua,
571908148bcSJon Maloy 				 struct tipc_socket_addr *sk)
572b97bf3fdSPer Liden {
573b89afb11SJon Maloy 	struct tipc_net *tn = tipc_net(net);
574b89afb11SJon Maloy 	bool legacy = tn->legacy_addr_format;
575b89afb11SJon Maloy 	u32 self = tipc_own_addr(net);
576908148bcSJon Maloy 	u32 inst = ua->sa.instance;
577908148bcSJon Maloy 	struct service_range *r;
578218527feSJon Maloy 	struct tipc_service *sc;
579218527feSJon Maloy 	struct publication *p;
580908148bcSJon Maloy 	struct list_head *l;
581908148bcSJon Maloy 	bool res = false;
582b97bf3fdSPer Liden 
583908148bcSJon Maloy 	if (!tipc_in_scope(legacy, sk->node, self))
584908148bcSJon Maloy 		return true;
585b97bf3fdSPer Liden 
58697ede29eSYing Xue 	rcu_read_lock();
5876e44867bSJon Maloy 	sc = tipc_service_find(net, ua);
588218527feSJon Maloy 	if (unlikely(!sc))
589d5162f34STuong Lien 		goto exit;
590218527feSJon Maloy 
591218527feSJon Maloy 	spin_lock_bh(&sc->lock);
592908148bcSJon Maloy 	service_range_foreach_match(r, sc, inst, inst) {
593d5162f34STuong Lien 		/* Select lookup algo: local, closest-first or round-robin */
594908148bcSJon Maloy 		if (sk->node == self) {
595908148bcSJon Maloy 			l = &r->local_publ;
596908148bcSJon Maloy 			if (list_empty(l))
597d5162f34STuong Lien 				continue;
598908148bcSJon Maloy 			p = list_first_entry(l, struct publication, local_publ);
599908148bcSJon Maloy 			list_move_tail(&p->local_publ, &r->local_publ);
600908148bcSJon Maloy 		} else if (legacy && !sk->node && !list_empty(&r->local_publ)) {
601908148bcSJon Maloy 			l = &r->local_publ;
602908148bcSJon Maloy 			p = list_first_entry(l, struct publication, local_publ);
603908148bcSJon Maloy 			list_move_tail(&p->local_publ, &r->local_publ);
604ba765ec6SJon Maloy 		} else {
605908148bcSJon Maloy 			l = &r->all_publ;
606908148bcSJon Maloy 			p = list_first_entry(l, struct publication, all_publ);
607908148bcSJon Maloy 			list_move_tail(&p->all_publ, &r->all_publ);
608b97bf3fdSPer Liden 		}
609908148bcSJon Maloy 		*sk = p->sk;
610908148bcSJon Maloy 		res = true;
611d5162f34STuong Lien 		/* Todo: as for legacy, pick the first matching range only, a
612d5162f34STuong Lien 		 * "true" round-robin will be performed as needed.
613d5162f34STuong Lien 		 */
614d5162f34STuong Lien 		break;
615d5162f34STuong Lien 	}
616218527feSJon Maloy 	spin_unlock_bh(&sc->lock);
617d5162f34STuong Lien 
618d5162f34STuong Lien exit:
61997ede29eSYing Xue 	rcu_read_unlock();
620908148bcSJon Maloy 	return res;
621b97bf3fdSPer Liden }
622b97bf3fdSPer Liden 
62366db239cSJon Maloy /* tipc_nametbl_lookup_group(): lookup destinaton(s) in a communication group
62466db239cSJon Maloy  * Returns a list of one (== group anycast) or more (== group multicast)
62566db239cSJon Maloy  * destination socket/node pairs matching the given address.
62666db239cSJon Maloy  * The requester may or may not want to exclude himself from the list.
62766db239cSJon Maloy  */
tipc_nametbl_lookup_group(struct net * net,struct tipc_uaddr * ua,struct list_head * dsts,int * dstcnt,u32 exclude,bool mcast)628006ed14eSJon Maloy bool tipc_nametbl_lookup_group(struct net *net, struct tipc_uaddr *ua,
629006ed14eSJon Maloy 			       struct list_head *dsts, int *dstcnt,
630006ed14eSJon Maloy 			       u32 exclude, bool mcast)
631ee106d7fSJon Maloy {
632ee106d7fSJon Maloy 	u32 self = tipc_own_addr(net);
633006ed14eSJon Maloy 	u32 inst = ua->sa.instance;
634218527feSJon Maloy 	struct service_range *sr;
635218527feSJon Maloy 	struct tipc_service *sc;
636218527feSJon Maloy 	struct publication *p;
637ee106d7fSJon Maloy 
638ee106d7fSJon Maloy 	*dstcnt = 0;
639ee106d7fSJon Maloy 	rcu_read_lock();
6406e44867bSJon Maloy 	sc = tipc_service_find(net, ua);
641218527feSJon Maloy 	if (unlikely(!sc))
642ee106d7fSJon Maloy 		goto exit;
643218527feSJon Maloy 
644218527feSJon Maloy 	spin_lock_bh(&sc->lock);
645218527feSJon Maloy 
646d5162f34STuong Lien 	/* Todo: a full search i.e. service_range_foreach_match() instead? */
647006ed14eSJon Maloy 	sr = service_range_match_first(sc->ranges.rb_node, inst, inst);
648218527feSJon Maloy 	if (!sr)
649218527feSJon Maloy 		goto no_match;
650218527feSJon Maloy 
651218527feSJon Maloy 	list_for_each_entry(p, &sr->all_publ, all_publ) {
652006ed14eSJon Maloy 		if (p->scope != ua->scope)
653ee106d7fSJon Maloy 			continue;
654998d3907SJon Maloy 		if (p->sk.ref == exclude && p->sk.node == self)
655ee106d7fSJon Maloy 			continue;
656998d3907SJon Maloy 		tipc_dest_push(dsts, p->sk.node, p->sk.ref);
657ee106d7fSJon Maloy 		(*dstcnt)++;
65866db239cSJon Maloy 		if (mcast)
659ee106d7fSJon Maloy 			continue;
660218527feSJon Maloy 		list_move_tail(&p->all_publ, &sr->all_publ);
661ee106d7fSJon Maloy 		break;
662ee106d7fSJon Maloy 	}
663218527feSJon Maloy no_match:
664218527feSJon Maloy 	spin_unlock_bh(&sc->lock);
665ee106d7fSJon Maloy exit:
666ee106d7fSJon Maloy 	rcu_read_unlock();
667ee106d7fSJon Maloy 	return !list_empty(dsts);
668ee106d7fSJon Maloy }
669ee106d7fSJon Maloy 
67066db239cSJon Maloy /* tipc_nametbl_lookup_mcast_sockets(): look up node local destinaton sockets
67166db239cSJon Maloy  *                                      matching the given address
67266db239cSJon Maloy  * Used on nodes which have received a multicast/broadcast message
67366db239cSJon Maloy  * Returns a list of local sockets
67466db239cSJon Maloy  */
tipc_nametbl_lookup_mcast_sockets(struct net * net,struct tipc_uaddr * ua,struct list_head * dports)67545ceea2dSJon Maloy void tipc_nametbl_lookup_mcast_sockets(struct net *net, struct tipc_uaddr *ua,
6765ef21325SJon Maloy 				       struct list_head *dports)
677b97bf3fdSPer Liden {
678218527feSJon Maloy 	struct service_range *sr;
679218527feSJon Maloy 	struct tipc_service *sc;
680232d07b7SJon Maloy 	struct publication *p;
6815ef21325SJon Maloy 	u8 scope = ua->scope;
682b97bf3fdSPer Liden 
68397ede29eSYing Xue 	rcu_read_lock();
6846e44867bSJon Maloy 	sc = tipc_service_find(net, ua);
685218527feSJon Maloy 	if (!sc)
686b97bf3fdSPer Liden 		goto exit;
687b97bf3fdSPer Liden 
688218527feSJon Maloy 	spin_lock_bh(&sc->lock);
68945ceea2dSJon Maloy 	service_range_foreach_match(sr, sc, ua->sr.lower, ua->sr.upper) {
690218527feSJon Maloy 		list_for_each_entry(p, &sr->local_publ, local_publ) {
6915ef21325SJon Maloy 			if (scope == p->scope || scope == TIPC_ANY_SCOPE)
692998d3907SJon Maloy 				tipc_dest_push(dports, 0, p->sk.ref);
693968edbe1SAllan Stephens 		}
694b97bf3fdSPer Liden 	}
695218527feSJon Maloy 	spin_unlock_bh(&sc->lock);
696b97bf3fdSPer Liden exit:
69797ede29eSYing Xue 	rcu_read_unlock();
698b97bf3fdSPer Liden }
699b97bf3fdSPer Liden 
70066db239cSJon Maloy /* tipc_nametbl_lookup_mcast_nodes(): look up all destination nodes matching
70166db239cSJon Maloy  *                                    the given address. Used in sending node.
70266db239cSJon Maloy  * Used on nodes which are sending out a multicast/broadcast message
70366db239cSJon Maloy  * Returns a list of nodes, including own node if applicable
7042ae0b8afSJon Paul Maloy  */
tipc_nametbl_lookup_mcast_nodes(struct net * net,struct tipc_uaddr * ua,struct tipc_nlist * nodes)705833f8670SJon Maloy void tipc_nametbl_lookup_mcast_nodes(struct net *net, struct tipc_uaddr *ua,
706833f8670SJon Maloy 				     struct tipc_nlist *nodes)
7072ae0b8afSJon Paul Maloy {
708218527feSJon Maloy 	struct service_range *sr;
709218527feSJon Maloy 	struct tipc_service *sc;
710218527feSJon Maloy 	struct publication *p;
7112ae0b8afSJon Paul Maloy 
7122ae0b8afSJon Paul Maloy 	rcu_read_lock();
7136e44867bSJon Maloy 	sc = tipc_service_find(net, ua);
714218527feSJon Maloy 	if (!sc)
7152ae0b8afSJon Paul Maloy 		goto exit;
7162ae0b8afSJon Paul Maloy 
717218527feSJon Maloy 	spin_lock_bh(&sc->lock);
718833f8670SJon Maloy 	service_range_foreach_match(sr, sc, ua->sr.lower, ua->sr.upper) {
719218527feSJon Maloy 		list_for_each_entry(p, &sr->all_publ, all_publ) {
720998d3907SJon Maloy 			tipc_nlist_add(nodes, p->sk.node);
7212ae0b8afSJon Paul Maloy 		}
7222ae0b8afSJon Paul Maloy 	}
723218527feSJon Maloy 	spin_unlock_bh(&sc->lock);
7242ae0b8afSJon Paul Maloy exit:
7252ae0b8afSJon Paul Maloy 	rcu_read_unlock();
7262ae0b8afSJon Paul Maloy }
7272ae0b8afSJon Paul Maloy 
72875da2163SJon Maloy /* tipc_nametbl_build_group - build list of communication group members
72975da2163SJon Maloy  */
tipc_nametbl_build_group(struct net * net,struct tipc_group * grp,struct tipc_uaddr * ua)73075da2163SJon Maloy void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,
7316e44867bSJon Maloy 			      struct tipc_uaddr *ua)
73275da2163SJon Maloy {
733218527feSJon Maloy 	struct service_range *sr;
734218527feSJon Maloy 	struct tipc_service *sc;
73575da2163SJon Maloy 	struct publication *p;
736218527feSJon Maloy 	struct rb_node *n;
73775da2163SJon Maloy 
73875da2163SJon Maloy 	rcu_read_lock();
7396e44867bSJon Maloy 	sc = tipc_service_find(net, ua);
740218527feSJon Maloy 	if (!sc)
74175da2163SJon Maloy 		goto exit;
74275da2163SJon Maloy 
743218527feSJon Maloy 	spin_lock_bh(&sc->lock);
744218527feSJon Maloy 	for (n = rb_first(&sc->ranges); n; n = rb_next(n)) {
745218527feSJon Maloy 		sr = container_of(n, struct service_range, tree_node);
746218527feSJon Maloy 		list_for_each_entry(p, &sr->all_publ, all_publ) {
7476e44867bSJon Maloy 			if (p->scope != ua->scope)
74875da2163SJon Maloy 				continue;
7496e44867bSJon Maloy 			tipc_group_add_member(grp, p->sk.node, p->sk.ref,
7506e44867bSJon Maloy 					      p->sr.lower);
75175da2163SJon Maloy 		}
75275da2163SJon Maloy 	}
753218527feSJon Maloy 	spin_unlock_bh(&sc->lock);
75475da2163SJon Maloy exit:
75575da2163SJon Maloy 	rcu_read_unlock();
75675da2163SJon Maloy }
75775da2163SJon Maloy 
758218527feSJon Maloy /* tipc_nametbl_publish - add service binding to name table
759b97bf3fdSPer Liden  */
tipc_nametbl_publish(struct net * net,struct tipc_uaddr * ua,struct tipc_socket_addr * sk,u32 key)76050a3499aSJon Maloy struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,
76150a3499aSJon Maloy 					 struct tipc_socket_addr *sk, u32 key)
762b97bf3fdSPer Liden {
763218527feSJon Maloy 	struct name_table *nt = tipc_name_table(net);
764218527feSJon Maloy 	struct tipc_net *tn = tipc_net(net);
765218527feSJon Maloy 	struct publication *p = NULL;
766218527feSJon Maloy 	struct sk_buff *skb = NULL;
767cad2929dSHoang Huu Le 	u32 rc_dests;
768b97bf3fdSPer Liden 
7694ac1c8d0SYing Xue 	spin_lock_bh(&tn->nametbl_lock);
770218527feSJon Maloy 
771218527feSJon Maloy 	if (nt->local_publ_count >= TIPC_MAX_PUBL) {
772218527feSJon Maloy 		pr_warn("Bind failed, max limit %u reached\n", TIPC_MAX_PUBL);
773218527feSJon Maloy 		goto exit;
774b97bf3fdSPer Liden 	}
775b97bf3fdSPer Liden 
776a45ffa68SJon Maloy 	p = tipc_nametbl_insert_publ(net, ua, sk, key);
777218527feSJon Maloy 	if (p) {
778218527feSJon Maloy 		nt->local_publ_count++;
779218527feSJon Maloy 		skb = tipc_named_publish(net, p);
780fd6eced8SAllan Stephens 	}
781cad2929dSHoang Huu Le 	rc_dests = nt->rc_dests;
782218527feSJon Maloy exit:
7834ac1c8d0SYing Xue 	spin_unlock_bh(&tn->nametbl_lock);
784eab8c045SYing Xue 
785218527feSJon Maloy 	if (skb)
786cad2929dSHoang Huu Le 		tipc_node_broadcast(net, skb, rc_dests);
787218527feSJon Maloy 	return p;
788cad2929dSHoang Huu Le 
789b97bf3fdSPer Liden }
790b97bf3fdSPer Liden 
791b97bf3fdSPer Liden /**
792218527feSJon Maloy  * tipc_nametbl_withdraw - withdraw a service binding
7935c5d6796SRandy Dunlap  * @net: network namespace
7942c98da07SJon Maloy  * @ua: service address/range being unbound
7952c98da07SJon Maloy  * @sk: address of the socket being unbound from
7965c5d6796SRandy Dunlap  * @key: target publication key
797b97bf3fdSPer Liden  */
tipc_nametbl_withdraw(struct net * net,struct tipc_uaddr * ua,struct tipc_socket_addr * sk,u32 key)7982c98da07SJon Maloy void tipc_nametbl_withdraw(struct net *net, struct tipc_uaddr *ua,
7992c98da07SJon Maloy 			   struct tipc_socket_addr *sk, u32 key)
800b97bf3fdSPer Liden {
801218527feSJon Maloy 	struct name_table *nt = tipc_name_table(net);
802218527feSJon Maloy 	struct tipc_net *tn = tipc_net(net);
8035492390aSYing Xue 	struct sk_buff *skb = NULL;
804218527feSJon Maloy 	struct publication *p;
805cad2929dSHoang Huu Le 	u32 rc_dests;
806b97bf3fdSPer Liden 
8074ac1c8d0SYing Xue 	spin_lock_bh(&tn->nametbl_lock);
808218527feSJon Maloy 
8092c98da07SJon Maloy 	p = tipc_nametbl_remove_publ(net, ua, sk, key);
810218527feSJon Maloy 	if (p) {
811218527feSJon Maloy 		nt->local_publ_count--;
812218527feSJon Maloy 		skb = tipc_named_withdraw(net, p);
813218527feSJon Maloy 		list_del_init(&p->binding_sock);
814218527feSJon Maloy 		kfree_rcu(p, rcu);
8155492390aSYing Xue 	}
816cad2929dSHoang Huu Le 	rc_dests = nt->rc_dests;
8174ac1c8d0SYing Xue 	spin_unlock_bh(&tn->nametbl_lock);
8185492390aSYing Xue 
8192c98da07SJon Maloy 	if (skb)
820cad2929dSHoang Huu Le 		tipc_node_broadcast(net, skb, rc_dests);
821b97bf3fdSPer Liden }
822b97bf3fdSPer Liden 
823b97bf3fdSPer Liden /**
8244323add6SPer Liden  * tipc_nametbl_subscribe - add a subscription object to the name table
8255c5d6796SRandy Dunlap  * @sub: subscription to add
826b97bf3fdSPer Liden  */
tipc_nametbl_subscribe(struct tipc_subscription * sub)827c3317f4dSJon Maloy bool tipc_nametbl_subscribe(struct tipc_subscription *sub)
828b97bf3fdSPer Liden {
8295c45ab24SJon Maloy 	struct tipc_net *tn = tipc_net(sub->net);
830429189acSJon Maloy 	u32 type = sub->s.seq.type;
831218527feSJon Maloy 	struct tipc_service *sc;
8326e44867bSJon Maloy 	struct tipc_uaddr ua;
833c3317f4dSJon Maloy 	bool res = true;
834b97bf3fdSPer Liden 
83509f78b85SJon Maloy 	tipc_uaddr(&ua, TIPC_SERVICE_RANGE, TIPC_NODE_SCOPE, type,
836429189acSJon Maloy 		   sub->s.seq.lower, sub->s.seq.upper);
8374ac1c8d0SYing Xue 	spin_lock_bh(&tn->nametbl_lock);
8386e44867bSJon Maloy 	sc = tipc_service_find(sub->net, &ua);
839218527feSJon Maloy 	if (!sc)
8406e44867bSJon Maloy 		sc = tipc_service_create(sub->net, &ua);
841218527feSJon Maloy 	if (sc) {
842218527feSJon Maloy 		spin_lock_bh(&sc->lock);
843218527feSJon Maloy 		tipc_service_subscribe(sc, sub);
844218527feSJon Maloy 		spin_unlock_bh(&sc->lock);
845f131072cSAllan Stephens 	} else {
846429189acSJon Maloy 		pr_warn("Failed to subscribe for {%u,%u,%u}\n",
847429189acSJon Maloy 			type, sub->s.seq.lower, sub->s.seq.upper);
848c3317f4dSJon Maloy 		res = false;
849b97bf3fdSPer Liden 	}
8504ac1c8d0SYing Xue 	spin_unlock_bh(&tn->nametbl_lock);
851c3317f4dSJon Maloy 	return res;
852b97bf3fdSPer Liden }
853b97bf3fdSPer Liden 
854b97bf3fdSPer Liden /**
8554323add6SPer Liden  * tipc_nametbl_unsubscribe - remove a subscription object from name table
8565c5d6796SRandy Dunlap  * @sub: subscription to remove
857b97bf3fdSPer Liden  */
tipc_nametbl_unsubscribe(struct tipc_subscription * sub)8588985ecc7SJon Maloy void tipc_nametbl_unsubscribe(struct tipc_subscription *sub)
859b97bf3fdSPer Liden {
8605c45ab24SJon Maloy 	struct tipc_net *tn = tipc_net(sub->net);
861218527feSJon Maloy 	struct tipc_service *sc;
8626e44867bSJon Maloy 	struct tipc_uaddr ua;
863b97bf3fdSPer Liden 
864429189acSJon Maloy 	tipc_uaddr(&ua, TIPC_SERVICE_RANGE, TIPC_NODE_SCOPE,
865429189acSJon Maloy 		   sub->s.seq.type, sub->s.seq.lower, sub->s.seq.upper);
8664ac1c8d0SYing Xue 	spin_lock_bh(&tn->nametbl_lock);
8676e44867bSJon Maloy 	sc = tipc_service_find(sub->net, &ua);
868218527feSJon Maloy 	if (!sc)
869218527feSJon Maloy 		goto exit;
870218527feSJon Maloy 
871218527feSJon Maloy 	spin_lock_bh(&sc->lock);
872218527feSJon Maloy 	list_del_init(&sub->service_list);
873da0a75e8SJon Maloy 	tipc_sub_put(sub);
874218527feSJon Maloy 
875218527feSJon Maloy 	/* Delete service item if no more publications and subscriptions */
876218527feSJon Maloy 	if (RB_EMPTY_ROOT(&sc->ranges) && list_empty(&sc->subscriptions)) {
877218527feSJon Maloy 		hlist_del_init_rcu(&sc->service_list);
878218527feSJon Maloy 		kfree_rcu(sc, rcu);
879fb9962f3SYing Xue 	}
880218527feSJon Maloy 	spin_unlock_bh(&sc->lock);
881218527feSJon Maloy exit:
8824ac1c8d0SYing Xue 	spin_unlock_bh(&tn->nametbl_lock);
883b97bf3fdSPer Liden }
884b97bf3fdSPer Liden 
tipc_nametbl_init(struct net * net)8854ac1c8d0SYing Xue int tipc_nametbl_init(struct net *net)
886b97bf3fdSPer Liden {
887218527feSJon Maloy 	struct tipc_net *tn = tipc_net(net);
888218527feSJon Maloy 	struct name_table *nt;
889993bfe5dSYing Xue 	int i;
890993bfe5dSYing Xue 
89104b9ce48SJia-Ju Bai 	nt = kzalloc(sizeof(*nt), GFP_KERNEL);
892218527feSJon Maloy 	if (!nt)
893b97bf3fdSPer Liden 		return -ENOMEM;
894b97bf3fdSPer Liden 
895993bfe5dSYing Xue 	for (i = 0; i < TIPC_NAMETBL_SIZE; i++)
896218527feSJon Maloy 		INIT_HLIST_HEAD(&nt->services[i]);
897993bfe5dSYing Xue 
898218527feSJon Maloy 	INIT_LIST_HEAD(&nt->node_scope);
899218527feSJon Maloy 	INIT_LIST_HEAD(&nt->cluster_scope);
900988f3f16SJon Maloy 	rwlock_init(&nt->cluster_scope_lock);
901218527feSJon Maloy 	tn->nametbl = nt;
9024ac1c8d0SYing Xue 	spin_lock_init(&tn->nametbl_lock);
903b97bf3fdSPer Liden 	return 0;
904b97bf3fdSPer Liden }
905b97bf3fdSPer Liden 
9061bb8dce5SErik Hugne /**
907218527feSJon Maloy  * tipc_service_delete - purge all publications for a service and delete it
9085c5d6796SRandy Dunlap  * @net: the associated network namespace
9095c5d6796SRandy Dunlap  * @sc: tipc_service to delete
9101bb8dce5SErik Hugne  */
tipc_service_delete(struct net * net,struct tipc_service * sc)911218527feSJon Maloy static void tipc_service_delete(struct net *net, struct tipc_service *sc)
9121bb8dce5SErik Hugne {
913218527feSJon Maloy 	struct service_range *sr, *tmpr;
914be47e41dSJon Maloy 	struct publication *p, *tmp;
9151bb8dce5SErik Hugne 
916218527feSJon Maloy 	spin_lock_bh(&sc->lock);
917218527feSJon Maloy 	rbtree_postorder_for_each_entry_safe(sr, tmpr, &sc->ranges, tree_node) {
918be47e41dSJon Maloy 		list_for_each_entry_safe(p, tmp, &sr->all_publ, all_publ) {
9192c98da07SJon Maloy 			tipc_service_remove_publ(sr, &p->sk, p->key);
920218527feSJon Maloy 			kfree_rcu(p, rcu);
9211bb8dce5SErik Hugne 		}
922d5162f34STuong Lien 		rb_erase_augmented(&sr->tree_node, &sc->ranges, &sr_callbacks);
923be47e41dSJon Maloy 		kfree(sr);
924218527feSJon Maloy 	}
925218527feSJon Maloy 	hlist_del_init_rcu(&sc->service_list);
926218527feSJon Maloy 	spin_unlock_bh(&sc->lock);
927218527feSJon Maloy 	kfree_rcu(sc, rcu);
9281bb8dce5SErik Hugne }
9291bb8dce5SErik Hugne 
tipc_nametbl_stop(struct net * net)9304ac1c8d0SYing Xue void tipc_nametbl_stop(struct net *net)
931b97bf3fdSPer Liden {
932218527feSJon Maloy 	struct name_table *nt = tipc_name_table(net);
933218527feSJon Maloy 	struct tipc_net *tn = tipc_net(net);
934218527feSJon Maloy 	struct hlist_head *service_head;
935218527feSJon Maloy 	struct tipc_service *service;
936b97bf3fdSPer Liden 	u32 i;
937b97bf3fdSPer Liden 
9381bb8dce5SErik Hugne 	/* Verify name table is empty and purge any lingering
9391bb8dce5SErik Hugne 	 * publications, then release the name table
9401bb8dce5SErik Hugne 	 */
9414ac1c8d0SYing Xue 	spin_lock_bh(&tn->nametbl_lock);
942f046e7d9SYing Xue 	for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
943218527feSJon Maloy 		if (hlist_empty(&nt->services[i]))
944f705ab95SPaul Gortmaker 			continue;
945218527feSJon Maloy 		service_head = &nt->services[i];
946218527feSJon Maloy 		hlist_for_each_entry_rcu(service, service_head, service_list) {
947218527feSJon Maloy 			tipc_service_delete(net, service);
9481bb8dce5SErik Hugne 		}
949b97bf3fdSPer Liden 	}
9504ac1c8d0SYing Xue 	spin_unlock_bh(&tn->nametbl_lock);
951993bfe5dSYing Xue 
95297ede29eSYing Xue 	synchronize_net();
953218527feSJon Maloy 	kfree(nt);
954b97bf3fdSPer Liden }
9551593123aSRichard Alpe 
__tipc_nl_add_nametable_publ(struct tipc_nl_msg * msg,struct tipc_service * service,struct service_range * sr,u32 * last_key)956d8182804SRichard Alpe static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg,
957218527feSJon Maloy 					struct tipc_service *service,
958218527feSJon Maloy 					struct service_range *sr,
959218527feSJon Maloy 					u32 *last_key)
9601593123aSRichard Alpe {
9611593123aSRichard Alpe 	struct publication *p;
962218527feSJon Maloy 	struct nlattr *attrs;
963218527feSJon Maloy 	struct nlattr *b;
964218527feSJon Maloy 	void *hdr;
9651593123aSRichard Alpe 
966218527feSJon Maloy 	if (*last_key) {
967218527feSJon Maloy 		list_for_each_entry(p, &sr->all_publ, all_publ)
968218527feSJon Maloy 			if (p->key == *last_key)
9691593123aSRichard Alpe 				break;
970*a1f8fec4SDan Carpenter 		if (list_entry_is_head(p, &sr->all_publ, all_publ))
9711593123aSRichard Alpe 			return -EPIPE;
9721593123aSRichard Alpe 	} else {
973218527feSJon Maloy 		p = list_first_entry(&sr->all_publ,
974218527feSJon Maloy 				     struct publication,
975e50e73e1SJon Maloy 				     all_publ);
9761593123aSRichard Alpe 	}
9771593123aSRichard Alpe 
978218527feSJon Maloy 	list_for_each_entry_from(p, &sr->all_publ, all_publ) {
979218527feSJon Maloy 		*last_key = p->key;
9801593123aSRichard Alpe 
9811593123aSRichard Alpe 		hdr = genlmsg_put(msg->skb, msg->portid, msg->seq,
982bfb3e5ddSRichard Alpe 				  &tipc_genl_family, NLM_F_MULTI,
9831593123aSRichard Alpe 				  TIPC_NL_NAME_TABLE_GET);
9841593123aSRichard Alpe 		if (!hdr)
9851593123aSRichard Alpe 			return -EMSGSIZE;
9861593123aSRichard Alpe 
987ae0be8deSMichal Kubecek 		attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_NAME_TABLE);
9881593123aSRichard Alpe 		if (!attrs)
9891593123aSRichard Alpe 			goto msg_full;
9901593123aSRichard Alpe 
991ae0be8deSMichal Kubecek 		b = nla_nest_start_noflag(msg->skb, TIPC_NLA_NAME_TABLE_PUBL);
992218527feSJon Maloy 		if (!b)
9931593123aSRichard Alpe 			goto attr_msg_full;
9941593123aSRichard Alpe 
995218527feSJon Maloy 		if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_TYPE, service->type))
9961593123aSRichard Alpe 			goto publ_msg_full;
997218527feSJon Maloy 		if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_LOWER, sr->lower))
9981593123aSRichard Alpe 			goto publ_msg_full;
999218527feSJon Maloy 		if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_UPPER, sr->upper))
10001593123aSRichard Alpe 			goto publ_msg_full;
10011593123aSRichard Alpe 		if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_SCOPE, p->scope))
10021593123aSRichard Alpe 			goto publ_msg_full;
1003998d3907SJon Maloy 		if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_NODE, p->sk.node))
10041593123aSRichard Alpe 			goto publ_msg_full;
1005998d3907SJon Maloy 		if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_REF, p->sk.ref))
10061593123aSRichard Alpe 			goto publ_msg_full;
10071593123aSRichard Alpe 		if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_KEY, p->key))
10081593123aSRichard Alpe 			goto publ_msg_full;
10091593123aSRichard Alpe 
1010218527feSJon Maloy 		nla_nest_end(msg->skb, b);
10111593123aSRichard Alpe 		nla_nest_end(msg->skb, attrs);
10121593123aSRichard Alpe 		genlmsg_end(msg->skb, hdr);
10131593123aSRichard Alpe 	}
1014218527feSJon Maloy 	*last_key = 0;
10151593123aSRichard Alpe 
10161593123aSRichard Alpe 	return 0;
10171593123aSRichard Alpe 
10181593123aSRichard Alpe publ_msg_full:
1019218527feSJon Maloy 	nla_nest_cancel(msg->skb, b);
10201593123aSRichard Alpe attr_msg_full:
10211593123aSRichard Alpe 	nla_nest_cancel(msg->skb, attrs);
10221593123aSRichard Alpe msg_full:
10231593123aSRichard Alpe 	genlmsg_cancel(msg->skb, hdr);
10241593123aSRichard Alpe 
10251593123aSRichard Alpe 	return -EMSGSIZE;
10261593123aSRichard Alpe }
10271593123aSRichard Alpe 
__tipc_nl_service_range_list(struct tipc_nl_msg * msg,struct tipc_service * sc,u32 * last_lower,u32 * last_key)1028218527feSJon Maloy static int __tipc_nl_service_range_list(struct tipc_nl_msg *msg,
1029218527feSJon Maloy 					struct tipc_service *sc,
1030218527feSJon Maloy 					u32 *last_lower, u32 *last_key)
10311593123aSRichard Alpe {
1032218527feSJon Maloy 	struct service_range *sr;
1033218527feSJon Maloy 	struct rb_node *n;
10341593123aSRichard Alpe 	int err;
10351593123aSRichard Alpe 
1036218527feSJon Maloy 	for (n = rb_first(&sc->ranges); n; n = rb_next(n)) {
1037218527feSJon Maloy 		sr = container_of(n, struct service_range, tree_node);
1038218527feSJon Maloy 		if (sr->lower < *last_lower)
1039218527feSJon Maloy 			continue;
1040218527feSJon Maloy 		err = __tipc_nl_add_nametable_publ(msg, sc, sr, last_key);
10411593123aSRichard Alpe 		if (err) {
1042218527feSJon Maloy 			*last_lower = sr->lower;
10431593123aSRichard Alpe 			return err;
10441593123aSRichard Alpe 		}
10451593123aSRichard Alpe 	}
10461593123aSRichard Alpe 	*last_lower = 0;
10471593123aSRichard Alpe 	return 0;
10481593123aSRichard Alpe }
10491593123aSRichard Alpe 
tipc_nl_service_list(struct net * net,struct tipc_nl_msg * msg,u32 * last_type,u32 * last_lower,u32 * last_key)1050218527feSJon Maloy static int tipc_nl_service_list(struct net *net, struct tipc_nl_msg *msg,
1051218527feSJon Maloy 				u32 *last_type, u32 *last_lower, u32 *last_key)
10521593123aSRichard Alpe {
1053218527feSJon Maloy 	struct tipc_net *tn = tipc_net(net);
1054218527feSJon Maloy 	struct tipc_service *service = NULL;
1055218527feSJon Maloy 	struct hlist_head *head;
10566e44867bSJon Maloy 	struct tipc_uaddr ua;
10571593123aSRichard Alpe 	int err;
10581593123aSRichard Alpe 	int i;
10591593123aSRichard Alpe 
10601593123aSRichard Alpe 	if (*last_type)
10611593123aSRichard Alpe 		i = hash(*last_type);
10621593123aSRichard Alpe 	else
10631593123aSRichard Alpe 		i = 0;
10641593123aSRichard Alpe 
10651593123aSRichard Alpe 	for (; i < TIPC_NAMETBL_SIZE; i++) {
1066218527feSJon Maloy 		head = &tn->nametbl->services[i];
10671593123aSRichard Alpe 
1068d1841533SHoang Le 		if (*last_type ||
1069d1841533SHoang Le 		    (!i && *last_key && (*last_lower == *last_key))) {
10706e44867bSJon Maloy 			tipc_uaddr(&ua, TIPC_SERVICE_RANGE, TIPC_NODE_SCOPE,
10716e44867bSJon Maloy 				   *last_type, *last_lower, *last_lower);
10726e44867bSJon Maloy 			service = tipc_service_find(net, &ua);
1073218527feSJon Maloy 			if (!service)
10741593123aSRichard Alpe 				return -EPIPE;
10751593123aSRichard Alpe 		} else {
1076218527feSJon Maloy 			hlist_for_each_entry_rcu(service, head, service_list)
107797ede29eSYing Xue 				break;
1078218527feSJon Maloy 			if (!service)
10791593123aSRichard Alpe 				continue;
10801593123aSRichard Alpe 		}
10811593123aSRichard Alpe 
1082218527feSJon Maloy 		hlist_for_each_entry_from_rcu(service, service_list) {
1083218527feSJon Maloy 			spin_lock_bh(&service->lock);
1084218527feSJon Maloy 			err = __tipc_nl_service_range_list(msg, service,
1085218527feSJon Maloy 							   last_lower,
1086218527feSJon Maloy 							   last_key);
10871593123aSRichard Alpe 
10881593123aSRichard Alpe 			if (err) {
1089218527feSJon Maloy 				*last_type = service->type;
1090218527feSJon Maloy 				spin_unlock_bh(&service->lock);
10911593123aSRichard Alpe 				return err;
10921593123aSRichard Alpe 			}
1093218527feSJon Maloy 			spin_unlock_bh(&service->lock);
10941593123aSRichard Alpe 		}
10951593123aSRichard Alpe 		*last_type = 0;
10961593123aSRichard Alpe 	}
10971593123aSRichard Alpe 	return 0;
10981593123aSRichard Alpe }
10991593123aSRichard Alpe 
tipc_nl_name_table_dump(struct sk_buff * skb,struct netlink_callback * cb)11001593123aSRichard Alpe int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
11011593123aSRichard Alpe {
1102218527feSJon Maloy 	struct net *net = sock_net(skb->sk);
11031593123aSRichard Alpe 	u32 last_type = cb->args[0];
11041593123aSRichard Alpe 	u32 last_lower = cb->args[1];
1105218527feSJon Maloy 	u32 last_key = cb->args[2];
1106218527feSJon Maloy 	int done = cb->args[3];
11071593123aSRichard Alpe 	struct tipc_nl_msg msg;
1108218527feSJon Maloy 	int err;
11091593123aSRichard Alpe 
11101593123aSRichard Alpe 	if (done)
11111593123aSRichard Alpe 		return 0;
11121593123aSRichard Alpe 
11131593123aSRichard Alpe 	msg.skb = skb;
11141593123aSRichard Alpe 	msg.portid = NETLINK_CB(cb->skb).portid;
11151593123aSRichard Alpe 	msg.seq = cb->nlh->nlmsg_seq;
11161593123aSRichard Alpe 
111797ede29eSYing Xue 	rcu_read_lock();
1118218527feSJon Maloy 	err = tipc_nl_service_list(net, &msg, &last_type,
1119218527feSJon Maloy 				   &last_lower, &last_key);
11201593123aSRichard Alpe 	if (!err) {
11211593123aSRichard Alpe 		done = 1;
11221593123aSRichard Alpe 	} else if (err != -EMSGSIZE) {
11231593123aSRichard Alpe 		/* We never set seq or call nl_dump_check_consistent() this
11241593123aSRichard Alpe 		 * means that setting prev_seq here will cause the consistence
11251593123aSRichard Alpe 		 * check to fail in the netlink callback handler. Resulting in
11261593123aSRichard Alpe 		 * the NLMSG_DONE message having the NLM_F_DUMP_INTR flag set if
11271593123aSRichard Alpe 		 * we got an error.
11281593123aSRichard Alpe 		 */
11291593123aSRichard Alpe 		cb->prev_seq = 1;
11301593123aSRichard Alpe 	}
113197ede29eSYing Xue 	rcu_read_unlock();
11321593123aSRichard Alpe 
11331593123aSRichard Alpe 	cb->args[0] = last_type;
11341593123aSRichard Alpe 	cb->args[1] = last_lower;
1135218527feSJon Maloy 	cb->args[2] = last_key;
11361593123aSRichard Alpe 	cb->args[3] = done;
11371593123aSRichard Alpe 
11381593123aSRichard Alpe 	return skb->len;
11391593123aSRichard Alpe }
11403c724acdSJon Paul Maloy 
tipc_dest_find(struct list_head * l,u32 node,u32 port)1141a80ae530SJon Maloy struct tipc_dest *tipc_dest_find(struct list_head *l, u32 node, u32 port)
11423c724acdSJon Paul Maloy {
1143a80ae530SJon Maloy 	struct tipc_dest *dst;
11443c724acdSJon Paul Maloy 
1145a80ae530SJon Maloy 	list_for_each_entry(dst, l, list) {
114630935198SHaiqing Bai 		if (dst->node == node && dst->port == port)
1147a80ae530SJon Maloy 			return dst;
11483c724acdSJon Paul Maloy 	}
1149a80ae530SJon Maloy 	return NULL;
11503c724acdSJon Paul Maloy }
11513c724acdSJon Paul Maloy 
tipc_dest_push(struct list_head * l,u32 node,u32 port)1152a80ae530SJon Maloy bool tipc_dest_push(struct list_head *l, u32 node, u32 port)
11533c724acdSJon Paul Maloy {
1154a80ae530SJon Maloy 	struct tipc_dest *dst;
11553c724acdSJon Paul Maloy 
1156a80ae530SJon Maloy 	if (tipc_dest_find(l, node, port))
11574d8642d8SJon Paul Maloy 		return false;
11584d8642d8SJon Paul Maloy 
1159a80ae530SJon Maloy 	dst = kmalloc(sizeof(*dst), GFP_ATOMIC);
1160a80ae530SJon Maloy 	if (unlikely(!dst))
1161a80ae530SJon Maloy 		return false;
116230935198SHaiqing Bai 	dst->node = node;
116330935198SHaiqing Bai 	dst->port = port;
1164a80ae530SJon Maloy 	list_add(&dst->list, l);
11654d8642d8SJon Paul Maloy 	return true;
11664d8642d8SJon Paul Maloy }
11674d8642d8SJon Paul Maloy 
tipc_dest_pop(struct list_head * l,u32 * node,u32 * port)1168a80ae530SJon Maloy bool tipc_dest_pop(struct list_head *l, u32 *node, u32 *port)
11694d8642d8SJon Paul Maloy {
1170a80ae530SJon Maloy 	struct tipc_dest *dst;
11714d8642d8SJon Paul Maloy 
11724d8642d8SJon Paul Maloy 	if (list_empty(l))
1173a80ae530SJon Maloy 		return false;
1174a80ae530SJon Maloy 	dst = list_first_entry(l, typeof(*dst), list);
1175a80ae530SJon Maloy 	if (port)
1176a80ae530SJon Maloy 		*port = dst->port;
1177a80ae530SJon Maloy 	if (node)
1178a80ae530SJon Maloy 		*node = dst->node;
1179a80ae530SJon Maloy 	list_del(&dst->list);
1180a80ae530SJon Maloy 	kfree(dst);
11814d8642d8SJon Paul Maloy 	return true;
11824d8642d8SJon Paul Maloy }
1183a80ae530SJon Maloy 
tipc_dest_del(struct list_head * l,u32 node,u32 port)1184a80ae530SJon Maloy bool tipc_dest_del(struct list_head *l, u32 node, u32 port)
1185a80ae530SJon Maloy {
1186a80ae530SJon Maloy 	struct tipc_dest *dst;
1187a80ae530SJon Maloy 
1188a80ae530SJon Maloy 	dst = tipc_dest_find(l, node, port);
1189a80ae530SJon Maloy 	if (!dst)
11904d8642d8SJon Paul Maloy 		return false;
1191a80ae530SJon Maloy 	list_del(&dst->list);
1192a80ae530SJon Maloy 	kfree(dst);
1193a80ae530SJon Maloy 	return true;
11944d8642d8SJon Paul Maloy }
11954d8642d8SJon Paul Maloy 
tipc_dest_list_purge(struct list_head * l)1196a80ae530SJon Maloy void tipc_dest_list_purge(struct list_head *l)
11974d8642d8SJon Paul Maloy {
1198a80ae530SJon Maloy 	struct tipc_dest *dst, *tmp;
11994d8642d8SJon Paul Maloy 
1200a80ae530SJon Maloy 	list_for_each_entry_safe(dst, tmp, l, list) {
1201a80ae530SJon Maloy 		list_del(&dst->list);
1202a80ae530SJon Maloy 		kfree(dst);
12034d8642d8SJon Paul Maloy 	}
12044d8642d8SJon Paul Maloy }
1205