node.c 16.0 KB
Newer Older
P
Per Liden 已提交
1 2
/*
 * net/tipc/node.c: TIPC node management routines
3
 *
4
 * Copyright (c) 2000-2006, 2012-2015, Ericsson AB
5
 * Copyright (c) 2005-2006, 2010-2014, Wind River Systems
P
Per Liden 已提交
6 7
 * All rights reserved.
 *
P
Per Liden 已提交
8
 * Redistribution and use in source and binary forms, with or without
P
Per Liden 已提交
9 10
 * modification, are permitted provided that the following conditions are met:
 *
P
Per Liden 已提交
11 12 13 14 15 16 17 18
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the names of the copyright holders nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
P
Per Liden 已提交
19
 *
P
Per Liden 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
P
Per Liden 已提交
34 35 36 37
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "core.h"
38
#include "link.h"
P
Per Liden 已提交
39 40
#include "node.h"
#include "name_distr.h"
41
#include "socket.h"
42
#include "bcast.h"
P
Per Liden 已提交
43

44 45
static void node_lost_contact(struct tipc_node *n_ptr);
static void node_established_contact(struct tipc_node *n_ptr);
46
static void tipc_node_delete(struct tipc_node *node);
P
Per Liden 已提交
47

48 49 50 51 52 53 54
struct tipc_sock_conn {
	u32 port;
	u32 peer_port;
	u32 peer_node;
	struct list_head list;
};

55 56 57 58 59 60
static const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = {
	[TIPC_NLA_NODE_UNSPEC]		= { .type = NLA_UNSPEC },
	[TIPC_NLA_NODE_ADDR]		= { .type = NLA_U32 },
	[TIPC_NLA_NODE_UP]		= { .type = NLA_FLAG }
};

61 62 63 64 65 66
/*
 * A trivial power-of-two bitmask technique is used for speed, since this
 * operation is done for every incoming TIPC packet. The number of hash table
 * entries has been chosen so that no hash chain exceeds 8 nodes and will
 * usually be much smaller (typically only a single node).
 */
67
static unsigned int tipc_hashfn(u32 addr)
68 69 70 71
{
	return addr & (NODE_HTABLE_SIZE - 1);
}

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
static void tipc_node_kref_release(struct kref *kref)
{
	struct tipc_node *node = container_of(kref, struct tipc_node, kref);

	tipc_node_delete(node);
}

void tipc_node_put(struct tipc_node *node)
{
	kref_put(&node->kref, tipc_node_kref_release);
}

static void tipc_node_get(struct tipc_node *node)
{
	kref_get(&node->kref);
}

89
/*
90 91
 * tipc_node_find - locate specified node object, if it exists
 */
92
struct tipc_node *tipc_node_find(struct net *net, u32 addr)
93
{
94
	struct tipc_net *tn = net_generic(net, tipc_net_id);
95 96
	struct tipc_node *node;

97
	if (unlikely(!in_own_cluster_exact(net, addr)))
98 99
		return NULL;

100
	rcu_read_lock();
101 102
	hlist_for_each_entry_rcu(node, &tn->node_htable[tipc_hashfn(addr)],
				 hash) {
103
		if (node->addr == addr) {
104
			tipc_node_get(node);
105
			rcu_read_unlock();
106
			return node;
107
		}
108
	}
109
	rcu_read_unlock();
110 111 112
	return NULL;
}

113
struct tipc_node *tipc_node_create(struct net *net, u32 addr)
P
Per Liden 已提交
114
{
115
	struct tipc_net *tn = net_generic(net, tipc_net_id);
116
	struct tipc_node *n_ptr, *temp_node;
P
Per Liden 已提交
117

118
	spin_lock_bh(&tn->node_list_lock);
119 120 121
	n_ptr = tipc_node_find(net, addr);
	if (n_ptr)
		goto exit;
122
	n_ptr = kzalloc(sizeof(*n_ptr), GFP_ATOMIC);
123
	if (!n_ptr) {
124
		pr_warn("Node creation failed, no memory\n");
125
		goto exit;
126 127
	}
	n_ptr->addr = addr;
128
	n_ptr->net = net;
129
	kref_init(&n_ptr->kref);
130
	spin_lock_init(&n_ptr->lock);
131 132
	INIT_HLIST_NODE(&n_ptr->hash);
	INIT_LIST_HEAD(&n_ptr->list);
133
	INIT_LIST_HEAD(&n_ptr->publ_list);
134
	INIT_LIST_HEAD(&n_ptr->conn_sks);
135
	skb_queue_head_init(&n_ptr->bclink.namedq);
J
Jon Paul Maloy 已提交
136
	__skb_queue_head_init(&n_ptr->bclink.deferdq);
137 138
	hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]);
	list_for_each_entry_rcu(temp_node, &tn->node_list, list) {
139 140 141
		if (n_ptr->addr < temp_node->addr)
			break;
	}
142
	list_add_tail_rcu(&n_ptr->list, &temp_node->list);
Y
Ying Xue 已提交
143
	n_ptr->action_flags = TIPC_WAIT_PEER_LINKS_DOWN;
144
	n_ptr->signature = INVALID_NODE_SIG;
145 146
	n_ptr->active_links[0] = INVALID_BEARER_ID;
	n_ptr->active_links[1] = INVALID_BEARER_ID;
147
	tipc_node_get(n_ptr);
148
exit:
149
	spin_unlock_bh(&tn->node_list_lock);
P
Per Liden 已提交
150 151 152
	return n_ptr;
}

153
static void tipc_node_delete(struct tipc_node *node)
P
Per Liden 已提交
154
{
155 156 157
	list_del_rcu(&node->list);
	hlist_del_rcu(&node->hash);
	kfree_rcu(node, rcu);
P
Per Liden 已提交
158 159
}

160
void tipc_node_stop(struct net *net)
161
{
162
	struct tipc_net *tn = net_generic(net, tipc_net_id);
163 164
	struct tipc_node *node, *t_node;

165 166
	spin_lock_bh(&tn->node_list_lock);
	list_for_each_entry_safe(node, t_node, &tn->node_list, list)
167
		tipc_node_put(node);
168
	spin_unlock_bh(&tn->node_list_lock);
169 170
}

171
int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port)
172 173 174
{
	struct tipc_node *node;
	struct tipc_sock_conn *conn;
175
	int err = 0;
176

177
	if (in_own_node(net, dnode))
178 179
		return 0;

180
	node = tipc_node_find(net, dnode);
181 182 183 184 185
	if (!node) {
		pr_warn("Connecting sock to node 0x%x failed\n", dnode);
		return -EHOSTUNREACH;
	}
	conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
186 187 188 189
	if (!conn) {
		err = -EHOSTUNREACH;
		goto exit;
	}
190 191 192 193 194 195 196
	conn->peer_node = dnode;
	conn->port = port;
	conn->peer_port = peer_port;

	tipc_node_lock(node);
	list_add_tail(&conn->list, &node->conn_sks);
	tipc_node_unlock(node);
197 198 199
exit:
	tipc_node_put(node);
	return err;
200 201
}

202
void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port)
203 204 205 206
{
	struct tipc_node *node;
	struct tipc_sock_conn *conn, *safe;

207
	if (in_own_node(net, dnode))
208 209
		return;

210
	node = tipc_node_find(net, dnode);
211 212 213 214 215 216 217 218 219 220 221
	if (!node)
		return;

	tipc_node_lock(node);
	list_for_each_entry_safe(conn, safe, &node->conn_sks, list) {
		if (port != conn->port)
			continue;
		list_del(&conn->list);
		kfree(conn);
	}
	tipc_node_unlock(node);
222
	tipc_node_put(node);
223 224
}

P
Per Liden 已提交
225
/**
226
 * tipc_node_link_up - handle addition of link
227
 *
P
Per Liden 已提交
228 229
 * Link becomes active (alone or shared) or standby, depending on its priority.
 */
230
void tipc_node_link_up(struct tipc_node *n, int bearer_id)
P
Per Liden 已提交
231
{
232 233 234 235
	int *slot0 = &n->active_links[0];
	int *slot1 = &n->active_links[1];
	struct tipc_link_entry *links = n->links;
	struct tipc_link *l = n->links[bearer_id].link;
P
Per Liden 已提交
236

237
	/* Leave room for tunnel header when returning 'mtu' to users: */
238
	links[bearer_id].mtu = l->mtu - INT_H_SIZE;
239 240 241 242

	n->working_links++;
	n->action_flags |= TIPC_NOTIFY_LINK_UP;
	n->link_id = l->peer_bearer_id << 16 | l->bearer_id;
Y
Ying Xue 已提交
243

244
	pr_debug("Established link <%s> on network plane %c\n",
245
		 l->name, l->net_plane);
246

247
	/* No active links ? => take both active slots */
248 249 250
	if (*slot0 < 0) {
		*slot0 = bearer_id;
		*slot1 = bearer_id;
251 252
		node_established_contact(n);
		return;
P
Per Liden 已提交
253
	}
254 255 256

	/* Lower prio than current active ? => no slot */
	if (l->priority < links[*slot0].link->priority) {
257 258
		pr_debug("New link <%s> becomes standby\n", l->name);
		return;
P
Per Liden 已提交
259
	}
260
	tipc_link_dup_queue_xmit(links[*slot0].link, l);
261

262 263 264
	/* Same prio as current active ? => take one slot */
	if (l->priority == links[*slot0].link->priority) {
		*slot0 = bearer_id;
265
		return;
P
Per Liden 已提交
266 267
	}

268 269 270 271
	/* Higher prio than current active => take both active slots */
	pr_debug("Old link <%s> now standby\n", links[*slot0].link->name);
	*slot0 = bearer_id;
	*slot1 = bearer_id;
P
Per Liden 已提交
272 273 274
}

/**
275
 * tipc_node_link_down - handle loss of link
P
Per Liden 已提交
276
 */
277
void tipc_node_link_down(struct tipc_node *n, int bearer_id)
P
Per Liden 已提交
278
{
279 280 281 282
	int *slot0 = &n->active_links[0];
	int *slot1 = &n->active_links[1];
	int i, highest = 0;
	struct tipc_link *l, *_l;
P
Per Liden 已提交
283

284
	l = n->links[bearer_id].link;
285 286 287
	n->working_links--;
	n->action_flags |= TIPC_NOTIFY_LINK_DOWN;
	n->link_id = l->peer_bearer_id << 16 | l->bearer_id;
288

289
	pr_debug("Lost link <%s> on network plane %c\n",
290
		 l->name, l->net_plane);
291

292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
	/* Select new active link if any available */
	*slot0 = INVALID_BEARER_ID;
	*slot1 = INVALID_BEARER_ID;
	for (i = 0; i < MAX_BEARERS; i++) {
		_l = n->links[i].link;
		if (!_l || !tipc_link_is_up(_l))
			continue;
		if (_l->priority < highest)
			continue;
		if (_l->priority > highest) {
			highest = _l->priority;
			*slot0 = i;
			*slot1 = i;
			continue;
		}
		*slot1 = i;
	}
309 310 311 312
	if (tipc_node_is_up(n))
		tipc_link_failover_send_queue(l);
	else
		node_lost_contact(n);
P
Per Liden 已提交
313 314
}

315
bool tipc_node_is_up(struct tipc_node *n)
P
Per Liden 已提交
316
{
317
	return n->active_links[0] != INVALID_BEARER_ID;
P
Per Liden 已提交
318 319
}

320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
void tipc_node_check_dest(struct tipc_node *n, struct tipc_bearer *b,
			  bool *link_up, bool *addr_match,
			  struct tipc_media_addr *maddr)
{
	struct tipc_link *l = n->links[b->identity].link;
	struct tipc_media_addr *curr = &n->links[b->identity].maddr;

	*link_up = l && tipc_link_is_up(l);
	*addr_match = l && !memcmp(curr, maddr, sizeof(*maddr));
}

bool tipc_node_update_dest(struct tipc_node *n,  struct tipc_bearer *b,
			   struct tipc_media_addr *maddr)
{
	struct tipc_link *l = n->links[b->identity].link;
	struct tipc_media_addr *curr = &n->links[b->identity].maddr;
336
	struct sk_buff_head *inputq = &n->links[b->identity].inputq;
337 338

	if (!l)
339
		l = tipc_link_create(n, b, maddr, inputq, &n->bclink.namedq);
340 341 342 343 344 345 346 347
	if (!l)
		return false;
	memcpy(&l->media_addr, maddr, sizeof(*maddr));
	memcpy(curr, maddr, sizeof(*maddr));
	tipc_link_reset(l);
	return true;
}

348
void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
P
Per Liden 已提交
349
{
350
	n_ptr->links[l_ptr->bearer_id].link = l_ptr;
351
	n_ptr->link_cnt++;
P
Per Liden 已提交
352 353
}

354
void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
P
Per Liden 已提交
355
{
356 357 358
	int i;

	for (i = 0; i < MAX_BEARERS; i++) {
359
		if (l_ptr != n_ptr->links[i].link)
J
Jon Paul Maloy 已提交
360
			continue;
361
		n_ptr->links[i].link = NULL;
J
Jon Paul Maloy 已提交
362
		n_ptr->link_cnt--;
363
	}
P
Per Liden 已提交
364 365
}

366
static void node_established_contact(struct tipc_node *n_ptr)
P
Per Liden 已提交
367
{
Y
Ying Xue 已提交
368
	n_ptr->action_flags |= TIPC_NOTIFY_NODE_UP;
369
	n_ptr->bclink.oos_state = 0;
370 371
	n_ptr->bclink.acked = tipc_bclink_get_last_sent(n_ptr->net);
	tipc_bclink_add_node(n_ptr->net, n_ptr->addr);
P
Per Liden 已提交
372 373
}

374
static void node_lost_contact(struct tipc_node *n_ptr)
P
Per Liden 已提交
375 376
{
	char addr_string[16];
377 378 379 380 381
	struct tipc_sock_conn *conn, *safe;
	struct list_head *conns = &n_ptr->conn_sks;
	struct sk_buff *skb;
	struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
	uint i;
P
Per Liden 已提交
382

383 384
	pr_debug("Lost contact with %s\n",
		 tipc_addr_string_fill(addr_string, n_ptr->addr));
385 386

	/* Flush broadcast link info associated with lost node */
387
	if (n_ptr->bclink.recv_permitted) {
J
Jon Paul Maloy 已提交
388
		__skb_queue_purge(&n_ptr->bclink.deferdq);
389

390 391 392
		if (n_ptr->bclink.reasm_buf) {
			kfree_skb(n_ptr->bclink.reasm_buf);
			n_ptr->bclink.reasm_buf = NULL;
393 394
		}

395
		tipc_bclink_remove_node(n_ptr->net, n_ptr->addr);
396
		tipc_bclink_acknowledge(n_ptr, INVALID_LINK_SEQ);
P
Per Liden 已提交
397

398
		n_ptr->bclink.recv_permitted = false;
399
	}
P
Per Liden 已提交
400

401
	/* Abort any ongoing link failover */
P
Per Liden 已提交
402
	for (i = 0; i < MAX_BEARERS; i++) {
403
		struct tipc_link *l_ptr = n_ptr->links[i].link;
404
		if (!l_ptr)
P
Per Liden 已提交
405
			continue;
406 407 408 409 410
		l_ptr->flags &= ~LINK_FAILINGOVER;
		l_ptr->failover_checkpt = 0;
		l_ptr->failover_pkts = 0;
		kfree_skb(l_ptr->failover_skb);
		l_ptr->failover_skb = NULL;
411
		tipc_link_reset_fragments(l_ptr);
P
Per Liden 已提交
412 413
	}

414 415
	n_ptr->action_flags &= ~TIPC_WAIT_OWN_LINKS_DOWN;

416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
	/* Prevent re-contact with node until cleanup is done */
	n_ptr->action_flags |= TIPC_WAIT_PEER_LINKS_DOWN;

	/* Notify publications from this node */
	n_ptr->action_flags |= TIPC_NOTIFY_NODE_DOWN;

	/* Notify sockets connected to node */
	list_for_each_entry_safe(conn, safe, conns, list) {
		skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG,
				      SHORT_H_SIZE, 0, tn->own_addr,
				      conn->peer_node, conn->port,
				      conn->peer_port, TIPC_ERR_NO_NODE);
		if (likely(skb)) {
			skb_queue_tail(n_ptr->inputq, skb);
			n_ptr->action_flags |= TIPC_MSG_EVT;
		}
		list_del(&conn->list);
		kfree(conn);
	}
P
Per Liden 已提交
435 436
}

E
Erik Hugne 已提交
437 438 439 440 441 442 443 444 445
/**
 * tipc_node_get_linkname - get the name of a link
 *
 * @bearer_id: id of the bearer
 * @node: peer node address
 * @linkname: link name output buffer
 *
 * Returns 0 on success
 */
446 447
int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 addr,
			   char *linkname, size_t len)
E
Erik Hugne 已提交
448 449
{
	struct tipc_link *link;
450
	int err = -EINVAL;
451
	struct tipc_node *node = tipc_node_find(net, addr);
E
Erik Hugne 已提交
452

453 454 455 456 457 458
	if (!node)
		return err;

	if (bearer_id >= MAX_BEARERS)
		goto exit;

E
Erik Hugne 已提交
459
	tipc_node_lock(node);
460
	link = node->links[bearer_id].link;
E
Erik Hugne 已提交
461 462
	if (link) {
		strncpy(linkname, link->name, len);
463
		err = 0;
E
Erik Hugne 已提交
464
	}
465
exit:
E
Erik Hugne 已提交
466
	tipc_node_unlock(node);
467 468
	tipc_node_put(node);
	return err;
E
Erik Hugne 已提交
469
}
470 471 472

void tipc_node_unlock(struct tipc_node *node)
{
473
	struct net *net = node->net;
474
	u32 addr = 0;
475
	u32 flags = node->action_flags;
Y
Ying Xue 已提交
476
	u32 link_id = 0;
477
	struct list_head *publ_list;
478
	struct sk_buff_head *inputq = node->inputq;
479
	struct sk_buff_head *namedq;
480

481 482
	if (likely(!flags || (flags == TIPC_MSG_EVT))) {
		node->action_flags = 0;
483
		spin_unlock_bh(&node->lock);
484 485
		if (flags == TIPC_MSG_EVT)
			tipc_sk_rcv(net, inputq);
486 487 488
		return;
	}

Y
Ying Xue 已提交
489 490
	addr = node->addr;
	link_id = node->link_id;
491
	namedq = node->namedq;
492
	publ_list = &node->publ_list;
Y
Ying Xue 已提交
493

494 495 496 497
	node->action_flags &= ~(TIPC_MSG_EVT |
				TIPC_NOTIFY_NODE_DOWN | TIPC_NOTIFY_NODE_UP |
				TIPC_NOTIFY_LINK_DOWN | TIPC_NOTIFY_LINK_UP |
				TIPC_WAKEUP_BCAST_USERS | TIPC_BCAST_MSG_EVT |
498
				TIPC_NAMED_MSG_EVT | TIPC_BCAST_RESET);
Y
Ying Xue 已提交
499

500 501
	spin_unlock_bh(&node->lock);

502 503
	if (flags & TIPC_NOTIFY_NODE_DOWN)
		tipc_publ_notify(net, publ_list, addr);
504

505
	if (flags & TIPC_WAKEUP_BCAST_USERS)
506
		tipc_bclink_wakeup_users(net);
507

Y
Ying Xue 已提交
508
	if (flags & TIPC_NOTIFY_NODE_UP)
509
		tipc_named_node_up(net, addr);
Y
Ying Xue 已提交
510 511

	if (flags & TIPC_NOTIFY_LINK_UP)
512
		tipc_nametbl_publish(net, TIPC_LINK_STATE, addr, addr,
Y
Ying Xue 已提交
513 514 515
				     TIPC_NODE_SCOPE, link_id, addr);

	if (flags & TIPC_NOTIFY_LINK_DOWN)
516
		tipc_nametbl_withdraw(net, TIPC_LINK_STATE, addr,
Y
Ying Xue 已提交
517
				      link_id, addr);
518 519 520 521 522 523

	if (flags & TIPC_MSG_EVT)
		tipc_sk_rcv(net, inputq);

	if (flags & TIPC_NAMED_MSG_EVT)
		tipc_named_rcv(net, namedq);
524 525 526

	if (flags & TIPC_BCAST_MSG_EVT)
		tipc_bclink_input(net);
527 528 529

	if (flags & TIPC_BCAST_RESET)
		tipc_link_reset_all(node);
530
}
531 532

/* Caller should hold node lock for the passed node */
533
static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node)
534 535 536 537
{
	void *hdr;
	struct nlattr *attrs;

538
	hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
			  NLM_F_MULTI, TIPC_NL_NODE_GET);
	if (!hdr)
		return -EMSGSIZE;

	attrs = nla_nest_start(msg->skb, TIPC_NLA_NODE);
	if (!attrs)
		goto msg_full;

	if (nla_put_u32(msg->skb, TIPC_NLA_NODE_ADDR, node->addr))
		goto attr_msg_full;
	if (tipc_node_is_up(node))
		if (nla_put_flag(msg->skb, TIPC_NLA_NODE_UP))
			goto attr_msg_full;

	nla_nest_end(msg->skb, attrs);
	genlmsg_end(msg->skb, hdr);

	return 0;

attr_msg_full:
	nla_nest_cancel(msg->skb, attrs);
msg_full:
	genlmsg_cancel(msg->skb, hdr);

	return -EMSGSIZE;
}

int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
	int err;
569 570
	struct net *net = sock_net(skb->sk);
	struct tipc_net *tn = net_generic(net, tipc_net_id);
571 572 573 574 575 576 577 578 579 580 581 582 583
	int done = cb->args[0];
	int last_addr = cb->args[1];
	struct tipc_node *node;
	struct tipc_nl_msg msg;

	if (done)
		return 0;

	msg.skb = skb;
	msg.portid = NETLINK_CB(cb->skb).portid;
	msg.seq = cb->nlh->nlmsg_seq;

	rcu_read_lock();
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
	if (last_addr) {
		node = tipc_node_find(net, last_addr);
		if (!node) {
			rcu_read_unlock();
			/* We never set seq or call nl_dump_check_consistent()
			 * this means that setting prev_seq here will cause the
			 * consistence check to fail in the netlink callback
			 * handler. Resulting in the NLMSG_DONE message having
			 * the NLM_F_DUMP_INTR flag set if the node state
			 * changed while we released the lock.
			 */
			cb->prev_seq = 1;
			return -EPIPE;
		}
		tipc_node_put(node);
599 600
	}

601
	list_for_each_entry_rcu(node, &tn->node_list, list) {
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
		if (last_addr) {
			if (node->addr == last_addr)
				last_addr = 0;
			else
				continue;
		}

		tipc_node_lock(node);
		err = __tipc_nl_add_node(&msg, node);
		if (err) {
			last_addr = node->addr;
			tipc_node_unlock(node);
			goto out;
		}

		tipc_node_unlock(node);
	}
	done = 1;
out:
	cb->args[0] = done;
	cb->args[1] = last_addr;
	rcu_read_unlock();

	return skb->len;
}