]> git.ipfire.org Git - thirdparty/linux.git/blame - net/tipc/name_table.c
tipc: simplify call signatures for publication creation
[thirdparty/linux.git] / net / tipc / name_table.c
CommitLineData
b97bf3fd
PL
1/*
2 * net/tipc/name_table.c: TIPC name table code
c4307285 3 *
e50e73e1 4 * Copyright (c) 2000-2006, 2014-2018, Ericsson AB
993bfe5d 5 * Copyright (c) 2004-2008, 2010-2014, Wind River Systems
998d3907 6 * Copyright (c) 2020-2021, Red Hat Inc
b97bf3fd
PL
7 * All rights reserved.
8 *
9ea1fd3c 9 * Redistribution and use in source and binary forms, with or without
b97bf3fd
PL
10 * modification, are permitted provided that the following conditions are met:
11 *
9ea1fd3c
PL
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
b97bf3fd 20 *
9ea1fd3c
PL
21 * Alternatively, this software may be distributed under the terms of the
22 * GNU General Public License ("GPL") version 2 as published by the Free
23 * Software Foundation.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
b97bf3fd
PL
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
4ac1c8d0 38#include <net/sock.h>
41b416f1 39#include <linux/list_sort.h>
d5162f34 40#include <linux/rbtree_augmented.h>
b97bf3fd 41#include "core.h"
22ae7cff 42#include "netlink.h"
b97bf3fd
PL
43#include "name_table.h"
44#include "name_distr.h"
b97bf3fd 45#include "subscr.h"
1da46568 46#include "bcast.h"
22ae7cff 47#include "addr.h"
1d7e1c25 48#include "node.h"
75da2163 49#include "group.h"
b97bf3fd
PL
50
51/**
218527fe
JM
52 * struct service_range - container for all bindings of a service range
53 * @lower: service range lower bound
54 * @upper: service range upper bound
55 * @tree_node: member of service range RB tree
d5162f34 56 * @max: largest 'upper' in this node subtree
218527fe
JM
57 * @local_publ: list of identical publications made from this node
58 * Used by closest_first lookup and multicast lookup algorithm
59 * @all_publ: all publications identical to this one, whatever node and scope
60 * Used by round-robin lookup algorithm
b97bf3fd 61 */
218527fe 62struct service_range {
b52124a5
AS
63 u32 lower;
64 u32 upper;
218527fe 65 struct rb_node tree_node;
d5162f34 66 u32 max;
218527fe
JM
67 struct list_head local_publ;
68 struct list_head all_publ;
b52124a5
AS
69};
70
c4307285 71/**
218527fe
JM
72 * struct tipc_service - container for all published instances of a service type
73 * @type: 32 bit 'type' value for service
41b416f1 74 * @publ_cnt: increasing counter for publications in this service
218527fe
JM
75 * @ranges: rb tree containing all service ranges for this service
76 * @service_list: links to adjacent name ranges in hash chain
77 * @subscriptions: list of subscriptions for this service type
78 * @lock: spinlock controlling access to pertaining service ranges/publications
97ede29e 79 * @rcu: RCU callback head used for deferred freeing
b97bf3fd 80 */
218527fe 81struct tipc_service {
b97bf3fd 82 u32 type;
41b416f1 83 u32 publ_cnt;
218527fe
JM
84 struct rb_root ranges;
85 struct hlist_node service_list;
b97bf3fd 86 struct list_head subscriptions;
218527fe 87 spinlock_t lock; /* Covers service range list */
97ede29e 88 struct rcu_head rcu;
b97bf3fd
PL
89};
90
d5162f34
TL
91#define service_range_upper(sr) ((sr)->upper)
92RB_DECLARE_CALLBACKS_MAX(static, sr_callbacks,
93 struct service_range, tree_node, u32, max,
94 service_range_upper)
95
96#define service_range_entry(rbtree_node) \
97 (container_of(rbtree_node, struct service_range, tree_node))
98
99#define service_range_overlap(sr, start, end) \
100 ((sr)->lower <= (end) && (sr)->upper >= (start))
101
102/**
103 * service_range_foreach_match - iterate over tipc service rbtree for each
104 * range match
105 * @sr: the service range pointer as a loop cursor
106 * @sc: the pointer to tipc service which holds the service range rbtree
5c5d6796
RD
107 * @start: beginning of the search range (end >= start) for matching
108 * @end: end of the search range (end >= start) for matching
d5162f34
TL
109 */
110#define service_range_foreach_match(sr, sc, start, end) \
111 for (sr = service_range_match_first((sc)->ranges.rb_node, \
112 start, \
113 end); \
114 sr; \
115 sr = service_range_match_next(&(sr)->tree_node, \
116 start, \
117 end))
118
119/**
120 * service_range_match_first - find first service range matching a range
121 * @n: the root node of service range rbtree for searching
5c5d6796
RD
122 * @start: beginning of the search range (end >= start) for matching
123 * @end: end of the search range (end >= start) for matching
d5162f34
TL
124 *
125 * Return: the leftmost service range node in the rbtree that overlaps the
126 * specific range if any. Otherwise, returns NULL.
127 */
128static struct service_range *service_range_match_first(struct rb_node *n,
129 u32 start, u32 end)
130{
131 struct service_range *sr;
132 struct rb_node *l, *r;
133
134 /* Non overlaps in tree at all? */
135 if (!n || service_range_entry(n)->max < start)
136 return NULL;
137
138 while (n) {
139 l = n->rb_left;
140 if (l && service_range_entry(l)->max >= start) {
141 /* A leftmost overlap range node must be one in the left
142 * subtree. If not, it has lower > end, then nodes on
143 * the right side cannot satisfy the condition either.
144 */
145 n = l;
146 continue;
147 }
148
149 /* No one in the left subtree can match, return if this node is
150 * an overlap i.e. leftmost.
151 */
152 sr = service_range_entry(n);
153 if (service_range_overlap(sr, start, end))
154 return sr;
155
156 /* Ok, try to lookup on the right side */
157 r = n->rb_right;
158 if (sr->lower <= end &&
159 r && service_range_entry(r)->max >= start) {
160 n = r;
161 continue;
162 }
163 break;
164 }
165
166 return NULL;
167}
168
169/**
170 * service_range_match_next - find next service range matching a range
171 * @n: a node in service range rbtree from which the searching starts
5c5d6796
RD
172 * @start: beginning of the search range (end >= start) for matching
173 * @end: end of the search range (end >= start) for matching
d5162f34
TL
174 *
175 * Return: the next service range node to the given node in the rbtree that
176 * overlaps the specific range if any. Otherwise, returns NULL.
177 */
178static struct service_range *service_range_match_next(struct rb_node *n,
179 u32 start, u32 end)
180{
181 struct service_range *sr;
182 struct rb_node *p, *r;
183
184 while (n) {
185 r = n->rb_right;
186 if (r && service_range_entry(r)->max >= start)
187 /* A next overlap range node must be one in the right
188 * subtree. If not, it has lower > end, then any next
189 * successor (- an ancestor) of this node cannot
190 * satisfy the condition either.
191 */
192 return service_range_match_first(r, start, end);
193
194 /* No one in the right subtree can match, go up to find an
195 * ancestor of this node which is parent of a left-hand child.
196 */
197 while ((p = rb_parent(n)) && n == p->rb_right)
198 n = p;
199 if (!p)
200 break;
201
202 /* Return if this ancestor is an overlap */
203 sr = service_range_entry(p);
204 if (service_range_overlap(sr, start, end))
205 return sr;
206
207 /* Ok, try to lookup more from this ancestor */
208 if (sr->lower <= end) {
209 n = p;
210 continue;
211 }
212 break;
213 }
214
215 return NULL;
216}
217
05790c64 218static int hash(int x)
b97bf3fd 219{
f046e7d9 220 return x & (TIPC_NAMETBL_SIZE - 1);
b97bf3fd
PL
221}
222
223/**
218527fe 224 * tipc_publ_create - create a publication structure
a45ffa68
JM
225 * @ua: the service range the user is binding to
226 * @sk: the address of the socket that is bound
5c5d6796 227 * @key: publication key
b97bf3fd 228 */
a45ffa68
JM
229static struct publication *tipc_publ_create(struct tipc_uaddr *ua,
230 struct tipc_socket_addr *sk,
218527fe 231 u32 key)
b97bf3fd 232{
998d3907 233 struct publication *p = kzalloc(sizeof(*p), GFP_ATOMIC);
218527fe 234
998d3907 235 if (!p)
1fc54d8f 236 return NULL;
b97bf3fd 237
a45ffa68
JM
238 p->sr = ua->sr;
239 p->sk = *sk;
240 p->scope = ua->scope;
998d3907
JM
241 p->key = key;
242 INIT_LIST_HEAD(&p->binding_sock);
243 INIT_LIST_HEAD(&p->binding_node);
244 INIT_LIST_HEAD(&p->local_publ);
245 INIT_LIST_HEAD(&p->all_publ);
246 INIT_LIST_HEAD(&p->list);
247 return p;
b97bf3fd
PL
248}
249
250/**
218527fe 251 * tipc_service_create - create a service structure for the specified 'type'
5c5d6796
RD
252 * @type: service type
253 * @hd: name_table services list
c4307285 254 *
218527fe 255 * Allocates a single range structure and sets it to all 0's.
b97bf3fd 256 */
218527fe 257static struct tipc_service *tipc_service_create(u32 type, struct hlist_head *hd)
b97bf3fd 258{
218527fe 259 struct tipc_service *service = kzalloc(sizeof(*service), GFP_ATOMIC);
b97bf3fd 260
218527fe
JM
261 if (!service) {
262 pr_warn("Service creation failed, no memory\n");
1fc54d8f 263 return NULL;
b97bf3fd
PL
264 }
265
218527fe
JM
266 spin_lock_init(&service->lock);
267 service->type = type;
268 service->ranges = RB_ROOT;
269 INIT_HLIST_NODE(&service->service_list);
270 INIT_LIST_HEAD(&service->subscriptions);
271 hlist_add_head_rcu(&service->service_list, hd);
272 return service;
b97bf3fd
PL
273}
274
5f30721c
JM
275/* tipc_service_find_range - find service range matching publication parameters
276 */
277static struct service_range *tipc_service_find_range(struct tipc_service *sc,
278 u32 lower, u32 upper)
279{
5f30721c
JM
280 struct service_range *sr;
281
d5162f34
TL
282 service_range_foreach_match(sr, sc, lower, upper) {
283 /* Look for exact match */
284 if (sr->lower == lower && sr->upper == upper)
285 return sr;
5f30721c 286 }
5f30721c 287
d5162f34 288 return NULL;
5f30721c
JM
289}
290
218527fe
JM
291static struct service_range *tipc_service_create_range(struct tipc_service *sc,
292 u32 lower, u32 upper)
b97bf3fd 293{
218527fe 294 struct rb_node **n, *parent = NULL;
d5162f34 295 struct service_range *sr;
218527fe
JM
296
297 n = &sc->ranges.rb_node;
298 while (*n) {
218527fe 299 parent = *n;
d5162f34
TL
300 sr = service_range_entry(parent);
301 if (lower == sr->lower && upper == sr->upper)
302 return sr;
303 if (sr->max < upper)
304 sr->max = upper;
305 if (lower <= sr->lower)
306 n = &parent->rb_left;
b97bf3fd 307 else
d5162f34 308 n = &parent->rb_right;
b97bf3fd 309 }
218527fe
JM
310 sr = kzalloc(sizeof(*sr), GFP_ATOMIC);
311 if (!sr)
312 return NULL;
313 sr->lower = lower;
314 sr->upper = upper;
d5162f34 315 sr->max = upper;
218527fe
JM
316 INIT_LIST_HEAD(&sr->local_publ);
317 INIT_LIST_HEAD(&sr->all_publ);
318 rb_link_node(&sr->tree_node, parent, n);
d5162f34 319 rb_insert_augmented(&sr->tree_node, &sc->ranges, &sr_callbacks);
218527fe 320 return sr;
b97bf3fd
PL
321}
322
b26b5aa9
JM
323static bool tipc_service_insert_publ(struct net *net,
324 struct tipc_service *sc,
325 struct publication *p)
b97bf3fd 326{
218527fe
JM
327 struct tipc_subscription *sub, *tmp;
328 struct service_range *sr;
b26b5aa9
JM
329 struct publication *_p;
330 u32 node = p->sk.node;
218527fe 331 bool first = false;
b26b5aa9 332 bool res = false;
b52124a5 333
b26b5aa9
JM
334 spin_lock_bh(&sc->lock);
335 sr = tipc_service_create_range(sc, p->sr.lower, p->sr.upper);
37922ea4 336 if (!sr)
b26b5aa9 337 goto exit;
b97bf3fd 338
37922ea4 339 first = list_empty(&sr->all_publ);
b97bf3fd 340
218527fe 341 /* Return if the publication already exists */
b26b5aa9
JM
342 list_for_each_entry(_p, &sr->all_publ, all_publ) {
343 if (_p->key == p->key && (!_p->sk.node || _p->sk.node == node))
344 goto exit;
218527fe 345 }
b97bf3fd 346
b26b5aa9 347 if (in_own_node(net, p->sk.node))
218527fe
JM
348 list_add(&p->local_publ, &sr->local_publ);
349 list_add(&p->all_publ, &sr->all_publ);
b26b5aa9 350 p->id = sc->publ_cnt++;
b97bf3fd 351
617d3c7a 352 /* Any subscriptions waiting for notification? */
218527fe 353 list_for_each_entry_safe(sub, tmp, &sc->subscriptions, service_list) {
b26b5aa9
JM
354 tipc_sub_report_overlap(sub, p->sr.lower, p->sr.upper,
355 TIPC_PUBLISHED, p->sk.ref, p->sk.node,
356 p->scope, first);
b97bf3fd 357 }
b26b5aa9
JM
358 res = true;
359exit:
360 if (!res)
361 pr_warn("Failed to bind to %u,%u,%u\n",
362 p->sr.type, p->sr.lower, p->sr.upper);
363 spin_unlock_bh(&sc->lock);
364 return res;
b97bf3fd
PL
365}
366
367/**
218527fe 368 * tipc_service_remove_publ - remove a publication from a service
5c5d6796
RD
369 * @sr: service_range to remove publication from
370 * @node: target node
371 * @key: target publication key
b97bf3fd 372 */
5f30721c
JM
373static struct publication *tipc_service_remove_publ(struct service_range *sr,
374 u32 node, u32 key)
b97bf3fd 375{
218527fe 376 struct publication *p;
b52124a5 377
218527fe 378 list_for_each_entry(p, &sr->all_publ, all_publ) {
998d3907 379 if (p->key != key || (node && node != p->sk.node))
218527fe 380 continue;
5f30721c
JM
381 list_del(&p->all_publ);
382 list_del(&p->local_publ);
383 return p;
f6f0a4d2 384 }
5f30721c 385 return NULL;
b97bf3fd
PL
386}
387
5c5d6796 388/*
41b416f1
TL
389 * Code reused: time_after32() for the same purpose
390 */
391#define publication_after(pa, pb) time_after32((pa)->id, (pb)->id)
392static int tipc_publ_sort(void *priv, struct list_head *a,
393 struct list_head *b)
394{
395 struct publication *pa, *pb;
396
397 pa = container_of(a, struct publication, list);
398 pb = container_of(b, struct publication, list);
399 return publication_after(pa, pb);
400}
401
b97bf3fd 402/**
218527fe
JM
403 * tipc_service_subscribe - attach a subscription, and optionally
404 * issue the prescribed number of events if there is any service
405 * range overlapping with the requested range
5c5d6796
RD
406 * @service: the tipc_service to attach the @sub to
407 * @sub: the subscription to attach
b97bf3fd 408 */
218527fe 409static void tipc_service_subscribe(struct tipc_service *service,
8985ecc7 410 struct tipc_subscription *sub)
b97bf3fd 411{
218527fe 412 struct tipc_subscr *sb = &sub->evt.s;
41b416f1
TL
413 struct publication *p, *first, *tmp;
414 struct list_head publ_list;
218527fe 415 struct service_range *sr;
b6f88d9c 416 struct tipc_service_range r;
41b416f1 417 u32 filter;
a4273c73 418
b6f88d9c
JM
419 r.type = tipc_sub_read(sb, seq.type);
420 r.lower = tipc_sub_read(sb, seq.lower);
421 r.upper = tipc_sub_read(sb, seq.upper);
41b416f1 422 filter = tipc_sub_read(sb, filter);
b97bf3fd 423
da0a75e8 424 tipc_sub_get(sub);
218527fe 425 list_add(&sub->service_list, &service->subscriptions);
b97bf3fd 426
41b416f1 427 if (filter & TIPC_SUB_NO_STATUS)
b97bf3fd
PL
428 return;
429
41b416f1 430 INIT_LIST_HEAD(&publ_list);
b6f88d9c 431 service_range_foreach_match(sr, service, r.lower, r.upper) {
41b416f1 432 first = NULL;
218527fe 433 list_for_each_entry(p, &sr->all_publ, all_publ) {
41b416f1
TL
434 if (filter & TIPC_SUB_PORTS)
435 list_add_tail(&p->list, &publ_list);
436 else if (!first || publication_after(first, p))
437 /* Pick this range's *first* publication */
438 first = p;
b97bf3fd 439 }
41b416f1
TL
440 if (first)
441 list_add_tail(&first->list, &publ_list);
442 }
443
444 /* Sort the publications before reporting */
445 list_sort(NULL, &publ_list, tipc_publ_sort);
446 list_for_each_entry_safe(p, tmp, &publ_list, list) {
998d3907
JM
447 tipc_sub_report_overlap(sub, p->sr.lower, p->sr.upper,
448 TIPC_PUBLISHED, p->sk.ref, p->sk.node,
41b416f1
TL
449 p->scope, true);
450 list_del_init(&p->list);
b97bf3fd
PL
451 }
452}
453
218527fe 454static struct tipc_service *tipc_service_find(struct net *net, u32 type)
b97bf3fd 455{
218527fe
JM
456 struct name_table *nt = tipc_name_table(net);
457 struct hlist_head *service_head;
458 struct tipc_service *service;
b97bf3fd 459
218527fe
JM
460 service_head = &nt->services[hash(type)];
461 hlist_for_each_entry_rcu(service, service_head, service_list) {
462 if (service->type == type)
463 return service;
464 }
1fc54d8f 465 return NULL;
b97bf3fd
PL
466};
467
a45ffa68
JM
468struct publication *tipc_nametbl_insert_publ(struct net *net,
469 struct tipc_uaddr *ua,
470 struct tipc_socket_addr *sk,
471 u32 key)
b97bf3fd 472{
218527fe
JM
473 struct name_table *nt = tipc_name_table(net);
474 struct tipc_service *sc;
475 struct publication *p;
a45ffa68 476 u32 type = ua->sr.type;
b97bf3fd 477
a45ffa68 478 p = tipc_publ_create(ua, sk, key);
b26b5aa9
JM
479 if (!p)
480 return NULL;
481
a45ffa68
JM
482 if (ua->sr.lower > ua->sr.upper) {
483 pr_debug("Failed to bind illegal {%u,%u,%u} from node %u\n",
484 type, ua->sr.lower, ua->sr.upper, sk->node);
1fc54d8f 485 return NULL;
b97bf3fd 486 }
218527fe
JM
487 sc = tipc_service_find(net, type);
488 if (!sc)
489 sc = tipc_service_create(type, &nt->services[hash(type)]);
b26b5aa9
JM
490 if (sc && tipc_service_insert_publ(net, sc, p))
491 return p;
492 kfree(p);
493 return NULL;
b97bf3fd
PL
494}
495
4ac1c8d0 496struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
37922ea4
JM
497 u32 lower, u32 upper,
498 u32 node, u32 key)
b97bf3fd 499{
218527fe 500 struct tipc_service *sc = tipc_service_find(net, type);
5f30721c 501 struct tipc_subscription *sub, *tmp;
be47e41d 502 struct service_range *sr = NULL;
218527fe 503 struct publication *p = NULL;
5f30721c 504 bool last;
b97bf3fd 505
218527fe 506 if (!sc)
1fc54d8f 507 return NULL;
b97bf3fd 508
218527fe 509 spin_lock_bh(&sc->lock);
5f30721c
JM
510 sr = tipc_service_find_range(sc, lower, upper);
511 if (!sr)
512 goto exit;
513 p = tipc_service_remove_publ(sr, node, key);
514 if (!p)
515 goto exit;
516
517 /* Notify any waiting subscriptions */
518 last = list_empty(&sr->all_publ);
519 list_for_each_entry_safe(sub, tmp, &sc->subscriptions, service_list) {
520 tipc_sub_report_overlap(sub, lower, upper, TIPC_WITHDRAWN,
998d3907 521 p->sk.ref, node, p->scope, last);
5f30721c 522 }
be47e41d
JM
523
524 /* Remove service range item if this was its last publication */
5f30721c 525 if (list_empty(&sr->all_publ)) {
d5162f34 526 rb_erase_augmented(&sr->tree_node, &sc->ranges, &sr_callbacks);
be47e41d
JM
527 kfree(sr);
528 }
218527fe
JM
529
530 /* Delete service item if this no more publications and subscriptions */
531 if (RB_EMPTY_ROOT(&sc->ranges) && list_empty(&sc->subscriptions)) {
532 hlist_del_init_rcu(&sc->service_list);
533 kfree_rcu(sc, rcu);
fb9962f3 534 }
5f30721c 535exit:
218527fe
JM
536 spin_unlock_bh(&sc->lock);
537 return p;
b97bf3fd
PL
538}
539
2c53040f 540/**
218527fe 541 * tipc_nametbl_translate - perform service instance to socket translation
5c5d6796
RD
542 * @net: network namespace
543 * @type: message type
544 * @instance: message instance
545 * @dnode: the search domain used during translation
bc9f8143
AS
546 *
547 * On exit:
f20889f7 548 * - if translation is deferred to another node, leave 'dnode' unchanged and
5fcb7d47 549 * return 0
f20889f7 550 * - if translation is attempted and succeeds, set 'dnode' to the publishing
5fcb7d47 551 * node and return the published (non-zero) port number
f20889f7
JM
552 * - if translation is attempted and fails, set 'dnode' to 0 and return 0
553 *
554 * Note that for legacy users (node configured with Z.C.N address format) the
555 * 'closest-first' lookup algorithm must be maintained, i.e., if dnode is 0
556 * we must look in the local binding list first
b97bf3fd 557 */
f20889f7 558u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance, u32 *dnode)
b97bf3fd 559{
b89afb11
JM
560 struct tipc_net *tn = tipc_net(net);
561 bool legacy = tn->legacy_addr_format;
562 u32 self = tipc_own_addr(net);
218527fe
JM
563 struct service_range *sr;
564 struct tipc_service *sc;
f20889f7 565 struct list_head *list;
218527fe 566 struct publication *p;
e50e73e1 567 u32 port = 0;
bc9f8143 568 u32 node = 0;
b97bf3fd 569
f20889f7 570 if (!tipc_in_scope(legacy, *dnode, self))
b97bf3fd
PL
571 return 0;
572
97ede29e 573 rcu_read_lock();
218527fe
JM
574 sc = tipc_service_find(net, type);
575 if (unlikely(!sc))
d5162f34 576 goto exit;
218527fe
JM
577
578 spin_lock_bh(&sc->lock);
d5162f34
TL
579 service_range_foreach_match(sr, sc, instance, instance) {
580 /* Select lookup algo: local, closest-first or round-robin */
581 if (*dnode == self) {
582 list = &sr->local_publ;
583 if (list_empty(list))
584 continue;
585 p = list_first_entry(list, struct publication,
586 local_publ);
587 list_move_tail(&p->local_publ, &sr->local_publ);
588 } else if (legacy && !*dnode && !list_empty(&sr->local_publ)) {
589 list = &sr->local_publ;
590 p = list_first_entry(list, struct publication,
591 local_publ);
592 list_move_tail(&p->local_publ, &sr->local_publ);
593 } else {
594 list = &sr->all_publ;
595 p = list_first_entry(list, struct publication,
596 all_publ);
597 list_move_tail(&p->all_publ, &sr->all_publ);
598 }
998d3907
JM
599 port = p->sk.ref;
600 node = p->sk.node;
d5162f34
TL
601 /* Todo: as for legacy, pick the first matching range only, a
602 * "true" round-robin will be performed as needed.
603 */
604 break;
b97bf3fd 605 }
218527fe 606 spin_unlock_bh(&sc->lock);
d5162f34
TL
607
608exit:
97ede29e 609 rcu_read_unlock();
f20889f7 610 *dnode = node;
e50e73e1 611 return port;
b97bf3fd
PL
612}
613
232d07b7 614bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 scope,
ee106d7f
JM
615 struct list_head *dsts, int *dstcnt, u32 exclude,
616 bool all)
617{
618 u32 self = tipc_own_addr(net);
218527fe
JM
619 struct service_range *sr;
620 struct tipc_service *sc;
621 struct publication *p;
ee106d7f 622
ee106d7f
JM
623 *dstcnt = 0;
624 rcu_read_lock();
218527fe
JM
625 sc = tipc_service_find(net, type);
626 if (unlikely(!sc))
ee106d7f 627 goto exit;
218527fe
JM
628
629 spin_lock_bh(&sc->lock);
630
d5162f34
TL
631 /* Todo: a full search i.e. service_range_foreach_match() instead? */
632 sr = service_range_match_first(sc->ranges.rb_node, instance, instance);
218527fe
JM
633 if (!sr)
634 goto no_match;
635
636 list_for_each_entry(p, &sr->all_publ, all_publ) {
637 if (p->scope != scope)
638 continue;
998d3907 639 if (p->sk.ref == exclude && p->sk.node == self)
218527fe 640 continue;
998d3907 641 tipc_dest_push(dsts, p->sk.node, p->sk.ref);
218527fe
JM
642 (*dstcnt)++;
643 if (all)
644 continue;
645 list_move_tail(&p->all_publ, &sr->all_publ);
646 break;
ee106d7f 647 }
218527fe
JM
648no_match:
649 spin_unlock_bh(&sc->lock);
ee106d7f
JM
650exit:
651 rcu_read_unlock();
652 return !list_empty(dsts);
653}
654
ba765ec6
JM
655void tipc_nametbl_mc_lookup(struct net *net, u32 type, u32 lower, u32 upper,
656 u32 scope, bool exact, struct list_head *dports)
b97bf3fd 657{
218527fe
JM
658 struct service_range *sr;
659 struct tipc_service *sc;
232d07b7 660 struct publication *p;
b97bf3fd 661
97ede29e 662 rcu_read_lock();
218527fe
JM
663 sc = tipc_service_find(net, type);
664 if (!sc)
b97bf3fd
PL
665 goto exit;
666
218527fe 667 spin_lock_bh(&sc->lock);
d5162f34 668 service_range_foreach_match(sr, sc, lower, upper) {
218527fe 669 list_for_each_entry(p, &sr->local_publ, local_publ) {
232d07b7 670 if (p->scope == scope || (!exact && p->scope < scope))
998d3907 671 tipc_dest_push(dports, 0, p->sk.ref);
968edbe1 672 }
b97bf3fd 673 }
218527fe 674 spin_unlock_bh(&sc->lock);
b97bf3fd 675exit:
97ede29e 676 rcu_read_unlock();
b97bf3fd
PL
677}
678
2ae0b8af
JPM
679/* tipc_nametbl_lookup_dst_nodes - find broadcast destination nodes
680 * - Creates list of nodes that overlap the given multicast address
218527fe 681 * - Determines if any node local destinations overlap
2ae0b8af
JPM
682 */
683void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower,
e9a03445 684 u32 upper, struct tipc_nlist *nodes)
2ae0b8af 685{
218527fe
JM
686 struct service_range *sr;
687 struct tipc_service *sc;
688 struct publication *p;
2ae0b8af
JPM
689
690 rcu_read_lock();
218527fe
JM
691 sc = tipc_service_find(net, type);
692 if (!sc)
2ae0b8af
JPM
693 goto exit;
694
218527fe 695 spin_lock_bh(&sc->lock);
d5162f34 696 service_range_foreach_match(sr, sc, lower, upper) {
218527fe 697 list_for_each_entry(p, &sr->all_publ, all_publ) {
998d3907 698 tipc_nlist_add(nodes, p->sk.node);
2ae0b8af
JPM
699 }
700 }
218527fe 701 spin_unlock_bh(&sc->lock);
2ae0b8af
JPM
702exit:
703 rcu_read_unlock();
704}
705
75da2163
JM
706/* tipc_nametbl_build_group - build list of communication group members
707 */
708void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,
232d07b7 709 u32 type, u32 scope)
75da2163 710{
218527fe
JM
711 struct service_range *sr;
712 struct tipc_service *sc;
75da2163 713 struct publication *p;
218527fe 714 struct rb_node *n;
75da2163
JM
715
716 rcu_read_lock();
218527fe
JM
717 sc = tipc_service_find(net, type);
718 if (!sc)
75da2163
JM
719 goto exit;
720
218527fe
JM
721 spin_lock_bh(&sc->lock);
722 for (n = rb_first(&sc->ranges); n; n = rb_next(n)) {
723 sr = container_of(n, struct service_range, tree_node);
724 list_for_each_entry(p, &sr->all_publ, all_publ) {
232d07b7 725 if (p->scope != scope)
75da2163 726 continue;
998d3907 727 tipc_group_add_member(grp, p->sk.node, p->sk.ref, p->sr.lower);
75da2163
JM
728 }
729 }
218527fe 730 spin_unlock_bh(&sc->lock);
75da2163
JM
731exit:
732 rcu_read_unlock();
733}
734
218527fe 735/* tipc_nametbl_publish - add service binding to name table
b97bf3fd 736 */
50a3499a
JM
737struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,
738 struct tipc_socket_addr *sk, u32 key)
b97bf3fd 739{
218527fe
JM
740 struct name_table *nt = tipc_name_table(net);
741 struct tipc_net *tn = tipc_net(net);
742 struct publication *p = NULL;
743 struct sk_buff *skb = NULL;
cad2929d 744 u32 rc_dests;
b97bf3fd 745
4ac1c8d0 746 spin_lock_bh(&tn->nametbl_lock);
218527fe
JM
747
748 if (nt->local_publ_count >= TIPC_MAX_PUBL) {
749 pr_warn("Bind failed, max limit %u reached\n", TIPC_MAX_PUBL);
750 goto exit;
b97bf3fd 751 }
b97bf3fd 752
a45ffa68 753 p = tipc_nametbl_insert_publ(net, ua, sk, key);
218527fe
JM
754 if (p) {
755 nt->local_publ_count++;
756 skb = tipc_named_publish(net, p);
fd6eced8 757 }
cad2929d 758 rc_dests = nt->rc_dests;
218527fe 759exit:
4ac1c8d0 760 spin_unlock_bh(&tn->nametbl_lock);
eab8c045 761
218527fe 762 if (skb)
cad2929d 763 tipc_node_broadcast(net, skb, rc_dests);
218527fe 764 return p;
cad2929d 765
b97bf3fd
PL
766}
767
768/**
218527fe 769 * tipc_nametbl_withdraw - withdraw a service binding
5c5d6796
RD
770 * @net: network namespace
771 * @type: service type
772 * @lower: service range lower bound
773 * @upper: service range upper bound
774 * @key: target publication key
b97bf3fd 775 */
218527fe 776int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower,
37922ea4 777 u32 upper, u32 key)
b97bf3fd 778{
218527fe
JM
779 struct name_table *nt = tipc_name_table(net);
780 struct tipc_net *tn = tipc_net(net);
781 u32 self = tipc_own_addr(net);
5492390a 782 struct sk_buff *skb = NULL;
218527fe 783 struct publication *p;
cad2929d 784 u32 rc_dests;
b97bf3fd 785
4ac1c8d0 786 spin_lock_bh(&tn->nametbl_lock);
218527fe 787
37922ea4 788 p = tipc_nametbl_remove_publ(net, type, lower, upper, self, key);
218527fe
JM
789 if (p) {
790 nt->local_publ_count--;
791 skb = tipc_named_withdraw(net, p);
218527fe
JM
792 list_del_init(&p->binding_sock);
793 kfree_rcu(p, rcu);
5492390a 794 } else {
218527fe 795 pr_err("Failed to remove local publication {%u,%u,%u}/%u\n",
37922ea4 796 type, lower, upper, key);
5492390a 797 }
cad2929d 798 rc_dests = nt->rc_dests;
4ac1c8d0 799 spin_unlock_bh(&tn->nametbl_lock);
eab8c045 800
5492390a 801 if (skb) {
cad2929d 802 tipc_node_broadcast(net, skb, rc_dests);
b97bf3fd
PL
803 return 1;
804 }
b97bf3fd
PL
805 return 0;
806}
807
808/**
4323add6 809 * tipc_nametbl_subscribe - add a subscription object to the name table
5c5d6796 810 * @sub: subscription to add
b97bf3fd 811 */
c3317f4d 812bool tipc_nametbl_subscribe(struct tipc_subscription *sub)
b97bf3fd 813{
218527fe 814 struct name_table *nt = tipc_name_table(sub->net);
5c45ab24 815 struct tipc_net *tn = tipc_net(sub->net);
8985ecc7
JM
816 struct tipc_subscr *s = &sub->evt.s;
817 u32 type = tipc_sub_read(s, seq.type);
218527fe 818 struct tipc_service *sc;
c3317f4d 819 bool res = true;
b97bf3fd 820
4ac1c8d0 821 spin_lock_bh(&tn->nametbl_lock);
218527fe
JM
822 sc = tipc_service_find(sub->net, type);
823 if (!sc)
824 sc = tipc_service_create(type, &nt->services[hash(type)]);
825 if (sc) {
826 spin_lock_bh(&sc->lock);
827 tipc_service_subscribe(sc, sub);
828 spin_unlock_bh(&sc->lock);
c4307285 829 } else {
218527fe
JM
830 pr_warn("Failed to subscribe for {%u,%u,%u}\n", type,
831 tipc_sub_read(s, seq.lower),
832 tipc_sub_read(s, seq.upper));
c3317f4d 833 res = false;
c4307285 834 }
4ac1c8d0 835 spin_unlock_bh(&tn->nametbl_lock);
c3317f4d 836 return res;
b97bf3fd
PL
837}
838
839/**
4323add6 840 * tipc_nametbl_unsubscribe - remove a subscription object from name table
5c5d6796 841 * @sub: subscription to remove
b97bf3fd 842 */
8985ecc7 843void tipc_nametbl_unsubscribe(struct tipc_subscription *sub)
b97bf3fd 844{
5c45ab24 845 struct tipc_net *tn = tipc_net(sub->net);
218527fe 846 struct tipc_subscr *s = &sub->evt.s;
8985ecc7 847 u32 type = tipc_sub_read(s, seq.type);
218527fe 848 struct tipc_service *sc;
b97bf3fd 849
4ac1c8d0 850 spin_lock_bh(&tn->nametbl_lock);
218527fe
JM
851 sc = tipc_service_find(sub->net, type);
852 if (!sc)
853 goto exit;
854
855 spin_lock_bh(&sc->lock);
856 list_del_init(&sub->service_list);
857 tipc_sub_put(sub);
858
859 /* Delete service item if no more publications and subscriptions */
860 if (RB_EMPTY_ROOT(&sc->ranges) && list_empty(&sc->subscriptions)) {
861 hlist_del_init_rcu(&sc->service_list);
862 kfree_rcu(sc, rcu);
c4307285 863 }
218527fe
JM
864 spin_unlock_bh(&sc->lock);
865exit:
4ac1c8d0 866 spin_unlock_bh(&tn->nametbl_lock);
b97bf3fd
PL
867}
868
4ac1c8d0 869int tipc_nametbl_init(struct net *net)
b97bf3fd 870{
218527fe
JM
871 struct tipc_net *tn = tipc_net(net);
872 struct name_table *nt;
993bfe5d
YX
873 int i;
874
04b9ce48 875 nt = kzalloc(sizeof(*nt), GFP_KERNEL);
218527fe 876 if (!nt)
b97bf3fd
PL
877 return -ENOMEM;
878
993bfe5d 879 for (i = 0; i < TIPC_NAMETBL_SIZE; i++)
218527fe 880 INIT_HLIST_HEAD(&nt->services[i]);
993bfe5d 881
218527fe
JM
882 INIT_LIST_HEAD(&nt->node_scope);
883 INIT_LIST_HEAD(&nt->cluster_scope);
988f3f16 884 rwlock_init(&nt->cluster_scope_lock);
218527fe 885 tn->nametbl = nt;
4ac1c8d0 886 spin_lock_init(&tn->nametbl_lock);
b97bf3fd
PL
887 return 0;
888}
889
1bb8dce5 890/**
5c5d6796
RD
891 * tipc_service_delete - purge all publications for a service and delete it
892 * @net: the associated network namespace
893 * @sc: tipc_service to delete
1bb8dce5 894 */
218527fe 895static void tipc_service_delete(struct net *net, struct tipc_service *sc)
1bb8dce5 896{
218527fe 897 struct service_range *sr, *tmpr;
be47e41d 898 struct publication *p, *tmp;
218527fe
JM
899
900 spin_lock_bh(&sc->lock);
901 rbtree_postorder_for_each_entry_safe(sr, tmpr, &sc->ranges, tree_node) {
be47e41d 902 list_for_each_entry_safe(p, tmp, &sr->all_publ, all_publ) {
998d3907 903 tipc_service_remove_publ(sr, p->sk.node, p->key);
218527fe
JM
904 kfree_rcu(p, rcu);
905 }
d5162f34 906 rb_erase_augmented(&sr->tree_node, &sc->ranges, &sr_callbacks);
be47e41d 907 kfree(sr);
1bb8dce5 908 }
218527fe
JM
909 hlist_del_init_rcu(&sc->service_list);
910 spin_unlock_bh(&sc->lock);
911 kfree_rcu(sc, rcu);
1bb8dce5
EH
912}
913
4ac1c8d0 914void tipc_nametbl_stop(struct net *net)
b97bf3fd 915{
218527fe
JM
916 struct name_table *nt = tipc_name_table(net);
917 struct tipc_net *tn = tipc_net(net);
918 struct hlist_head *service_head;
919 struct tipc_service *service;
b97bf3fd
PL
920 u32 i;
921
1bb8dce5
EH
922 /* Verify name table is empty and purge any lingering
923 * publications, then release the name table
924 */
4ac1c8d0 925 spin_lock_bh(&tn->nametbl_lock);
f046e7d9 926 for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
218527fe 927 if (hlist_empty(&nt->services[i]))
f705ab95 928 continue;
218527fe
JM
929 service_head = &nt->services[i];
930 hlist_for_each_entry_rcu(service, service_head, service_list) {
931 tipc_service_delete(net, service);
1bb8dce5 932 }
b97bf3fd 933 }
4ac1c8d0 934 spin_unlock_bh(&tn->nametbl_lock);
993bfe5d 935
97ede29e 936 synchronize_net();
218527fe 937 kfree(nt);
b97bf3fd 938}
1593123a 939
d8182804 940static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg,
218527fe
JM
941 struct tipc_service *service,
942 struct service_range *sr,
943 u32 *last_key)
1593123a 944{
1593123a 945 struct publication *p;
218527fe
JM
946 struct nlattr *attrs;
947 struct nlattr *b;
948 void *hdr;
1593123a 949
218527fe
JM
950 if (*last_key) {
951 list_for_each_entry(p, &sr->all_publ, all_publ)
952 if (p->key == *last_key)
1593123a 953 break;
218527fe 954 if (p->key != *last_key)
1593123a
RA
955 return -EPIPE;
956 } else {
218527fe
JM
957 p = list_first_entry(&sr->all_publ,
958 struct publication,
e50e73e1 959 all_publ);
1593123a
RA
960 }
961
218527fe
JM
962 list_for_each_entry_from(p, &sr->all_publ, all_publ) {
963 *last_key = p->key;
1593123a
RA
964
965 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq,
bfb3e5dd 966 &tipc_genl_family, NLM_F_MULTI,
1593123a
RA
967 TIPC_NL_NAME_TABLE_GET);
968 if (!hdr)
969 return -EMSGSIZE;
970
ae0be8de 971 attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_NAME_TABLE);
1593123a
RA
972 if (!attrs)
973 goto msg_full;
974
ae0be8de 975 b = nla_nest_start_noflag(msg->skb, TIPC_NLA_NAME_TABLE_PUBL);
218527fe 976 if (!b)
1593123a
RA
977 goto attr_msg_full;
978
218527fe 979 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_TYPE, service->type))
1593123a 980 goto publ_msg_full;
218527fe 981 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_LOWER, sr->lower))
1593123a 982 goto publ_msg_full;
218527fe 983 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_UPPER, sr->upper))
1593123a
RA
984 goto publ_msg_full;
985 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_SCOPE, p->scope))
986 goto publ_msg_full;
998d3907 987 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_NODE, p->sk.node))
1593123a 988 goto publ_msg_full;
998d3907 989 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_REF, p->sk.ref))
1593123a
RA
990 goto publ_msg_full;
991 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_KEY, p->key))
992 goto publ_msg_full;
993
218527fe 994 nla_nest_end(msg->skb, b);
1593123a
RA
995 nla_nest_end(msg->skb, attrs);
996 genlmsg_end(msg->skb, hdr);
997 }
218527fe 998 *last_key = 0;
1593123a
RA
999
1000 return 0;
1001
1002publ_msg_full:
218527fe 1003 nla_nest_cancel(msg->skb, b);
1593123a
RA
1004attr_msg_full:
1005 nla_nest_cancel(msg->skb, attrs);
1006msg_full:
1007 genlmsg_cancel(msg->skb, hdr);
1008
1009 return -EMSGSIZE;
1010}
1011
218527fe
JM
1012static int __tipc_nl_service_range_list(struct tipc_nl_msg *msg,
1013 struct tipc_service *sc,
1014 u32 *last_lower, u32 *last_key)
1593123a 1015{
218527fe
JM
1016 struct service_range *sr;
1017 struct rb_node *n;
1593123a
RA
1018 int err;
1019
218527fe
JM
1020 for (n = rb_first(&sc->ranges); n; n = rb_next(n)) {
1021 sr = container_of(n, struct service_range, tree_node);
1022 if (sr->lower < *last_lower)
1023 continue;
1024 err = __tipc_nl_add_nametable_publ(msg, sc, sr, last_key);
1593123a 1025 if (err) {
218527fe 1026 *last_lower = sr->lower;
1593123a
RA
1027 return err;
1028 }
1029 }
1030 *last_lower = 0;
1593123a
RA
1031 return 0;
1032}
1033
218527fe
JM
1034static int tipc_nl_service_list(struct net *net, struct tipc_nl_msg *msg,
1035 u32 *last_type, u32 *last_lower, u32 *last_key)
1593123a 1036{
218527fe
JM
1037 struct tipc_net *tn = tipc_net(net);
1038 struct tipc_service *service = NULL;
1039 struct hlist_head *head;
1593123a
RA
1040 int err;
1041 int i;
1042
1043 if (*last_type)
1044 i = hash(*last_type);
1045 else
1046 i = 0;
1047
1048 for (; i < TIPC_NAMETBL_SIZE; i++) {
218527fe 1049 head = &tn->nametbl->services[i];
1593123a 1050
d1841533
HL
1051 if (*last_type ||
1052 (!i && *last_key && (*last_lower == *last_key))) {
218527fe
JM
1053 service = tipc_service_find(net, *last_type);
1054 if (!service)
1593123a
RA
1055 return -EPIPE;
1056 } else {
218527fe 1057 hlist_for_each_entry_rcu(service, head, service_list)
97ede29e 1058 break;
218527fe 1059 if (!service)
1593123a
RA
1060 continue;
1061 }
1062
218527fe
JM
1063 hlist_for_each_entry_from_rcu(service, service_list) {
1064 spin_lock_bh(&service->lock);
1065 err = __tipc_nl_service_range_list(msg, service,
1066 last_lower,
1067 last_key);
1593123a
RA
1068
1069 if (err) {
218527fe
JM
1070 *last_type = service->type;
1071 spin_unlock_bh(&service->lock);
1593123a
RA
1072 return err;
1073 }
218527fe 1074 spin_unlock_bh(&service->lock);
1593123a
RA
1075 }
1076 *last_type = 0;
1077 }
1078 return 0;
1079}
1080
1081int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
1082{
218527fe 1083 struct net *net = sock_net(skb->sk);
1593123a
RA
1084 u32 last_type = cb->args[0];
1085 u32 last_lower = cb->args[1];
218527fe
JM
1086 u32 last_key = cb->args[2];
1087 int done = cb->args[3];
1593123a 1088 struct tipc_nl_msg msg;
218527fe 1089 int err;
1593123a
RA
1090
1091 if (done)
1092 return 0;
1093
1094 msg.skb = skb;
1095 msg.portid = NETLINK_CB(cb->skb).portid;
1096 msg.seq = cb->nlh->nlmsg_seq;
1097
97ede29e 1098 rcu_read_lock();
218527fe
JM
1099 err = tipc_nl_service_list(net, &msg, &last_type,
1100 &last_lower, &last_key);
1593123a
RA
1101 if (!err) {
1102 done = 1;
1103 } else if (err != -EMSGSIZE) {
1104 /* We never set seq or call nl_dump_check_consistent() this
1105 * means that setting prev_seq here will cause the consistence
1106 * check to fail in the netlink callback handler. Resulting in
1107 * the NLMSG_DONE message having the NLM_F_DUMP_INTR flag set if
1108 * we got an error.
1109 */
1110 cb->prev_seq = 1;
1111 }
97ede29e 1112 rcu_read_unlock();
1593123a
RA
1113
1114 cb->args[0] = last_type;
1115 cb->args[1] = last_lower;
218527fe 1116 cb->args[2] = last_key;
1593123a
RA
1117 cb->args[3] = done;
1118
1119 return skb->len;
1120}
3c724acd 1121
a80ae530 1122struct tipc_dest *tipc_dest_find(struct list_head *l, u32 node, u32 port)
3c724acd 1123{
a80ae530 1124 struct tipc_dest *dst;
3c724acd 1125
a80ae530 1126 list_for_each_entry(dst, l, list) {
30935198
HB
1127 if (dst->node == node && dst->port == port)
1128 return dst;
3c724acd 1129 }
a80ae530 1130 return NULL;
4d8642d8
JPM
1131}
1132
a80ae530 1133bool tipc_dest_push(struct list_head *l, u32 node, u32 port)
4d8642d8 1134{
a80ae530 1135 struct tipc_dest *dst;
4d8642d8 1136
a80ae530 1137 if (tipc_dest_find(l, node, port))
4d8642d8
JPM
1138 return false;
1139
a80ae530
JM
1140 dst = kmalloc(sizeof(*dst), GFP_ATOMIC);
1141 if (unlikely(!dst))
1142 return false;
30935198
HB
1143 dst->node = node;
1144 dst->port = port;
a80ae530 1145 list_add(&dst->list, l);
4d8642d8
JPM
1146 return true;
1147}
1148
a80ae530 1149bool tipc_dest_pop(struct list_head *l, u32 *node, u32 *port)
4d8642d8 1150{
a80ae530 1151 struct tipc_dest *dst;
4d8642d8
JPM
1152
1153 if (list_empty(l))
a80ae530
JM
1154 return false;
1155 dst = list_first_entry(l, typeof(*dst), list);
1156 if (port)
1157 *port = dst->port;
1158 if (node)
1159 *node = dst->node;
1160 list_del(&dst->list);
1161 kfree(dst);
1162 return true;
4d8642d8
JPM
1163}
1164
a80ae530 1165bool tipc_dest_del(struct list_head *l, u32 node, u32 port)
4d8642d8 1166{
a80ae530 1167 struct tipc_dest *dst;
4d8642d8 1168
a80ae530
JM
1169 dst = tipc_dest_find(l, node, port);
1170 if (!dst)
1171 return false;
1172 list_del(&dst->list);
1173 kfree(dst);
1174 return true;
4d8642d8
JPM
1175}
1176
a80ae530 1177void tipc_dest_list_purge(struct list_head *l)
4d8642d8 1178{
a80ae530 1179 struct tipc_dest *dst, *tmp;
4d8642d8 1180
a80ae530
JM
1181 list_for_each_entry_safe(dst, tmp, l, list) {
1182 list_del(&dst->list);
1183 kfree(dst);
3c724acd
JPM
1184 }
1185}
1186
a80ae530 1187int tipc_dest_list_len(struct list_head *l)
3c724acd 1188{
a80ae530 1189 struct tipc_dest *dst;
4d8642d8 1190 int i = 0;
3c724acd 1191
a80ae530 1192 list_for_each_entry(dst, l, list) {
4d8642d8 1193 i++;
3c724acd 1194 }
4d8642d8 1195 return i;
3c724acd 1196}