node.c 15.8 KB
Newer Older
P
Per Liden 已提交
1 2
/*
 * net/tipc/node.c: TIPC node management routines
3
 *
4
 * Copyright (c) 2000-2006, 2012-2014, 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);
J
Jon Paul Maloy 已提交
135
	__skb_queue_head_init(&n_ptr->bclink.deferdq);
136 137
	hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]);
	list_for_each_entry_rcu(temp_node, &tn->node_list, list) {
138 139 140
		if (n_ptr->addr < temp_node->addr)
			break;
	}
141
	list_add_tail_rcu(&n_ptr->list, &temp_node->list);
Y
Ying Xue 已提交
142
	n_ptr->action_flags = TIPC_WAIT_PEER_LINKS_DOWN;
143
	n_ptr->signature = INVALID_NODE_SIG;
144
	tipc_node_get(n_ptr);
145
exit:
146
	spin_unlock_bh(&tn->node_list_lock);
P
Per Liden 已提交
147 148 149
	return n_ptr;
}

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

157
void tipc_node_stop(struct net *net)
158
{
159
	struct tipc_net *tn = net_generic(net, tipc_net_id);
160 161
	struct tipc_node *node, *t_node;

162 163
	spin_lock_bh(&tn->node_list_lock);
	list_for_each_entry_safe(node, t_node, &tn->node_list, list)
164
		tipc_node_put(node);
165
	spin_unlock_bh(&tn->node_list_lock);
166 167
}

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

174
	if (in_own_node(net, dnode))
175 176
		return 0;

177
	node = tipc_node_find(net, dnode);
178 179 180 181 182
	if (!node) {
		pr_warn("Connecting sock to node 0x%x failed\n", dnode);
		return -EHOSTUNREACH;
	}
	conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
183 184 185 186
	if (!conn) {
		err = -EHOSTUNREACH;
		goto exit;
	}
187 188 189 190 191 192 193
	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);
194 195 196
exit:
	tipc_node_put(node);
	return err;
197 198
}

199
void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port)
200 201 202 203
{
	struct tipc_node *node;
	struct tipc_sock_conn *conn, *safe;

204
	if (in_own_node(net, dnode))
205 206
		return;

207
	node = tipc_node_find(net, dnode);
208 209 210 211 212 213 214 215 216 217 218
	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);
219
	tipc_node_put(node);
220 221
}

P
Per Liden 已提交
222
/**
223
 * tipc_node_link_up - handle addition of link
224
 *
P
Per Liden 已提交
225 226
 * Link becomes active (alone or shared) or standby, depending on its priority.
 */
227
void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
P
Per Liden 已提交
228
{
229
	struct tipc_link **active = &n_ptr->active_links[0];
P
Per Liden 已提交
230

231
	n_ptr->working_links++;
Y
Ying Xue 已提交
232 233 234
	n_ptr->action_flags |= TIPC_NOTIFY_LINK_UP;
	n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;

235 236
	pr_debug("Established link <%s> on network plane %c\n",
		 l_ptr->name, l_ptr->net_plane);
237

P
Per Liden 已提交
238 239 240
	if (!active[0]) {
		active[0] = active[1] = l_ptr;
		node_established_contact(n_ptr);
241
		goto exit;
P
Per Liden 已提交
242
	}
243
	if (l_ptr->priority < active[0]->priority) {
244
		pr_debug("New link <%s> becomes standby\n", l_ptr->name);
245
		goto exit;
P
Per Liden 已提交
246
	}
247
	tipc_link_dup_queue_xmit(active[0], l_ptr);
248
	if (l_ptr->priority == active[0]->priority) {
P
Per Liden 已提交
249
		active[0] = l_ptr;
250
		goto exit;
P
Per Liden 已提交
251
	}
252
	pr_debug("Old link <%s> becomes standby\n", active[0]->name);
253
	if (active[1] != active[0])
254
		pr_debug("Old link <%s> becomes standby\n", active[1]->name);
P
Per Liden 已提交
255
	active[0] = active[1] = l_ptr;
256 257
exit:
	/* Leave room for changeover header when returning 'mtu' to users: */
258 259
	n_ptr->act_mtus[0] = active[0]->mtu - INT_H_SIZE;
	n_ptr->act_mtus[1] = active[1]->mtu - INT_H_SIZE;
P
Per Liden 已提交
260 261 262 263 264
}

/**
 * node_select_active_links - select active link
 */
265
static void node_select_active_links(struct tipc_node *n_ptr)
P
Per Liden 已提交
266
{
267
	struct tipc_link **active = &n_ptr->active_links[0];
P
Per Liden 已提交
268 269 270
	u32 i;
	u32 highest_prio = 0;

271
	active[0] = active[1] = NULL;
P
Per Liden 已提交
272 273

	for (i = 0; i < MAX_BEARERS; i++) {
274
		struct tipc_link *l_ptr = n_ptr->links[i];
P
Per Liden 已提交
275

276
		if (!l_ptr || !tipc_link_is_up(l_ptr) ||
P
Per Liden 已提交
277 278 279 280
		    (l_ptr->priority < highest_prio))
			continue;

		if (l_ptr->priority > highest_prio) {
281
			highest_prio = l_ptr->priority;
P
Per Liden 已提交
282 283 284 285 286 287 288 289
			active[0] = active[1] = l_ptr;
		} else {
			active[1] = l_ptr;
		}
	}
}

/**
290
 * tipc_node_link_down - handle loss of link
P
Per Liden 已提交
291
 */
292
void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
P
Per Liden 已提交
293
{
294
	struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
295
	struct tipc_link **active;
P
Per Liden 已提交
296

297
	n_ptr->working_links--;
Y
Ying Xue 已提交
298 299
	n_ptr->action_flags |= TIPC_NOTIFY_LINK_DOWN;
	n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;
300

301
	if (!tipc_link_is_active(l_ptr)) {
302 303
		pr_debug("Lost standby link <%s> on network plane %c\n",
			 l_ptr->name, l_ptr->net_plane);
P
Per Liden 已提交
304 305
		return;
	}
306 307
	pr_debug("Lost link <%s> on network plane %c\n",
		 l_ptr->name, l_ptr->net_plane);
P
Per Liden 已提交
308 309 310 311 312 313 314 315

	active = &n_ptr->active_links[0];
	if (active[0] == l_ptr)
		active[0] = active[1];
	if (active[1] == l_ptr)
		active[1] = active[0];
	if (active[0] == l_ptr)
		node_select_active_links(n_ptr);
316
	if (tipc_node_is_up(n_ptr))
317
		tipc_link_failover_send_queue(l_ptr);
318
	else
P
Per Liden 已提交
319
		node_lost_contact(n_ptr);
320 321 322

	/* Leave room for changeover header when returning 'mtu' to users: */
	if (active[0]) {
323 324
		n_ptr->act_mtus[0] = active[0]->mtu - INT_H_SIZE;
		n_ptr->act_mtus[1] = active[1]->mtu - INT_H_SIZE;
325 326 327
		return;
	}
	/* Loopback link went down? No fragmentation needed from now on. */
328
	if (n_ptr->addr == tn->own_addr) {
329 330 331
		n_ptr->act_mtus[0] = MAX_MSG_SIZE;
		n_ptr->act_mtus[1] = MAX_MSG_SIZE;
	}
P
Per Liden 已提交
332 333
}

334
int tipc_node_active_links(struct tipc_node *n_ptr)
P
Per Liden 已提交
335
{
336
	return n_ptr->active_links[0] != NULL;
P
Per Liden 已提交
337 338
}

339
int tipc_node_is_up(struct tipc_node *n_ptr)
P
Per Liden 已提交
340
{
341
	return tipc_node_active_links(n_ptr);
P
Per Liden 已提交
342 343
}

344
void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
P
Per Liden 已提交
345
{
346
	n_ptr->links[l_ptr->bearer_id] = l_ptr;
347
	n_ptr->link_cnt++;
P
Per Liden 已提交
348 349
}

350
void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
P
Per Liden 已提交
351
{
352 353 354
	int i;

	for (i = 0; i < MAX_BEARERS; i++) {
J
Jon Paul Maloy 已提交
355 356 357 358
		if (l_ptr != n_ptr->links[i])
			continue;
		n_ptr->links[i] = NULL;
		n_ptr->link_cnt--;
359
	}
P
Per Liden 已提交
360 361
}

362
static void node_established_contact(struct tipc_node *n_ptr)
P
Per Liden 已提交
363
{
Y
Ying Xue 已提交
364
	n_ptr->action_flags |= TIPC_NOTIFY_NODE_UP;
365
	n_ptr->bclink.oos_state = 0;
366 367
	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 已提交
368 369
}

370
static void node_lost_contact(struct tipc_node *n_ptr)
P
Per Liden 已提交
371 372
{
	char addr_string[16];
373 374 375 376 377
	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 已提交
378

379 380
	pr_debug("Lost contact with %s\n",
		 tipc_addr_string_fill(addr_string, n_ptr->addr));
381 382

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

386 387 388
		if (n_ptr->bclink.reasm_buf) {
			kfree_skb(n_ptr->bclink.reasm_buf);
			n_ptr->bclink.reasm_buf = NULL;
389 390
		}

391
		tipc_bclink_remove_node(n_ptr->net, n_ptr->addr);
392
		tipc_bclink_acknowledge(n_ptr, INVALID_LINK_SEQ);
P
Per Liden 已提交
393

394
		n_ptr->bclink.recv_permitted = false;
395
	}
P
Per Liden 已提交
396

397
	/* Abort any ongoing link failover */
P
Per Liden 已提交
398
	for (i = 0; i < MAX_BEARERS; i++) {
399
		struct tipc_link *l_ptr = n_ptr->links[i];
400
		if (!l_ptr)
P
Per Liden 已提交
401
			continue;
402 403 404 405 406
		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;
407
		tipc_link_reset_fragments(l_ptr);
P
Per Liden 已提交
408 409
	}

410 411
	n_ptr->action_flags &= ~TIPC_WAIT_OWN_LINKS_DOWN;

412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
	/* 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 已提交
431 432
}

E
Erik Hugne 已提交
433 434 435 436 437 438 439 440 441
/**
 * 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
 */
442 443
int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 addr,
			   char *linkname, size_t len)
E
Erik Hugne 已提交
444 445
{
	struct tipc_link *link;
446
	int err = -EINVAL;
447
	struct tipc_node *node = tipc_node_find(net, addr);
E
Erik Hugne 已提交
448

449 450 451 452 453 454
	if (!node)
		return err;

	if (bearer_id >= MAX_BEARERS)
		goto exit;

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

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

477 478
	if (likely(!flags || (flags == TIPC_MSG_EVT))) {
		node->action_flags = 0;
479
		spin_unlock_bh(&node->lock);
480 481
		if (flags == TIPC_MSG_EVT)
			tipc_sk_rcv(net, inputq);
482 483 484
		return;
	}

Y
Ying Xue 已提交
485 486
	addr = node->addr;
	link_id = node->link_id;
487
	namedq = node->namedq;
488
	publ_list = &node->publ_list;
Y
Ying Xue 已提交
489

490 491 492 493
	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 |
494
				TIPC_NAMED_MSG_EVT | TIPC_BCAST_RESET);
Y
Ying Xue 已提交
495

496 497
	spin_unlock_bh(&node->lock);

498 499
	if (flags & TIPC_NOTIFY_NODE_DOWN)
		tipc_publ_notify(net, publ_list, addr);
500

501
	if (flags & TIPC_WAKEUP_BCAST_USERS)
502
		tipc_bclink_wakeup_users(net);
503

Y
Ying Xue 已提交
504
	if (flags & TIPC_NOTIFY_NODE_UP)
505
		tipc_named_node_up(net, addr);
Y
Ying Xue 已提交
506 507

	if (flags & TIPC_NOTIFY_LINK_UP)
508
		tipc_nametbl_publish(net, TIPC_LINK_STATE, addr, addr,
Y
Ying Xue 已提交
509 510 511
				     TIPC_NODE_SCOPE, link_id, addr);

	if (flags & TIPC_NOTIFY_LINK_DOWN)
512
		tipc_nametbl_withdraw(net, TIPC_LINK_STATE, addr,
Y
Ying Xue 已提交
513
				      link_id, addr);
514 515 516 517 518 519

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

	if (flags & TIPC_NAMED_MSG_EVT)
		tipc_named_rcv(net, namedq);
520 521 522

	if (flags & TIPC_BCAST_MSG_EVT)
		tipc_bclink_input(net);
523 524 525

	if (flags & TIPC_BCAST_RESET)
		tipc_link_reset_all(node);
526
}
527 528

/* Caller should hold node lock for the passed node */
529
static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node)
530 531 532 533
{
	void *hdr;
	struct nlattr *attrs;

534
	hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
535 536 537 538 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
			  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;
565 566
	struct net *net = sock_net(skb->sk);
	struct tipc_net *tn = net_generic(net, tipc_net_id);
567 568 569 570 571 572 573 574 575 576 577 578 579
	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();
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
	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);
595 596
	}

597
	list_for_each_entry_rcu(node, &tn->node_list, list) {
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
		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;
}