node.c 18.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 38 39 40
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "core.h"
#include "config.h"
#include "node.h"
#include "name_distr.h"
41
#include "socket.h"
P
Per Liden 已提交
42

43 44
static void node_lost_contact(struct tipc_node *n_ptr);
static void node_established_contact(struct tipc_node *n_ptr);
P
Per Liden 已提交
45

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

53 54 55 56 57 58
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 }
};

59 60 61 62 63 64
/*
 * 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).
 */
65
static unsigned int tipc_hashfn(u32 addr)
66 67 68 69
{
	return addr & (NODE_HTABLE_SIZE - 1);
}

70
/*
71 72
 * tipc_node_find - locate specified node object, if it exists
 */
73
struct tipc_node *tipc_node_find(struct net *net, u32 addr)
74
{
75
	struct tipc_net *tn = net_generic(net, tipc_net_id);
76 77
	struct tipc_node *node;

78
	if (unlikely(!in_own_cluster_exact(net, addr)))
79 80
		return NULL;

81
	rcu_read_lock();
82 83
	hlist_for_each_entry_rcu(node, &tn->node_htable[tipc_hashfn(addr)],
				 hash) {
84
		if (node->addr == addr) {
85
			rcu_read_unlock();
86
			return node;
87
		}
88
	}
89
	rcu_read_unlock();
90 91 92
	return NULL;
}

93
struct tipc_node *tipc_node_create(struct net *net, u32 addr)
P
Per Liden 已提交
94
{
95
	struct tipc_net *tn = net_generic(net, tipc_net_id);
96
	struct tipc_node *n_ptr, *temp_node;
P
Per Liden 已提交
97

98
	spin_lock_bh(&tn->node_list_lock);
99

100
	n_ptr = kzalloc(sizeof(*n_ptr), GFP_ATOMIC);
101
	if (!n_ptr) {
102
		spin_unlock_bh(&tn->node_list_lock);
103
		pr_warn("Node creation failed, no memory\n");
104 105 106 107
		return NULL;
	}

	n_ptr->addr = addr;
108
	n_ptr->net = net;
109
	spin_lock_init(&n_ptr->lock);
110 111
	INIT_HLIST_NODE(&n_ptr->hash);
	INIT_LIST_HEAD(&n_ptr->list);
112
	INIT_LIST_HEAD(&n_ptr->publ_list);
113
	INIT_LIST_HEAD(&n_ptr->conn_sks);
114
	skb_queue_head_init(&n_ptr->waiting_sks);
115
	__skb_queue_head_init(&n_ptr->bclink.deferred_queue);
116

117
	hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]);
118

119
	list_for_each_entry_rcu(temp_node, &tn->node_list, list) {
120 121 122
		if (n_ptr->addr < temp_node->addr)
			break;
	}
123
	list_add_tail_rcu(&n_ptr->list, &temp_node->list);
Y
Ying Xue 已提交
124
	n_ptr->action_flags = TIPC_WAIT_PEER_LINKS_DOWN;
125
	n_ptr->signature = INVALID_NODE_SIG;
126

127
	tn->num_nodes++;
128

129
	spin_unlock_bh(&tn->node_list_lock);
P
Per Liden 已提交
130 131 132
	return n_ptr;
}

133
static void tipc_node_delete(struct tipc_net *tn, struct tipc_node *n_ptr)
P
Per Liden 已提交
134
{
135 136 137
	list_del_rcu(&n_ptr->list);
	hlist_del_rcu(&n_ptr->hash);
	kfree_rcu(n_ptr, rcu);
138

139
	tn->num_nodes--;
P
Per Liden 已提交
140 141
}

142
void tipc_node_stop(struct net *net)
143
{
144
	struct tipc_net *tn = net_generic(net, tipc_net_id);
145 146
	struct tipc_node *node, *t_node;

147 148 149 150
	spin_lock_bh(&tn->node_list_lock);
	list_for_each_entry_safe(node, t_node, &tn->node_list, list)
		tipc_node_delete(tn, node);
	spin_unlock_bh(&tn->node_list_lock);
151 152
}

153
int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port)
154 155 156 157
{
	struct tipc_node *node;
	struct tipc_sock_conn *conn;

158
	if (in_own_node(net, dnode))
159 160
		return 0;

161
	node = tipc_node_find(net, dnode);
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
	if (!node) {
		pr_warn("Connecting sock to node 0x%x failed\n", dnode);
		return -EHOSTUNREACH;
	}
	conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
	if (!conn)
		return -EHOSTUNREACH;
	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);
	return 0;
}

179
void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port)
180 181 182 183
{
	struct tipc_node *node;
	struct tipc_sock_conn *conn, *safe;

184
	if (in_own_node(net, dnode))
185 186
		return;

187
	node = tipc_node_find(net, dnode);
188 189 190 191 192 193 194 195 196 197 198 199 200
	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);
}

201
void tipc_node_abort_sock_conns(struct net *net, struct list_head *conns)
202
{
203
	struct tipc_net *tn = net_generic(net, tipc_net_id);
204 205 206 207
	struct tipc_sock_conn *conn, *safe;
	struct sk_buff *buf;

	list_for_each_entry_safe(conn, safe, conns, list) {
208 209 210 211 212
		buf = tipc_msg_create(net, 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);
213
		if (likely(buf))
214
			tipc_sk_rcv(net, buf);
215 216 217 218 219
		list_del(&conn->list);
		kfree(conn);
	}
}

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

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

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

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

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

269
	active[0] = active[1] = NULL;
P
Per Liden 已提交
270 271

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

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

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

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

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

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

	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);
314
	if (tipc_node_is_up(n_ptr))
315
		tipc_link_failover_send_queue(l_ptr);
316
	else
P
Per Liden 已提交
317
		node_lost_contact(n_ptr);
318 319 320 321 322 323 324 325 326

	/* Leave room for changeover header when returning 'mtu' to users: */
	if (active[0]) {
		n_ptr->act_mtus[0] = active[0]->max_pkt - INT_H_SIZE;
		n_ptr->act_mtus[1] = active[1]->max_pkt - INT_H_SIZE;
		return;
	}

	/* Loopback link went down? No fragmentation needed from now on. */
327
	if (n_ptr->addr == tn->own_addr) {
328 329 330
		n_ptr->act_mtus[0] = MAX_MSG_SIZE;
		n_ptr->act_mtus[1] = MAX_MSG_SIZE;
	}
P
Per Liden 已提交
331 332
}

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

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

343
void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
P
Per Liden 已提交
344
{
345 346
	struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);

347
	n_ptr->links[l_ptr->bearer_id] = l_ptr;
348 349 350
	spin_lock_bh(&tn->node_list_lock);
	tn->num_links++;
	spin_unlock_bh(&tn->node_list_lock);
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
	struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
357 358 359
	int i;

	for (i = 0; i < MAX_BEARERS; i++) {
J
Jon Paul Maloy 已提交
360 361 362
		if (l_ptr != n_ptr->links[i])
			continue;
		n_ptr->links[i] = NULL;
363 364 365
		spin_lock_bh(&tn->node_list_lock);
		tn->num_links--;
		spin_unlock_bh(&tn->node_list_lock);
J
Jon Paul Maloy 已提交
366
		n_ptr->link_cnt--;
367
	}
P
Per Liden 已提交
368 369
}

370
static void node_established_contact(struct tipc_node *n_ptr)
P
Per Liden 已提交
371
{
Y
Ying Xue 已提交
372
	n_ptr->action_flags |= TIPC_NOTIFY_NODE_UP;
373
	n_ptr->bclink.oos_state = 0;
374 375
	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 已提交
376 377
}

378
static void node_lost_contact(struct tipc_node *n_ptr)
P
Per Liden 已提交
379 380 381 382
{
	char addr_string[16];
	u32 i;

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) {
388
		__skb_queue_purge(&n_ptr->bclink.deferred_queue);
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 402

	/* Abort link changeover */
	for (i = 0; i < MAX_BEARERS; i++) {
403
		struct tipc_link *l_ptr = n_ptr->links[i];
404
		if (!l_ptr)
P
Per Liden 已提交
405 406 407
			continue;
		l_ptr->reset_checkpoint = l_ptr->next_in_no;
		l_ptr->exp_msg_count = 0;
408
		tipc_link_reset_fragments(l_ptr);
409 410 411 412

		/* Link marked for deletion after failover? => do it now */
		if (l_ptr->flags & LINK_STOPPED)
			tipc_link_delete(l_ptr);
P
Per Liden 已提交
413 414
	}

415 416
	n_ptr->action_flags &= ~TIPC_WAIT_OWN_LINKS_DOWN;

417 418 419
	/* Notify subscribers and prevent re-contact with node until
	 * cleanup is done.
	 */
420 421
	n_ptr->action_flags |= TIPC_WAIT_PEER_LINKS_DOWN |
			       TIPC_NOTIFY_NODE_DOWN;
P
Per Liden 已提交
422 423
}

424 425
struct sk_buff *tipc_node_get_nodes(struct net *net, const void *req_tlv_area,
				    int req_tlv_space)
P
Per Liden 已提交
426
{
427
	struct tipc_net *tn = net_generic(net, tipc_net_id);
P
Per Liden 已提交
428 429
	u32 domain;
	struct sk_buff *buf;
430
	struct tipc_node *n_ptr;
431
	struct tipc_node_info node_info;
432
	u32 payload_size;
P
Per Liden 已提交
433 434

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
435
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
P
Per Liden 已提交
436

A
Al Viro 已提交
437
	domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
438 439 440
	if (!tipc_addr_domain_valid(domain))
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (network address)");
P
Per Liden 已提交
441

442 443 444
	spin_lock_bh(&tn->node_list_lock);
	if (!tn->num_nodes) {
		spin_unlock_bh(&tn->node_list_lock);
445
		return tipc_cfg_reply_none();
446
	}
P
Per Liden 已提交
447

448
	/* For now, get space for all other nodes */
449
	payload_size = TLV_SPACE(sizeof(node_info)) * tn->num_nodes;
450
	if (payload_size > 32768u) {
451
		spin_unlock_bh(&tn->node_list_lock);
452 453
		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
						   " (too many nodes)");
454
	}
455
	spin_unlock_bh(&tn->node_list_lock);
456

457
	buf = tipc_cfg_reply_alloc(payload_size);
458
	if (!buf)
P
Per Liden 已提交
459 460 461
		return NULL;

	/* Add TLVs for all nodes in scope */
462
	rcu_read_lock();
463
	list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {
464
		if (!tipc_in_scope(domain, n_ptr->addr))
P
Per Liden 已提交
465
			continue;
466 467 468
		node_info.addr = htonl(n_ptr->addr);
		node_info.up = htonl(tipc_node_is_up(n_ptr));
		tipc_cfg_append_tlv(buf, TIPC_TLV_NODE_INFO,
469
				    &node_info, sizeof(node_info));
P
Per Liden 已提交
470
	}
471
	rcu_read_unlock();
P
Per Liden 已提交
472 473 474
	return buf;
}

475 476
struct sk_buff *tipc_node_get_links(struct net *net, const void *req_tlv_area,
				    int req_tlv_space)
P
Per Liden 已提交
477
{
478
	struct tipc_net *tn = net_generic(net, tipc_net_id);
P
Per Liden 已提交
479 480
	u32 domain;
	struct sk_buff *buf;
481
	struct tipc_node *n_ptr;
482
	struct tipc_link_info link_info;
483
	u32 payload_size;
P
Per Liden 已提交
484 485

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
486
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
P
Per Liden 已提交
487

A
Al Viro 已提交
488
	domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
489 490 491
	if (!tipc_addr_domain_valid(domain))
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (network address)");
P
Per Liden 已提交
492

493
	if (!tn->own_addr)
494 495
		return tipc_cfg_reply_none();

496
	spin_lock_bh(&tn->node_list_lock);
497
	/* Get space for all unicast links + broadcast link */
498
	payload_size = TLV_SPACE((sizeof(link_info)) * (tn->num_links + 1));
499
	if (payload_size > 32768u) {
500
		spin_unlock_bh(&tn->node_list_lock);
501 502
		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
						   " (too many links)");
503
	}
504
	spin_unlock_bh(&tn->node_list_lock);
505

506
	buf = tipc_cfg_reply_alloc(payload_size);
507
	if (!buf)
P
Per Liden 已提交
508 509 510
		return NULL;

	/* Add TLV for broadcast link */
511
	link_info.dest = htonl(tipc_cluster_mask(tn->own_addr));
512
	link_info.up = htonl(1);
513
	strlcpy(link_info.str, tipc_bclink_name, TIPC_MAX_LINK_NAME);
514
	tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
P
Per Liden 已提交
515 516

	/* Add TLVs for any other links in scope */
517
	rcu_read_lock();
518
	list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {
519
		u32 i;
P
Per Liden 已提交
520

521
		if (!tipc_in_scope(domain, n_ptr->addr))
P
Per Liden 已提交
522
			continue;
523
		tipc_node_lock(n_ptr);
524 525 526 527 528 529 530
		for (i = 0; i < MAX_BEARERS; i++) {
			if (!n_ptr->links[i])
				continue;
			link_info.dest = htonl(n_ptr->addr);
			link_info.up = htonl(tipc_link_is_up(n_ptr->links[i]));
			strcpy(link_info.str, n_ptr->links[i]->name);
			tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO,
531
					    &link_info, sizeof(link_info));
532
		}
533
		tipc_node_unlock(n_ptr);
P
Per Liden 已提交
534
	}
535
	rcu_read_unlock();
P
Per Liden 已提交
536 537
	return buf;
}
E
Erik Hugne 已提交
538 539 540 541 542 543 544 545 546 547

/**
 * 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
 */
548 549
int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 addr,
			   char *linkname, size_t len)
E
Erik Hugne 已提交
550 551
{
	struct tipc_link *link;
552
	struct tipc_node *node = tipc_node_find(net, addr);
E
Erik Hugne 已提交
553

E
Erik Hugne 已提交
554
	if ((bearer_id >= MAX_BEARERS) || !node)
E
Erik Hugne 已提交
555 556 557 558 559 560 561 562 563 564 565
		return -EINVAL;
	tipc_node_lock(node);
	link = node->links[bearer_id];
	if (link) {
		strncpy(linkname, link->name, len);
		tipc_node_unlock(node);
		return 0;
	}
	tipc_node_unlock(node);
	return -EINVAL;
}
566 567 568

void tipc_node_unlock(struct tipc_node *node)
{
569
	struct net *net = node->net;
570
	LIST_HEAD(nsub_list);
571
	LIST_HEAD(conn_sks);
572
	struct sk_buff_head waiting_sks;
573
	u32 addr = 0;
Y
Ying Xue 已提交
574 575
	int flags = node->action_flags;
	u32 link_id = 0;
576

Y
Ying Xue 已提交
577
	if (likely(!flags)) {
578 579 580 581
		spin_unlock_bh(&node->lock);
		return;
	}

Y
Ying Xue 已提交
582 583
	addr = node->addr;
	link_id = node->link_id;
584
	__skb_queue_head_init(&waiting_sks);
Y
Ying Xue 已提交
585 586

	if (flags & TIPC_WAKEUP_USERS)
587
		skb_queue_splice_init(&node->waiting_sks, &waiting_sks);
Y
Ying Xue 已提交
588 589

	if (flags & TIPC_NOTIFY_NODE_DOWN) {
590
		list_replace_init(&node->publ_list, &nsub_list);
591
		list_replace_init(&node->conn_sks, &conn_sks);
592
	}
Y
Ying Xue 已提交
593 594 595 596 597
	node->action_flags &= ~(TIPC_WAKEUP_USERS | TIPC_NOTIFY_NODE_DOWN |
				TIPC_NOTIFY_NODE_UP | TIPC_NOTIFY_LINK_UP |
				TIPC_NOTIFY_LINK_DOWN |
				TIPC_WAKEUP_BCAST_USERS);

598 599
	spin_unlock_bh(&node->lock);

600
	while (!skb_queue_empty(&waiting_sks))
601
		tipc_sk_rcv(net, __skb_dequeue(&waiting_sks));
602

603
	if (!list_empty(&conn_sks))
604
		tipc_node_abort_sock_conns(net, &conn_sks);
605

606
	if (!list_empty(&nsub_list))
607
		tipc_publ_notify(net, &nsub_list, addr);
608

609
	if (flags & TIPC_WAKEUP_BCAST_USERS)
610
		tipc_bclink_wakeup_users(net);
611

Y
Ying Xue 已提交
612
	if (flags & TIPC_NOTIFY_NODE_UP)
613
		tipc_named_node_up(net, addr);
Y
Ying Xue 已提交
614 615

	if (flags & TIPC_NOTIFY_LINK_UP)
616
		tipc_nametbl_publish(net, TIPC_LINK_STATE, addr, addr,
Y
Ying Xue 已提交
617 618 619
				     TIPC_NODE_SCOPE, link_id, addr);

	if (flags & TIPC_NOTIFY_LINK_DOWN)
620
		tipc_nametbl_withdraw(net, TIPC_LINK_STATE, addr,
Y
Ying Xue 已提交
621
				      link_id, addr);
622
}
623 624

/* Caller should hold node lock for the passed node */
625
static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node)
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
{
	void *hdr;
	struct nlattr *attrs;

	hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family,
			  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;
661 662
	struct net *net = sock_net(skb->sk);
	struct tipc_net *tn = net_generic(net, tipc_net_id);
663 664 665 666 667 668 669 670 671 672 673 674 675 676
	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();

677
	if (last_addr && !tipc_node_find(net, last_addr)) {
678 679 680 681 682 683 684 685 686 687 688
		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;
	}

689
	list_for_each_entry_rcu(node, &tn->node_list, list) {
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
		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;
}