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